From fd3ae7a5e989ab62e6c128f79f5ebfae972f7fac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Garillot?= Date: Wed, 28 Feb 2024 15:53:19 -0500 Subject: [PATCH] test: check field representations in used libraries --- src/gadgets/nonnative/util.rs | 40 ++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/src/gadgets/nonnative/util.rs b/src/gadgets/nonnative/util.rs index 61a60263c..22ed4f4a3 100644 --- a/src/gadgets/nonnative/util.rs +++ b/src/gadgets/nonnative/util.rs @@ -245,7 +245,7 @@ fn write_be(f: &F, mut writer: W) -> io::Result<()> { /// Convert a field element to a natural number pub fn f_to_nat(f: &Scalar) -> BigInt { let mut s = Vec::new(); - write_be(f, &mut s).unwrap(); // f.to_repr().write_be(&mut s).unwrap(); + write_be(f, &mut s).unwrap(); BigInt::from_bytes_le(Sign::Plus, f.to_repr().as_ref()) } @@ -254,3 +254,41 @@ pub fn f_to_nat(f: &Scalar) -> BigInt { pub fn nat_to_f(n: &BigInt) -> Option { Scalar::from_str_vartime(&format!("{n}")) } + +#[cfg(test)] +mod tests { + use bitvec::field::BitField as _; + use ff::PrimeFieldBits; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + // the write_be function above assumes Field::to_repr() outputs a representation that's an instance + // of `AsRef<[u8]>` in lower endian. We test that here, as this is not what the I2OSP standard recommends + // and may change in some implementations. + fn test_repr_is_le_with() { + let mut rng = ChaCha20Rng::from_seed([0u8; 32]); + for _i in 0..50 { + let f = F::random(&mut rng); + // This is guaranteed to be in LE + let le_bits = f.to_le_bits(); + let leftmost_u64 = le_bits[..64].load_le::(); + + // This is not + let f_repr = f.to_repr(); + let bytes: [u8; 8] = f_repr.as_ref()[..8].try_into().unwrap(); + let u64_from_repr = u64::from_le_bytes(bytes); + + assert_eq!(leftmost_u64, u64_from_repr); + } + } + + #[test] + fn test_repr_is_le() { + test_repr_is_le_with::(); + test_repr_is_le_with::(); + test_repr_is_le_with::(); + test_repr_is_le_with::(); + test_repr_is_le_with::(); + test_repr_is_le_with::(); + } +}