Skip to content

Commit

Permalink
test
Browse files Browse the repository at this point in the history
  • Loading branch information
Oppen committed Nov 13, 2023
1 parent 14b58ff commit 65b1fef
Showing 1 changed file with 121 additions and 18 deletions.
139 changes: 121 additions & 18 deletions crates/starknet-types-core/src/felt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,20 +63,98 @@ impl Felt {
UnsignedInteger::from_limbs([544, 0, 0, 32]),
));

/// Creates a new [Felt] from its big-endian representation in a [u8] slice.
/// This is as performant as [from_bytes_le](Felt::from_bytes_le)
pub fn from_bytes_be(bytes: &[u8]) -> Result<Self, FromBytesError> {
FieldElement::from_bytes_be(bytes)
pub fn from_bytes_be(bytes: &[u8; 32]) -> Self {
FieldElement::from_bytes_be(&*bytes)
.map(Self)
.expect("from_bytes_be shouldn't fail for these many bytes")
}

pub fn from_bytes_le(bytes: &[u8; 32]) -> Self {
FieldElement::from_bytes_le(&*bytes)
.map(Self)
.map_err(|_| FromBytesError)
.expect("from_bytes_le shouldn't fail for these many bytes")
}

/// Creates a new [Felt] from its big-endian representation in a [u8] slice.
/// This is as performant as [from_bytes_le](Felt::from_bytes_le).
/// All bytes in the slice are consumed, as if first creating a big integer
/// from them, but the conversion is performed in constant space on the stack.
pub fn from_bytes_be_slice(bytes: &[u8]) -> Self {
// NB: lambdaworks ignores the remaining bytes when len > 32, so we loop.
const OVERFLOW: Felt = Self(FieldElement::from_hex_unchecked("1000000000000000000000000000000000000000000000000000000000000000"));
println!("OF={OVERFLOW:x}");

let mut factor = Self::ONE;
let mut res = Self::ZERO;
let chunks = bytes.rchunks_exact(32);
let remainder = chunks.remainder();

for chunk in chunks {
let digit = Self::from_bytes_be(&chunk.try_into().expect("conversion to same-sized array"));
println!("d={digit:x} f={factor:x}");
res += digit * factor;
factor *= OVERFLOW;
}

if remainder.is_empty() {
println!("r={res:x}");
return res;
}

let mut remainder = remainder.iter().rev().cloned();
let buf: [u8; 32] = core::array::from_fn(|_| remainder.next().unwrap_or_default());
println!("buf={buf:?}");
let digit = Self::from_bytes_le(&buf);
println!("d={digit:x} f={factor:x}");
res += digit * factor;

println!("r={res:x}");
res
}

/// Creates a new [Felt] from its little-endian representation in a [u8] slice.
/// This is as performant as [from_bytes_be](Felt::from_bytes_be)
pub fn from_bytes_le(bytes: &[u8]) -> Result<Self, FromBytesError> {
FieldElement::from_bytes_le(bytes)
/// This is as performant as [from_bytes_be](Felt::from_bytes_be).
/// All bytes in the slice are consumed, as if first creating a big integer
/// from them, but the conversion is performed in constant space on the stack.
pub fn from_bytes_le_slice(bytes: &[u8]) -> Self {
// NB: lambdaworks ignores the remaining bytes when len > 32, so we loop.
const OVERFLOW: Felt = Self(FieldElement::from_hex_unchecked("1000000000000000000000000000000000000000000000000000000000000000"));

let mut factor = Self::ONE;
let mut res = Self::ZERO;
let chunks = bytes.chunks_exact(32);
let remainder = chunks.remainder();

for chunk in chunks {
let digit = Self::from_bytes_le(&chunk.try_into().expect("conversion to same-sized array"));
res += digit * factor;
factor *= OVERFLOW;
}

if remainder.is_empty() {
return res;
}

let mut remainder = remainder.iter().cloned();
let buf: [u8; 32] = core::array::from_fn(|_| remainder.next().unwrap_or_default());
let digit = Self::from_bytes_le(&buf);
res += digit * factor;

res
/*
// XXX: temporary hack: copy to a long-enough buffer to ensure `from_bytes_le`
// never fails; this logic will be moved to `from_bytes_le` itself, with an
// alternative implementation expecting the right size if needed.
const BUFLEN: usize = core::mem::size_of::<Felt>();
const ZEROES: [u8; BUFLEN] = [0; BUFLEN];
let buf = [
&bytes[..BUFLEN.min(bytes.len())],
&ZEROES[..BUFLEN.saturating_sub(bytes.len())],
].concat();
FieldElement::from_bytes_le(&buf)
.map(Self)
.map_err(|_| FromBytesError)
.expect("from_bytes_le shouldn't fail for these many bytes")
*/
}

/// Converts to big-endian byte representation in a [u8] array.
Expand Down Expand Up @@ -835,24 +913,24 @@ mod test {

proptest! {
#[test]
fn new_in_range(ref x in any::<[u8; 40]>()) {
let x_be = Felt::from_bytes_be(x).unwrap();
fn new_in_range(ref x in any::<[u8; 32]>()) {
let x_be = Felt::from_bytes_be(x);
prop_assert!(x_be < Felt::MAX);
let x_le = Felt::from_bytes_le(x).unwrap();
let x_le = Felt::from_bytes_le(x);
prop_assert!(x_le < Felt::MAX);
}

#[test]
fn to_be_bytes(ref x in any::<Felt>()) {
let bytes = x.to_bytes_be();
let y = &Felt::from_bytes_be(&bytes).unwrap();
let y = &Felt::from_bytes_be(&bytes);
prop_assert_eq!(x, y);
}

#[test]
fn to_le_bytes(ref x in any::<Felt>()) {
let bytes = x.to_bytes_le();
let y = &Felt::from_bytes_le(&bytes).unwrap();
let y = &Felt::from_bytes_le(&bytes);
prop_assert_eq!(x, y);
}

Expand All @@ -869,7 +947,7 @@ mod test {
res[i] = acc;
acc = 0;
}
let y = &Felt::from_bytes_be(&res).unwrap();
let y = &Felt::from_bytes_be(&res);
prop_assert_eq!(x, y);
}

Expand All @@ -893,13 +971,38 @@ mod test {
bytes[(3 - i) * 8 + j] = limb_bytes[j]
}
}
let y = &Felt::from_bytes_le(&bytes).unwrap();
let y = &Felt::from_bytes_le(&bytes);
prop_assert_eq!(x, y);
}

#[test]
fn from_bytes_be_in_range(ref x in any::<[u8; 40]>()) {
let x = Felt::from_bytes_be(x).unwrap();
fn from_bytes_le_slice_works_for_all_lengths(x in 0..99usize) {
let mut bytes = [0u8; 100];
bytes[0] = 1;
let expected = match x {
0 => Felt::ZERO,
_ => Felt::ONE,
};
let x = Felt::from_bytes_le_slice(&bytes[0..x]);
prop_assert_eq!(x, expected);
}

#[test]
fn from_bytes_be_slice_works_for_all_lengths(x in 0..100usize) {
let mut bytes = [0u8; 100];
bytes[0] = 1;
let expected = match x {
0 => Felt::ZERO,
x => Felt::TWO.pow(8 * (x - 1) as u32),
};
println!("{}", 8 * (x - 1));
let x = Felt::from_bytes_be_slice(&bytes[0..x]);
prop_assert_eq!(x, expected, "x={:x} expected={:x}", x, expected);
}

#[test]
fn from_bytes_be_in_range(ref x in any::<[u8; 32]>()) {
let x = Felt::from_bytes_be(x);
prop_assert!(x <= Felt::MAX);
}

Expand Down

0 comments on commit 65b1fef

Please sign in to comment.