diff --git a/Cargo.toml b/Cargo.toml index 78224c68..193739d3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ bincode = "1.3.3" serde_json = "1.0.105" hex = "0.4" rand_chacha = "0.3.1" +impls = "1" # Added to make sure we are able to build the lib in the CI. # Notice this will never be loaded for someone using this lib as dep. diff --git a/src/bn256/fq.rs b/src/bn256/fq.rs index 23da849a..2a2ce01c 100644 --- a/src/bn256/fq.rs +++ b/src/bn256/fq.rs @@ -285,88 +285,79 @@ impl WithSmallOrderMulGroup<3> for Fq { #[cfg(test)] mod test { use super::*; - use crate::ff_ext::Legendre; - use ff::Field; - use rand_core::OsRng; - - #[test] - fn test_sqrt_fq() { - let v = (Fq::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); - - for _ in 0..10000 { - let a = Fq::random(OsRng); - let mut b = a; - b = b.square(); - assert_eq!(b.legendre(), 1); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - - let mut c = Fq::one(); - for _ in 0..10000 { - let mut b = c; - b = b.square(); - assert_eq!(b.legendre(), 1); - - b = b.sqrt().unwrap(); - - if b != c { - b = b.neg(); - } - - assert_eq!(b, c); - - c += &Fq::one(); - } - } - - #[test] - fn test_from_u512() { - assert_eq!( + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); + crate::field_testing_suite!( + Fq, + "from_uniform_bytes", + [ Fq::from_raw([ - 0x1f8905a172affa8a, - 0xde45ad177dcf3306, - 0xaaa7987907d73ae2, - 0x24d349431d468e30, + 0xd1f334151139642a, + 0xb0f28bcaa90fdb88, + 0x9a13255d88eca613, + 0x02afef300dd32d9a, ]), - Fq::from_u512([ - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa - ]) - ); - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("fq".to_string()); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("fq".to_string()); - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("fq".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("fq".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("fq".to_string()); - } + Fq::from_raw([ + 0x03cd906680808fbe, + 0xc28902db5aef5254, + 0x3dbdb406ae292ddf, + 0x276ec249e6b9e195 + ]), + Fq::from_raw([ + 0xb0e07ded189e91f7, + 0x9e3b0caae2b98899, + 0x49e511f19341fdcf, + 0x1ea71260f64b72da + ]), + Fq::from_raw([ + 0x61132be14bb978d4, + 0xe27e09a20808067b, + 0x3842cc8fd1d8406f, + 0x13163c8a13fd550b + ]), + Fq::from_raw([ + 0x04a6495a33d39ac5, + 0xc918e75bb383fae0, + 0x80068784d577b035, + 0x1dd962b86e44e1be + ]), + Fq::from_raw([ + 0x107ffeecf4cb3348, + 0x53a0adb5491a4944, + 0x50028f636ffcb780, + 0x0af7f3aa38015c1d + ]), + Fq::from_raw([ + 0x22513787342eba07, + 0x4fac22ed88770319, + 0x0b7c31082cc92b13, + 0x250e22a8cac6e790 + ]), + Fq::from_raw([ + 0x5954fd7dda014940, + 0x9df859b2124e66fa, + 0xaab48d94eadd9d14, + 0x2a9a75013e3da632 + ]), + Fq::from_raw([ + 0xedd59c88fee718de, + 0x2b034dcfe6de3844, + 0x76b0e2e360488694, + 0x068998ef20d62df1 + ]), + Fq::from_raw([ + 0xac161667911634a4, + 0x296c2f453152552f, + 0x2653625dfaa1cf74, + 0x171abf201a2587d7 + ]), + ] + ); } diff --git a/src/bn256/fq12.rs b/src/bn256/fq12.rs index 77bece1f..b77604d5 100644 --- a/src/bn256/fq12.rs +++ b/src/bn256/fq12.rs @@ -490,118 +490,23 @@ pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ ]; #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_fq12_mul_by_014() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fq2::random(&mut rng); - let c1 = Fq2::random(&mut rng); - let c5 = Fq2::random(&mut rng); - let mut a = Fq12::random(&mut rng); - let mut b = a; - - a.mul_by_014(&c0, &c1, &c5); - b.mul_assign(&Fq12 { - c0: Fq6 { - c0, - c1, - c2: Fq2::zero(), - }, - c1: Fq6 { - c0: Fq2::zero(), - c1: c5, - c2: Fq2::zero(), - }, - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fq12_mul_by_034() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fq2::random(&mut rng); - let c3 = Fq2::random(&mut rng); - let c4 = Fq2::random(&mut rng); - let mut a = Fq12::random(&mut rng); - let mut b = a; - - a.mul_by_034(&c0, &c3, &c4); - b.mul_assign(&Fq12 { - c0: Fq6 { - c0, - c1: Fq2::zero(), - c2: Fq2::zero(), - }, - c1: Fq6 { - c0: c3, - c1: c4, - c2: Fq2::zero(), - }, - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_squaring() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let mut a = Fq12::random(&mut rng); - let mut b = a; - b.mul_assign(&a); - a.square_assign(); - assert_eq!(a, b); - } -} - -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..100 { - for i in 0..14 { - let mut a = Fq12::random(&mut rng); - let mut b = a; - - for _ in 0..i { - a = a.pow_vartime([ - 0x3c208c16d87cfd47, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, - ]); - } - b.frobenius_map(i); - - assert_eq!(a, b); - } - } -} - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fq12".to_string()); +mod test { + use super::*; + crate::field_testing_suite!(Fq12, "field_arithmetic"); + // extension field-specific + crate::field_testing_suite!(Fq12, "f12_tests", Fq6, Fq2); + crate::field_testing_suite!( + Fq12, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fq::MODULUS) + [ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ] + ); } diff --git a/src/bn256/fq2.rs b/src/bn256/fq2.rs index 7325b21b..d5f25fca 100644 --- a/src/bn256/fq2.rs +++ b/src/bn256/fq2.rs @@ -418,6 +418,7 @@ impl From for Fq2 { } } +// This trait is only implemented to satisfy the requirement of CurveExt impl PrimeField for Fq2 { type Repr = Fq2Bytes; @@ -541,213 +542,79 @@ impl WithSmallOrderMulGroup<3> for Fq2 { } #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_ser() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let a0 = Fq2::random(&mut rng); - let a_bytes = a0.to_bytes(); - let a1 = Fq2::from_bytes(&a_bytes).unwrap(); - assert_eq!(a0, a1); -} - -#[test] -fn test_fq2_ordering() { - let mut a = Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }; - - let mut b = a; - - assert!(a.cmp(&b) == Ordering::Equal); - b.c0 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c0 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Equal); - b.c1 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c0 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c1 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Greater); - b.c0 += &Fq::one(); - assert!(a.cmp(&b) == Ordering::Equal); -} - -#[test] -fn test_fq2_basics() { - assert_eq!( - Fq2 { - c0: Fq::zero(), - c1: Fq::zero(), - }, - Fq2::ZERO +mod test { + use super::*; + crate::field_testing_suite!(Fq2, "field_arithmetic"); + crate::field_testing_suite!(Fq2, "conversion"); + crate::field_testing_suite!(Fq2, "serialization"); + crate::field_testing_suite!(Fq2, "quadratic_residue"); + crate::field_testing_suite!(Fq2, "sqrt"); + crate::field_testing_suite!(Fq2, "zeta", Fq); + // extension field-specific + crate::field_testing_suite!(Fq2, "f2_tests", Fq); + crate::field_testing_suite!( + Fq2, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fq::MODULUS) + [ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ] ); - assert_eq!( - Fq2 { + + #[test] + fn test_fq2_squaring() { + let mut a = Fq2 { c0: Fq::one(), - c1: Fq::zero(), - }, - Fq2::ONE - ); - assert_eq!(Fq2::ZERO.is_zero().unwrap_u8(), 1); - assert_eq!(Fq2::ONE.is_zero().unwrap_u8(), 0); - assert_eq!( - Fq2 { - c0: Fq::zero(), c1: Fq::one(), - } - .is_zero() - .unwrap_u8(), - 0 - ); -} + }; // u + 1 + a.square_assign(); + assert_eq!( + a, + Fq2 { + c0: Fq::zero(), + c1: Fq::one() + Fq::one(), + } + ); // 2u -#[test] -fn test_fq2_squaring() { - let mut a = Fq2 { - c0: Fq::one(), - c1: Fq::one(), - }; // u + 1 - a.square_assign(); - assert_eq!( - a, - Fq2 { + let mut a = Fq2 { c0: Fq::zero(), - c1: Fq::one() + Fq::one(), - } - ); // 2u - - let mut a = Fq2 { - c0: Fq::zero(), - c1: Fq::one(), - }; // u - a.square_assign(); - assert_eq!(a, { - let neg1 = -Fq::one(); - Fq2 { - c0: neg1, - c1: Fq::zero(), - } - }); // -1 -} - -#[test] -fn test_fq2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let nine = Fq::one().double().double().double() + Fq::one(); - let nqr = Fq2 { - c0: nine, - c1: Fq::one(), - }; - - for _ in 0..1000 { - let mut a = Fq2::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -pub fn test_sqrt() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..10000 { - let a = Fq2::random(&mut rng); - if a.legendre() == -1 { - assert!(bool::from(a.sqrt().is_none())); - } - } - - for _ in 0..10000 { - let a = Fq2::random(&mut rng); - let mut b = a; - b.square_assign(); - assert_eq!(b.legendre(), 1); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - - let mut c = Fq2::ONE; - for _ in 0..10000 { - let mut b = c; - b.square_assign(); - assert_eq!(b.legendre(), 1); - - b = b.sqrt().unwrap(); - - if b != c { - b = b.neg(); - } - - assert_eq!(b, c); - - c += &Fq2::ONE; - } -} - -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); + c1: Fq::one(), + }; // u + a.square_assign(); + assert_eq!(a, { + let neg1 = -Fq::one(); + Fq2 { + c0: neg1, + c1: Fq::zero(), + } + }); // -1 + } + + #[test] + fn test_fq2_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let nine = Fq::one().double().double().double() + Fq::one(); + let nqr = Fq2 { + c0: nine, + c1: Fq::one(), + }; - for _ in 0..100 { - for i in 0..14 { + for _ in 0..1000 { let mut a = Fq2::random(&mut rng); let mut b = a; - - for _ in 0..i { - a = a.pow([ - 0x3c208c16d87cfd47, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, - ]); - } - b.frobenius_map(i); + a.mul_by_nonresidue(); + b.mul_assign(&nqr); assert_eq!(a, b); } } } - -#[test] -fn test_zeta() { - let zeta = Fq2::new(Fq::ZETA.square(), Fq::zero()); - assert_eq!(zeta, Fq2::ZETA); -} - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fq2".to_string()); -} - -#[test] -fn test_serialization() { - crate::tests::field::random_serialization_test::("fq2".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("fq2".to_string()); -} diff --git a/src/bn256/fq6.rs b/src/bn256/fq6.rs index 8fc46578..de01d6c8 100644 --- a/src/bn256/fq6.rs +++ b/src/bn256/fq6.rs @@ -586,124 +586,23 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ ]; #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_fq6_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let nqr = Fq6 { - c0: Fq2::zero(), - c1: Fq2::one(), - c2: Fq2::zero(), - }; - - for _ in 0..1000 { - let mut a = Fq6::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fq6_mul_by_1() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c1 = Fq2::random(&mut rng); - let mut a = Fq6::random(&mut rng); - let mut b = a; - - a.mul_by_1(&c1); - b.mul_assign(&Fq6 { - c0: Fq2::zero(), - c1, - c2: Fq2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fq6_mul_by_01() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fq2::random(&mut rng); - let c1 = Fq2::random(&mut rng); - let mut a = Fq6::random(&mut rng); - let mut b = a; - - a.mul_by_01(&c0, &c1); - b.mul_assign(&Fq6 { - c0, - c1, - c2: Fq2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_squaring() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let mut a = Fq6::random(&mut rng); - let mut b = a; - b.mul_assign(&a); - a.square_assign(); - assert_eq!(a, b); - } -} - -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..100 { - for i in 0..14 { - let mut a = Fq6::random(&mut rng); - let mut b = a; - - for _ in 0..i { - a = a.pow_vartime([ - 0x3c208c16d87cfd47, - 0x97816a916871ca8d, - 0xb85045b68181585d, - 0x30644e72e131a029, - ]); - } - b.frobenius_map(i); - - assert_eq!(a, b); - } - } -} - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fq6".to_string()); +mod test { + use super::*; + crate::field_testing_suite!(Fq6, "field_arithmetic"); + // extension field-specific + crate::field_testing_suite!(Fq6, "f6_tests", Fq2); + crate::field_testing_suite!( + Fq6, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fq::MODULUS) + [ + 0x3c208c16d87cfd47, + 0x97816a916871ca8d, + 0xb85045b68181585d, + 0x30644e72e131a029, + ] + ); } diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index c256f488..96dab322 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -332,129 +332,87 @@ impl WithSmallOrderMulGroup<3> for Fr { #[cfg(test)] mod test { - use crate::serde::SerdeObject; - use super::*; - use ark_std::{end_timer, start_timer}; - use ff::Field; - use rand::SeedableRng; - use rand_core::OsRng; - use rand_xorshift::XorShiftRng; - - #[test] - fn test_sqrt() { - let v = (Fr::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fr::TWO_INV || (-v) == Fr::TWO_INV); - - for _ in 0..10000 { - let a = Fr::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("bn256 scalar".to_string()); - } - - #[test] - fn test_delta() { - assert_eq!(Fr::DELTA, GENERATOR.pow([1u64 << Fr::S])); - assert_eq!(Fr::DELTA, Fr::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fr::S])); - } - - #[test] - fn test_from_u512() { - assert_eq!( + crate::field_testing_suite!(Fr, "field_arithmetic"); + crate::field_testing_suite!(Fr, "conversion"); + crate::field_testing_suite!(Fr, "serialization"); + crate::field_testing_suite!(Fr, "quadratic_residue"); + crate::field_testing_suite!(Fr, "bits"); + crate::field_testing_suite!(Fr, "serialization_check"); + crate::field_testing_suite!(Fr, "constants", MODULUS_STR); + crate::field_testing_suite!(Fr, "sqrt"); + crate::field_testing_suite!(Fr, "zeta"); + crate::field_testing_suite!( + Fr, + "from_uniform_bytes", + [ Fr::from_raw([ - 0x7e7140b5196b9e6f, - 0x9abac9e4157b6172, - 0xf04bc41062fd7322, - 0x1185fa9c9fef6326, + 0x2ca6366467811a07, + 0x22727e3db430ed7e, + 0xbdb79bcb97d9e250, + 0x2cee6d1152d1d7b0 ]), - Fr::from_u512([ - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa, - 0xaaaaaaaaaaaaaaaa - ]) - ); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("fr".to_string()); - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("fr".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("fr".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("fr".to_string()); - } - - fn is_less_than(x: &[u64; 4], y: &[u64; 4]) -> bool { - match x[3].cmp(&y[3]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[2].cmp(&y[2]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[1].cmp(&y[1]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - x[0].lt(&y[0]) - } - - #[test] - fn test_serialization_check() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let start = start_timer!(|| "serialize fr"); - // failure check - for _ in 0..1000000 { - let rand_word = [(); 4].map(|_| rng.next_u64()); - let a = Fr(rand_word); - let rand_bytes = a.to_raw_bytes(); - match is_less_than(&rand_word, &MODULUS.0) { - false => { - assert!(Fr::from_raw_bytes(&rand_bytes).is_none()); - } - _ => { - assert_eq!(Fr::from_raw_bytes(&rand_bytes), Some(a)); - } - } - } - end_timer!(start); - } + Fr::from_raw([ + 0x6ec33f1a3af8cb2d, + 0x2c8f3330e85dab4b, + 0xfeeff4ae1b019172, + 0x095cd2a455dd67b6 + ]), + Fr::from_raw([ + 0x4741eee9c02c9f33, + 0xfc0111dd8aeb7e7a, + 0xb1d79e2a22d4ab08, + 0x0cb7168893a7bbda + ]), + Fr::from_raw([ + 0xc2ff8410555287f8, + 0x0927fbea8c6049c8, + 0xc0edccc8e4d3efe4, + 0x1d724b76911436c4 + ]), + Fr::from_raw([ + 0xdef98bc8d4db6e5b, + 0x42f0ea50590d557e, + 0x1f311a3b8114fd9a, + 0x0487c555645c67b1 + ]), + Fr::from_raw([ + 0x8ad4879b05ceb610, + 0x2e4e9a46537c84b0, + 0x5cfa7c43c9dfcfa1, + 0x0b6b2a4d122d0bb6 + ]), + Fr::from_raw([ + 0xe7f11ee016df7fe7, + 0x6419da89bd8aef3d, + 0x3511f5d293af95c8, + 0x10379c1d4d49593a + ]), + Fr::from_raw([ + 0xd63080c8aa3ecd37, + 0x19c20f30b56fe458, + 0xc9dbbcb3aa780e06, + 0x28a4e2b8273762c6 + ]), + Fr::from_raw([ + 0xecea51b521eac0b8, + 0x65fff58a5881c562, + 0x603ac7d1e06ef3af, + 0x1e0c2c51226eecea + ]), + Fr::from_raw([ + 0xe6ec4779b8bd6516, + 0x0d5411f3cb9504ae, + 0xff706ec73df8e92a, + 0x2c56d60b3e351e56 + ]), + ] + ); #[test] fn bench_fr_from_u16() { + use ark_std::{end_timer, start_timer}; + let repeat = 10000000; let mut rng = ark_std::test_rng(); let base = (0..repeat).map(|_| (rng.next_u32() % (1 << 16)) as u64); @@ -464,9 +422,4 @@ mod test { end_timer!(timer); } - - #[test] - fn test_quadratic_residue() { - crate::tests::field::random_quadratic_residue_test::(); - } } diff --git a/src/pluto_eris/fields/fp.rs b/src/pluto_eris/fields/fp.rs index 6692dd90..a7ff3588 100644 --- a/src/pluto_eris/fields/fp.rs +++ b/src/pluto_eris/fields/fp.rs @@ -401,54 +401,20 @@ impl WithSmallOrderMulGroup<3> for Fp { #[cfg(test)] mod test { - use crate::serde::SerdeObject; - use super::*; - use ark_std::{end_timer, start_timer}; - use ff::Field; - use rand::SeedableRng; - use rand_core::OsRng; - use rand_xorshift::XorShiftRng; - - #[test] - fn test_sqrt() { - let v = (Fp::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); - - for _ in 0..10000 { - let a = Fp::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("Eris scalar".to_string()); - } - - #[test] - fn test_delta() { - assert_eq!(Fp::DELTA, GENERATOR.pow([1u64 << Fp::S])); - assert_eq!(Fp::DELTA, Fp::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fp::S])); - } - - #[test] - fn test_zeta() { - assert_eq!(Fp::ZETA * Fp::ZETA * Fp::ZETA, Fp::ONE); - assert_ne!(Fp::ZETA * Fp::ZETA, Fp::ONE); - } - - #[test] - fn test_from_u512() { - const N_VECS: usize = 10; - let expected_results = [ + crate::field_testing_suite!(Fp, "field_arithmetic"); + crate::field_testing_suite!(Fp, "conversion"); + crate::field_testing_suite!(Fp, "serialization"); + crate::field_testing_suite!(Fp, "quadratic_residue"); + crate::field_testing_suite!(Fp, "bits"); + crate::field_testing_suite!(Fp, "serialization_check"); + crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "sqrt"); + crate::field_testing_suite!(Fp, "zeta"); + crate::field_testing_suite!( + Fp, + "from_uniform_bytes", + [ Fp::from_raw([ 0x93638251ffeffed3, 0x4d32f4d20020be11, @@ -539,91 +505,6 @@ mod test { 0xd7d5d8bc4497465a, 0x08ce8bee1323d4f9, ]), - ]; - - let mut seeded_rng = XorShiftRng::seed_from_u64(0u64); - let uniform_bytes = std::iter::from_fn(|| { - let mut bytes = [0u8; 64]; - seeded_rng.fill_bytes(&mut bytes); - Some(bytes) - }) - .take(N_VECS) - .collect::>(); - - for i in 0..N_VECS { - let p = Fp::from_uniform_bytes(&uniform_bytes[i]); - assert_eq!(expected_results[i], p); - } - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("Fp".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("Fp".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("Fp".to_string()); - } - - fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool { - match x[6].cmp(&y[6]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[5].cmp(&y[5]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[4].cmp(&y[4]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[3].cmp(&y[3]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[2].cmp(&y[2]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[1].cmp(&y[1]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - x[0].lt(&y[0]) - } - - #[test] - fn test_serialization_check() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let start = start_timer!(|| "serialize Fp"); - // failure check - for _ in 0..1000000 { - let rand_word = [(); 7].map(|_| rng.next_u64()); - let a = Fp(rand_word); - let rand_bytes = a.to_raw_bytes(); - match is_less_than(&rand_word, &MODULUS.0) { - false => { - assert!(Fp::from_raw_bytes(&rand_bytes).is_none()); - } - _ => { - assert_eq!(Fp::from_raw_bytes(&rand_bytes), Some(a)); - } - } - } - end_timer!(start); - } + ] + ); } diff --git a/src/pluto_eris/fields/fp12.rs b/src/pluto_eris/fields/fp12.rs index 7a2fd89d..b6e08a8c 100644 --- a/src/pluto_eris/fields/fp12.rs +++ b/src/pluto_eris/fields/fp12.rs @@ -546,121 +546,26 @@ pub const FROBENIUS_COEFF_FP12_C1: [Fp2; 12] = [ ]; #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_fp12_mul_by_014() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fp2::random(&mut rng); - let c1 = Fp2::random(&mut rng); - let c5 = Fp2::random(&mut rng); - let mut a = Fp12::random(&mut rng); - let mut b = a; - - a.mul_by_014(&c0, &c1, &c5); - b.mul_assign(&Fp12 { - c0: Fp6 { - c0, - c1, - c2: Fp2::zero(), - }, - c1: Fp6 { - c0: Fp2::zero(), - c1: c5, - c2: Fp2::zero(), - }, - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fp12_mul_by_034() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fp2::random(&mut rng); - let c3 = Fp2::random(&mut rng); - let c4 = Fp2::random(&mut rng); - let mut a = Fp12::random(&mut rng); - let mut b = a; - - a.mul_by_034(&c0, &c3, &c4); - b.mul_assign(&Fp12 { - c0: Fp6 { - c0, - c1: Fp2::zero(), - c2: Fp2::zero(), - }, - c1: Fp6 { - c0: c3, - c1: c4, - c2: Fp2::zero(), - }, - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_squaring() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let mut a = Fp12::random(&mut rng); - let mut b = a; - b.mul_assign(&a); - a.square_assign(); - assert_eq!(a, b); - } -} - -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..50 { - for i in 0..13 { - let mut a = Fp12::random(&mut rng); - let mut b = a; - - for _ in 0..i { - a = a.pow_vartime([ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - } - b.frobenius_map(i); - - assert_eq!(a, b); - } - } -} - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fp12".to_string()); +mod test { + use super::*; + crate::field_testing_suite!(Fp12, "field_arithmetic"); + // extension field-specific + crate::field_testing_suite!(Fp12, "f12_tests", Fp6, Fp2); + crate::field_testing_suite!( + Fp12, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fp::MODULUS) + [ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, + ] + ); } diff --git a/src/pluto_eris/fields/fp2.rs b/src/pluto_eris/fields/fp2.rs index ca2924fe..9b455480 100644 --- a/src/pluto_eris/fields/fp2.rs +++ b/src/pluto_eris/fields/fp2.rs @@ -568,210 +568,82 @@ impl WithSmallOrderMulGroup<3> for Fp2 { } #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_ser() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let a0 = Fp2::random(&mut rng); - let a_bytes = a0.to_bytes(); - let a1 = Fp2::from_bytes(&a_bytes).unwrap(); - assert_eq!(a0, a1); -} - -#[test] -fn test_fp2_ordering() { - let mut a = Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }; - - let mut b = a; - - assert!(a.cmp(&b) == Ordering::Equal); - b.c0 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c0 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Equal); - b.c1 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c0 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Less); - a.c1 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Greater); - b.c0 += &Fp::one(); - assert!(a.cmp(&b) == Ordering::Equal); -} - -#[test] -fn test_fp2_basics() { - assert_eq!( - Fp2 { - c0: Fp::zero(), - c1: Fp::zero(), - }, - Fp2::ZERO +mod test { + use super::*; + crate::field_testing_suite!(Fp2, "field_arithmetic"); + crate::field_testing_suite!(Fp2, "conversion"); + crate::field_testing_suite!(Fp2, "serialization"); + crate::field_testing_suite!(Fp2, "quadratic_residue"); + crate::field_testing_suite!(Fp2, "sqrt"); + crate::field_testing_suite!(Fp2, "zeta", Fp); + // extension field-specific + crate::field_testing_suite!(Fp2, "f2_tests", Fp); + crate::field_testing_suite!( + Fp2, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fp::MODULUS) + [ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, + ] ); - assert_eq!( - Fp2 { + + #[test] + fn test_fp2_squaring() { + // u + 1 + let mut a = Fp2 { c0: Fp::one(), - c1: Fp::zero(), - }, - Fp2::ONE - ); - assert_eq!(Fp2::ZERO.is_zero().unwrap_u8(), 1); - assert_eq!(Fp2::ONE.is_zero().unwrap_u8(), 0); - assert_eq!( - Fp2 { - c0: Fp::zero(), c1: Fp::one(), - } - .is_zero() - .unwrap_u8(), - 0 - ); -} - -#[test] -fn test_fp2_squaring() { - // u + 1 - let mut a = Fp2 { - c0: Fp::one(), - c1: Fp::one(), - }; - // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u - a.square_assign(); - let minus_4 = -Fp::from(4u64); - assert_eq!( - a, - Fp2 { - c0: minus_4, - c1: Fp::one() + Fp::one(), - } - ); - - // u - let mut a = Fp2 { - c0: Fp::zero(), - c1: Fp::one(), - }; - // u^2 - a.square_assign(); - assert_eq!( - a, - Fp2 { - c0: U_SQUARE, - c1: Fp::zero(), - } - ); -} - -#[test] -fn test_fp2_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let nqr = super::fp6::V_CUBE; - for _ in 0..1000 { - let mut a = Fp2::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -pub fn test_sqrt() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - const N_ITER: usize = 1000; - for _ in 0..N_ITER { - let a = Fp2::random(&mut rng); - if a.legendre() == -1 { - assert!(bool::from(a.sqrt().is_none())); - } - } - - for _ in 0..N_ITER { - let a = Fp2::random(&mut rng); - let mut b = a; - b.square_assign(); - assert_eq!(b.legendre(), 1); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - - let mut c = Fp2::ONE; - for _ in 0..N_ITER { - let mut b = c; - b.square_assign(); - assert_eq!(b.legendre(), 1); - - b = b.sqrt().unwrap(); - - if b != c { - b = b.neg(); - } - - assert_eq!(b, c); + }; + // (u + 1) ^2 = 1 + u^2 + 2u = -4 + 2u + a.square_assign(); + let minus_4 = -Fp::from(4u64); + assert_eq!( + a, + Fp2 { + c0: minus_4, + c1: Fp::one() + Fp::one(), + } + ); - c += &Fp2::ONE; + // u + let mut a = Fp2 { + c0: Fp::zero(), + c1: Fp::one(), + }; + // u^2 + a.square_assign(); + assert_eq!( + a, + Fp2 { + c0: U_SQUARE, + c1: Fp::zero(), + } + ); } -} -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..50 { - for i in 0..8 { + #[test] + fn test_fp2_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + let nqr = crate::pluto_eris::fields::fp6::V_CUBE; + for _ in 0..1000 { let mut a = Fp2::random(&mut rng); let mut b = a; - - for _ in 0..i { - a = a.pow_vartime([ - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - } - b.frobenius_map(i); + a.mul_by_nonresidue(); + b.mul_assign(&nqr); assert_eq!(a, b); } } } - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fp2".to_string()); -} - -#[test] -fn test_serialization() { - crate::tests::field::random_serialization_test::("fp2".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("fp2".to_string()); -} diff --git a/src/pluto_eris/fields/fp6.rs b/src/pluto_eris/fields/fp6.rs index 99cad3e4..2e298eca 100644 --- a/src/pluto_eris/fields/fp6.rs +++ b/src/pluto_eris/fields/fp6.rs @@ -659,128 +659,26 @@ pub(crate) const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [ ]; #[cfg(test)] -use rand::SeedableRng; -#[cfg(test)] -use rand_xorshift::XorShiftRng; - -#[test] -fn test_fp6_mul_nonresidue() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - let nqr = Fp6 { - c0: Fp2::zero(), - c1: Fp2::one(), - c2: Fp2::zero(), - }; - - for _ in 0..1000 { - let mut a = Fp6::random(&mut rng); - let mut b = a; - a.mul_by_nonresidue(); - b.mul_assign(&nqr); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fp6_mul_by_1() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c1 = Fp2::random(&mut rng); - let mut a = Fp6::random(&mut rng); - let mut b = a; - - a.mul_by_1(&c1); - b.mul_assign(&Fp6 { - c0: Fp2::zero(), - c1, - c2: Fp2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_fp6_mul_by_01() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let c0 = Fp2::random(&mut rng); - let c1 = Fp2::random(&mut rng); - let mut a = Fp6::random(&mut rng); - let mut b = a; - - a.mul_by_01(&c0, &c1); - b.mul_assign(&Fp6 { - c0, - c1, - c2: Fp2::zero(), - }); - - assert_eq!(a, b); - } -} - -#[test] -fn test_squaring() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..1000 { - let mut a = Fp6::random(&mut rng); - let mut b = a; - b.mul_assign(&a); - a.square_assign(); - assert_eq!(a, b); - } -} - -#[test] -fn test_frobenius() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - for _ in 0..50 { - for i in 0..8 { - let mut a = Fp6::random(&mut rng); - let mut b = a; - - for _ in 0..i { - a = a.pow_vartime([ - // p - 0x9ffffcd300000001, - 0xa2a7e8c30006b945, - 0xe4a7a5fe8fadffd6, - 0x443f9a5cda8a6c7b, - 0xa803ca76f439266f, - 0x0130e0000d7f70e4, - 0x2400000000002400, - ]); - } - b.frobenius_map(i); - - assert_eq!(a, b); - } - } -} - -#[test] -fn test_field() { - crate::tests::field::random_field_tests::("fp6".to_string()); +mod test { + use super::*; + crate::field_testing_suite!(Fp6, "field_arithmetic"); + // extension field-specific + crate::field_testing_suite!(Fp6, "f6_tests", Fp2); + crate::field_testing_suite!( + Fp6, + "frobenius", + // Frobenius endomorphism power parameter for extension field + // ϕ: E → E + // (x, y) ↦ (x^p, y^p) + // p: modulus of base field (Here, Fp::MODULUS) + [ + 0x9ffffcd300000001, + 0xa2a7e8c30006b945, + 0xe4a7a5fe8fadffd6, + 0x443f9a5cda8a6c7b, + 0xa803ca76f439266f, + 0x0130e0000d7f70e4, + 0x2400000000002400, + ] + ); } diff --git a/src/pluto_eris/fields/fq.rs b/src/pluto_eris/fields/fq.rs index b8835d41..782ca241 100644 --- a/src/pluto_eris/fields/fq.rs +++ b/src/pluto_eris/fields/fq.rs @@ -392,54 +392,20 @@ impl WithSmallOrderMulGroup<3> for Fq { #[cfg(test)] mod test { - use crate::serde::SerdeObject; - use super::*; - use ark_std::{end_timer, start_timer}; - use ff::Field; - use rand::SeedableRng; - use rand_core::OsRng; - use rand_xorshift::XorShiftRng; - - #[test] - fn test_sqrt() { - let v = (Fq::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); - - for _ in 0..10000 { - let a = Fq::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("Pluto scalar".to_string()); - } - - #[test] - fn test_zeta() { - assert_eq!(Fq::ZETA * Fq::ZETA * Fq::ZETA, Fq::ONE); - assert_ne!(Fq::ZETA * Fq::ZETA, Fq::ONE); - } - - #[test] - fn test_delta() { - assert_eq!(Fq::DELTA, GENERATOR.pow([1u64 << Fq::S])); - assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S])); - } - - #[test] - fn test_from_u512() { - const N_VECS: usize = 10; - let expected_results = [ + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); + crate::field_testing_suite!( + Fq, + "from_uniform_bytes", + [ Fq::from_raw([ 0x93638251ffeffed3, 0xb17ab6ae332352b4, @@ -530,91 +496,6 @@ mod test { 0xd7d5d8bc4497465a, 0x08ce8bee1323d4f9, ]), - ]; - - let mut seeded_rng = XorShiftRng::seed_from_u64(0u64); - let uniform_bytes = std::iter::from_fn(|| { - let mut bytes = [0u8; 64]; - seeded_rng.fill_bytes(&mut bytes); - Some(bytes) - }) - .take(N_VECS) - .collect::>(); - - for i in 0..N_VECS { - let q = Fq::from_uniform_bytes(&uniform_bytes[i]); - assert_eq!(expected_results[i], q); - } - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("Fq".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("Fq".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("Fq".to_string()); - } - - fn is_less_than(x: &[u64; 7], y: &[u64; 7]) -> bool { - match x[6].cmp(&y[6]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[5].cmp(&y[5]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[4].cmp(&y[4]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[3].cmp(&y[3]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[2].cmp(&y[2]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - match x[1].cmp(&y[1]) { - core::cmp::Ordering::Less => return true, - core::cmp::Ordering::Greater => return false, - _ => {} - } - x[0].lt(&y[0]) - } - - #[test] - fn test_serialization_check() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, - 0xbc, 0xe5, - ]); - let start = start_timer!(|| "serialize Fq"); - // failure check - for _ in 0..1000000 { - let rand_word = [(); 7].map(|_| rng.next_u64()); - let a = Fq(rand_word); - let rand_bytes = a.to_raw_bytes(); - match is_less_than(&rand_word, &MODULUS.0) { - false => { - assert!(Fq::from_raw_bytes(&rand_bytes).is_none()); - } - _ => { - assert_eq!(Fq::from_raw_bytes(&rand_bytes), Some(a)); - } - } - } - end_timer!(start); - } + ] + ); } diff --git a/src/secp256k1/fp.rs b/src/secp256k1/fp.rs index 1538544f..db5888a2 100644 --- a/src/secp256k1/fp.rs +++ b/src/secp256k1/fp.rs @@ -293,78 +293,13 @@ extend_field_legendre!(Fp); #[cfg(test)] mod test { use super::*; - use ff::Field; - use rand_core::OsRng; - - #[test] - fn test_sqrt() { - // NB: TWO_INV is standing in as a "random" field element - let v = (Fp::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); - - for _ in 0..10000 { - let a = Fp::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_constants() { - assert_eq!( - Fp::MODULUS, - "0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f", - ); - - assert_eq!(Fp::from(2) * Fp::TWO_INV, Fp::ONE); - } - - #[test] - fn test_delta() { - assert_eq!(Fp::DELTA, MULTIPLICATIVE_GENERATOR.pow([1u64 << Fp::S])); - } - - #[test] - fn test_root_of_unity() { - assert_eq!(Fp::ROOT_OF_UNITY.pow_vartime([1 << Fp::S]), Fp::one()); - } - - #[test] - fn test_inv_root_of_unity() { - assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap()); - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("secp256k1 base".to_string()); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("secp256k1 base".to_string()); - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("secp256k1 base".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("secp256k1 base".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("secp256k1 base".to_string()); - } - - #[test] - fn test_quadratic_residue() { - crate::tests::field::random_quadratic_residue_test::(); - } + crate::field_testing_suite!(Fp, "field_arithmetic"); + crate::field_testing_suite!(Fp, "conversion"); + crate::field_testing_suite!(Fp, "serialization"); + crate::field_testing_suite!(Fp, "quadratic_residue"); + crate::field_testing_suite!(Fp, "bits"); + crate::field_testing_suite!(Fp, "serialization_check"); + crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "sqrt"); + crate::field_testing_suite!(Fp, "zeta"); } diff --git a/src/secp256k1/fq.rs b/src/secp256k1/fq.rs index 09087227..4f4277c3 100644 --- a/src/secp256k1/fq.rs +++ b/src/secp256k1/fq.rs @@ -300,77 +300,13 @@ extend_field_legendre!(Fq); #[cfg(test)] mod test { use super::*; - use ff::Field; - use rand_core::OsRng; - - #[test] - fn test_sqrt() { - // NB: TWO_INV is standing in as a "random" field element - let v = (Fq::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); - - for _ in 0..10000 { - let a = Fq::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_constants() { - assert_eq!( - Fq::MODULUS, - "0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", - ); - - assert_eq!(Fq::from(2) * Fq::TWO_INV, Fq::ONE); - } - - #[test] - fn test_delta() { - assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S])); - } - - #[test] - fn test_root_of_unity() { - assert_eq!(Fq::ROOT_OF_UNITY.pow_vartime([1 << Fq::S]), Fq::one()); - } - - #[test] - fn test_inv_root_of_unity() { - assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::ROOT_OF_UNITY.invert().unwrap()); - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("secp256k1 scalar".to_string()); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("secp256k1 scalar".to_string()); - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("secp256k1 scalar".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("secp256k1 scalar".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("secp256k1 scalar".to_string()); - } - #[test] - fn test_quadratic_residue() { - crate::tests::field::random_quadratic_residue_test::(); - } + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "bits"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); } diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index f3497c81..43824aa9 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -311,78 +311,13 @@ extend_field_legendre!(Fp); #[cfg(test)] mod test { use super::*; - use ff::Field; - use rand_core::OsRng; - - #[test] - fn test_sqrt() { - // NB: TWO_INV is standing in as a "random" field element - let v = (Fp::TWO_INV).square().sqrt().unwrap(); - assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV); - - for _ in 0..10000 { - let a = Fp::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_constants() { - assert_eq!( - Fp::MODULUS, - "0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff", - ); - - assert_eq!(Fp::from(2) * Fp::TWO_INV, Fp::ONE); - } - - #[test] - fn test_delta() { - assert_eq!(Fp::DELTA, MULTIPLICATIVE_GENERATOR.pow([1u64 << Fp::S])); - } - - #[test] - fn test_root_of_unity() { - assert_eq!(Fp::ROOT_OF_UNITY.pow_vartime([1 << Fp::S]), Fp::one()); - } - - #[test] - fn test_inv_root_of_unity() { - assert_eq!(Fp::ROOT_OF_UNITY_INV, Fp::ROOT_OF_UNITY.invert().unwrap()); - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("secp256r1 base".to_string()); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("secp256r1 base".to_string()); - } - - #[test] - #[cfg(feature = "bits")] - fn test_bits() { - crate::tests::field::random_bits_tests::("secp256r1 base".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("secp256r1 base".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("secp256r1 base".to_string()); - } - - #[test] - fn test_quadratic_residue() { - crate::tests::field::random_quadratic_residue_test::(); - } + crate::field_testing_suite!(Fp, "field_arithmetic"); + crate::field_testing_suite!(Fp, "conversion"); + crate::field_testing_suite!(Fp, "serialization"); + crate::field_testing_suite!(Fp, "quadratic_residue"); + crate::field_testing_suite!(Fp, "bits"); + crate::field_testing_suite!(Fp, "serialization_check"); + crate::field_testing_suite!(Fp, "constants", MODULUS_STR); + crate::field_testing_suite!(Fp, "sqrt"); + crate::field_testing_suite!(Fp, "zeta"); } diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index d611097e..d17120a6 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -300,78 +300,12 @@ extend_field_legendre!(Fq); #[cfg(test)] mod test { use super::*; - use ff::Field; - use rand_core::OsRng; - - #[test] - fn test_zeta() { - assert_eq!(Fq::ZETA * Fq::ZETA * Fq::ZETA, Fq::ONE); - assert_ne!(Fq::ZETA * Fq::ZETA, Fq::ONE); - } - - #[test] - fn test_sqrt() { - // NB: TWO_INV is standing in as a "random" field element - // let v = (Fq::TWO_INV).square().sqrt().unwrap(); - // assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV); - - for _ in 0..10000 { - let a = Fq::random(OsRng); - let mut b = a; - b = b.square(); - - let b = b.sqrt().unwrap(); - let mut negb = b; - negb = negb.neg(); - - assert!(a == b || a == negb); - } - } - - #[test] - fn test_constants() { - assert_eq!( - Fq::MODULUS, - "0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", - ); - - assert_eq!(Fq::from(2) * Fq::TWO_INV, Fq::ONE); - } - - #[test] - fn test_delta() { - assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S])); - } - - #[test] - fn test_root_of_unity() { - assert_eq!(Fq::ROOT_OF_UNITY.pow_vartime([1 << Fq::S]), Fq::one()); - } - - #[test] - fn test_inv_root_of_unity() { - assert_eq!(Fq::ROOT_OF_UNITY_INV, Fq::ROOT_OF_UNITY.invert().unwrap()); - } - - #[test] - fn test_field() { - crate::tests::field::random_field_tests::("secp256r1 scalar".to_string()); - } - - #[test] - fn test_conversion() { - crate::tests::field::random_conversion_tests::("secp256r1 scalar".to_string()); - } - - #[test] - fn test_serialization() { - crate::tests::field::random_serialization_test::("secp256r1 scalar".to_string()); - #[cfg(feature = "derive_serde")] - crate::tests::field::random_serde_test::("secp256r1 scalar".to_string()); - } - - #[test] - fn test_quadratic_residue() { - crate::tests::field::random_quadratic_residue_test::(); - } + crate::field_testing_suite!(Fq, "field_arithmetic"); + crate::field_testing_suite!(Fq, "conversion"); + crate::field_testing_suite!(Fq, "serialization"); + crate::field_testing_suite!(Fq, "quadratic_residue"); + crate::field_testing_suite!(Fq, "serialization_check"); + crate::field_testing_suite!(Fq, "constants", MODULUS_STR); + crate::field_testing_suite!(Fq, "sqrt"); + crate::field_testing_suite!(Fq, "zeta"); } diff --git a/src/tests/curve.rs b/src/tests/curve.rs index 86bed834..390ea5de 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -1,5 +1,3 @@ -#![allow(clippy::eq_op)] - #[macro_export] macro_rules! curve_testing_suite { ($($curve: ident),*) => { diff --git a/src/tests/field.rs b/src/tests/field.rs index 020bb985..cd0f79fb 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,309 +1,735 @@ -use crate::serde::SerdeObject; -use crate::{ff::Field, ff_ext::Legendre}; -use ark_std::{end_timer, start_timer}; -use rand::{RngCore, SeedableRng}; -use rand_xorshift::XorShiftRng; - -#[cfg(feature = "derive_serde")] -use serde::{Deserialize, Serialize}; - -pub fn random_field_tests(type_name: String) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - - random_multiplication_tests::(&mut rng, type_name.clone()); - random_addition_tests::(&mut rng, type_name.clone()); - random_subtraction_tests::(&mut rng, type_name.clone()); - random_negation_tests::(&mut rng, type_name.clone()); - random_doubling_tests::(&mut rng, type_name.clone()); - random_squaring_tests::(&mut rng, type_name.clone()); - random_inversion_tests::(&mut rng, type_name.clone()); - random_expansion_tests::(&mut rng, type_name); - - assert_eq!(F::ZERO.is_zero().unwrap_u8(), 1); - { - let mut z = F::ZERO; - z = z.neg(); - assert_eq!(z.is_zero().unwrap_u8(), 1); - } - - assert!(bool::from(F::ZERO.invert().is_none())); - - // Multiplication by zero - { - let mut a = F::random(&mut rng); - a.mul_assign(&F::ZERO); - assert_eq!(a.is_zero().unwrap_u8(), 1); - } - - // Addition by zero - { - let mut a = F::random(&mut rng); - let copy = a; - a.add_assign(&F::ZERO); - assert_eq!(a, copy); - } -} +#[macro_export] +macro_rules! field_testing_suite { + ($field: ident, "field_arithmetic") => { + fn random_multiplication_tests(mut rng: R, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); + + let mut t0 = a; // (a * b) * c + t0.mul_assign(&b); + t0.mul_assign(&c); + + let mut t1 = a; // (a * c) * b + t1.mul_assign(&c); + t1.mul_assign(&b); + + let mut t2 = b; // (b * c) * a + t2.mul_assign(&c); + t2.mul_assign(&a); + + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } + } -fn random_multiplication_tests(mut rng: R, type_name: String) { - let _message = format!("multiplication {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let b = F::random(&mut rng); - let c = F::random(&mut rng); - - let mut t0 = a; // (a * b) * c - t0.mul_assign(&b); - t0.mul_assign(&c); - - let mut t1 = a; // (a * c) * b - t1.mul_assign(&c); - t1.mul_assign(&b); - - let mut t2 = b; // (b * c) * a - t2.mul_assign(&c); - t2.mul_assign(&a); - - assert_eq!(t0, t1); - assert_eq!(t1, t2); - } - end_timer!(start); -} + fn random_addition_tests(mut rng: R, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); -fn random_addition_tests(mut rng: R, type_name: String) { - let _message = format!("addition {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let b = F::random(&mut rng); - let c = F::random(&mut rng); - - let mut t0 = a; // (a + b) + c - t0.add_assign(&b); - t0.add_assign(&c); - - let mut t1 = a; // (a + c) + b - t1.add_assign(&c); - t1.add_assign(&b); - - let mut t2 = b; // (b + c) + a - t2.add_assign(&c); - t2.add_assign(&a); - - assert_eq!(t0, t1); - assert_eq!(t1, t2); - } - end_timer!(start); -} + let mut t0 = a; // (a + b) + c + t0.add_assign(&b); + t0.add_assign(&c); -fn random_subtraction_tests(mut rng: R, type_name: String) { - let _message = format!("subtraction {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let b = F::random(&mut rng); + let mut t1 = a; // (a + c) + b + t1.add_assign(&c); + t1.add_assign(&b); - let mut t0 = a; // (a - b) - t0.sub_assign(&b); + let mut t2 = b; // (b + c) + a + t2.add_assign(&c); + t2.add_assign(&a); - let mut t1 = b; // (b - a) - t1.sub_assign(&a); + assert_eq!(t0, t1); + assert_eq!(t1, t2); + } + } - let mut t2 = t0; // (a - b) + (b - a) = 0 - t2.add_assign(&t1); + fn random_subtraction_tests(mut rng: R, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let b = F::random(&mut rng); - assert_eq!(t2.is_zero().unwrap_u8(), 1); - } - end_timer!(start); -} + let mut t0 = a; // (a - b) + t0.sub_assign(&b); -fn random_negation_tests(mut rng: R, type_name: String) { - let _message = format!("negation {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let mut b = a; - b = b.neg(); - b.add_assign(&a); - - assert_eq!(b.is_zero().unwrap_u8(), 1); - } - end_timer!(start); -} + let mut t1 = b; // (b - a) + t1.sub_assign(&a); -fn random_doubling_tests(mut rng: R, type_name: String) { - let _message = format!("doubling {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let mut a = F::random(&mut rng); - let mut b = a; - a.add_assign(&b); - b = b.double(); - - assert_eq!(a, b); - } - end_timer!(start); -} + let mut t2 = t0; // (a - b) + (b - a) = 0 + t2.add_assign(&t1); -fn random_squaring_tests(mut rng: R, type_name: String) { - let _message = format!("squaring {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let mut a = F::random(&mut rng); - let mut b = a; - a.mul_assign(&b); - b = b.square(); - - assert_eq!(a, b); - } - end_timer!(start); -} + assert_eq!(t2.is_zero().unwrap_u8(), 1); + } + } -fn random_inversion_tests(mut rng: R, type_name: String) { - assert!(bool::from(F::ZERO.invert().is_none())); + fn random_negation_tests(mut rng: R, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let mut b = a; + b = b.neg(); + b.add_assign(&a); - let _message = format!("inversion {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let mut a = F::random(&mut rng); - let b = a.invert().unwrap(); // probablistically nonzero - a.mul_assign(&b); + assert_eq!(b.is_zero().unwrap_u8(), 1); + } + } - assert_eq!(a, F::ONE); - } - end_timer!(start); -} + fn random_doubling_tests(mut rng: R, n: usize) { + for _ in 0..n { + let mut a = F::random(&mut rng); + let mut b = a; + a.add_assign(&b); + b = b.double(); -fn random_expansion_tests(mut rng: R, type_name: String) { - let _message = format!("expansion {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) - - let a = F::random(&mut rng); - let b = F::random(&mut rng); - let c = F::random(&mut rng); - let d = F::random(&mut rng); - - let mut t0 = a; - t0.add_assign(&b); - let mut t1 = c; - t1.add_assign(&d); - t0.mul_assign(&t1); - - let mut t2 = a; - t2.mul_assign(&c); - let mut t3 = b; - t3.mul_assign(&c); - let mut t4 = a; - t4.mul_assign(&d); - let mut t5 = b; - t5.mul_assign(&d); - - t2.add_assign(&t3); - t2.add_assign(&t4); - t2.add_assign(&t5); - - assert_eq!(t0, t2); - } - end_timer!(start); -} + assert_eq!(a, b); + } + } -pub fn random_conversion_tests>(type_name: String) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let _message = format!("conversion {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let bytes = a.to_repr(); - let b = F::from_repr(bytes).unwrap(); - assert_eq!(a, b); - } - end_timer!(start); -} + fn random_squaring_tests(mut rng: R, n: usize) { + for _ in 0..n { + let mut a = F::random(&mut rng); + let mut b = a; + a.mul_assign(&b); + b = b.square(); -#[cfg(feature = "bits")] -pub fn random_bits_tests(type_name: String) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let _message = format!("to_le_bits {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let bytes = a.to_repr(); - let bits = a.to_le_bits(); - for idx in 0..bits.len() { - assert_eq!(bits[idx], ((bytes.as_ref()[idx / 8] >> (idx % 8)) & 1) == 1); - } - } - end_timer!(start); -} + assert_eq!(a, b); + } + } -pub fn random_serialization_test(type_name: String) { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let _message = format!("serialization with SerdeObject {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - let a = F::random(&mut rng); - let bytes = a.to_raw_bytes(); - let b = F::from_raw_bytes(&bytes).unwrap(); - assert_eq!(a, b); - let mut buf = Vec::new(); - a.write_raw(&mut buf).unwrap(); - let b = F::read_raw(&mut &buf[..]).unwrap(); - assert_eq!(a, b); - } - end_timer!(start); -} + fn random_inversion_tests(mut rng: R, n: usize) { + assert!(bool::from(F::ZERO.invert().is_none())); -#[cfg(feature = "derive_serde")] -pub fn random_serde_test(type_name: String) -where - F: Field + SerdeObject + Serialize + for<'de> Deserialize<'de>, -{ - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - let _message = format!("serialization with serde {type_name}"); - let start = start_timer!(|| _message); - for _ in 0..1000000 { - // byte serialization - let a = F::random(&mut rng); - let bytes = bincode::serialize(&a).unwrap(); - let reader = std::io::Cursor::new(bytes); - let b: F = bincode::deserialize_from(reader).unwrap(); - assert_eq!(a, b); - - // json serialization - let json = serde_json::to_string(&a).unwrap(); - let reader = std::io::Cursor::new(json); - let b: F = serde_json::from_reader(reader).unwrap(); - assert_eq!(a, b); - } - end_timer!(start); -} + for _ in 0..n { + let mut a = F::random(&mut rng); + let b = a.invert().unwrap(); // probablistically nonzero + a.mul_assign(&b); + + assert_eq!(a, F::ONE); + } + } + + fn random_expansion_tests(mut rng: R, n: usize) { + for _ in 0..n { + // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) + + let a = F::random(&mut rng); + let b = F::random(&mut rng); + let c = F::random(&mut rng); + let d = F::random(&mut rng); + + let mut t0 = a; + t0.add_assign(&b); + let mut t1 = c; + t1.add_assign(&d); + t0.mul_assign(&t1); + + let mut t2 = a; + t2.mul_assign(&c); + let mut t3 = b; + t3.mul_assign(&c); + let mut t4 = a; + t4.mul_assign(&d); + let mut t5 = b; + t5.mul_assign(&d); + + t2.add_assign(&t3); + t2.add_assign(&t4); + t2.add_assign(&t5); + + assert_eq!(t0, t2); + } + } + + fn zero_tests(mut rng: R) { + assert_eq!(F::ZERO.is_zero().unwrap_u8(), 1); + { + let mut z = F::ZERO; + z = z.neg(); + assert_eq!(z.is_zero().unwrap_u8(), 1); + } + + assert!(bool::from(F::ZERO.invert().is_none())); + + // Multiplication by zero + { + let mut a = F::random(&mut rng); + a.mul_assign(&F::ZERO); + assert_eq!(a.is_zero().unwrap_u8(), 1); + } + + // Addition by zero + { + let mut a = F::random(&mut rng); + let copy = a; + a.add_assign(&F::ZERO); + assert_eq!(a, copy); + } + } + + fn one_tests(mut rng: R) { + assert!(bool::from(F::ONE.invert().is_some())); + + // Multiplication by one + { + let mut a = F::random(&mut rng); + let copy = a; + a.mul_assign(&F::ONE); + assert_eq!(a, copy); + } + + // Addition by one + { + let mut a = F::random(&mut rng); + let copy = a; + a.add_assign(&F::ONE); + assert_eq!(a, copy + F::ONE); + } + } + + use ff::Field; + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + + #[test] + fn test_field() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + + // reduce the number of tests for high-degree extension fields since TOO long + let n = if impls::impls!($field: ff::PrimeField) { 1000000 } else { 100000 }; + + // normal cases + random_multiplication_tests::<$field, _>(&mut rng, n); + random_addition_tests::<$field, _>(&mut rng, n); + random_subtraction_tests::<$field, _>(&mut rng, n); + random_negation_tests::<$field, _>(&mut rng, n); + random_doubling_tests::<$field, _>(&mut rng, n); + random_squaring_tests::<$field, _>(&mut rng, n); + random_inversion_tests::<$field, _>(&mut rng, n); + random_expansion_tests::<$field, _>(&mut rng, n); + + // edge cases + zero_tests::<$field, _>(&mut rng); + one_tests::<$field, _>(&mut rng); + } + }; + + ($field: ident, "conversion") => { + #[test] + fn test_conversion() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, + 0x06, 0xbc, 0xe5, + ]); + for _ in 0..1000000 { + let a = $field::random(&mut rng); + let bytes = a.to_repr(); + let b = $field::from_repr(bytes).unwrap(); + assert_eq!(a, b); + } + } + }; + + ($field: ident, "serialization") => { + macro_rules! random_serialization_test { + ($f: ident) => { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, + 0x06, 0xbc, 0xe5, + ]); + for _ in 0..1000000 { + let a = $f::random(&mut rng); + let bytes = a.to_raw_bytes(); + let b = $f::from_raw_bytes(&bytes).unwrap(); + assert_eq!(a, b); + let mut buf = Vec::new(); + a.write_raw(&mut buf).unwrap(); + let b = $f::read_raw(&mut &buf[..]).unwrap(); + assert_eq!(a, b); + } + }; + } + + #[cfg(feature = "derive_serde")] + macro_rules! random_serde_test { + ($f: ident) => { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, + 0x06, 0xbc, 0xe5, + ]); + for _ in 0..1000000 { + // byte serialization + let a = $f::random(&mut rng); + let bytes = bincode::serialize(&a).unwrap(); + let reader = std::io::Cursor::new(bytes); + let b: $f = bincode::deserialize_from(reader).unwrap(); + assert_eq!(a, b); + + // json serialization + let json = serde_json::to_string(&a).unwrap(); + let reader = std::io::Cursor::new(json); + let b: $f = serde_json::from_reader(reader).unwrap(); + assert_eq!(a, b); + } + }; + } + + #[test] + fn test_serialization() { + use crate::serde::SerdeObject; + random_serialization_test!($field); + #[cfg(feature = "derive_serde")] + random_serde_test!($field); + } + }; + + ($field: ident, "quadratic_residue") => { + #[test] + fn test_quadratic_residue() { + use crate::ff_ext::Legendre; + use ff::Field; + use rand_core::SeedableRng; + use rand_xorshift::XorShiftRng; + + // random quadratic residue test + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, + 0x06, 0xbc, 0xe5, + ]); + for _ in 0..100000 { + let elem = $field::random(&mut rng); + let is_quad_res_or_zero: bool = elem.sqrt().is_some().into(); + let is_quad_non_res: bool = elem.ct_quadratic_non_residue().into(); + assert_eq!(!is_quad_non_res, is_quad_res_or_zero) + } + } + }; + + ($field: ident, "bits") => { + #[test] + #[cfg(feature = "bits")] + fn test_bits() { + use ff::PrimeFieldBits; + // random bit test + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, + 0x06, 0xbc, 0xe5, + ]); + for _ in 0..1000000 { + let a = $field::random(&mut rng); + let bytes = a.to_repr(); + let bits = a.to_le_bits(); + for idx in 0..bits.len() { + assert_eq!(bits[idx], ((bytes.as_ref()[idx / 8] >> (idx % 8)) & 1) == 1); + } + } + } + }; + + ($field: ident, "serialization_check") => { + fn is_less_than(x: &[u64; N], y: &[u64; N]) -> bool { + for i in (1..N).rev() { + match x[i].cmp(&y[i]) { + core::cmp::Ordering::Less => return true, + core::cmp::Ordering::Greater => return false, + _ => {} + } + } + x[0].lt(&y[0]) + } + + #[test] + fn test_serialization_check() { + use crate::serde::SerdeObject; + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, + 0xbc, 0xe5, + ]); + const LIMBS: usize = $field::size() / 8; + // failure check + for _ in 0..1000000 { + let rand_word = [(); LIMBS].map(|_| rng.next_u64()); + let a = $field(rand_word); + let rand_bytes = a.to_raw_bytes(); + match is_less_than::(&rand_word, &MODULUS.0) { + false => { + assert!($field::from_raw_bytes(&rand_bytes).is_none()); + } + _ => { + assert_eq!($field::from_raw_bytes(&rand_bytes), Some(a)); + } + } + } + } + }; + + ($field: ident, "constants", $modulus_str: expr) => { + #[test] + fn test_primefield_constants() { + assert_eq!($field::MODULUS, $modulus_str); + assert_eq!( + $field::ROOT_OF_UNITY_INV, + $field::ROOT_OF_UNITY.invert().unwrap() + ); + assert_eq!($field::from(2) * $field::TWO_INV, $field::ONE); + if $field::S != 0 { + assert_eq!( + $field::ROOT_OF_UNITY.pow_vartime([1 << $field::S]), + $field::one() + ); + assert_eq!( + $field::DELTA, + $field::MULTIPLICATIVE_GENERATOR.pow([1u64 << $field::S]) + ); + } + } + }; + + ($field: ident, "sqrt") => { + #[test] + fn test_sqrt() { + use crate::ff_ext::Legendre; + use rand_core::OsRng; + + let v = ($field::TWO_INV).square().sqrt().unwrap(); + assert!(v == $field::TWO_INV || (-v) == $field::TWO_INV); + + for _ in 0..10000 { + let a = $field::random(OsRng); + if a.legendre() == -1 { + assert!(bool::from(a.sqrt().is_none())); + } + } + + for _ in 0..10000 { + let a = $field::random(OsRng); + let mut b = a; + b = b.square(); + assert_eq!(b.legendre(), 1); + + let b = b.sqrt().unwrap(); + let mut negb = b; + negb = negb.neg(); + + assert!(a == b || a == negb); + } + + let mut c = $field::one(); + for _ in 0..10000 { + let mut b = c; + b = b.square(); + assert_eq!(b.legendre(), 1); + + b = b.sqrt().unwrap(); + + if b != c { + b = b.neg(); + } + + assert_eq!(b, c); + + c += &$field::one(); + } + } + }; + + ($field: ident, "zeta" $(, $base_field: ident)*) => { + #[test] + fn test_zeta() { + assert_eq!($field::ZETA * $field::ZETA * $field::ZETA, $field::ONE); + assert_ne!($field::ZETA * $field::ZETA, $field::ONE); + $( + let zeta = $field::new($base_field::ZETA.square(), $base_field::zero()); + assert_eq!(zeta, $field::ZETA); + )* + } + }; + + ($field: ident, "from_uniform_bytes", $test_vectors: expr) => { + #[test] + fn test_from_uniform_bytes() { + const N_VECS: usize = 10; + assert!($test_vectors.len() == N_VECS); + + let mut seeded_rng = XorShiftRng::seed_from_u64(0u64); + let uniform_bytes = std::iter::from_fn(|| { + let mut bytes = [0u8; 64]; + seeded_rng.fill_bytes(&mut bytes); + Some(bytes) + }) + .take(N_VECS) + .collect::>(); + + for i in 0..N_VECS { + let q = $field::from_uniform_bytes(&uniform_bytes[i]); + assert_eq!($test_vectors[i], q); + } + } + }; + + ($ext_field: ident, "f2_tests", $base_field: ident) => { + #[test] + fn test_ser() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + let a0 = $ext_field::random(&mut rng); + let a_bytes = a0.to_bytes(); + let a1 = $ext_field::from_bytes(&a_bytes).unwrap(); + assert_eq!(a0, a1); + } + + #[test] + fn test_f2_ordering() { + let mut a = $ext_field { + c0: $base_field::zero(), + c1: $base_field::zero(), + }; + + let mut b = a; + + assert!(a.cmp(&b) == Ordering::Equal); + b.c0 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c0 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Equal); + b.c1 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c0 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Less); + a.c1 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Greater); + b.c0 += &$base_field::one(); + assert!(a.cmp(&b) == Ordering::Equal); + } + + #[test] + fn test_f2_basics() { + assert_eq!( + $ext_field { + c0: $base_field::zero(), + c1: $base_field::zero(), + }, + $ext_field::ZERO + ); + assert_eq!( + $ext_field { + c0: $base_field::one(), + c1: $base_field::zero(), + }, + $ext_field::ONE + ); + assert_eq!($ext_field::ZERO.is_zero().unwrap_u8(), 1); + assert_eq!($ext_field::ONE.is_zero().unwrap_u8(), 0); + assert_eq!( + $ext_field { + c0: $base_field::zero(), + c1: $base_field::one(), + } + .is_zero() + .unwrap_u8(), + 0 + ); + } + }; + + ($ext_field: ident, "f6_tests", $base_field: ident) => { + #[test] + fn test_f6_mul_nonresidue() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + let nqr = $ext_field { + c0: $base_field::zero(), + c1: $base_field::one(), + c2: $base_field::zero(), + }; + + for _ in 0..1000 { + let mut a = $ext_field::random(&mut rng); + let mut b = a; + a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } + } + + #[test] + fn test_f6_mul_by_1() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c1 = $base_field::random(&mut rng); + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + a.mul_by_1(&c1); + b.mul_assign(&$ext_field { + c0: $base_field::zero(), + c1, + c2: $base_field::zero(), + }); + + assert_eq!(a, b); + } + } -pub fn random_quadratic_residue_test() { - let mut rng = XorShiftRng::from_seed([ - 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, - 0xe5, - ]); - for _ in 0..100000 { - let elem = F::random(&mut rng); - let is_quad_res_or_zero: bool = elem.sqrt().is_some().into(); - let is_quad_non_res: bool = elem.ct_quadratic_non_residue().into(); - assert_eq!(!is_quad_non_res, is_quad_res_or_zero) - } + #[test] + fn test_f6_mul_by_01() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = $base_field::random(&mut rng); + let c1 = $base_field::random(&mut rng); + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + a.mul_by_01(&c0, &c1); + b.mul_assign(&$ext_field { + c0, + c1, + c2: $base_field::zero(), + }); + + assert_eq!(a, b); + } + } + + #[test] + fn test_squaring() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = $ext_field::random(&mut rng); + let mut b = a; + b.mul_assign(&a); + a.square_assign(); + assert_eq!(a, b); + } + } + }; + + ($ext_field: ident, "f12_tests", $base_field_1: ident, $base_field_2: ident) => { + #[test] + fn test_f12_mul_by_014() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = $base_field_2::random(&mut rng); + let c1 = $base_field_2::random(&mut rng); + let c5 = $base_field_2::random(&mut rng); + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + a.mul_by_014(&c0, &c1, &c5); + b.mul_assign(&$ext_field { + c0: $base_field_1 { + c0, + c1, + c2: $base_field_2::zero(), + }, + c1: $base_field_1 { + c0: $base_field_2::zero(), + c1: c5, + c2: $base_field_2::zero(), + }, + }); + + assert_eq!(a, b); + } + } + + #[test] + fn test_f12_mul_by_034() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let c0 = $base_field_2::random(&mut rng); + let c3 = $base_field_2::random(&mut rng); + let c4 = $base_field_2::random(&mut rng); + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + a.mul_by_034(&c0, &c3, &c4); + b.mul_assign(&$ext_field { + c0: $base_field_1 { + c0, + c1: $base_field_2::zero(), + c2: $base_field_2::zero(), + }, + c1: $base_field_1 { + c0: c3, + c1: c4, + c2: $base_field_2::zero(), + }, + }); + + assert_eq!(a, b); + } + } + + #[test] + fn test_squaring() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..1000 { + let mut a = $ext_field::random(&mut rng); + let mut b = a; + b.mul_assign(&a); + a.square_assign(); + assert_eq!(a, b); + } + } + }; + + ($ext_field: ident, "frobenius", $frobenius_param: expr) => { + #[test] + fn test_frobenius() { + let mut rng = XorShiftRng::from_seed([ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, + 0xe5, + ]); + + for _ in 0..50 { + for i in 0..8 { + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + for _ in 0..i { + a = a.pow($frobenius_param); + } + b.frobenius_map(i); + + assert_eq!(a, b); + } + } + } + }; }