diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index b49a1649..3ac7b89b 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -201,82 +201,25 @@ impl> DivAssign for QuadraticExtension { #[cfg(test)] mod tests { - use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quadratic::QuadraticExtension; - use crate::field::extension_field::Frobenius; - use crate::field::field_types::Field; - use crate::test_field_arithmetic; + mod crandall { + use crate::{test_field_arithmetic, test_field_extension}; - #[test] - fn test_add_neg_sub_mul() { - type F = QuadraticExtension; - let x = F::rand(); - let y = F::rand(); - let z = F::rand(); - assert_eq!(x + (-x), F::ZERO); - assert_eq!(-x, F::ZERO - x); - assert_eq!(x + x, x * F::TWO); - assert_eq!(x * (-x), -x.square()); - assert_eq!(x + y, y + x); - assert_eq!(x * y, y * x); - assert_eq!(x * (y * z), (x * y) * z); - assert_eq!(x - (y + z), (x - y) - z); - assert_eq!((x + y) - z, x + (y - z)); - assert_eq!(x * (y + z), x * y + x * z); - } - - #[test] - fn test_inv_div() { - type F = QuadraticExtension; - let x = F::rand(); - let y = F::rand(); - let z = F::rand(); - assert_eq!(x * x.inverse(), F::ONE); - assert_eq!(x.inverse() * x, F::ONE); - assert_eq!(x.square().inverse(), x.inverse().square()); - assert_eq!((x / y) * y, x); - assert_eq!(x / (y * z), (x / y) / z); - assert_eq!((x * y) / z, x * (y / z)); - } - - #[test] - fn test_frobenius() { - type F = QuadraticExtension; - let x = F::rand(); - assert_eq!(x.exp_biguint(&CrandallField::order()), x.frobenius()); - } - - #[test] - fn test_field_order() { - // F::order() = 340282366831806780677557380898690695169 = 18446744071293632512 *18446744071293632514 + 1 - type F = QuadraticExtension; - let x = F::rand(); - assert_eq!( - x.exp_u64(18446744071293632512) - .exp_u64(18446744071293632514), - F::ONE + test_field_extension!(crate::field::crandall_field::CrandallField, 2); + test_field_arithmetic!( + crate::field::extension_field::quadratic::QuadraticExtension< + crate::field::crandall_field::CrandallField, + > ); } - #[test] - fn test_power_of_two_gen() { - type F = QuadraticExtension; - // F::order() = 2^29 * 2762315674048163 * 229454332791453 + 1 - assert_eq!( - F::MULTIPLICATIVE_GROUP_GENERATOR - .exp_u64(2762315674048163) - .exp_u64(229454332791453), - F::POWER_OF_TWO_GENERATOR - ); - assert_eq!( - F::POWER_OF_TWO_GENERATOR.exp_u64(1 << (F::TWO_ADICITY - CrandallField::TWO_ADICITY)), - CrandallField::POWER_OF_TWO_GENERATOR.into() + mod goldilocks { + use crate::{test_field_arithmetic, test_field_extension}; + + test_field_extension!(crate::field::goldilocks_field::GoldilocksField, 2); + test_field_arithmetic!( + crate::field::extension_field::quadratic::QuadraticExtension< + crate::field::goldilocks_field::GoldilocksField, + > ); } - - test_field_arithmetic!( - crate::field::extension_field::quadratic::QuadraticExtension< - crate::field::crandall_field::CrandallField, - > - ); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index e89a7be5..97fc195e 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -227,108 +227,25 @@ impl> DivAssign for QuarticExtension { #[cfg(test)] mod tests { - use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quartic::QuarticExtension; - use crate::field::extension_field::Frobenius; - use crate::field::field_types::Field; - use crate::test_field_arithmetic; + mod crandall { + use crate::{test_field_arithmetic, test_field_extension}; - fn exp_naive(x: F, power: u128) -> F { - let mut current = x; - let mut product = F::ONE; - - for j in 0..128 { - if (power >> j & 1) != 0 { - product *= current; - } - current = current.square(); - } - product - } - - #[test] - fn test_add_neg_sub_mul() { - type F = QuarticExtension; - let x = F::rand(); - let y = F::rand(); - let z = F::rand(); - assert_eq!(x + (-x), F::ZERO); - assert_eq!(-x, F::ZERO - x); - assert_eq!(x + x, x * F::TWO.into()); - assert_eq!(x * (-x), -x.square()); - assert_eq!(x + y, y + x); - assert_eq!(x * y, y * x); - assert_eq!(x * (y * z), (x * y) * z); - assert_eq!(x - (y + z), (x - y) - z); - assert_eq!((x + y) - z, x + (y - z)); - assert_eq!(x * (y + z), x * y + x * z); - } - - #[test] - fn test_inv_div() { - type F = QuarticExtension; - let x = F::rand(); - let y = F::rand(); - let z = F::rand(); - assert_eq!(x * x.inverse(), F::ONE); - assert_eq!(x.inverse() * x, F::ONE); - assert_eq!(x.square().inverse(), x.inverse().square()); - assert_eq!((x / y) * y, x); - assert_eq!(x / (y * z), (x / y) / z); - assert_eq!((x * y) / z, x * (y / z)); - } - - #[test] - fn test_frobenius() { - type F = QuarticExtension; - const D: usize = 4; - let x = F::rand(); - assert_eq!(x.exp_biguint(&CrandallField::order()), x.frobenius()); - for count in 2..D { - assert_eq!( - x.repeated_frobenius(count), - (0..count).fold(x, |acc, _| acc.frobenius()) - ); - } - } - - #[test] - fn test_field_order() { - // F::order() = 340282366831806780677557380898690695168 * 340282366831806780677557380898690695170 + 1 - type F = QuarticExtension; - let x = F::rand(); - assert_eq!( - exp_naive( - exp_naive(x, 340282366831806780677557380898690695168), - 340282366831806780677557380898690695170 - ), - F::ONE + test_field_extension!(crate::field::crandall_field::CrandallField, 4); + test_field_arithmetic!( + crate::field::extension_field::quartic::QuarticExtension< + crate::field::crandall_field::CrandallField, + > ); } - #[test] - fn test_power_of_two_gen() { - type F = QuarticExtension; - // F::order() = 2^30 * 1090552343587053358839971118999869 * 98885475095492590491252558464653635 + 1 - assert_eq!( - exp_naive( - exp_naive( - F::MULTIPLICATIVE_GROUP_GENERATOR, - 1090552343587053358839971118999869 - ), - 98885475095492590491252558464653635 - ), - F::POWER_OF_TWO_GENERATOR - ); - assert_eq!( - F::POWER_OF_TWO_GENERATOR.exp_u64(1 << (F::TWO_ADICITY - CrandallField::TWO_ADICITY)), - CrandallField::POWER_OF_TWO_GENERATOR.into() + mod goldilocks { + use crate::{test_field_arithmetic, test_field_extension}; + + test_field_extension!(crate::field::goldilocks_field::GoldilocksField, 4); + test_field_arithmetic!( + crate::field::extension_field::quartic::QuarticExtension< + crate::field::goldilocks_field::GoldilocksField, + > ); } - - test_field_arithmetic!( - crate::field::extension_field::quartic::QuarticExtension< - crate::field::crandall_field::CrandallField, - > - ); } diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index c08c555e..285af2ee 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -1,3 +1,7 @@ +use crate::field::extension_field::Extendable; +use crate::field::extension_field::Frobenius; +use crate::field::field_types::Field; + #[macro_export] macro_rules! test_field_arithmetic { ($field:ty) => { @@ -93,3 +97,91 @@ macro_rules! test_field_arithmetic { } }; } + +pub(crate) fn test_add_neg_sub_mul, const D: usize>() { + let x = BF::Extension::rand(); + let y = BF::Extension::rand(); + let z = BF::Extension::rand(); + assert_eq!(x + (-x), BF::Extension::ZERO); + assert_eq!(-x, BF::Extension::ZERO - x); + assert_eq!(x + x, x * BF::Extension::TWO); + assert_eq!(x * (-x), -x.square()); + assert_eq!(x + y, y + x); + assert_eq!(x * y, y * x); + assert_eq!(x * (y * z), (x * y) * z); + assert_eq!(x - (y + z), (x - y) - z); + assert_eq!((x + y) - z, x + (y - z)); + assert_eq!(x * (y + z), x * y + x * z); +} + +pub(crate) fn test_inv_div, const D: usize>() { + let x = BF::Extension::rand(); + let y = BF::Extension::rand(); + let z = BF::Extension::rand(); + assert_eq!(x * x.inverse(), BF::Extension::ONE); + assert_eq!(x.inverse() * x, BF::Extension::ONE); + assert_eq!(x.square().inverse(), x.inverse().square()); + assert_eq!((x / y) * y, x); + assert_eq!(x / (y * z), (x / y) / z); + assert_eq!((x * y) / z, x * (y / z)); +} + +pub(crate) fn test_frobenius, const D: usize>() { + let x = BF::Extension::rand(); + assert_eq!(x.exp_biguint(&BF::order()), x.frobenius()); + for count in 2..D { + assert_eq!( + x.repeated_frobenius(count), + (0..count).fold(x, |acc, _| acc.frobenius()) + ); + } +} + +pub(crate) fn test_field_order, const D: usize>() { + let x = BF::Extension::rand(); + assert_eq!( + x.exp_biguint(&(BF::Extension::order() - 1u8)), + BF::Extension::ONE + ); +} + +pub(crate) fn test_power_of_two_gen, const D: usize>() { + assert_eq!( + BF::Extension::MULTIPLICATIVE_GROUP_GENERATOR + .exp_biguint(&(BF::Extension::order() >> BF::Extension::TWO_ADICITY)), + BF::Extension::POWER_OF_TWO_GENERATOR, + ); + assert_eq!( + BF::Extension::POWER_OF_TWO_GENERATOR + .exp_u64(1 << (BF::Extension::TWO_ADICITY - BF::TWO_ADICITY)), + BF::POWER_OF_TWO_GENERATOR.into() + ); +} + +#[macro_export] +macro_rules! test_field_extension { + ($field:ty, $d:expr) => { + mod field_extension { + #[test] + fn test_add_neg_sub_mul() { + crate::field::field_testing::test_add_neg_sub_mul::<$field, $d>(); + } + #[test] + fn test_inv_div() { + crate::field::field_testing::test_inv_div::<$field, $d>(); + } + #[test] + fn test_frobenius() { + crate::field::field_testing::test_frobenius::<$field, $d>(); + } + #[test] + fn test_field_order() { + crate::field::field_testing::test_field_order::<$field, $d>(); + } + #[test] + fn test_power_of_two_gen() { + crate::field::field_testing::test_power_of_two_gen::<$field, $d>(); + } + } + }; +} diff --git a/src/field/goldilocks_field.rs b/src/field/goldilocks_field.rs index 3b98d78c..c4bc1e24 100644 --- a/src/field/goldilocks_field.rs +++ b/src/field/goldilocks_field.rs @@ -8,6 +8,9 @@ use num::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; +use crate::field::extension_field::quadratic::QuadraticExtension; +use crate::field::extension_field::quartic::QuarticExtension; +use crate::field::extension_field::Extendable; use crate::field::field_types::{Field, PrimeField}; use crate::field::inversion::try_inverse_u64; @@ -213,6 +216,35 @@ impl DivAssign for GoldilocksField { } } +impl Extendable<2> for GoldilocksField { + type Extension = QuadraticExtension; + + // Verifiable in Sage with + // `R. = GF(p)[]; assert (x^2 - 7).is_irreducible()`. + const W: Self = Self(7); + + const EXT_MULTIPLICATIVE_GROUP_GENERATOR: [Self; 2] = + [Self(18081566051660590251), Self(16121475356294670766)]; + + const EXT_POWER_OF_TWO_GENERATOR: [Self; 2] = [Self(0), Self(15659105665374529263)]; +} + +impl Extendable<4> for GoldilocksField { + type Extension = QuarticExtension; + + const W: Self = Self(7); + + const EXT_MULTIPLICATIVE_GROUP_GENERATOR: [Self; 4] = [ + Self(5024755240244648895), + Self(13227474371289740625), + Self(3912887029498544536), + Self(3900057112666848848), + ]; + + const EXT_POWER_OF_TWO_GENERATOR: [Self; 4] = + [Self(0), Self(0), Self(0), Self(12587610116473453104)]; +} + /// Reduces to a 64-bit value. The result might not be in canonical form; it could be in between the /// field order and `2^64`. #[inline]