diff --git a/src/bls12381/fq.rs b/src/bls12381/fq.rs index f647077f..11320f22 100644 --- a/src/bls12381/fq.rs +++ b/src/bls12381/fq.rs @@ -37,16 +37,19 @@ impl ExtField for Fq { #[cfg(test)] mod test { use super::*; - 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"); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 96); + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; + + constants_test!(Fq); + + arith_test!(Fq); + legendre_test!(Fq); + test!(arith, Fq, sqrt_test, 1000); + + serde_test!(Fq PrimeFieldBits); + from_uniform_bytes_test!(Fq, 1000, L 64, L 96); + #[test] fn test_fq_mul_nonresidue() { let e = Fq::random(rand_core::OsRng); diff --git a/src/bls12381/fq12.rs b/src/bls12381/fq12.rs index c43cad26..e81006d0 100644 --- a/src/bls12381/fq12.rs +++ b/src/bls12381/fq12.rs @@ -268,17 +268,31 @@ pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ #[cfg(test)] mod test { + macro_rules! test_fq12 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::bls12381::fq12::test::$test(&mut rng, $size); + } + } + }; + } use super::*; - crate::field_testing_suite!(Fq12, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fq12, "quadratic_sparse_mul", 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) - Fq::MODULUS_LIMBS - ); + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + use ff::Field; + use rand::RngCore; + + arith_test!(Fq12); + // TODO Compile problems with derive_serde feature + // serde_test!(fq12); + + // F12 specific + setup_f12_test_funcs!(Fq12, Fq6, Fq2); + test_fq12!(f12_mul_by_014_, 500); + test_fq12!(f12_mul_by_034_, 500); + frobenius_test!(Fq12, Fq, 8); } diff --git a/src/bls12381/fq2.rs b/src/bls12381/fq2.rs index 0ee075da..d88f286e 100644 --- a/src/bls12381/fq2.rs +++ b/src/bls12381/fq2.rs @@ -65,23 +65,21 @@ impl ExtField for Fq2 { 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) - Fq::MODULUS_LIMBS - ); + use crate::{ + arith_test, constants_test, f2_test, frobenius_test, legendre_test, serde_test, test, + }; + use rand_core::RngCore; + + constants_test!(Fq2); + + arith_test!(Fq2); + legendre_test!(Fq2); + test!(arith, Fq2, sqrt_test, 1000); + + serde_test!(Fq2); + + f2_test!(Fq2, Fq); + frobenius_test!(Fq2, Fq, 20); #[test] fn test_fq2_mul_nonresidue() { diff --git a/src/bls12381/fq6.rs b/src/bls12381/fq6.rs index bb3ed5b2..19fe7b0a 100644 --- a/src/bls12381/fq6.rs +++ b/src/bls12381/fq6.rs @@ -277,22 +277,32 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ #[cfg(test)] mod test { use super::*; - crate::field_testing_suite!(Fq6, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fq6, "cubic_sparse_mul", 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) - Fq::MODULUS_LIMBS - ); + use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; + use rand_core::RngCore; + + macro_rules! test_fq6 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::bls12381::fq6::test::$test(&mut rng, $size); + } + } + }; + } + + arith_test!(Fq6); + setup_f6_test_funcs!(Fq6, Fq2); + test_fq6!(f6_mul_nonresidue_, 1000); + test_fq6!(f6_mul_by_1_, 1000); + test_fq6!(f6_mul_by_01_, 1000); + frobenius_test!(Fq6, Fq, 10); #[test] fn test_fq6_mul_nonresidue() { - use ff::Field; let e = Fq6::random(rand_core::OsRng); let a0 = e.mul_by_nonresidue(); let a1 = e * Fq6::NON_RESIDUE; diff --git a/src/bls12381/fr.rs b/src/bls12381/fr.rs index ee62adc6..67a06b29 100644 --- a/src/bls12381/fr.rs +++ b/src/bls12381/fr.rs @@ -24,15 +24,17 @@ crate::impl_from_bool!(Fr); #[cfg(test)] mod test { - use super::*; - 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"); - crate::field_testing_suite!(Fr, "sqrt"); - crate::field_testing_suite!(Fr, "zeta"); - crate::field_testing_suite!(Fr, "from_uniform_bytes", 64); + use super::Fr; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; + + constants_test!(Fr); + + arith_test!(Fr); + legendre_test!(Fr); + test!(arith, Fr, sqrt_test, 1000); + + serde_test!(Fr PrimeFieldBits); + from_uniform_bytes_test!(Fr, 1000, L 64); } diff --git a/src/bn256/fq.rs b/src/bn256/fq.rs index c82c6e26..d3fa7fbc 100644 --- a/src/bn256/fq.rs +++ b/src/bn256/fq.rs @@ -35,22 +35,17 @@ impl ExtField for Fq { #[cfg(test)] mod test { - use super::*; - 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"); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 48); - #[test] - fn test_fq_mul_nonresidue() { - let e = Fq::random(rand_core::OsRng); - let a0 = e.mul_by_nonresidue(); - let a1 = e * Fq::NON_RESIDUE; - assert_eq!(a0, a1); - } + use super::Fq; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; + + constants_test!(Fq); + + arith_test!(Fq); + legendre_test!(Fq); + test!(arith, Fq, sqrt_test, 1000); + + serde_test!(Fq PrimeFieldBits); + from_uniform_bytes_test!(Fq, 1000, L 64, L 48); } diff --git a/src/bn256/fq12.rs b/src/bn256/fq12.rs index d10c73d7..c6186ac7 100644 --- a/src/bn256/fq12.rs +++ b/src/bn256/fq12.rs @@ -195,17 +195,30 @@ pub const FROBENIUS_COEFF_FQ12_C1: [Fq2; 12] = [ #[cfg(test)] mod test { + + macro_rules! test_fq12 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::bn256::fq12::test::$test(&mut rng, $size); + } + } + }; + } use super::*; - crate::field_testing_suite!(Fq12, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fq12, "quadratic_sparse_mul", 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) - Fq::MODULUS_LIMBS - ); + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + use ff::Field; + use rand::RngCore; + + arith_test!(Fq12); + + // F12 specific + setup_f12_test_funcs!(Fq12, Fq6, Fq2); + test_fq12!(f12_mul_by_014_, 500); + test_fq12!(f12_mul_by_034_, 500); + frobenius_test!(Fq12, Fq, 8); } diff --git a/src/bn256/fq2.rs b/src/bn256/fq2.rs index 3eb4f0ee..2aa478ac 100644 --- a/src/bn256/fq2.rs +++ b/src/bn256/fq2.rs @@ -68,23 +68,20 @@ impl ExtField for Fq2 { 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) - Fq::MODULUS_LIMBS - ); + use crate::{ + arith_test, constants_test, f2_test, frobenius_test, legendre_test, serde_test, test, + }; + use rand_core::RngCore; + + constants_test!(Fq2); + arith_test!(Fq2); + legendre_test!(Fq2); + test!(arith, Fq2, sqrt_test, 1000); + + serde_test!(Fq2); + + f2_test!(Fq2, Fq); + frobenius_test!(Fq2, Fq, 20); #[test] fn test_fq2_mul_nonresidue() { diff --git a/src/bn256/fq6.rs b/src/bn256/fq6.rs index f2e63e89..fcdef910 100644 --- a/src/bn256/fq6.rs +++ b/src/bn256/fq6.rs @@ -204,25 +204,27 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ #[cfg(test)] mod test { use super::*; - crate::field_testing_suite!(Fq6, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fq6, "cubic_sparse_mul", 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) - Fq::MODULUS_LIMBS - ); + use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; + use rand_core::RngCore; - #[test] - fn test_fq6_mul_nonresidue() { - use ff::Field; - let e = Fq6::random(rand_core::OsRng); - let a0 = e.mul_by_nonresidue(); - let a1 = e * Fq6::NON_RESIDUE; - assert_eq!(a0, a1); + macro_rules! test_fq6 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::bn256::fq6::test::$test(&mut rng, $size); + } + } + }; } + + arith_test!(Fq6); + setup_f6_test_funcs!(Fq6, Fq2); + test_fq6!(f6_mul_nonresidue_, 1000); + test_fq6!(f6_mul_by_1_, 1000); + test_fq6!(f6_mul_by_01_, 1000); + frobenius_test!(Fq6, Fq, 10); } diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index 986378d0..edc1e02c 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -45,16 +45,17 @@ mod table_tests; #[cfg(test)] mod test { + use super::Fr; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; - use super::*; - 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"); - crate::field_testing_suite!(Fr, "sqrt"); - crate::field_testing_suite!(Fr, "zeta"); - crate::field_testing_suite!(Fr, "from_uniform_bytes", 64); + constants_test!(Fr); + + arith_test!(Fr); + legendre_test!(Fr); + test!(arith, Fr, sqrt_test, 1000); + + serde_test!(Fr PrimeFieldBits); + from_uniform_bytes_test!(Fr, 1000, L 64, L 48); } diff --git a/src/derive/field/tower.rs b/src/derive/field/tower.rs index bbdd1324..9f508fba 100644 --- a/src/derive/field/tower.rs +++ b/src/derive/field/tower.rs @@ -102,10 +102,21 @@ macro_rules! impl_tower2 { const CAPACITY: u32 = $base::NUM_BITS; const S: u32 = $base::S; - // TODO: Check that we can just 0 this and forget. - const ROOT_OF_UNITY: Self = $field::ZERO; - const ROOT_OF_UNITY_INV: Self = $field::ZERO; - const DELTA: Self = $field::ZERO; + // Unused variables (Because this is not a Prime Field). + // These are just used to pass the constants test. + const ROOT_OF_UNITY: Self = $field { + c0: $base::ROOT_OF_UNITY, + c1: $base::ZERO, + }; + const ROOT_OF_UNITY_INV: Self = $field { + c0: $base::ROOT_OF_UNITY_INV, + c1: $base::ZERO, + }; + + const DELTA: Self = $field { + c0: $base::DELTA, + c1: $base::ZERO, + }; const TWO_INV: Self = $field { c0: $base::TWO_INV, diff --git a/src/ff_ext/cubic.rs b/src/ff_ext/cubic.rs index c8e90808..95b7a8c6 100644 --- a/src/ff_ext/cubic.rs +++ b/src/ff_ext/cubic.rs @@ -10,6 +10,7 @@ pub struct CubicExtField { pub trait CubicSparseMul { type Base: ExtField; + #[must_use] fn mul_by_1(lhs: &CubicExtField, c1: &Self::Base) -> CubicExtField { let b_b = lhs.c1 * c1; @@ -24,6 +25,7 @@ pub trait CubicSparseMul { } } + #[must_use] fn mul_by_01( lhs: &CubicExtField, c0: &Self::Base, diff --git a/src/ff_ext/mod.rs b/src/ff_ext/mod.rs index da4d3aa6..46eff06a 100644 --- a/src/ff_ext/mod.rs +++ b/src/ff_ext/mod.rs @@ -35,6 +35,7 @@ macro_rules! extend_field_legendre { pub trait ExtField: ff::Field { const NON_RESIDUE: Self; + #[must_use] fn mul_by_nonresidue(&self) -> Self { Self::NON_RESIDUE * self } diff --git a/src/lib.rs b/src/lib.rs index d2b929e1..f5caae2d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ pub mod secq256k1; #[macro_use] mod derive; -// Re-export to simplify down stream dependencies +// Re-export to simplify downstream dependencies. pub use ff; pub use group; pub use pairing; diff --git a/src/pluto_eris/fp.rs b/src/pluto_eris/fp.rs index d3c1a8da..7f85ef46 100644 --- a/src/pluto_eris/fp.rs +++ b/src/pluto_eris/fp.rs @@ -41,24 +41,17 @@ impl ExtField for Fp { #[cfg(test)] mod test { + use super::Fp; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; - use super::*; - 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"); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!(Fp, "from_uniform_bytes", 64, 72, 112); + constants_test!(Fp); - #[test] - fn test_fq_mul_nonresidue() { - let e = Fp::random(rand_core::OsRng); - let a0 = e.mul_by_nonresidue(); - let a1 = e * Fp::NON_RESIDUE; - assert_eq!(a0, a1); - } + arith_test!(Fp); + legendre_test!(Fp); + test!(arith, Fp, sqrt_test, 1000); + + serde_test!(Fp PrimeFieldBits); + from_uniform_bytes_test!(Fp, 1000, L 64, L 72, L 112); } diff --git a/src/pluto_eris/fp12.rs b/src/pluto_eris/fp12.rs index 1b64080a..31a7776f 100644 --- a/src/pluto_eris/fp12.rs +++ b/src/pluto_eris/fp12.rs @@ -254,25 +254,29 @@ pub const FROBENIUS_COEFF_FP12_C1: [Fp2; 12] = [ #[cfg(test)] mod test { + macro_rules! test_fp12 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::pluto_eris::fp12::test::$test(&mut rng, $size); + } + } + }; + } use super::*; - crate::field_testing_suite!(Fp12, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fp12, "quadratic_sparse_mul", 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, - ] - ); + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + use ff::Field; + use rand::RngCore; + + arith_test!(Fp12); + + // F12 specific + setup_f12_test_funcs!(Fp12, Fp6, Fp2); + test_fp12!(f12_mul_by_014_, 500); + test_fp12!(f12_mul_by_034_, 500); + frobenius_test!(Fp12, Fp, 8); } diff --git a/src/pluto_eris/fp2.rs b/src/pluto_eris/fp2.rs index bd488f6b..a3f64b4a 100644 --- a/src/pluto_eris/fp2.rs +++ b/src/pluto_eris/fp2.rs @@ -1,4 +1,5 @@ use super::fp::Fp; +use crate::ff::FromUniformBytes; use crate::ff::{Field, PrimeField, WithSmallOrderMulGroup}; use crate::ff_ext::quadratic::{QuadExtField, QuadExtFieldArith, SQRT}; use crate::ff_ext::{ExtField, Legendre}; @@ -11,6 +12,7 @@ crate::impl_binops_multiplicative!(Fp2, Fp2); crate::impl_binops_calls!(Fp2); crate::impl_sum_prod!(Fp2); crate::impl_tower2!(Fp, Fp2); +crate::impl_tower2_from_uniform_bytes!(Fp, Fp2, 128); pub type Fp2 = QuadExtField; @@ -78,29 +80,66 @@ impl ExtField for Fp2 { 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) - Fp::MODULUS_LIMBS - ); + use crate::{arith_test, constants_test, legendre_test, serde_test, test}; + use rand_core::RngCore; + + constants_test!(Fp2); + + arith_test!(Fp2); + legendre_test!(Fp2); + test!(arith, Fp2, sqrt_test, 1000); + + serde_test!(Fp2); + + crate::f2_test!(Fp2, Fp); + crate::frobenius_test!(Fp2, Fp, 20); + + #[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: Fp::NON_RESIDUE, + c1: Fp::zero(), + } + ); + } #[test] - fn test_fq2_mul_nonresidue() { - let e = Fp2::random(rand_core::OsRng); - let a0 = e.mul_by_nonresidue(); - let a1 = e * Fp2::NON_RESIDUE; - assert_eq!(a0, a1); + fn test_fp2_mul_nonresidue() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + for _ in 0..1000 { + let mut a = Fp2::random(&mut rng); + let mut b = a; + a = a.mul_by_nonresidue(); + b.mul_assign(&Fp2::NON_RESIDUE); + + assert_eq!(a, b); + } } } diff --git a/src/pluto_eris/fp6.rs b/src/pluto_eris/fp6.rs index 111c9b11..9b8df7db 100644 --- a/src/pluto_eris/fp6.rs +++ b/src/pluto_eris/fp6.rs @@ -251,38 +251,35 @@ pub(crate) const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [ #[cfg(test)] mod test { use super::*; - crate::field_testing_suite!(Fp6, "field_arithmetic"); - // extension field-specific - crate::field_testing_suite!(Fp6, "cubic_sparse_mul", 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, - ] - ); + use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; + use rand_core::RngCore; - #[test] - fn test_fq2_mul_nonresidue() { - let nqr = Fp6 { - c0: Fp2::ZERO, - c1: Fp2::ONE, - c2: Fp2::ZERO, + macro_rules! test_fp6 { + ($test:ident, $size: expr) => { + paste::paste! { + #[test] + fn [< $test test >]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed(crate::tests::SEED); + crate::pluto_eris::fp6::test::$test(&mut rng, $size); + } + } }; + } + arith_test!(Fp6); + setup_f6_test_funcs!(Fp6, Fp2); + test_fp6!(f6_mul_nonresidue_, 1000); + test_fp6!(f6_mul_by_1_, 1000); + test_fp6!(f6_mul_by_01_, 1000); + frobenius_test!(Fp6, Fp, 10); + + #[test] + fn test_fp6_mul_nonresidue() { let e = Fp6::random(rand_core::OsRng); let a0 = e.mul_by_nonresidue(); - let a1 = e * nqr; + let a1 = e * Fp6::NON_RESIDUE; assert_eq!(a0, a1); } diff --git a/src/pluto_eris/fq.rs b/src/pluto_eris/fq.rs index c1897e4c..f1717576 100644 --- a/src/pluto_eris/fq.rs +++ b/src/pluto_eris/fq.rs @@ -24,16 +24,17 @@ crate::impl_from_bool!(Fq); #[cfg(test)] mod test { + use super::Fq; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; - use super::*; - 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"); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 64, 72, 112); + constants_test!(Fq); + + arith_test!(Fq); + legendre_test!(Fq); + test!(arith, Fq, sqrt_test, 1000); + + serde_test!(Fq PrimeFieldBits); + from_uniform_bytes_test!(Fq, 1000, L 64, L 72, L 112); } diff --git a/src/secp256k1/fp.rs b/src/secp256k1/fp.rs index c486ce8e..8f036576 100644 --- a/src/secp256k1/fp.rs +++ b/src/secp256k1/fp.rs @@ -24,16 +24,15 @@ crate::impl_from_bool!(Fp); #[cfg(test)] mod test { + use super::Fp; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; - use super::*; - 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"); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); + constants_test!(Fp); + arith_test!(Fp); + legendre_test!(Fp); + test!(arith, Fp, sqrt_test, 1000); + serde_test!(Fp PrimeFieldBits); + from_uniform_bytes_test!(Fp, 1000, L 64, L 48); } diff --git a/src/secp256k1/fq.rs b/src/secp256k1/fq.rs index 0f93e4c9..037d51f0 100644 --- a/src/secp256k1/fq.rs +++ b/src/secp256k1/fq.rs @@ -24,15 +24,17 @@ crate::impl_from_bool!(Fq); #[cfg(test)] mod test { - use super::*; - 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"); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 48, 64); + use super::Fq; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; + + constants_test!(Fq); + + arith_test!(Fq); + legendre_test!(Fq); + test!(arith, Fq, sqrt_test, 1000); + + serde_test!(Fq); + from_uniform_bytes_test!(Fq, 1000, L 64, L 48); } diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index 76324047..ce423d5d 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -24,15 +24,17 @@ crate::impl_from_bool!(Fp); #[cfg(test)] mod test { - use super::*; - 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"); - crate::field_testing_suite!(Fp, "sqrt"); - crate::field_testing_suite!(Fp, "zeta"); - crate::field_testing_suite!(Fp, "from_uniform_bytes", 48, 64); + use super::Fp; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; + + constants_test!(Fp); + + arith_test!(Fp); + legendre_test!(Fp); + test!(arith, Fp, sqrt_test, 1000); + + serde_test!(Fp PrimeFieldBits); + from_uniform_bytes_test!(Fp, 1000, L 64, L 48); } diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index ef1c2d35..8e0c1071 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -24,16 +24,17 @@ crate::impl_from_bool!(Fq); #[cfg(test)] mod test { + use super::Fq; + use crate::{ + arith_test, constants_test, from_uniform_bytes_test, legendre_test, serde_test, test, + }; - use super::*; - 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"); - crate::field_testing_suite!(Fq, "sqrt"); - crate::field_testing_suite!(Fq, "zeta"); - crate::field_testing_suite!(Fq, "from_uniform_bytes", 48, 64); + constants_test!(Fq); + + arith_test!(Fq); + legendre_test!(Fq); + test!(arith, Fq, sqrt_test, 1000); + + serde_test!(Fq PrimeFieldBits); + from_uniform_bytes_test!(Fq, 1000, L 64, L 48); } diff --git a/src/tests/field.rs b/src/tests/field.rs index 655f076e..280d4131 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -1,654 +1,38 @@ -use ff::{FromUniformBytes, PrimeField}; +#[cfg(test)] +pub(crate) mod arith; -#[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_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); - - 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); - } - } - - 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); - - let mut t0 = a; // (a - b) - t0.sub_assign(&b); - - let mut t1 = b; // (b - a) - t1.sub_assign(&a); - - let mut t2 = t0; // (a - b) + (b - a) = 0 - t2.add_assign(&t1); - - assert_eq!(t2.is_zero().unwrap_u8(), 1); - } - } - - 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); - - assert_eq!(b.is_zero().unwrap_u8(), 1); - } - } - - 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(); - - assert_eq!(a, b); - } - } - - 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(); - - assert_eq!(a, b); - } - } - - fn random_inversion_tests(mut rng: R, n: usize) { - assert!(bool::from(F::ZERO.invert().is_none())); - - for _ in 0..n { - let mut a = F::random(&mut rng); - let b = a.invert().unwrap(); // probabilistically 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); +#[cfg(test)] +pub(crate) mod constants; - 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); - } - }; +#[cfg(test)] +#[macro_use] +pub(crate) mod extensions; - ($field: ident, "conversion") => { - #[test] - fn test_conversion() { - use ff::PrimeField; - 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(test)] +pub(crate) mod legendre; - #[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); - } - }; +#[cfg(test)] +pub(crate) mod serde; - ($field: ident, "quadratic_residue") => { +#[macro_export] +macro_rules! test { + ($mod: ident, $field:ident, $test:ident, $size:expr) => { #[test] - fn test_quadratic_residue() { - use $crate::ff_ext::Legendre; - use ff::Field; - use rand_core::SeedableRng; + fn $test() { + use super::*; + use rand::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,PrimeField}; - // 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") => { - #[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 $field::is_less_than_modulus(&rand_word) { - false => { - assert!($field::from_raw_bytes(&rand_bytes).is_none()); - } - _ => { - assert_eq!($field::from_raw_bytes(&rand_bytes), Some(a)); - } - } - } - } - }; - - ($field: ident, "constants") => { - #[test] - fn test_primefield_constants() { - use ff::PrimeField; - 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 ff::PrimeField; - 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() { - use ff::WithSmallOrderMulGroup; - 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", $($L:expr),* $(,)?) => { - - #[test] - fn test_from_uniform_bytes() { - $( - $crate::tests::field::run_test_from_uniform_bytes::<$field, $L>(); - )* - } - }; - - ($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, "cubic_sparse_mul", $base_field: ident) => { - #[test] - fn test_cubic_sparse_mul() { - 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 e = $ext_field::random(&mut rng); - - let a0 = $ext_field::mul_by_1(&e, &c1); - let a1 = e * $ext_field { - c0: $base_field::zero(), - c1, - c2: $base_field::zero(), - }; - - assert_eq!(a0, a1); - - - let a0 = $ext_field::mul_by_01(&e, &c0, &c1); - let a1 = e * $ext_field { - c0, - c1, - c2: $base_field::zero(), - }; - - assert_eq!(a0, a1); - } + let mut rng = XorShiftRng::from_seed($crate::tests::SEED); + $crate::tests::field::$mod::$test::<$field>(&mut rng, $size); } }; - - ($ext_field: ident, "quadratic_sparse_mul", $base_field_1: ident, $base_field_2: ident) => { - #[test] - fn test_quadratic_sparse_mul() { - 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 c2 = $base_field_2::random(&mut rng); - - - let mut a0 = $ext_field::random(&mut rng); - let a1 = a0 * $ext_field { - c0: $base_field_1 { - c0, - c1, - c2: $base_field_2::zero(), - }, - c1: $base_field_1 { - c0: $base_field_2::zero(), - c1: c2, - c2: $base_field_2::zero(), - }, - }; - $ext_field::mul_by_014(&mut a0, &c0, &c1, &c2); - assert_eq!(a0, a1); - - let mut a0 = $ext_field::random(&mut rng); - let a1 = a0 * $ext_field { - c0: $base_field_1 { - c0, - c1: $base_field_2::zero(), - c2: $base_field_2::zero(), - }, - c1: $base_field_1 { - c0: c1, - c1: c2, - c2: $base_field_2::zero(), - }, - }; - $ext_field::mul_by_034(&mut a0, &c0, &c1, &c2); - assert_eq!(a0, a1); - } - } - }; - - ($ext_field: ident, "frobenius", $frobenius_param: expr) => { + ($mod: ident, $field:ident, $test:ident) => { #[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); - } - } + fn $test() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed($crate::tests::SEED); + $crate::tests::field::$mod::$test::<$field>(&mut rng); } }; } - -pub(crate) fn run_test_from_uniform_bytes() -where - F: FromUniformBytes, -{ - use num_bigint::BigUint; - use rand_core::OsRng; - use rand_core::RngCore; - - let uniform_bytes = [0u8; L]; - assert_eq!(F::from_uniform_bytes(&uniform_bytes), F::ZERO); - - let mut uniform_bytes = [u8::MAX; L]; - - for _ in 0..10000 { - let e0 = BigUint::from_bytes_le(&uniform_bytes); - let e0: F = crate::tests::big_to_fe(&e0); - - let e1 = F::from_uniform_bytes(&uniform_bytes); - assert_eq!(e0, e1); - - OsRng.fill_bytes(&mut uniform_bytes[..]); - } -} diff --git a/src/tests/field/arith.rs b/src/tests/field/arith.rs new file mode 100644 index 00000000..09d11af9 --- /dev/null +++ b/src/tests/field/arith.rs @@ -0,0 +1,219 @@ +use ff::Field; +use rand::RngCore; + +pub(crate) fn mul_test(mut rng: impl RngCore, 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); + } +} + +pub(crate) fn add_test(mut rng: impl RngCore, 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.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); + } +} + +pub(crate) fn sub_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let b = F::random(&mut rng); + + let mut t0 = a; // (a - b) + t0.sub_assign(&b); + + let mut t1 = b; // (b - a) + t1.sub_assign(&a); + + let mut t2 = t0; // (a - b) + (b - a) = 0 + t2.add_assign(&t1); + + assert_eq!(t2.is_zero().unwrap_u8(), 1); + } +} + +pub(crate) fn neg_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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); + } +} + +pub(crate) fn double_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let mut a = F::random(&mut rng); + let mut b = a; + a.add_assign(&b); + b = b.double(); + + assert_eq!(a, b); + } +} + +pub(crate) fn square_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let mut a = F::random(&mut rng); + let mut b = a; + a.mul_assign(&b); + b = b.square(); + + assert_eq!(a, b); + } +} + +pub(crate) fn inv_test(mut rng: impl RngCore, n: usize) { + assert!(bool::from(F::ZERO.invert().is_none())); + + for _ in 0..n { + let mut a = F::random(&mut rng); + let b = a.invert().unwrap(); // probabilistically nonzero + a.mul_assign(&b); + + assert_eq!(a, F::ONE); + } +} + +pub(crate) fn expansion_test(mut rng: impl RngCore, 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); + } +} + +pub(crate) fn zero_test(mut rng: impl RngCore) { + 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); + } +} + +pub(crate) fn one_test(mut rng: impl RngCore) { + 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); + } +} + +#[macro_export] +macro_rules! arith_test { + ($field:ident) => { + test!(arith, $field, mul_test, 1000); + test!(arith, $field, add_test, 1000); + test!(arith, $field, sub_test, 1000); + test!(arith, $field, neg_test, 1000); + test!(arith, $field, double_test, 1000); + test!(arith, $field, square_test, 1000); + test!(arith, $field, inv_test, 1000); + test!(arith, $field, expansion_test, 1000); + test!(arith, $field, one_test); + test!(arith, $field, zero_test); + }; +} + +// This test is autside the `arith_test` macro since it is only +// implemented for prime fields and quadratic extensions. +pub(crate) fn sqrt_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let a = F::random(&mut rng); + let b = a.square(); + + let b = b.sqrt().unwrap(); + let negb = b.neg(); + + assert!(a == b || a == negb); + } +} diff --git a/src/tests/field/constants.rs b/src/tests/field/constants.rs new file mode 100644 index 00000000..bbf7b438 --- /dev/null +++ b/src/tests/field/constants.rs @@ -0,0 +1,32 @@ +use ff::PrimeField; +pub(crate) fn primefield_constants_test() { + assert_eq!(F::ROOT_OF_UNITY_INV, F::ROOT_OF_UNITY.invert().unwrap()); + assert_eq!(F::from(2) * F::TWO_INV, F::ONE); + if F::S != 0 { + assert_eq!(F::ROOT_OF_UNITY.pow_vartime([1 << F::S]), F::ONE); + assert_eq!(F::DELTA, F::MULTIPLICATIVE_GENERATOR.pow([1u64 << F::S])); + } +} + +use ff::WithSmallOrderMulGroup; +pub(crate) fn zeta_test>() { + assert_eq!(F::ZETA * F::ZETA * F::ZETA, F::ONE); + assert_ne!(F::ZETA * F::ZETA, F::ONE); +} + +#[macro_export] +macro_rules! constants_test { + ($field:ident) => { + #[test] + fn primefield_constants_test() { + use super::*; + $crate::tests::field::constants::primefield_constants_test::<$field>(); + } + + #[test] + fn zeta_test() { + use super::*; + $crate::tests::field::constants::zeta_test::<$field>(); + } + }; +} diff --git a/src/tests/field/extensions.rs b/src/tests/field/extensions.rs new file mode 100644 index 00000000..a0079c85 --- /dev/null +++ b/src/tests/field/extensions.rs @@ -0,0 +1,206 @@ +// F2 tests +#[macro_export] +macro_rules! f2_test { + ($ext_field:ident, + $base_field:ident) => { + #[test] + fn f2_ordering_test() { + use ark_std::cmp::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 f2_zero_one_test() { + 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 + ); + } + }; +} + +// F6 tests +#[macro_export] +macro_rules! setup_f6_test_funcs { + ($ext_field:ident, + $base_field:ident) => { + fn f6_mul_nonresidue_(mut rng: impl RngCore, n: usize) { + let nqr = $ext_field { + c0: $base_field::zero(), + c1: $base_field::one(), + c2: $base_field::zero(), + }; + + for _ in 0..n { + let mut a = $ext_field::random(&mut rng); + let mut b = a; + a = a.mul_by_nonresidue(); + b.mul_assign(&nqr); + + assert_eq!(a, b); + } + } + + fn f6_mul_by_1_(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let c1 = $base_field::random(&mut rng); + let mut a = $ext_field::random(&mut rng); + let mut b = a; + + a = <$ext_field as CubicSparseMul>::mul_by_1(&a, &c1); + b.mul_assign(&$ext_field { + c0: $base_field::zero(), + c1, + c2: $base_field::zero(), + }); + + assert_eq!(a, b); + } + } + + fn f6_mul_by_01_(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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 = <$ext_field as CubicSparseMul>::mul_by_01(&a, &c0, &c1); + b.mul_assign(&$ext_field { + c0, + c1, + c2: $base_field::zero(), + }); + + assert_eq!(a, b); + } + } + }; +} + +// F12 tests +#[macro_export] +macro_rules! setup_f12_test_funcs { + ($ext_field:ident, + $base_field_1:ident, + $base_field_2:ident) => { + fn f12_mul_by_014_(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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; + <$ext_field as QuadSparseMul>::mul_by_014(&mut a, &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); + } + } + + fn f12_mul_by_034_(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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; + + <$ext_field as QuadSparseMul>::mul_by_034(&mut a, &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); + } + } + }; +} + +#[macro_export] +macro_rules! frobenius_test { + ($field:ident, $base: ident, $size: expr) => { + fn test_frobenius(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + for i in 0..12 { + let mut a = $field::random(&mut rng); + let mut b = a; + + for _ in 0..i { + a = a.pow($base::MODULUS_LIMBS); + } + b.frobenius_map(i); + + assert_eq!(a, b); + } + } + } + + #[test] + fn frobenius_test() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed($crate::tests::SEED); + test_frobenius(&mut rng, $size); + } + }; +} diff --git a/src/tests/field/legendre.rs b/src/tests/field/legendre.rs new file mode 100644 index 00000000..ad65e477 --- /dev/null +++ b/src/tests/field/legendre.rs @@ -0,0 +1,32 @@ +use crate::ff_ext::Legendre; +use ff::PrimeField; +use rand::RngCore; + +pub(crate) fn legendre_symbol_test(mut rng: impl RngCore, n: usize) { + assert_eq!(F::ZERO.legendre(), 0); + for _ in 0..n { + let a = F::random(&mut rng); + if a.legendre() == -1 { + assert!(bool::from(a.sqrt().is_none())); + } + let b = a.square(); + assert_eq!(b.legendre(), 1); + } +} + +pub(crate) fn quadratic_residue_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + let elem = F::random(&mut rng); + let is_quad_non_res: bool = elem.ct_quadratic_non_residue().into(); + let is_quad_res_or_zero: bool = elem.ct_quadratic_residue().into(); + assert_eq!(!is_quad_non_res, is_quad_res_or_zero) + } +} + +#[macro_export] +macro_rules! legendre_test { + ($field:ident) => { + test!(legendre, $field, legendre_symbol_test, 1000); + test!(legendre, $field, quadratic_residue_test, 1000); + }; +} diff --git a/src/tests/field/serde.rs b/src/tests/field/serde.rs new file mode 100644 index 00000000..9192b09b --- /dev/null +++ b/src/tests/field/serde.rs @@ -0,0 +1,127 @@ +use ff::{Field, FromUniformBytes, PrimeField}; +use rand::RngCore; + +use crate::serde::SerdeObject; + +// Tests to_repr/ from_repr +pub(crate) fn from_to_repr_test(mut rng: impl RngCore, n: usize) { + // n = 1M + for _ in 0..n { + let a = F::random(&mut rng); + let bytes = a.to_repr(); + let b = F::from_repr(bytes).unwrap(); + assert_eq!(a, b); + } +} + +// Tests to_raw_bytes / from_raw_bytes + read_raw /write_raw +pub(crate) fn from_to_raw_bytes_test(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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); + } +} + +// Tests derive_serde +#[cfg(feature = "derive_serde")] +pub(crate) fn derive_serde_test(mut rng: impl RngCore, n: usize) +where + for<'de> F: Field + serde::Serialize + serde::Deserialize<'de>, +{ + for _ in 0..n { + // byte serialization + let a = F::random(&mut rng); + let bytes = bincode::serialize(&a).unwrap(); + let reader = std::io::Cursor::new(bytes); + let b = 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); + } +} + +#[cfg(feature = "bits")] +pub(crate) fn test_bits(mut rng: impl RngCore, n: usize) { + for _ in 0..n { + 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); + } + } +} + +#[macro_export] +macro_rules! serde_test { + ($field:ident) => { + test!(serde, $field, from_to_repr_test, 100_000); + test!(serde, $field, from_to_raw_bytes_test, 100_000); + #[cfg(feature = "derive_serde")] + test!(serde, $field, derive_serde_test, 100_000); + }; + + ($field:ident PrimeFieldBits) => { + serde_test!($field); + #[cfg(feature = "bits")] + test!(serde, $field, test_bits, 100_000); + }; +} + +// Out of serde_tests macro, since it needs to be tested for several generic L. +// Tests from_uniform_bytes **for prime fields only**. +pub(crate) fn from_uniform_bytes_test( + mut rng: impl RngCore, + n: usize, +) where + F: FromUniformBytes, +{ + use num_bigint::BigUint; + + let uniform_bytes = [0u8; L]; + assert_eq!(F::from_uniform_bytes(&uniform_bytes), F::ZERO); + + let mut uniform_bytes = [u8::MAX; L]; + + for _ in 0..n { + let e0 = BigUint::from_bytes_le(&uniform_bytes); + let e0: F = crate::tests::big_to_fe(&e0); + + let e1 = F::from_uniform_bytes(&uniform_bytes); + assert_eq!(e0, e1); + + rng.fill_bytes(&mut uniform_bytes[..]); + } +} + +#[macro_export] +macro_rules! from_uniform_bytes_test { + ($field:ident, $size:expr, L $L: expr ) => { + paste::paste! { + #[test] + fn [< from_uniform_bytes_test_ $L>]() { + use rand::SeedableRng; + use rand_xorshift::XorShiftRng; + let mut rng = XorShiftRng::from_seed($crate::tests::SEED); + $crate::tests::field::serde::from_uniform_bytes_test::<$field, $L>(&mut rng, $size); + } + + } + }; + + ($field:ident,$size:expr, L $L:expr, $(L $rest:expr),+ ) => { + from_uniform_bytes_test!( $field, $size, L $L ); + from_uniform_bytes_test! { $field, $size, $(L $rest),+ } + }; +} diff --git a/src/tests/mod.rs b/src/tests/mod.rs index db7095a4..9673e0a5 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -3,9 +3,16 @@ use num_bigint::BigUint; use pasta_curves::arithmetic::CurveAffine; pub mod curve; +#[macro_use] pub mod field; pub mod pairing; +// SEED for random tests. +pub(crate) const SEED: [u8; 16] = [ + 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, +]; +// Helper functions for converting between +// Field <> BigInt <> Hex string pub(crate) fn hex_to_bytes(hex: &str) -> Vec { let bytes = hex.as_bytes().to_vec(); bytes @@ -23,8 +30,8 @@ pub(crate) fn hex_to_field(hex: &str) -> F { } pub(crate) fn point_from_hex(x: &str, y: &str) -> C { - let x = crate::tests::hex_to_field(x); - let y = crate::tests::hex_to_field(y); + let x = hex_to_field(x); + let y = hex_to_field(y); C::from_xy(x, y).unwrap() }