diff options
Diffstat (limited to 'vendor/crypto-bigint/src/uint/encoding.rs')
-rw-r--r-- | vendor/crypto-bigint/src/uint/encoding.rs | 278 |
1 files changed, 278 insertions, 0 deletions
diff --git a/vendor/crypto-bigint/src/uint/encoding.rs b/vendor/crypto-bigint/src/uint/encoding.rs new file mode 100644 index 000000000..a83976238 --- /dev/null +++ b/vendor/crypto-bigint/src/uint/encoding.rs @@ -0,0 +1,278 @@ +//! Const-friendly decoding operations for [`UInt`] + +#[cfg(all(feature = "der", feature = "generic-array"))] +mod der; + +#[cfg(feature = "rlp")] +mod rlp; + +use super::UInt; +use crate::{Encoding, Limb, Word}; + +impl<const LIMBS: usize> UInt<LIMBS> { + /// Create a new [`UInt`] from the provided big endian bytes. + pub const fn from_be_slice(bytes: &[u8]) -> Self { + assert!( + bytes.len() == Limb::BYTE_SIZE * LIMBS, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTE_SIZE]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTE_SIZE { + buf[j] = bytes[i * Limb::BYTE_SIZE + j]; + j += 1; + } + res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); + i += 1; + } + + UInt::new(res) + } + + /// Create a new [`UInt`] from the provided big endian hex string. + pub const fn from_be_hex(hex: &str) -> Self { + let bytes = hex.as_bytes(); + + assert!( + bytes.len() == Limb::BYTE_SIZE * LIMBS * 2, + "hex string is not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTE_SIZE]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTE_SIZE { + let offset = (i * Limb::BYTE_SIZE + j) * 2; + buf[j] = decode_hex_byte([bytes[offset], bytes[offset + 1]]); + j += 1; + } + res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf)); + i += 1; + } + + UInt::new(res) + } + + /// Create a new [`UInt`] from the provided little endian bytes. + pub const fn from_le_slice(bytes: &[u8]) -> Self { + assert!( + bytes.len() == Limb::BYTE_SIZE * LIMBS, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTE_SIZE]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTE_SIZE { + buf[j] = bytes[i * Limb::BYTE_SIZE + j]; + j += 1; + } + res[i] = Limb(Word::from_le_bytes(buf)); + i += 1; + } + + UInt::new(res) + } + + /// Create a new [`UInt`] from the provided little endian hex string. + pub const fn from_le_hex(hex: &str) -> Self { + let bytes = hex.as_bytes(); + + assert!( + bytes.len() == Limb::BYTE_SIZE * LIMBS * 2, + "bytes are not the expected size" + ); + + let mut res = [Limb::ZERO; LIMBS]; + let mut buf = [0u8; Limb::BYTE_SIZE]; + let mut i = 0; + + while i < LIMBS { + let mut j = 0; + while j < Limb::BYTE_SIZE { + let offset = (i * Limb::BYTE_SIZE + j) * 2; + buf[j] = decode_hex_byte([bytes[offset], bytes[offset + 1]]); + j += 1; + } + res[i] = Limb(Word::from_le_bytes(buf)); + i += 1; + } + + UInt::new(res) + } + + /// Serialize this [`UInt`] as big-endian, writing it into the provided + /// byte slice. + #[inline] + #[cfg_attr(docsrs, doc(cfg(feature = "generic-array")))] + pub(crate) fn write_be_bytes(&self, out: &mut [u8]) { + debug_assert_eq!(out.len(), Limb::BYTE_SIZE * LIMBS); + + for (src, dst) in self + .limbs + .iter() + .rev() + .cloned() + .zip(out.chunks_exact_mut(Limb::BYTE_SIZE)) + { + dst.copy_from_slice(&src.to_be_bytes()); + } + } + + /// Serialize this [`UInt`] as little-endian, writing it into the provided + /// byte slice. + #[inline] + #[cfg_attr(docsrs, doc(cfg(feature = "generic-array")))] + pub(crate) fn write_le_bytes(&self, out: &mut [u8]) { + debug_assert_eq!(out.len(), Limb::BYTE_SIZE * LIMBS); + + for (src, dst) in self + .limbs + .iter() + .cloned() + .zip(out.chunks_exact_mut(Limb::BYTE_SIZE)) + { + dst.copy_from_slice(&src.to_le_bytes()); + } + } +} + +/// Decode a single byte encoded as two hexadecimal characters. +const fn decode_hex_byte(bytes: [u8; 2]) -> u8 { + let mut i = 0; + let mut result = 0u8; + + while i < 2 { + result <<= 4; + result |= match bytes[i] { + b @ b'0'..=b'9' => b - b'0', + b @ b'a'..=b'f' => 10 + b - b'a', + b @ b'A'..=b'F' => 10 + b - b'A', + b => { + assert!( + matches!(b, b'0'..=b'9' | b'a' ..= b'f' | b'A'..=b'F'), + "invalid hex byte" + ); + 0 + } + }; + + i += 1; + } + + result +} + +#[cfg(test)] +mod tests { + use crate::Limb; + use hex_literal::hex; + + #[cfg(feature = "alloc")] + use {crate::U128, alloc::format}; + + #[cfg(target_pointer_width = "32")] + use crate::U64 as UIntEx; + + #[cfg(target_pointer_width = "64")] + use crate::U128 as UIntEx; + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_be_slice() { + let bytes = hex!("0011223344556677"); + let n = UIntEx::from_be_slice(&bytes); + assert_eq!(n.limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_be_slice() { + let bytes = hex!("00112233445566778899aabbccddeeff"); + let n = UIntEx::from_be_slice(&bytes); + assert_eq!( + n.limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_le_slice() { + let bytes = hex!("7766554433221100"); + let n = UIntEx::from_le_slice(&bytes); + assert_eq!(n.limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_le_slice() { + let bytes = hex!("ffeeddccbbaa99887766554433221100"); + let n = UIntEx::from_le_slice(&bytes); + assert_eq!( + n.limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_be_hex() { + let n = UIntEx::from_be_hex("0011223344556677"); + assert_eq!(n.limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_be_hex() { + let n = UIntEx::from_be_hex("00112233445566778899aabbccddeeff"); + assert_eq!( + n.limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[test] + #[cfg(target_pointer_width = "32")] + fn from_le_hex() { + let n = UIntEx::from_le_hex("7766554433221100"); + assert_eq!(n.limbs(), &[Limb(0x44556677), Limb(0x00112233)]); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn from_le_hex() { + let n = UIntEx::from_le_hex("ffeeddccbbaa99887766554433221100"); + assert_eq!( + n.limbs(), + &[Limb(0x8899aabbccddeeff), Limb(0x0011223344556677)] + ); + } + + #[cfg(feature = "alloc")] + #[test] + fn hex_upper() { + let hex = "AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDD"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, format!("{:X}", n)); + } + + #[cfg(feature = "alloc")] + #[test] + fn hex_lower() { + let hex = "aaaaaaaabbbbbbbbccccccccdddddddd"; + let n = U128::from_be_hex(hex); + assert_eq!(hex, format!("{:x}", n)); + } +} |