#[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> {
pub const fn from_be_slice(bytes: &[u8]) -> Self {
assert!(
bytes.len() == Limb::BYTES * LIMBS,
"bytes are not the expected size"
);
let mut res = [Limb::ZERO; LIMBS];
let mut buf = [0u8; Limb::BYTES];
let mut i = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
buf[j] = bytes[i * Limb::BYTES + j];
j += 1;
}
res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf));
i += 1;
}
Uint::new(res)
}
pub const fn from_be_hex(hex: &str) -> Self {
let bytes = hex.as_bytes();
assert!(
bytes.len() == Limb::BYTES * LIMBS * 2,
"hex string is not the expected size"
);
let mut res = [Limb::ZERO; LIMBS];
let mut buf = [0u8; Limb::BYTES];
let mut i = 0;
let mut err = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
let offset = (i * Limb::BYTES + j) * 2;
let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]);
err |= byte_err;
buf[j] = result;
j += 1;
}
res[LIMBS - i - 1] = Limb(Word::from_be_bytes(buf));
i += 1;
}
assert!(err == 0, "invalid hex byte");
Uint::new(res)
}
pub const fn from_le_slice(bytes: &[u8]) -> Self {
assert!(
bytes.len() == Limb::BYTES * LIMBS,
"bytes are not the expected size"
);
let mut res = [Limb::ZERO; LIMBS];
let mut buf = [0u8; Limb::BYTES];
let mut i = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
buf[j] = bytes[i * Limb::BYTES + j];
j += 1;
}
res[i] = Limb(Word::from_le_bytes(buf));
i += 1;
}
Uint::new(res)
}
pub const fn from_le_hex(hex: &str) -> Self {
let bytes = hex.as_bytes();
assert!(
bytes.len() == Limb::BYTES * LIMBS * 2,
"bytes are not the expected size"
);
let mut res = [Limb::ZERO; LIMBS];
let mut buf = [0u8; Limb::BYTES];
let mut i = 0;
let mut err = 0;
while i < LIMBS {
let mut j = 0;
while j < Limb::BYTES {
let offset = (i * Limb::BYTES + j) * 2;
let (result, byte_err) = decode_hex_byte([bytes[offset], bytes[offset + 1]]);
err |= byte_err;
buf[j] = result;
j += 1;
}
res[i] = Limb(Word::from_le_bytes(buf));
i += 1;
}
assert!(err == 0, "invalid hex byte");
Uint::new(res)
}
#[inline]
pub(crate) fn write_be_bytes(&self, out: &mut [u8]) {
debug_assert_eq!(out.len(), Limb::BYTES * LIMBS);
for (src, dst) in self
.limbs
.iter()
.rev()
.cloned()
.zip(out.chunks_exact_mut(Limb::BYTES))
{
dst.copy_from_slice(&src.to_be_bytes());
}
}
#[inline]
pub(crate) fn write_le_bytes(&self, out: &mut [u8]) {
debug_assert_eq!(out.len(), Limb::BYTES * LIMBS);
for (src, dst) in self
.limbs
.iter()
.cloned()
.zip(out.chunks_exact_mut(Limb::BYTES))
{
dst.copy_from_slice(&src.to_le_bytes());
}
}
}
#[inline(always)]
const fn decode_nibble(src: u8) -> u16 {
let byte = src as i16;
let mut ret: i16 = -1;
ret += (((0x2fi16 - byte) & (byte - 0x3a)) >> 8) & (byte - 47);
ret += (((0x40i16 - byte) & (byte - 0x47)) >> 8) & (byte - 54);
ret += (((0x60i16 - byte) & (byte - 0x67)) >> 8) & (byte - 86);
ret as u16
}
#[inline(always)]
const fn decode_hex_byte(bytes: [u8; 2]) -> (u8, u16) {
let hi = decode_nibble(bytes[0]);
let lo = decode_nibble(bytes[1]);
let byte = (hi << 4) | lo;
let err = byte >> 8;
let result = byte as u8;
(result, err)
}
#[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.as_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.as_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.as_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.as_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.as_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.as_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.as_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.as_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));
}
}