use ark_ff::{ biginteger::{BigInteger, BigInteger256}, fields::{ fp6_3over2::Fp6Parameters, FftField, FftParameters, Field, FpParameters, PrimeField, SquareRootField, }, One, UniformRand, Zero, }; use ark_serialize::{buffer_bit_byte_size, CanonicalSerialize}; use ark_std::rand::Rng; use ark_std::test_rng; use core::{ cmp::Ordering, ops::{AddAssign, MulAssign, SubAssign}, }; use crate::{Fq, Fq12, Fq2, Fq6, Fq6Parameters, FqParameters, Fr}; use ark_algebra_test_templates::fields::*; pub(crate) const ITERATIONS: usize = 5; #[test] fn test_fr() { let mut rng = test_rng(); for _ in 0..ITERATIONS { let a: Fr = rng.gen(); let b: Fr = rng.gen(); field_test(a, b); primefield_test::(); sqrt_field_test(b); let byte_size = a.serialized_size(); field_serialization_test::(byte_size); } } #[test] fn test_fq() { let mut rng = test_rng(); for _ in 0..ITERATIONS { let a: Fq = rng.gen(); let b: Fq = rng.gen(); field_test(a, b); primefield_test::(); sqrt_field_test(a); let byte_size = a.serialized_size(); let (_, buffer_size) = buffer_bit_byte_size(Fq::size_in_bits()); assert_eq!(byte_size, buffer_size); field_serialization_test::(byte_size); } } #[test] fn test_fq2() { let mut rng = test_rng(); for _ in 0..ITERATIONS { let a: Fq2 = rng.gen(); let b: Fq2 = rng.gen(); field_test(a, b); sqrt_field_test(a); } frobenius_test::(Fq::characteristic(), 13); let byte_size = Fq2::zero().serialized_size(); field_serialization_test::(byte_size); } #[test] fn test_fq6() { let mut rng = test_rng(); for _ in 0..ITERATIONS { let g: Fq6 = rng.gen(); let h: Fq6 = rng.gen(); field_test(g, h); } frobenius_test::(Fq::characteristic(), 13); let byte_size = Fq6::zero().serialized_size(); field_serialization_test::(byte_size); } #[test] fn test_fq12() { let mut rng = test_rng(); for _ in 0..ITERATIONS { let g: Fq12 = rng.gen(); let h: Fq12 = rng.gen(); field_test(g, h); } frobenius_test::(Fq::characteristic(), 13); let byte_size = Fq12::zero().serialized_size(); field_serialization_test::(byte_size); } #[test] fn test_fq_repr_from() { assert_eq!(BigInteger256::from(100), BigInteger256([100, 0, 0, 0])); } #[test] fn test_fq_repr_is_odd() { assert!(!BigInteger256::from(0).is_odd()); assert!(BigInteger256::from(0).is_even()); assert!(BigInteger256::from(1).is_odd()); assert!(!BigInteger256::from(1).is_even()); assert!(!BigInteger256::from(324834872).is_odd()); assert!(BigInteger256::from(324834872).is_even()); assert!(BigInteger256::from(324834873).is_odd()); assert!(!BigInteger256::from(324834873).is_even()); } #[test] fn test_fq_repr_is_zero() { assert!(BigInteger256::from(0).is_zero()); assert!(!BigInteger256::from(1).is_zero()); assert!(!BigInteger256([0, 0, 1, 0]).is_zero()); } #[test] fn test_fq_repr_num_bits() { let mut a = BigInteger256::from(0); assert_eq!(0, a.num_bits()); a = BigInteger256::from(1); for i in 1..257 { assert_eq!(i, a.num_bits()); a.mul2(); } assert_eq!(0, a.num_bits()); } #[test] fn test_fq_add_assign() { // Test associativity let mut rng = ark_std::test_rng(); for _ in 0..1000 { // Generate a, b, c and ensure (a + b) + c == a + (b + c). let a = Fq::rand(&mut rng); let b = Fq::rand(&mut rng); let c = Fq::rand(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); tmp1.add_assign(&c); let mut tmp2 = b; tmp2.add_assign(&c); tmp2.add_assign(&a); assert_eq!(tmp1, tmp2); } } #[test] fn test_fq_sub_assign() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { // Ensure that (a - b) + (b - a) = 0. let a = Fq::rand(&mut rng); let b = Fq::rand(&mut rng); let mut tmp1 = a; tmp1.sub_assign(&b); let mut tmp2 = b; tmp2.sub_assign(&a); tmp1.add_assign(&tmp2); assert!(tmp1.is_zero()); } } #[test] fn test_fq_mul_assign() { let mut rng = ark_std::test_rng(); for _ in 0..1000000 { // Ensure that (a * b) * c = a * (b * c) let a = Fq::rand(&mut rng); let b = Fq::rand(&mut rng); let c = Fq::rand(&mut rng); let mut tmp1 = a; tmp1.mul_assign(&b); tmp1.mul_assign(&c); let mut tmp2 = b; tmp2.mul_assign(&c); tmp2.mul_assign(&a); assert_eq!(tmp1, tmp2); } for _ in 0..1000000 { // Ensure that r * (a + b + c) = r*a + r*b + r*c let r = Fq::rand(&mut rng); let mut a = Fq::rand(&mut rng); let mut b = Fq::rand(&mut rng); let mut c = Fq::rand(&mut rng); let mut tmp1 = a; tmp1.add_assign(&b); tmp1.add_assign(&c); tmp1.mul_assign(&r); a.mul_assign(&r); b.mul_assign(&r); c.mul_assign(&r); a.add_assign(&b); a.add_assign(&c); assert_eq!(tmp1, a); } } #[test] fn test_fq_squaring() { let mut rng = ark_std::test_rng(); for _ in 0..1000000 { // Ensure that (a * a) = a^2 let a = Fq::rand(&mut rng); let mut tmp = a; tmp.square_in_place(); let mut tmp2 = a; tmp2.mul_assign(&a); assert_eq!(tmp, tmp2); } } #[test] fn test_fq_inverse() { assert!(Fq::zero().inverse().is_none()); let mut rng = ark_std::test_rng(); let one = Fq::one(); for _ in 0..1000 { // Ensure that a * a^-1 = 1 let mut a = Fq::rand(&mut rng); let ainv = a.inverse().unwrap(); a.mul_assign(&ainv); assert_eq!(a, one); } } #[test] fn test_fq_double_in_place() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { // Ensure doubling a is equivalent to adding a to itself. let mut a = Fq::rand(&mut rng); let mut b = a; b.add_assign(&a); a.double_in_place(); assert_eq!(a, b); } } #[test] fn test_fq_negate() { { let a = -Fq::zero(); assert!(a.is_zero()); } let mut rng = ark_std::test_rng(); for _ in 0..1000 { // Ensure (a - (-a)) = 0. let mut a = Fq::rand(&mut rng); let b = -a; a.add_assign(&b); assert!(a.is_zero()); } } #[test] fn test_fq_pow() { let mut rng = ark_std::test_rng(); for i in 0..1000 { // Exponentiate by various small numbers and ensure it consists with repeated // multiplication. let a = Fq::rand(&mut rng); let target = a.pow(&[i]); let mut c = Fq::one(); for _ in 0..i { c.mul_assign(&a); } assert_eq!(c, target); } for _ in 0..1000 { // Exponentiating by the modulus should have no effect in a prime field. let a = Fq::rand(&mut rng); assert_eq!(a, a.pow(Fq::characteristic())); } } #[test] fn test_fq_sqrt() { let mut rng = ark_std::test_rng(); assert_eq!(Fq::zero().sqrt().unwrap(), Fq::zero()); for _ in 0..1000 { // Ensure sqrt(a^2) = a or -a let a = Fq::rand(&mut rng); let nega = -a; let mut b = a; b.square_in_place(); let b = b.sqrt().unwrap(); assert!(a == b || nega == b); } for _ in 0..1000 { // Ensure sqrt(a)^2 = a for random a let a = Fq::rand(&mut rng); if let Some(mut tmp) = a.sqrt() { tmp.square_in_place(); assert_eq!(a, tmp); } } } #[test] fn test_fq_num_bits() { assert_eq!(FqParameters::MODULUS_BITS, 254); assert_eq!(FqParameters::CAPACITY, 253); } #[test] fn test_fq_root_of_unity() { assert_eq!(FqParameters::TWO_ADICITY, 1); assert_eq!( Fq::multiplicative_generator().pow([ 0x9e10460b6c3e7ea3, 0xcbc0b548b438e546, 0xdc2822db40c0ac2e, 0x183227397098d014, ]), Fq::two_adic_root_of_unity() ); assert_eq!( Fq::two_adic_root_of_unity().pow([1 << FqParameters::TWO_ADICITY]), Fq::one() ); assert!(Fq::multiplicative_generator().sqrt().is_none()); } #[test] fn test_fq_ordering() { // BigInteger256's ordering is well-tested, but we still need to make sure the // Fq elements aren't being compared in Montgomery form. for i in 0..100 { assert!(Fq::from(BigInteger256::from(i + 1)) > Fq::from(BigInteger256::from(i))); } } #[test] fn test_fq_legendre() { use ark_ff::fields::LegendreSymbol::*; assert_eq!(QuadraticResidue, Fq::one().legendre()); assert_eq!(Zero, Fq::zero().legendre()); assert_eq!( QuadraticResidue, Fq::from(BigInteger256::from(4)).legendre() ); assert_eq!( QuadraticNonResidue, Fq::from(BigInteger256::from(5)).legendre() ); } #[test] fn test_fq2_ordering() { let mut a = Fq2::new(Fq::zero(), Fq::zero()); let mut b = a.clone(); assert!(a.cmp(&b) == Ordering::Equal); b.c0.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Less); a.c0.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Equal); b.c1.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Less); a.c0.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Less); a.c1.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Greater); b.c0.add_assign(&Fq::one()); assert!(a.cmp(&b) == Ordering::Equal); } #[test] fn test_fq2_basics() { assert_eq!(Fq2::new(Fq::zero(), Fq::zero(),), Fq2::zero()); assert_eq!(Fq2::new(Fq::one(), Fq::zero(),), Fq2::one()); assert!(Fq2::zero().is_zero()); assert!(!Fq2::one().is_zero()); assert!(!Fq2::new(Fq::zero(), Fq::one(),).is_zero()); } #[test] fn test_fq2_legendre() { use ark_ff::fields::LegendreSymbol::*; assert_eq!(Zero, Fq2::zero().legendre()); // i^2 = -1 let mut m1 = -Fq2::one(); assert_eq!(QuadraticResidue, m1.legendre()); m1 = Fq6Parameters::mul_fp2_by_nonresidue(&m1); assert_eq!(QuadraticNonResidue, m1.legendre()); } #[test] fn test_fq6_mul_by_1() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { let c1 = Fq2::rand(&mut rng); let mut a = Fq6::rand(&mut rng); let mut b = a; a.mul_by_1(&c1); b.mul_assign(&Fq6::new(Fq2::zero(), c1, Fq2::zero())); assert_eq!(a, b); } } #[test] fn test_fq6_mul_by_01() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { let c0 = Fq2::rand(&mut rng); let c1 = Fq2::rand(&mut rng); let mut a = Fq6::rand(&mut rng); let mut b = a; a.mul_by_01(&c0, &c1); b.mul_assign(&Fq6::new(c0, c1, Fq2::zero())); assert_eq!(a, b); } } #[test] fn test_fq12_mul_by_014() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { let c0 = Fq2::rand(&mut rng); let c1 = Fq2::rand(&mut rng); let c5 = Fq2::rand(&mut rng); let mut a = Fq12::rand(&mut rng); let mut b = a; a.mul_by_014(&c0, &c1, &c5); b.mul_assign(&Fq12::new( Fq6::new(c0, c1, Fq2::zero()), Fq6::new(Fq2::zero(), c5, Fq2::zero()), )); assert_eq!(a, b); } } #[test] fn test_fq12_mul_by_034() { let mut rng = ark_std::test_rng(); for _ in 0..1000 { let c0 = Fq2::rand(&mut rng); let c3 = Fq2::rand(&mut rng); let c4 = Fq2::rand(&mut rng); let mut a = Fq12::rand(&mut rng); let mut b = a; a.mul_by_034(&c0, &c3, &c4); b.mul_assign(&Fq12::new( Fq6::new(c0, Fq2::zero(), Fq2::zero()), Fq6::new(c3, c4, Fq2::zero()), )); assert_eq!(a, b); } }