refactor(cipher-core): extract shared block parsing logic

Add generic BlockInt trait and parse_block_int<T>() function to
cipher-core, eliminating duplicate parsing code in aes and des crates.
    - BlockInt trait abstracts over u64/u128 integer types
    - Supports hex (0x), binary (0b), and ASCII string formats
    - Improved BlockError::InvalidByteStringLength with max/actual fields
This commit is contained in:
2025-12-30 23:55:52 +02:00
parent 656e112d9f
commit 451986d702
5 changed files with 120 additions and 112 deletions

View File

@@ -2,7 +2,7 @@ use crate::{
block::{Block32, secret_block},
sbox::SboxLookup,
};
use cipher_core::{BlockError, InputBlock};
use cipher_core::{parse_block_int, BlockError, InputBlock};
use std::{
ops::BitXor,
slice::{from_raw_parts, from_raw_parts_mut},
@@ -68,63 +68,10 @@ impl Block128 {
impl FromStr for Block128 {
type Err = BlockError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(Self(parse_string_to_u128(s)?))
Ok(Self(parse_block_int(s)?))
}
}
fn parse_string_to_u128(s: &str) -> Result<u128, BlockError> {
let trimmed = s.trim();
if trimmed.is_empty() {
return Err(BlockError::EmptyBlock);
}
// Hexadecimal with 0x/0X prefix
if let Some(hex_str) = trimmed
.strip_prefix("0x")
.or_else(|| trimmed.strip_prefix("0X"))
{
return parse_radix(hex_str, 16);
}
// Binary with 0b/0B prefix
if let Some(bin_str) = trimmed
.strip_prefix("0b")
.or_else(|| trimmed.strip_prefix("0B"))
{
return parse_radix(bin_str, 2);
}
ascii_string_to_u128(trimmed)
}
fn parse_radix(s: &str, radix: u32) -> Result<u128, BlockError> {
let trimmed = s.trim_start_matches('0');
if trimmed.is_empty() {
return Ok(0);
}
u128::from_str_radix(trimmed, radix).map_err(BlockError::from)
}
fn ascii_string_to_u128(s: &str) -> Result<u128, BlockError> {
if s.len() > 16 {
return Err(BlockError::InvalidByteStringLength(s.len()));
}
if !s.is_ascii() {
return Err(BlockError::conversion_error(
"u64",
"String contains non-ASCII characters",
));
}
let mut bytes = [0u8; 16];
let offset = 16 - s.len();
bytes[offset..].copy_from_slice(s.as_bytes());
Ok(u128::from_be_bytes(bytes))
}
impl From<[u8; 16]> for Block128 {
fn from(bytes: [u8; 16]) -> Self {
Self::from_be_bytes(bytes)