Skip to content

Conversation

@AliAlimohammadi
Copy link
Contributor

@AliAlimohammadi AliAlimohammadi commented Jan 7, 2026

Description

This PR adds an implementation of Base32 encoding and decoding to the ciphers module. Base32 is a binary-to-text encoding scheme that represents binary data using 32 ASCII characters (A-Z and 2-7), following RFC 4648 specifications.

Implementation Details

The implementation provides two public functions:

1. base32_encode(data: &[u8]) -> Vec<u8>

  • Encodes arbitrary binary data into base32 format
  • Uses the standard alphabet: A-Z and 2-7 (32 characters total)
  • Each 5 bits of input maps to one base32 character
  • Output is padded with '=' to make length a multiple of 8
  • Returns Vec for consistency with other encoding functions
  • Time Complexity: $O(n)$ where $n$ is the number of input bytes
  • Space Complexity: $O(n)$ for the output (approximately 1.6x input size)

2. base32_decode(data: &[u8]) -> Result<Vec<u8>, String>

  • Decodes base32-encoded data back to binary
  • Handles both padded and unpadded input
  • Validates input characters against the base32 alphabet
  • Returns Result with descriptive error messages
  • Time Complexity: $O(n)$ where $n$ is the length of input
  • Space Complexity: $O(n)$ for the output (approximately 0.625x input size)

Algorithm Details

  • Character Set: A-Z (26 letters) + 2-7 (6 digits) = 32 characters
  • Encoding: Groups of 5 bits → one base32 character
  • Padding: '=' characters added to make output length multiple of 8
  • RFC Compliance: Follows RFC 4648 standard base32 alphabet
  • Case Sensitivity: Uses uppercase only (standard alphabet)
  • Efficiency: Uses write! macro instead of format! for better performance

Use Cases

Base32 is commonly used when:

  • Case-insensitive encoding is needed
  • Avoiding confusing characters (0/O, 1/l/I) is important
  • Human-readable encoding is desired (e.g., backup codes, file names)
  • Double-clicking should select the entire string

Changes Made

  • ✅ Added src/ciphers/base32.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
    • Single character encoding
    • Various padding scenarios (0-5 padding characters)
    • Long strings and complex data
    • Binary data with all byte values
    • Input with and without padding
    • Invalid character detection
    • All charset characters
    • Edge cases
  • ✅ Added detailed documentation with examples for all public functions
  • ✅ Included doctests demonstrating usage
  • ✅ Optimized for performance (uses write! instead of format!)
  • ✅ Zero clippy warnings

Type of Change

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

Test Coverage

  • ✅ Basic encoding: b"Hello World!"b"JBSWY3DPEBLW64TMMQQQ===="
  • ✅ Basic decoding: b"JBSWY3DPEBLW64TMMQQQ====""b"Hello World!"
  • ✅ Numbers: b"123456"b"GEZDGNBVGY======"
  • ✅ Long strings: b"some long complex string"b"ONXW2ZJANRXW4ZZAMNXW24DMMV4CA43UOJUW4ZY="
  • ✅ Round-trip verification for various strings
  • ✅ Empty input handling
  • ✅ Single character encoding/decoding
  • ✅ Padding variations (f, fo, foo, foob, fooba, foobar)
  • ✅ Binary data encoding
  • ✅ Decoding without padding
  • ✅ Invalid character detection
  • ✅ All charset characters coverage
  • ✅ Doctests for public API

Examples

use the_algorithms_rust::ciphers::{base32_encode, base32_decode};

// Basic encoding
let encoded = base32_encode(b"Hello World!");
assert_eq!(encoded, b"JBSWY3DPEBLW64TMMQQQ====");

// Basic decoding
let decoded = base32_decode(b"JBSWY3DPEBLW64TMMQQQ====").unwrap();
assert_eq!(decoded, b"Hello World!");

// Decoding works with or without padding
let decoded = base32_decode(b"JBSWY3DPEBLW64TMMQQQ").unwrap();
assert_eq!(decoded, b"Hello World!");

// Round-trip encoding
let original = b"some long complex string";
let encoded = base32_encode(original);
let decoded = base32_decode(&encoded).unwrap();
assert_eq!(decoded, original);

// Error handling - invalid characters
match base32_decode(b"INVALID!@#$") {
    Err(e) => println!("Error: {}", e), // "Invalid base32 character: !"
    Ok(_) => unreachable!(),
}

// Binary data
let binary = vec![0x00, 0x01, 0x02, 0xFF, 0xFE, 0xFD];
let encoded = base32_encode(&binary);
let decoded = base32_decode(&encoded).unwrap();
assert_eq!(decoded, binary);

// Different padding lengths
assert_eq!(base32_encode(b"f"), b"MY======");      // 6 padding chars
assert_eq!(base32_encode(b"fo"), b"MZXQ====");     // 4 padding chars
assert_eq!(base32_encode(b"foo"), b"MZXW6===");    // 3 padding chars
assert_eq!(base32_encode(b"foob"), b"MZXW6YQ=");   // 1 padding char
assert_eq!(base32_encode(b"fooba"), b"MZXW6YTB");  // 0 padding chars

Performance Optimizations

  • Uses write! macro instead of format! in loops (avoids intermediate allocations)
  • Pre-allocates strings with known capacity
  • Uses is_multiple_of() for clearer intent
  • Single-pass encoding and decoding
  • Efficient chunk processing

Code Quality

  • ✅ Zero clippy warnings (including pedantic lints)
  • ✅ Idiomatic Rust code
  • ✅ Comprehensive error handling
  • ✅ Clear, descriptive error messages
  • ✅ Detailed inline comments
  • ✅ Extensive rustdoc documentation
  • ✅ Follows repository 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 4648 specifications

@codecov-commenter
Copy link

codecov-commenter commented Jan 7, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.93%. Comparing base (9ec7535) to head (7b5a337).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #991      +/-   ##
==========================================
+ Coverage   95.86%   95.93%   +0.06%     
==========================================
  Files         360      361       +1     
  Lines       24476    24613     +137     
==========================================
+ Hits        23465    23613     +148     
+ Misses       1011     1000      -11     

☔ 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.

@AliAlimohammadi
Copy link
Contributor Author

@siriak, this is ready to be merged.

@siriak siriak merged commit f92b944 into TheAlgorithms:master Jan 7, 2026
7 checks passed
@AliAlimohammadi AliAlimohammadi deleted the add-base32-cipher branch January 7, 2026 22:46
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