diff --git a/Cargo.toml b/Cargo.toml index 26717081..8c4968ec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,6 @@ unroll = "0.1.5" anyhow = "1.0.40" serde = { version = "1.0", features = ["derive"] } serde_cbor = "0.11.1" -num-bigint = "0.2.3" [profile.release] opt-level = 3 diff --git a/src/field/cosets.rs b/src/field/cosets.rs index 5e297acc..f2edd892 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -1,4 +1,4 @@ -use num_bigint::BigUint; +use num::bigint::BigUint; use crate::field::field::Field; diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 3946ead5..54749531 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -6,7 +6,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use itertools::Itertools; use num::Integer; -use num_bigint::BigUint; +use num::bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -252,15 +252,7 @@ impl Field for CrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let smallest_two: Vec<_> = n - .to_u32_digits() - .iter() - .take(2) - .pad_using(2, |_| &0u32) - .map(|x| *x as u64) - .collect(); - let n_u64 = smallest_two[0] + (1u64 << 32) * smallest_two[1]; - Self(n_u64) + Self(n.iter_u64_digits().next().unwrap_or(0)) } fn cube_root(&self) -> Self { @@ -480,7 +472,8 @@ impl Frobenius<1> for CrandallField {} #[cfg(test)] mod tests { - use crate::test_prime_field_arithmetic; + use crate::{test_field_arithmetic, test_prime_field_arithmetic}; test_prime_field_arithmetic!(crate::field::crandall_field::CrandallField); + test_field_arithmetic!(crate::field::crandall_field::CrandallField); } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 48608f48..156a71b3 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -4,7 +4,7 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use itertools::Itertools; -use num_bigint::BigUint; +use num::bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 52452387..7de88817 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -5,7 +5,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use itertools::Itertools; use num::traits::Pow; -use num_bigint::BigUint; +use num::bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -141,13 +141,13 @@ impl Field for QuarticCrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let first = n.clone() % Self::CHARACTERISTIC; - let mut remaining = n.clone() / Self::CHARACTERISTIC; - let second = remaining.clone() % Self::CHARACTERISTIC; + let first = &n % Self::CHARACTERISTIC; + let mut remaining = &n / Self::CHARACTERISTIC; + let second = &remaining % Self::CHARACTERISTIC; remaining = remaining / Self::CHARACTERISTIC; - let third = remaining.clone() % Self::CHARACTERISTIC; + let third = &remaining % Self::CHARACTERISTIC; remaining = remaining / Self::CHARACTERISTIC; - let fourth = remaining.clone() % Self::CHARACTERISTIC; + let fourth = &remaining % Self::CHARACTERISTIC; Self([ >::BaseField::from_canonical_biguint(first), diff --git a/src/field/field.rs b/src/field/field.rs index 3f77fc1e..4075d6d7 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -5,7 +5,7 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use num::{Integer, Zero}; -use num_bigint::BigUint; +use num::bigint::BigUint; use rand::Rng; use serde::de::DeserializeOwned; use serde::Serialize; diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 5ea6fb73..18e844e8 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -1,7 +1,7 @@ -use num_bigint::BigUint; +use num::bigint::BigUint; use crate::field::field::Field; -use crate::util::{bits_u64, ceil_div_usize}; +use crate::util::ceil_div_usize; /// Generates a series of non-negative integers less than /// `modulus` which cover a range of values and which will @@ -9,7 +9,7 @@ use crate::util::{bits_u64, ceil_div_usize}; /// boundaries. pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { //assert!(word_bits == 32 || word_bits == 64); - let modwords = ceil_div_usize(modulus.bits(), word_bits); + let modwords = ceil_div_usize(modulus.bits() as usize, word_bits); // Start with basic set close to zero: 0 .. 10 const BIGGEST_SMALL: u32 = 10; let smalls: Vec<_> = (0..BIGGEST_SMALL).map(BigUint::from).collect(); @@ -148,13 +148,128 @@ pub fn run_binaryop_test_cases( } } + +#[macro_export] +macro_rules! test_field_arithmetic { + ($field:ty) => { + mod field_arithmetic { + use num::bigint::BigUint; + use rand::{thread_rng, Rng}; + + use crate::field::field::Field; + + #[test] + fn batch_inversion() { + let xs = (1..=3) + .map(|i| <$field>::from_canonical_u64(i)) + .collect::>(); + let invs = <$field>::batch_multiplicative_inverse(&xs); + for (x, inv) in xs.into_iter().zip(invs) { + assert_eq!(x * inv, <$field>::ONE); + } + } + + #[test] + fn primitive_root_order() { + for n_power in 0..8 { + let root = <$field>::primitive_root_of_unity(n_power); + let order = <$field>::generator_order(root); + assert_eq!(order, 1 << n_power, "2^{}'th primitive root", n_power); + } + } + + #[test] + fn negation() { + let zero = <$field>::ZERO; + let order = <$field>::order(); + + for i in [ + BigUint::from(0u32), + BigUint::from(1u32), + BigUint::from(2u32), + order.clone() - 2u32, + order.clone() - 1u32, + ] { + let i_f = <$field>::from_canonical_biguint(i); + assert_eq!(i_f + -i_f, zero); + } + } + + #[test] + fn bits() { + assert_eq!(<$field>::ZERO.bits(), 0); + assert_eq!(<$field>::ONE.bits(), 1); + assert_eq!(<$field>::TWO.bits(), 2); + assert_eq!(<$field>::from_canonical_u64(3).bits(), 2); + assert_eq!(<$field>::from_canonical_u64(4).bits(), 3); + assert_eq!(<$field>::from_canonical_u64(5).bits(), 3); + } + + #[test] + fn exponentiation() { + type F = $field; + + assert_eq!(F::ZERO.exp_u32(0), ::ONE); + assert_eq!(F::ONE.exp_u32(0), ::ONE); + assert_eq!(F::TWO.exp_u32(0), ::ONE); + + assert_eq!(F::ZERO.exp_u32(1), ::ZERO); + assert_eq!(F::ONE.exp_u32(1), ::ONE); + assert_eq!(F::TWO.exp_u32(1), ::TWO); + + assert_eq!(F::ZERO.kth_root_u32(1), ::ZERO); + assert_eq!(F::ONE.kth_root_u32(1), ::ONE); + assert_eq!(F::TWO.kth_root_u32(1), ::TWO); + + for power in 1..10 { + if F::is_monomial_permutation(power) { + let x = F::rand(); + assert_eq!(x.exp(power).kth_root(power), x); + } + } + } + + #[test] + fn exponentiation_large() { + type F = $field; + + let mut rng = rand::thread_rng(); + + let base = F::rand(); + let pow = BigUint::from(rng.gen::()); + let cycles = rng.gen::(); + let mul_group_order = F::order() - 1u32; + let big_pow = &pow + &mul_group_order * cycles; + let big_pow_wrong = &pow + &mul_group_order * cycles + 1u32; + + assert_eq!(base.exp_biguint(pow.clone()), base.exp_biguint(big_pow)); + assert_ne!(base.exp_biguint(pow), base.exp_biguint(big_pow_wrong)); + } + + #[test] + fn inverse_2exp() { + // Just check consistency with try_inverse() + type F = $field; + + let v = ::PrimeField::TWO_ADICITY; + + for e in [0, 1, 2, 3, 4, v - 2, v - 1, v, v + 1, v + 2, 123 * v] { + let x = F::TWO.exp(e as u64).inverse(); + let y = F::inverse_2exp(e); + assert_eq!(x, y); + } + } + } + }; +} + #[macro_export] macro_rules! test_prime_field_arithmetic { ($field:ty) => { mod prime_field_arithmetic { use std::ops::{Add, Mul, Neg, Sub}; - use num_bigint::BigUint; + use num::bigint::BigUint; use crate::field::field::Field; @@ -266,99 +381,3 @@ macro_rules! test_prime_field_arithmetic { } }; } - -#[macro_export] -macro_rules! test_field_arithmetic { - ($field:ty) => { - mod field_arithmetic { - use num_bigint::BigUint; - - use crate::field::field::Field; - - #[test] - fn batch_inversion() { - let xs = (1..=3) - .map(|i| <$field>::from_canonical_u64(i)) - .collect::>(); - let invs = <$field>::batch_multiplicative_inverse(&xs); - for (x, inv) in xs.into_iter().zip(invs) { - assert_eq!(x * inv, <$field>::ONE); - } - } - - #[test] - fn primitive_root_order() { - for n_power in 0..8 { - let root = <$field>::primitive_root_of_unity(n_power); - let order = <$field>::generator_order(root); - assert_eq!(order, 1 << n_power, "2^{}'th primitive root", n_power); - } - } - - #[test] - fn negation() { - let zero = <$field>::ZERO; - let order = <$field>::order(); - - for i in [ - BigUint::from(0u32), - BigUint::from(1u32), - BigUint::from(2u32), - order.clone() - 2u32, - order.clone() - 1u32, - ] { - let i_f = <$field>::from_canonical_biguint(i); - assert_eq!(i_f + -i_f, zero); - } - } - - #[test] - fn bits() { - assert_eq!(<$field>::ZERO.bits(), 0); - assert_eq!(<$field>::ONE.bits(), 1); - assert_eq!(<$field>::TWO.bits(), 2); - assert_eq!(<$field>::from_canonical_u64(3).bits(), 2); - assert_eq!(<$field>::from_canonical_u64(4).bits(), 3); - assert_eq!(<$field>::from_canonical_u64(5).bits(), 3); - } - - #[test] - fn exponentiation() { - type F = $field; - - assert_eq!(F::ZERO.exp_u32(0), ::ONE); - assert_eq!(F::ONE.exp_u32(0), ::ONE); - assert_eq!(F::TWO.exp_u32(0), ::ONE); - - assert_eq!(F::ZERO.exp_u32(1), ::ZERO); - assert_eq!(F::ONE.exp_u32(1), ::ONE); - assert_eq!(F::TWO.exp_u32(1), ::TWO); - - assert_eq!(F::ZERO.kth_root_u32(1), ::ZERO); - assert_eq!(F::ONE.kth_root_u32(1), ::ONE); - assert_eq!(F::TWO.kth_root_u32(1), ::TWO); - - for power in 1..10 { - if F::is_monomial_permutation(power) { - let x = F::rand(); - assert_eq!(x.exp(power).kth_root(power), x); - } - } - } - - #[test] - fn inverse_2exp() { - // Just check consistency with try_inverse() - type F = $field; - - let v = ::PrimeField::TWO_ADICITY; - - for e in [0, 1, 2, 3, 4, v - 2, v - 1, v, v + 1, v + 2, 123 * v] { - let x = F::TWO.exp(e as u64).inverse(); - let y = F::inverse_2exp(e); - assert_eq!(x, y); - } - } - } - }; -}