#![allow(unused)] use ark_ff::fields::{FftField, FftParameters, Field, LegendreSymbol, PrimeField, SquareRootField}; use ark_serialize::{buffer_bit_byte_size, Flags, SWFlags}; use ark_std::io::Cursor; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; pub const ITERATIONS: u32 = 40; fn random_negation_tests(rng: &mut R) { for _ in 0..ITERATIONS { let a = F::rand(rng); let mut b = -a; b += &a; assert!(b.is_zero()); } } fn random_addition_tests(rng: &mut R) { for _ in 0..ITERATIONS { let a = F::rand(rng); let b = F::rand(rng); let c = F::rand(rng); let t0 = (a + &b) + &c; // (a + b) + c let t1 = (a + &c) + &b; // (a + c) + b let t2 = (b + &c) + &a; // (b + c) + a assert_eq!(t0, t1); assert_eq!(t1, t2); } } fn random_subtraction_tests(rng: &mut R) { for _ in 0..ITERATIONS { let a = F::rand(rng); let b = F::rand(rng); let t0 = a - &b; // (a - b) let mut t1 = b; // (b - a) t1 -= &a; let mut t2 = t0; // (a - b) + (b - a) = 0 t2 += &t1; assert!(t2.is_zero()); } } fn random_multiplication_tests(rng: &mut R) { for _ in 0..ITERATIONS { let a = F::rand(rng); let b = F::rand(rng); let c = F::rand(rng); let mut t0 = a; // (a * b) * c t0 *= &b; t0 *= &c; let mut t1 = a; // (a * c) * b t1 *= &c; t1 *= &b; let mut t2 = b; // (b * c) * a t2 *= &c; t2 *= &a; assert_eq!(t0, t1); assert_eq!(t1, t2); } } fn random_inversion_tests(rng: &mut R) { assert!(F::zero().inverse().is_none()); for _ in 0..ITERATIONS { let mut a = F::rand(rng); let b = a.inverse().unwrap(); // probablistically nonzero a *= &b; assert_eq!(a, F::one()); } } fn random_doubling_tests(rng: &mut R) { for _ in 0..ITERATIONS { let mut a = F::rand(rng); let mut b = a; a += &b; b.double_in_place(); assert_eq!(a, b); } } fn random_squaring_tests(rng: &mut R) { for _ in 0..ITERATIONS { let mut a = F::rand(rng); let mut b = a; a *= &b; b.square_in_place(); assert_eq!(a, b); } } fn random_expansion_tests(rng: &mut R) { for _ in 0..ITERATIONS { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) let a = F::rand(rng); let b = F::rand(rng); let c = F::rand(rng); let d = F::rand(rng); let mut t0 = a; t0 += &b; let mut t1 = c; t1 += &d; t0 *= &t1; let mut t2 = a; t2 *= &c; let mut t3 = b; t3 *= &c; let mut t4 = a; t4 *= &d; let mut t5 = b; t5 *= &d; t2 += &t3; t2 += &t4; t2 += &t5; assert_eq!(t0, t2); } for _ in 0..ITERATIONS { // Compare (a + b)c and (a*c + b*c) let a = F::rand(rng); let b = F::rand(rng); let c = F::rand(rng); let t0 = (a + &b) * &c; let t2 = a * &c + &(b * &c); assert_eq!(t0, t2); } } fn random_field_tests() { let mut rng = XorShiftRng::seed_from_u64(1231275789u64); random_negation_tests::(&mut rng); random_addition_tests::(&mut rng); random_subtraction_tests::(&mut rng); random_multiplication_tests::(&mut rng); random_inversion_tests::(&mut rng); random_doubling_tests::(&mut rng); random_squaring_tests::(&mut rng); random_expansion_tests::(&mut rng); assert!(F::zero().is_zero()); { let z = -F::zero(); assert!(z.is_zero()); } assert!(F::zero().inverse().is_none()); // Multiplication by zero { let a = F::rand(&mut rng) * &F::zero(); assert!(a.is_zero()); } // Addition by zero { let mut a = F::rand(&mut rng); let copy = a; a += &F::zero(); assert_eq!(a, copy); } } fn random_sqrt_tests() { let mut rng = XorShiftRng::seed_from_u64(1231275789u64); for _ in 0..ITERATIONS { let a = F::rand(&mut rng); let b = a.square(); assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); let b = b.sqrt().unwrap(); assert!(a == b || a == -b); } let mut c = F::one(); for _ in 0..ITERATIONS { let mut b = c.square(); assert_eq!(b.legendre(), LegendreSymbol::QuadraticResidue); b = b.sqrt().unwrap(); if b != c { b = -b; } assert_eq!(b, c); c += &F::one(); } } pub fn from_str_test() { { let mut rng = XorShiftRng::seed_from_u64(1231275789u64); for _ in 0..ITERATIONS { let n: u64 = rng.gen(); let a = F::from_str(&ark_std::format!("{}", n)) .map_err(|_| ()) .unwrap(); let b = F::from_repr(n.into()).unwrap(); assert_eq!(a, b); } } assert!(F::from_str("").is_err()); assert!(F::from_str("0").map_err(|_| ()).unwrap().is_zero()); assert!(F::from_str("00").is_err()); assert!(F::from_str("00000000000").is_err()); } pub fn field_test(a: F, b: F) { let zero = F::zero(); assert_eq!(zero, zero); assert_eq!(zero.is_zero(), true); assert_eq!(zero.is_one(), false); let one = F::one(); assert_eq!(one, one); assert_eq!(one.is_zero(), false); assert_eq!(one.is_one(), true); assert_eq!(zero + &one, one); let two = one + &one; assert_eq!(two, two); assert_ne!(zero, two); assert_ne!(one, two); // a == a assert_eq!(a, a); // a + 0 = a assert_eq!(a + &zero, a); // a - 0 = a assert_eq!(a - &zero, a); // a - a = 0 assert_eq!(a - &a, zero); // 0 - a = -a assert_eq!(zero - &a, -a); // a.double() = a + a assert_eq!(a.double(), a + &a); // b.double() = b + b assert_eq!(b.double(), b + &b); // a + b = b + a assert_eq!(a + &b, b + &a); // a - b = -(b - a) assert_eq!(a - &b, -(b - &a)); // (a + b) + a = a + (b + a) assert_eq!((a + &b) + &a, a + &(b + &a)); // (a + b).double() = (a + b) + (b + a) assert_eq!((a + &b).double(), (a + &b) + &(b + &a)); // a * 0 = 0 assert_eq!(a * &zero, zero); // a * 1 = a assert_eq!(a * &one, a); // a * 2 = a.double() assert_eq!(a * &two, a.double()); // a * a^-1 = 1 assert_eq!(a * &a.inverse().unwrap(), one); // a * a = a^2 assert_eq!(a * &a, a.square()); // a * a * a = a^3 assert_eq!(a * &(a * &a), a.pow([0x3, 0x0, 0x0, 0x0])); // a * b = b * a assert_eq!(a * &b, b * &a); // (a * b) * a = a * (b * a) assert_eq!((a * &b) * &a, a * &(b * &a)); // (a + b)^2 = a^2 + 2ab + b^2 assert_eq!( (a + &b).square(), a.square() + &((a * &b) + &(a * &b)) + &b.square() ); // (a - b)^2 = (-(b - a))^2 assert_eq!((a - &b).square(), (-(b - &a)).square()); random_field_tests::(); } pub fn fft_field_test() { assert_eq!( F::two_adic_root_of_unity().pow([1 << F::FftParams::TWO_ADICITY]), F::one() ); if let Some(small_subgroup_base) = F::FftParams::SMALL_SUBGROUP_BASE { let small_subgroup_base_adicity = F::FftParams::SMALL_SUBGROUP_BASE_ADICITY.unwrap(); let large_subgroup_root_of_unity = F::large_subgroup_root_of_unity().unwrap(); assert_eq!( large_subgroup_root_of_unity.pow([(1 << F::FftParams::TWO_ADICITY) * (small_subgroup_base as u64).pow(small_subgroup_base_adicity)]), F::one() ); for i in 0..F::FftParams::TWO_ADICITY { for j in 0..small_subgroup_base_adicity { use core::convert::TryFrom; let size = usize::try_from(1 << i as usize).unwrap() * usize::try_from((small_subgroup_base as u64).pow(j)).unwrap(); let root = F::get_root_of_unity(size).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); } } } else { for i in 0..F::FftParams::TWO_ADICITY { let size = 1 << i; let root = F::get_root_of_unity(size).unwrap(); assert_eq!(root.pow([size as u64]), F::one()); } } } pub fn primefield_test() { from_str_test::(); let one = F::one(); assert_eq!(F::from(one.into_repr()), one); fft_field_test::(); } pub fn sqrt_field_test(elem: F) { let square = elem.square(); let sqrt = square.sqrt().unwrap(); assert!(sqrt == elem || sqrt == -elem); if let Some(sqrt) = elem.sqrt() { assert!(sqrt.square() == elem || sqrt.square() == -elem); } random_sqrt_tests::(); } pub fn frobenius_test>(characteristic: C, maxpower: usize) { let mut rng = XorShiftRng::seed_from_u64(1231275789u64); for _ in 0..ITERATIONS { let a = F::rand(&mut rng); let mut a_0 = a; a_0.frobenius_map(0); assert_eq!(a, a_0); let mut a_q = a.pow(&characteristic); for power in 1..maxpower { let mut a_qi = a; a_qi.frobenius_map(power); assert_eq!(a_qi, a_q, "failed on power {}", power); a_q = a_q.pow(&characteristic); } } } pub fn field_serialization_test(buf_size: usize) { let mut rng = XorShiftRng::seed_from_u64(1231275789u64); for _ in 0..ITERATIONS { let a = F::rand(&mut rng); { let mut serialized = vec![0u8; buf_size]; let mut cursor = Cursor::new(&mut serialized[..]); a.serialize(&mut cursor).unwrap(); let mut cursor = Cursor::new(&serialized[..]); let b = F::deserialize(&mut cursor).unwrap(); assert_eq!(a, b); } { let mut serialized = vec![0u8; a.uncompressed_size()]; let mut cursor = Cursor::new(&mut serialized[..]); a.serialize_uncompressed(&mut cursor).unwrap(); let mut cursor = Cursor::new(&serialized[..]); let b = F::deserialize_uncompressed(&mut cursor).unwrap(); assert_eq!(a, b); } { let mut serialized = vec![0u8; buf_size]; let mut cursor = Cursor::new(&mut serialized[..]); a.serialize_with_flags(&mut cursor, SWFlags::from_y_sign(true)) .unwrap(); let mut cursor = Cursor::new(&serialized[..]); let (b, flags) = F::deserialize_with_flags::<_, SWFlags>(&mut cursor).unwrap(); assert_eq!(flags.is_positive(), Some(true)); assert!(!flags.is_infinity()); assert_eq!(a, b); } #[derive(Default, Clone, Copy, Debug)] struct DummyFlags; impl Flags for DummyFlags { fn u8_bitmask(&self) -> u8 { 0 } fn from_u8(_value: u8) -> Self { DummyFlags } fn from_u8_remove_flags(_value: &mut u8) -> Self { DummyFlags } fn len() -> usize { 200 } } use ark_serialize::SerializationError; { let mut serialized = vec![0; buf_size]; assert!(if let SerializationError::NotEnoughSpace = a .serialize_with_flags(&mut &mut serialized[..], DummyFlags) .unwrap_err() { true } else { false }); assert!(if let SerializationError::NotEnoughSpace = F::deserialize_with_flags::<_, DummyFlags>(&mut &serialized[..]).unwrap_err() { true } else { false }); } { let mut serialized = vec![0; buf_size - 1]; let mut cursor = Cursor::new(&mut serialized[..]); a.serialize(&mut cursor).unwrap_err(); let mut cursor = Cursor::new(&serialized[..]); F::deserialize(&mut cursor).unwrap_err(); } } }