Skip to content

Conversation

@AliAlimohammadi
Copy link
Contributor

@AliAlimohammadi AliAlimohammadi commented Jan 7, 2026

Description

This PR adds an implementation of Base16 encoding (also known as hexadecimal encoding) to the ciphers module. Base16 is a binary-to-text encoding scheme that represents binary data using 16 ASCII characters (0-9 and A-F), following RFC 3548 Section 6 specifications.

Implementation Details

The implementation provides two public functions:

1. base16_encode(data: &[u8]) -> String

  • Encodes arbitrary binary data into uppercase hexadecimal format
  • Each byte is represented by exactly two hexadecimal characters
  • Uses efficient fold + write! pattern for optimal performance
  • Returns uppercase string (0-9, A-F)
  • Time Complexity: $O(n)$ where n is the number of input bytes
  • Space Complexity: $O(n)$ for the output string (2 chars per byte)

2. base16_decode(data: &str) -> Result<Vec<u8>, String>

  • Decodes base16-encoded string back to binary data
  • Validates input according to RFC 3548 Section 6:
    • Must contain even number of characters
    • Must only contain uppercase hexadecimal characters (0-9, A-F)
    • Rejects lowercase hex characters (a-f)
  • Returns Result with detailed error messages for invalid input
  • Time Complexity: $O(n)$ where n is the length of the input string
  • Space Complexity: $O(n)$ for the output bytes

Algorithm Details

  • Character Set: Uppercase hexadecimal (0-9, A-F)
  • Encoding: Each byte → two hex characters (e.g., 0x48"48")
  • RFC Compliance: Follows RFC 3548 Section 6 (uppercase requirement)
  • Validation: Strict input validation with clear error messages
  • Error Handling: Returns Result<Vec<u8>, String> for decoding
  • Performance: Single-pass encoding/decoding with no intermediate allocations

RFC 3548 Compliance

This implementation strictly follows RFC 3548 Section 6, which specifies:

  • Base16 alphabet uses uppercase letters (A-F, not a-f)
  • Encoded data must have an even number of characters
  • Each pair of characters represents one byte of data

Changes Made

  • ✅ Added src/ciphers/base16.rs with complete implementation
  • ✅ Updated src/ciphers/mod.rs to include and export the new module
  • ✅ Implemented comprehensive unit tests covering:
    • Basic encoding and decoding
    • Round-trip encoding/decoding verification
    • Empty input handling
    • Special characters (null bytes, 0xFF)
    • All 256 possible byte values
    • Uppercase validation (rejects lowercase hex)
    • Odd-length input rejection
    • Invalid character rejection
  • ✅ Added detailed documentation with examples for all public functions
  • ✅ Included doctests demonstrating usage
  • ✅ Zero clippy warnings (passes pedantic and restriction lints)
  • ✅ Proper error handling with descriptive messages

Type of Change

  • ✅ New cipher/encoding implementation
  • ✅ Documentation (rustdoc comments and examples)
  • ✅ Comprehensive test suite (18 unit tests + 3 doctests)

Testing

All tests pass successfully:

cargo test base16
cargo test --doc base16
cargo fmt --check
cargo clippy -- -D warnings

Test Coverage

  • ✅ Basic encoding: b"Hello World!""48656C6C6F20576F726C6421"
  • ✅ Basic decoding: "48656C6C6F20576F726C6421"b"Hello World!"
  • ✅ Round-trip verification (encode → decode → original)
  • ✅ Empty input handling
  • ✅ Special characters (null bytes, 0xFF, etc.)
  • ✅ All 256 possible byte values
  • ✅ Uppercase-only validation (rejects lowercase a-f)
  • ✅ Odd-length input rejection with clear error message
  • ✅ Invalid character rejection
  • ✅ Mixed case rejection
  • ✅ Comprehensive edge cases
  • ✅ Doctests for public API with proper imports

Examples

use the_algorithms_rust::ciphers::{base16_encode, base16_decode};

// Basic encoding
let encoded = base16_encode(b"Hello World!");
assert_eq!(encoded, "48656C6C6F20576F726C6421");

// Basic decoding
let decoded = base16_decode("48656C6C6F20576F726C6421").unwrap();
assert_eq!(decoded, b"Hello World!");

// Round-trip encoding
let original = b"The quick brown fox";
let encoded = base16_encode(original);
let decoded = base16_decode(&encoded).unwrap();
assert_eq!(decoded, original);

// Error handling - odd length
match base16_decode("ABC") {
    Err(e) => println!("Error: {}", e), // "Data does not have an even number of hex digits."
    Ok(_) => unreachable!(),
}

// Error handling - lowercase hex (not RFC 3548 compliant)
match base16_decode("48656c6c6f") {
    Err(e) => println!("Error: {}", e), // "Data is not uppercase hex or it contains invalid characters."
    Ok(_) => unreachable!(),
}

// Error handling - invalid characters
match base16_decode("Hello!") {
    Err(e) => println!("Error: {}", e), // "Data is not uppercase hex or it contains invalid characters."
    Ok(_) => unreachable!(),
}

// Special characters and binary data
let data = vec![0x00, 0x01, 0xFF, 0xAB, 0xCD];
let encoded = base16_encode(&data);
assert_eq!(encoded, "0001FFABCD");
let decoded = base16_decode(&encoded).unwrap();
assert_eq!(decoded, data);

Code Quality

  • ✅ Zero clippy warnings (including pedantic and restriction lints)
  • ✅ Idiomatic Rust code using modern patterns
  • ✅ Efficient implementation with fold instead of map + collect
  • ✅ Inline format arguments for better readability
  • ✅ Uses is_multiple_of() for clearer intent
  • ✅ Proper Result handling with descriptive error messages
  • ✅ Comprehensive rustdoc documentation
  • ✅ Follows repository code style conventions

Checklist

  • ✅ My code follows the style guidelines of this project
  • ✅ I have performed a self-review of my own code
  • ✅ I have commented my code, particularly in hard-to-understand areas
  • ✅ I have made corresponding changes to the documentation
  • ✅ My changes generate no new warnings
  • ✅ I have added tests that prove my implementation is correct
  • ✅ New and existing unit tests pass locally with my changes
  • ✅ I have checked my code with cargo fmt
  • ✅ I have checked my code with cargo clippy
  • ✅ Any dependent changes have been merged and published
  • ✅ Doctests use correct import paths (public re-exports)
  • ✅ Implementation follows RFC 3548 Section 6 specifications

@AliAlimohammadi
Copy link
Contributor Author

@siriak, this is ready to be merged.

@codecov-commenter
Copy link

Codecov Report

❌ Patch coverage is 97.08738% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 95.91%. Comparing base (a82ee7d) to head (a1d76c2).

Files with missing lines Patch % Lines
src/ciphers/base16.rs 97.08% 3 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff            @@
##           master     #990    +/-   ##
========================================
  Coverage   95.90%   95.91%            
========================================
  Files         359      360     +1     
  Lines       24373    24476   +103     
========================================
+ Hits        23376    23476   +100     
- Misses        997     1000     +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@siriak siriak merged commit 9ec7535 into TheAlgorithms:master Jan 7, 2026
7 checks passed
@AliAlimohammadi AliAlimohammadi deleted the add-base16-cipher branch January 7, 2026 19:36
@AliAlimohammadi AliAlimohammadi changed the title feat: add base16 cipher implentation feat: add base16 cipher implementation Jan 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants