From 8a51e6a323dac63d42ff39721b49946de8de8485 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Mon, 19 Jul 2021 17:11:22 -0700 Subject: [PATCH 01/25] started --- Cargo.toml | 1 + src/field/cosets.rs | 27 ++++++++++++++++++++------- src/field/field.rs | 8 +++++++- src/fri/mod.rs | 20 ++++++++++++++++++++ 4 files changed, 48 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8c4968ec..bbd0bfdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ 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 33f95242..8c1a03d6 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -1,14 +1,27 @@ -use crate::field::field::Field; +use num_bigint::BigUInt; +use crate::field::field::{Field, FieldOrder}; /// Finds a set of shifts that result in unique cosets for the multiplicative subgroup of size /// `2^subgroup_bits`. pub(crate) fn get_unique_coset_shifts(subgroup_size: usize, num_shifts: usize) -> Vec { - // From Lagrange's theorem. - let num_cosets = (F::ORDER - 1) / (subgroup_size as u64); - assert!( - num_shifts as u64 <= num_cosets, - "The subgroup does not have enough distinct cosets" - ); + match F::ORDER { + FieldOrder::U64(order) => { + // From Lagrange's theorem. + let num_cosets = (order - 1) / (subgroup_size as u64); + assert!( + num_shifts as u64 <= num_cosets, + "The subgroup does not have enough distinct cosets" + ); + }, + FieldOrder::Big(order) => { + // From Lagrange's theorem. + let num_cosets = (order - 1) / (subgroup_size as BigUInt); + assert!( + num_shifts as BigUInt <= num_cosets, + "The subgroup does not have enough distinct cosets" + ); + } + } // Let g be a generator of the entire multiplicative group. Let n be the order of the subgroup. // The subgroup can be written as . We can use g^0, ..., g^(num_shifts - 1) as our diff --git a/src/field/field.rs b/src/field/field.rs index 28a52202..4928ffb7 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -4,6 +4,7 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use num_bigint::BigUInt; use num::Integer; use rand::Rng; use serde::de::DeserializeOwned; @@ -12,6 +13,11 @@ use serde::Serialize; use crate::field::extension_field::Frobenius; use crate::util::bits_u64; +pub enum FieldOrder { + U64(u64), + Big(BigUInt) + } + /// A finite field with prime order less than 2^64. pub trait Field: 'static @@ -44,7 +50,7 @@ pub trait Field: const NEG_ONE: Self; const CHARACTERISTIC: u64; - const ORDER: u64; + const ORDER: FieldOrder; const TWO_ADICITY: usize; /// Generator of the entire multiplicative group, i.e. all non-zero elements. diff --git a/src/fri/mod.rs b/src/fri/mod.rs index ab7137c2..89e75875 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -10,6 +10,8 @@ const EPSILON: f64 = 0.01; pub struct FriConfig { pub proof_of_work_bits: u32, + pub rate_bits: usize, + /// The arity of each FRI reduction step, expressed (i.e. the log2 of the actual arity). /// For example, `[3, 2, 1]` would describe a FRI reduction tree with 8-to-1 reduction, then /// a 4-to-1 reduction, then a 2-to-1 reduction. After these reductions, the reduced polynomial @@ -42,3 +44,21 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { 1.0 / (2.0 * EPSILON * rate.sqrt()) } } + +fn fri_soundness( + num_functions: usize, + rate_bits: usize, + codeword_size_bits: usize, + m: usize, + arity_bits: usize, + num_rounds: usize, + field_size_bits: usize, + num_queries: usize, +) { + let rho = 1.0 / ((1 >> rate_bits) as f32); + + let alpha = rho.sqrt() * (1.0 + 1.0 / (2.0 * m as f32)); + + let term_1 = (m as f32 + 0.5).powi(7) / (rho.powf(1.5) * (1 << (field_size_bits - 2 * codeword_size_bits + 1)) as f32); + let term_2 = (2.0 * m + 1.0) * ((1 << codeword_size_bits) as f32 + 1.0) +} From b103c0774f459922b3fd82185734a5128f5976c4 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Tue, 20 Jul 2021 15:42:27 -0700 Subject: [PATCH 02/25] progress --- Cargo.toml | 2 +- src/field/cosets.rs | 28 ++++++------------- src/field/crandall_field.rs | 21 ++++++++------ src/field/extension_field/quadratic.rs | 6 ++-- src/field/extension_field/quartic.rs | 6 ++-- src/field/field.rs | 38 ++++++++++++++++---------- src/field/field_testing.rs | 16 ++++++----- src/fri/mod.rs | 18 ------------ src/fri/prover.rs | 2 +- src/fri/recursive_verifier.rs | 2 +- src/fri/verifier.rs | 2 +- 11 files changed, 64 insertions(+), 77 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bbd0bfdf..26717081 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ unroll = "0.1.5" anyhow = "1.0.40" serde = { version = "1.0", features = ["derive"] } serde_cbor = "0.11.1" -num_bigint = "0.2.3" +num-bigint = "0.2.3" [profile.release] opt-level = 3 diff --git a/src/field/cosets.rs b/src/field/cosets.rs index 8c1a03d6..58c8b838 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -1,27 +1,15 @@ -use num_bigint::BigUInt; -use crate::field::field::{Field, FieldOrder}; +use num_bigint::BigUint; +use crate::field::field::Field; /// Finds a set of shifts that result in unique cosets for the multiplicative subgroup of size /// `2^subgroup_bits`. pub(crate) fn get_unique_coset_shifts(subgroup_size: usize, num_shifts: usize) -> Vec { - match F::ORDER { - FieldOrder::U64(order) => { - // From Lagrange's theorem. - let num_cosets = (order - 1) / (subgroup_size as u64); - assert!( - num_shifts as u64 <= num_cosets, - "The subgroup does not have enough distinct cosets" - ); - }, - FieldOrder::Big(order) => { - // From Lagrange's theorem. - let num_cosets = (order - 1) / (subgroup_size as BigUInt); - assert!( - num_shifts as BigUInt <= num_cosets, - "The subgroup does not have enough distinct cosets" - ); - } - } + // From Lagrange's theorem. + let num_cosets = (F::ORDER - 1u32) / (subgroup_size as u32); + assert!( + BigUint::from(num_shifts) <= num_cosets, + "The subgroup does not have enough distinct cosets" + ); // Let g be a generator of the entire multiplicative group. Let n be the order of the subgroup. // The subgroup can be written as . We can use g^0, ..., g^(num_shifts - 1) as our diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 9d38ff1a..2d635ae1 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use num_bigint::BigUint; use num::Integer; use serde::{Deserialize, Serialize}; @@ -12,6 +13,8 @@ use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::{Extendable, Frobenius}; use crate::field::field::Field; +const FIELD_ORDER: u64 = 18446744071293632513; + /// EPSILON = 9 * 2**28 - 1 const EPSILON: u64 = 2415919103; @@ -142,11 +145,11 @@ impl Field for CrandallField { const ZERO: Self = Self(0); const ONE: Self = Self(1); const TWO: Self = Self(2); - const NEG_ONE: Self = Self(Self::ORDER - 1); + const NEG_ONE: Self = Self(FIELD_ORDER - 1); - const ORDER: u64 = 18446744071293632513; + const ORDER : BigUint = BigUint::from(FIELD_ORDER); const TWO_ADICITY: usize = 28; - const CHARACTERISTIC: u64 = Self::ORDER; + const CHARACTERISTIC: u64 = FIELD_ORDER; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(5); const POWER_OF_TWO_GENERATOR: Self = Self(10281950781551402419); @@ -170,7 +173,7 @@ impl Field for CrandallField { // Based on Algorithm 16 of "Efficient Software-Implementation of Finite Fields with // Applications to Cryptography". - let p = Self::ORDER; + let p = FIELD_ORDER; let mut u = self.to_canonical_u64(); let mut v = p; let mut b = 1u64; @@ -228,8 +231,8 @@ impl Field for CrandallField { fn to_canonical_u64(&self) -> u64 { let mut c = self.0; // We only need one condition subtraction, since 2 * ORDER would not fit in a u64. - if c >= Self::ORDER { - c -= Self::ORDER; + if c >= FIELD_ORDER { + c -= FIELD_ORDER; } c } @@ -336,7 +339,7 @@ impl Neg for CrandallField { if self.is_zero() { Self::ZERO } else { - Self(Self::ORDER - self.to_canonical_u64()) + Self(FIELD_ORDER - self.to_canonical_u64()) } } } @@ -348,7 +351,7 @@ impl Add for CrandallField { #[allow(clippy::suspicious_arithmetic_impl)] fn add(self, rhs: Self) -> Self { let (sum, over) = self.0.overflowing_add(rhs.0); - Self(sum.overflowing_sub((over as u64) * Self::ORDER).0) + Self(sum.overflowing_sub((over as u64) * FIELD_ORDER).0) } } @@ -371,7 +374,7 @@ impl Sub for CrandallField { #[allow(clippy::suspicious_arithmetic_impl)] fn sub(self, rhs: Self) -> Self { let (diff, under) = self.0.overflowing_sub(rhs.to_canonical_u64()); - Self(diff.overflowing_add((under as u64) * Self::ORDER).0) + Self(diff.overflowing_add((under as u64) * FIELD_ORDER).0) } } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 256803ab..9ed3a1ee 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use num_bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -51,9 +52,8 @@ impl Field for QuadraticCrandallField { const TWO: Self = Self([CrandallField::TWO, CrandallField::ZERO]); const NEG_ONE: Self = Self([CrandallField::NEG_ONE, CrandallField::ZERO]); - const CHARACTERISTIC: u64 = CrandallField::ORDER; - // Does not fit in 64-bits. - const ORDER: u64 = 0; + const CHARACTERISTIC: u64 = CrandallField::CHARACTERISTIC; + const ORDER: BigUint = CrandallField::ORDER * CrandallField::ORDER; const TWO_ADICITY: usize = 29; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ CrandallField(6483724566312148654), diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 9390c521..16a11b52 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -3,6 +3,8 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use num::traits::Pow; +use num_bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -73,9 +75,9 @@ impl Field for QuarticCrandallField { CrandallField::ZERO, ]); - const CHARACTERISTIC: u64 = CrandallField::ORDER; + const CHARACTERISTIC: u64 = CrandallField::CHARACTERISTIC; // Does not fit in 64-bits. - const ORDER: u64 = 0; + const ORDER: BigUint = CrandallField::ORDER.pow(4); const TWO_ADICITY: usize = 30; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ CrandallField(12476589904174392631), diff --git a/src/field/field.rs b/src/field/field.rs index 4928ffb7..552c8f54 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -4,8 +4,8 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use num_bigint::BigUInt; -use num::Integer; +use num_bigint::BigUint; +use num::{Integer, Zero}; use rand::Rng; use serde::de::DeserializeOwned; use serde::Serialize; @@ -13,11 +13,6 @@ use serde::Serialize; use crate::field::extension_field::Frobenius; use crate::util::bits_u64; -pub enum FieldOrder { - U64(u64), - Big(BigUInt) - } - /// A finite field with prime order less than 2^64. pub trait Field: 'static @@ -50,7 +45,7 @@ pub trait Field: const NEG_ONE: Self; const CHARACTERISTIC: u64; - const ORDER: FieldOrder; + const ORDER: BigUint; const TWO_ADICITY: usize; /// Generator of the entire multiplicative group, i.e. all non-zero elements. @@ -218,18 +213,33 @@ pub trait Field: self.exp(power as u64) } + fn exp_bigint(&self, power: BigUint) -> Self { + let digits = power.to_u32_digits(); + let radix = 1u64 << 32; + + let mut result = Self::ONE; + for (radix_power, &digit) in digits.iter().enumerate() { + let mut current = self.exp_u32(digit); + for _ in 0..radix_power { + current = current.exp(radix); + } + result *= current; + } + result + } + /// Returns whether `x^power` is a permutation of this field. fn is_monomial_permutation(power: u64) -> bool { match power { 0 => false, 1 => true, - _ => (Self::ORDER - 1).gcd(&power) == 1, + _ => (Self::ORDER - 1u32).gcd(&BigUint::from(power)) == BigUint::from(1u32), } } fn kth_root(&self, k: u64) -> Self { let p = Self::ORDER; - let p_minus_1 = p - 1; + let p_minus_1 = p - 1u32; debug_assert!( Self::is_monomial_permutation(k), "Not a permutation of this field" @@ -242,10 +252,10 @@ pub trait Field: // x^((p + n(p - 1))/k)^k = x, // implying that x^((p + n(p - 1))/k) is a k'th root of x. for n in 0..k { - let numerator = p as u128 + n as u128 * p_minus_1 as u128; - if numerator % k as u128 == 0 { - let power = (numerator / k as u128) as u64 % p_minus_1; - return self.exp(power); + let numerator = p + p_minus_1 * n; + if numerator % k == BigUint::zero() { + let power = (numerator / k) % p_minus_1; + return self.exp_bigint(power); } } panic!( diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 1f5bff6f..e4870b37 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -1,3 +1,5 @@ +use num_bigint::BigUint; + use crate::field::field::Field; use crate::util::{bits_u64, ceil_div_usize}; @@ -5,9 +7,9 @@ use crate::util::{bits_u64, ceil_div_usize}; /// `modulus` which cover a range of values and which will /// generate lots of carries, especially at `word_bits` word /// boundaries. -pub fn test_inputs(modulus: u64, word_bits: usize) -> Vec { +pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { assert!(word_bits == 32 || word_bits == 64); - let modwords = ceil_div_usize(bits_u64(modulus), word_bits); + let modwords = ceil_div_usize(modulus.bits(), word_bits); // Start with basic set close to zero: 0 .. 10 const BIGGEST_SMALL: u32 = 10; let smalls: Vec<_> = (0..BIGGEST_SMALL).map(u64::from).collect(); @@ -32,17 +34,17 @@ pub fn test_inputs(modulus: u64, word_bits: usize) -> Vec { let diff_max = basic_inputs .iter() .map(|&x| u64::MAX - x) - .filter(|&x| x < modulus) + .filter(|&x| BigUint::from(x) < modulus) .collect(); // Inputs 'difference from' modulus value let diff_mod = basic_inputs .iter() - .filter(|&&x| x < modulus && x != 0) + .filter(|&&x| BigUint::from(x) < modulus && x != 0) .map(|&x| modulus - x) .collect(); let basics = basic_inputs .into_iter() - .filter(|&x| x < modulus) + .filter(|&x| BigUint::from(x) < modulus) .collect::>(); [basics, diff_max, diff_mod].concat() @@ -59,7 +61,7 @@ pub fn test_inputs(modulus: u64, word_bits: usize) -> Vec { /// coordinate-wise to the inputs from `test_inputs(modulus, /// word_bits)` and panic if the two resulting vectors differ. pub fn run_unaryop_test_cases( - modulus: u64, + modulus: BigUint, word_bits: usize, op: UnaryOp, expected_op: ExpectedOp, @@ -90,7 +92,7 @@ pub fn run_unaryop_test_cases( /// `inputs.len()`. Panic if the two functions ever give /// different answers. pub fn run_binaryop_test_cases( - modulus: u64, + modulus: BigUint, word_bits: usize, op: BinaryOp, expected_op: ExpectedOp, diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 89e75875..87fe3db5 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -44,21 +44,3 @@ fn fri_l(codeword_len: usize, rate_log: usize, conjecture: bool) -> f64 { 1.0 / (2.0 * EPSILON * rate.sqrt()) } } - -fn fri_soundness( - num_functions: usize, - rate_bits: usize, - codeword_size_bits: usize, - m: usize, - arity_bits: usize, - num_rounds: usize, - field_size_bits: usize, - num_queries: usize, -) { - let rho = 1.0 / ((1 >> rate_bits) as f32); - - let alpha = rho.sqrt() * (1.0 + 1.0 / (2.0 * m as f32)); - - let term_1 = (m as f32 + 0.5).powi(7) / (rho.powf(1.5) * (1 << (field_size_bits - 2 * codeword_size_bits + 1)) as f32); - let term_2 = (2.0 * m + 1.0) * ((1 << codeword_size_bits) as f32 + 1.0) -} diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 1c642d17..76e7739c 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -115,7 +115,7 @@ fn fri_proof_of_work(current_hash: Hash, config: &FriConfig) -> F { ) .to_canonical_u64() .leading_zeros() - >= config.proof_of_work_bits + F::ORDER.leading_zeros() + >= config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32 }) .map(F::from_canonical_u64) .expect("Proof of work failed. This is highly unlikely!") diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index b8a7c20f..eda618cd 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -59,7 +59,7 @@ impl, const D: usize> CircuitBuilder { inputs.push(proof.pow_witness); let hash = self.hash_n_to_m(inputs, 1, false)[0]; - self.assert_leading_zeros(hash, config.proof_of_work_bits + F::ORDER.leading_zeros()); + self.assert_leading_zeros(hash, config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32); } pub fn verify_fri_proof( diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index df0c33fc..796c2694 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -58,7 +58,7 @@ fn fri_verify_proof_of_work, const D: usize>( ); ensure!( hash.to_canonical_u64().leading_zeros() - >= config.proof_of_work_bits + F::ORDER.leading_zeros(), + >= config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32, "Invalid proof of work witness." ); From 5062029d3f7c18804b21bffd33e2ded8e3993815 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 09:32:18 -0700 Subject: [PATCH 03/25] fixes --- src/field/extension_field/quartic.rs | 2 +- src/fri/mod.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 16a11b52..7539b272 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -77,7 +77,7 @@ impl Field for QuarticCrandallField { const CHARACTERISTIC: u64 = CrandallField::CHARACTERISTIC; // Does not fit in 64-bits. - const ORDER: BigUint = CrandallField::ORDER.pow(4); + const ORDER: BigUint = CrandallField::ORDER.pow(4u32); const TWO_ADICITY: usize = 30; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ CrandallField(12476589904174392631), diff --git a/src/fri/mod.rs b/src/fri/mod.rs index 87fe3db5..ab7137c2 100644 --- a/src/fri/mod.rs +++ b/src/fri/mod.rs @@ -10,8 +10,6 @@ const EPSILON: f64 = 0.01; pub struct FriConfig { pub proof_of_work_bits: u32, - pub rate_bits: usize, - /// The arity of each FRI reduction step, expressed (i.e. the log2 of the actual arity). /// For example, `[3, 2, 1]` would describe a FRI reduction tree with 8-to-1 reduction, then /// a 4-to-1 reduction, then a 2-to-1 reduction. After these reductions, the reduced polynomial From c5bbe9d5032a87713f2fc096ccfc64025982dcd3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 09:56:00 -0700 Subject: [PATCH 04/25] fixes --- src/field/crandall_field.rs | 7 ++++++- src/field/extension_field/mod.rs | 4 ++-- src/field/extension_field/target.rs | 4 ++-- src/field/field.rs | 6 ++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 2d635ae1..465b0593 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -6,6 +6,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use num_bigint::BigUint; use num::Integer; +use rand::Rng; use serde::{Deserialize, Serialize}; use crate::field::extension_field::quadratic::QuadraticCrandallField; @@ -147,7 +148,7 @@ impl Field for CrandallField { const TWO: Self = Self(2); const NEG_ONE: Self = Self(FIELD_ORDER - 1); - const ORDER : BigUint = BigUint::from(FIELD_ORDER); + const ORDER: BigUint = BigUint::from(FIELD_ORDER); const TWO_ADICITY: usize = 28; const CHARACTERISTIC: u64 = FIELD_ORDER; @@ -329,6 +330,10 @@ impl Field for CrandallField { } result } + + fn rand_from_rng(rng: &mut R) -> Self { + Self::from_canonical_u64(rng.gen_range(0, FIELD_ORDER)) + } } impl Neg for CrandallField { diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 2a176fe9..f579004f 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -34,8 +34,8 @@ pub trait Frobenius: OEF { return self.repeated_frobenius(count % D); } let arr = self.to_basefield_array(); - let k = (Self::BaseField::ORDER - 1) / (D as u64); - let z0 = Self::W.exp(k * count as u64); + let k = (Self::BaseField::ORDER - 1u32) / (D as u64); + let z0 = Self::W.exp_bigint(k * count as u64); let mut res = [Self::BaseField::ZERO; D]; for (i, z) in z0.powers().take(D).enumerate() { res[i] = arr[i] * z; diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 455ee38f..f13255b4 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -31,8 +31,8 @@ impl ExtensionTarget { return self.repeated_frobenius(count % D, builder); } let arr = self.to_target_array(); - let k = (F::ORDER - 1) / (D as u64); - let z0 = F::Extension::W.exp(k * count as u64); + let k = (F::ORDER - 1u32) / (D as u64); + let z0 = F::Extension::W.exp_bigint(k * count as u64); let zs = z0 .powers() .take(D) diff --git a/src/field/field.rs b/src/field/field.rs index 552c8f54..bcdafc61 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -184,6 +184,8 @@ pub trait Field: Self::from_canonical_u64(n as u64) } + fn rand_from_rng(rng: &mut R) -> Self; + fn bits(&self) -> usize { bits_u64(self.to_canonical_u64()) } @@ -308,10 +310,6 @@ pub trait Field: Self::mds(vec.to_vec()).try_into().unwrap() } - fn rand_from_rng(rng: &mut R) -> Self { - Self::from_canonical_u64(rng.gen_range(0, Self::ORDER)) - } - fn rand() -> Self { Self::rand_from_rng(&mut rand::thread_rng()) } From 1dd850b0e546162f58e978c665f1ced62ee1a5f3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 13:05:32 -0700 Subject: [PATCH 05/25] fixes --- src/circuit_builder.rs | 2 +- src/field/cosets.rs | 2 +- src/field/crandall_field.rs | 12 +++- src/field/extension_field/mod.rs | 4 +- src/field/extension_field/quadratic.rs | 23 ++++++-- src/field/extension_field/quartic.rs | 27 +++++++-- src/field/extension_field/target.rs | 4 +- src/field/field.rs | 19 +++--- src/field/field_testing.rs | 82 ++++++++++---------------- src/fri/prover.rs | 2 +- src/fri/recursive_verifier.rs | 2 +- src/fri/verifier.rs | 2 +- 12 files changed, 104 insertions(+), 77 deletions(-) diff --git a/src/circuit_builder.rs b/src/circuit_builder.rs index 2cfeb720..ad9d9337 100644 --- a/src/circuit_builder.rs +++ b/src/circuit_builder.rs @@ -274,7 +274,7 @@ impl, const D: usize> CircuitBuilder { self.constant(F::TWO) } - /// Returns a routable target with a value of `ORDER - 1`. + /// Returns a routable target with a value of `order() - 1`. pub fn neg_one(&mut self) -> Target { self.constant(F::NEG_ONE) } diff --git a/src/field/cosets.rs b/src/field/cosets.rs index 0f43a12b..d8dd27b4 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -5,7 +5,7 @@ use crate::field::field::Field; /// `2^subgroup_bits`. pub(crate) fn get_unique_coset_shifts(subgroup_size: usize, num_shifts: usize) -> Vec { // From Lagrange's theorem. - let num_cosets = (F::ORDER - 1u32) / (subgroup_size as u32); + let num_cosets = (F::order() - 1u32) / (subgroup_size as u32); assert!( BigUint::from(num_shifts) <= num_cosets, "The subgroup does not have enough distinct cosets" diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 465b0593..ce5a2b3a 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; 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::Integer; use rand::Rng; @@ -148,13 +149,16 @@ impl Field for CrandallField { const TWO: Self = Self(2); const NEG_ONE: Self = Self(FIELD_ORDER - 1); - const ORDER: BigUint = BigUint::from(FIELD_ORDER); const TWO_ADICITY: usize = 28; const CHARACTERISTIC: u64 = FIELD_ORDER; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self(5); const POWER_OF_TWO_GENERATOR: Self = Self(10281950781551402419); + fn order() -> BigUint { + BigUint::from(FIELD_ORDER) + } + #[inline] fn square(&self) -> Self { *self * *self @@ -243,6 +247,12 @@ impl Field for CrandallField { Self(n) } + fn from_canonical_biguint(n: BigUint) -> Self { + let last_two : Vec<_> = n.to_u32_digits().iter().rev().take(2).pad_using(2, |_| &0u32).map(|x| *x as u64).collect(); + let n_u64 = last_two[0] + (1u64 << 32) * last_two[1]; + Self(n_u64) + } + fn cube_root(&self) -> Self { let x0 = *self; let x1 = x0.square(); diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index f579004f..6a927b04 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -34,8 +34,8 @@ pub trait Frobenius: OEF { return self.repeated_frobenius(count % D); } let arr = self.to_basefield_array(); - let k = (Self::BaseField::ORDER - 1u32) / (D as u64); - let z0 = Self::W.exp_bigint(k * count as u64); + let k = (Self::BaseField::order() - 1u32) / (D as u64); + let z0 = Self::W.exp_biguint(k * count as u64); let mut res = [Self::BaseField::ZERO; D]; for (i, z) in z0.powers().take(D).enumerate() { res[i] = arr[i] * z; diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 9ed3a1ee..4c734188 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -3,6 +3,7 @@ use std::hash::Hash; 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 rand::Rng; use serde::{Deserialize, Serialize}; @@ -53,7 +54,6 @@ impl Field for QuadraticCrandallField { const NEG_ONE: Self = Self([CrandallField::NEG_ONE, CrandallField::ZERO]); const CHARACTERISTIC: u64 = CrandallField::CHARACTERISTIC; - const ORDER: BigUint = CrandallField::ORDER * CrandallField::ORDER; const TWO_ADICITY: usize = 29; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ CrandallField(6483724566312148654), @@ -65,6 +65,10 @@ impl Field for QuadraticCrandallField { const POWER_OF_TWO_GENERATOR: Self = Self([CrandallField::ZERO, CrandallField(14420468973723774561)]); + fn order() -> BigUint { + CrandallField::order() * CrandallField::order() + } + // Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography. fn try_inverse(&self) -> Option { if self.is_zero() { @@ -86,6 +90,17 @@ impl Field for QuadraticCrandallField { >::BaseField::from_canonical_u64(n).into() } + fn from_canonical_biguint(n: BigUint) -> Self { + let last_four : Vec<_> = n.to_u32_digits().iter().rev().take(4).pad_using(4, |_| &0u32).map(|x| *x as u64).collect(); + let last_u64 = last_four[0] + (1u64 << 32) * last_four[1]; + let next_last_u64 = last_four[2] + (1u64 << 32) * last_four[3]; + + Self([ + >::BaseField::from_canonical_u64(last_u64), + >::BaseField::from_canonical_u64(next_last_u64), + ]) + } + fn rand_from_rng(rng: &mut R) -> Self { Self([ >::BaseField::rand_from_rng(rng), @@ -238,14 +253,14 @@ mod tests { type F = QuadraticCrandallField; let x = F::rand(); assert_eq!( - x.exp(>::BaseField::ORDER), + x.exp_biguint(>::BaseField::order()), x.frobenius() ); } #[test] fn test_field_order() { - // F::ORDER = 340282366831806780677557380898690695169 = 18446744071293632512 *18446744071293632514 + 1 + // F::order() = 340282366831806780677557380898690695169 = 18446744071293632512 *18446744071293632514 + 1 type F = QuadraticCrandallField; let x = F::rand(); assert_eq!( @@ -257,7 +272,7 @@ mod tests { #[test] fn test_power_of_two_gen() { type F = QuadraticCrandallField; - // F::ORDER = 2^29 * 2762315674048163 * 229454332791453 + 1 + // F::order() = 2^29 * 2762315674048163 * 229454332791453 + 1 assert_eq!( F::MULTIPLICATIVE_GROUP_GENERATOR .exp(2762315674048163) diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 7539b272..8eb0d6fb 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -3,6 +3,7 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use itertools::Itertools; use num::traits::Pow; use num_bigint::BigUint; use rand::Rng; @@ -77,7 +78,6 @@ impl Field for QuarticCrandallField { const CHARACTERISTIC: u64 = CrandallField::CHARACTERISTIC; // Does not fit in 64-bits. - const ORDER: BigUint = CrandallField::ORDER.pow(4u32); const TWO_ADICITY: usize = 30; const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ CrandallField(12476589904174392631), @@ -95,6 +95,10 @@ impl Field for QuarticCrandallField { CrandallField(15170983443234254033), ]); + fn order() -> BigUint { + CrandallField::order().pow(4u32) + } + // Algorithm 11.3.4 in Handbook of Elliptic and Hyperelliptic Curve Cryptography. fn try_inverse(&self) -> Option { if self.is_zero() { @@ -119,6 +123,21 @@ impl Field for QuarticCrandallField { >::BaseField::from_canonical_u64(n).into() } + fn from_canonical_biguint(n: BigUint) -> Self { + let last_eight : Vec<_> = n.to_u32_digits().iter().rev().take(8).pad_using(8, |_| &0u32).map(|x| *x as u64).collect(); + let last_u64 = last_eight[0] + (1u64 << 32) * last_eight[1]; + let next_last_u64 = last_eight[2] + (1u64 << 32) * last_eight[3]; + let third_last_u64 = last_eight[4] + (1u64 << 32) * last_eight[5]; + let fourth_last_u64 = last_eight[6] + (1u64 << 32) * last_eight[7]; + + Self([ + >::BaseField::from_canonical_u64(last_u64), + >::BaseField::from_canonical_u64(next_last_u64), + >::BaseField::from_canonical_u64(third_last_u64), + >::BaseField::from_canonical_u64(fourth_last_u64), + ]) + } + fn rand_from_rng(rng: &mut R) -> Self { Self([ >::BaseField::rand_from_rng(rng), @@ -303,7 +322,7 @@ mod tests { const D: usize = 4; let x = F::rand(); assert_eq!( - exp_naive(x, >::BaseField::ORDER as u128), + x.exp_biguint(>::BaseField::order()), x.frobenius() ); for count in 2..D { @@ -316,7 +335,7 @@ mod tests { #[test] fn test_field_order() { - // F::ORDER = 340282366831806780677557380898690695168 * 340282366831806780677557380898690695170 + 1 + // F::order() = 340282366831806780677557380898690695168 * 340282366831806780677557380898690695170 + 1 type F = QuarticCrandallField; let x = F::rand(); assert_eq!( @@ -331,7 +350,7 @@ mod tests { #[test] fn test_power_of_two_gen() { type F = QuarticCrandallField; - // F::ORDER = 2^30 * 1090552343587053358839971118999869 * 98885475095492590491252558464653635 + 1 + // F::order() = 2^30 * 1090552343587053358839971118999869 * 98885475095492590491252558464653635 + 1 assert_eq!( exp_naive( exp_naive( diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index f13255b4..502ea896 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -31,8 +31,8 @@ impl ExtensionTarget { return self.repeated_frobenius(count % D, builder); } let arr = self.to_target_array(); - let k = (F::ORDER - 1u32) / (D as u64); - let z0 = F::Extension::W.exp_bigint(k * count as u64); + let k = (F::order() - 1u32) / (D as u64); + let z0 = F::Extension::W.exp_biguint(k * count as u64); let zs = z0 .powers() .take(D) diff --git a/src/field/field.rs b/src/field/field.rs index bcdafc61..ce4e52be 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -45,7 +45,6 @@ pub trait Field: const NEG_ONE: Self; const CHARACTERISTIC: u64; - const ORDER: BigUint; const TWO_ADICITY: usize; /// Generator of the entire multiplicative group, i.e. all non-zero elements. @@ -53,6 +52,8 @@ pub trait Field: /// Generator of a multiplicative subgroup of order `2^TWO_ADICITY`. const POWER_OF_TWO_GENERATOR: Self; + fn order() -> BigUint; + fn is_zero(&self) -> bool { *self == Self::ZERO } @@ -184,6 +185,8 @@ pub trait Field: Self::from_canonical_u64(n as u64) } + fn from_canonical_biguint(n: BigUint) -> Self; + fn rand_from_rng(rng: &mut R) -> Self; fn bits(&self) -> usize { @@ -215,7 +218,7 @@ pub trait Field: self.exp(power as u64) } - fn exp_bigint(&self, power: BigUint) -> Self { + fn exp_biguint(&self, power: BigUint) -> Self { let digits = power.to_u32_digits(); let radix = 1u64 << 32; @@ -235,13 +238,13 @@ pub trait Field: match power { 0 => false, 1 => true, - _ => (Self::ORDER - 1u32).gcd(&BigUint::from(power)) == BigUint::from(1u32), + _ => (Self::order() - 1u32).gcd(&BigUint::from(power)) == BigUint::from(1u32), } } fn kth_root(&self, k: u64) -> Self { - let p = Self::ORDER; - let p_minus_1 = p - 1u32; + let p = Self::order().clone(); + let p_minus_1 = p.clone() - 1u32; debug_assert!( Self::is_monomial_permutation(k), "Not a permutation of this field" @@ -254,10 +257,10 @@ pub trait Field: // x^((p + n(p - 1))/k)^k = x, // implying that x^((p + n(p - 1))/k) is a k'th root of x. for n in 0..k { - let numerator = p + p_minus_1 * n; - if numerator % k == BigUint::zero() { + let numerator = p.clone() + &p_minus_1 * n; + if numerator.clone() % k == BigUint::zero() { let power = (numerator / k) % p_minus_1; - return self.exp_bigint(power); + return self.exp_biguint(power); } } panic!( diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index e4870b37..c30c641e 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -7,14 +7,14 @@ use crate::util::{bits_u64, ceil_div_usize}; /// `modulus` which cover a range of values and which will /// generate lots of carries, especially at `word_bits` word /// boundaries. -pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { - assert!(word_bits == 32 || word_bits == 64); +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); // Start with basic set close to zero: 0 .. 10 const BIGGEST_SMALL: u32 = 10; - let smalls: Vec<_> = (0..BIGGEST_SMALL).map(u64::from).collect(); + let smalls: Vec<_> = (0..BIGGEST_SMALL).map(BigUint::from).collect(); // ... and close to MAX: MAX - x - let word_max = (1u64 << word_bits) - 1; + let word_max = (BigUint::from(1u32) << word_bits) - 1u32; let bigs = smalls.iter().map(|x| &word_max - x).collect(); let one_words = [smalls, bigs].concat(); // For each of the one word inputs above, create a new one at word i. @@ -24,28 +24,28 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { one_words .iter() .map(|x| x << (word_bits * i)) - .collect::>() + .collect::>() }) .collect(); - let basic_inputs: Vec = [one_words, multiple_words].concat(); + let basic_inputs: Vec = [one_words, multiple_words].concat(); // Biggest value that will fit in `modwords` words // Inputs 'difference from' maximum value let diff_max = basic_inputs .iter() - .map(|&x| u64::MAX - x) + .map(|&x| word_max - x) .filter(|&x| BigUint::from(x) < modulus) .collect(); // Inputs 'difference from' modulus value let diff_mod = basic_inputs .iter() - .filter(|&&x| BigUint::from(x) < modulus && x != 0) + .filter(|&&x| BigUint::from(x) < modulus && x != BigUint::from(0u32)) .map(|&x| modulus - x) .collect(); let basics = basic_inputs .into_iter() .filter(|&x| BigUint::from(x) < modulus) - .collect::>(); + .collect::>(); [basics, diff_max, diff_mod].concat() // // There should be a nicer way to express the code above; something @@ -68,13 +68,13 @@ pub fn run_unaryop_test_cases( ) where F: Field, UnaryOp: Fn(F) -> F, - ExpectedOp: Fn(u64) -> u64, + ExpectedOp: Fn(BigUint) -> BigUint, { let inputs = test_inputs(modulus, word_bits); let expected: Vec<_> = inputs.iter().map(|&x| expected_op(x)).collect(); let output: Vec<_> = inputs .iter() - .map(|&x| op(F::from_canonical_u64(x)).to_canonical_u64()) + .map(|&x| op(F::from_canonical_biguint(x)).to_canonical_biguint()) .collect(); // Compare expected outputs with actual outputs for i in 0..inputs.len() { @@ -99,7 +99,7 @@ pub fn run_binaryop_test_cases( ) where F: Field, BinaryOp: Fn(F, F) -> F, - ExpectedOp: Fn(u64, u64) -> u64, + ExpectedOp: Fn(BigUint, BigUint) -> BigUint, { let inputs = test_inputs(modulus, word_bits); @@ -125,7 +125,7 @@ pub fn run_binaryop_test_cases( .iter() .zip(shifted_inputs.clone()) .map(|(&x, &y)| { - op(F::from_canonical_u64(x), F::from_canonical_u64(y)).to_canonical_u64() + op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)).to_canonical_u64() }) .collect(); @@ -145,6 +145,7 @@ macro_rules! test_arithmetic { ($field:ty) => { mod arithmetic { use std::ops::{Add, Mul, Neg, Sub}; + use num_bigint::BigUint; use crate::field::field::Field; @@ -154,77 +155,56 @@ macro_rules! test_arithmetic { #[test] fn arithmetic_addition() { - let modulus = <$field>::ORDER; + let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( modulus, WORD_BITS, <$field>::add, - |x, y| { - let (z, over) = x.overflowing_add(y); - if over { - z.overflowing_sub(modulus).0 - } else if z >= modulus { - z - modulus - } else { - z - } - }, + BigUint::add, ) } #[test] fn arithmetic_subtraction() { - let modulus = <$field>::ORDER; + let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( modulus, WORD_BITS, <$field>::sub, - |x, y| { - if x >= y { - x - y - } else { - &modulus - y + x - } - }, + BigUint::sub, ) } #[test] fn arithmetic_negation() { - let modulus = <$field>::ORDER; + let modulus = <$field>::order(); crate::field::field_testing::run_unaryop_test_cases( modulus, WORD_BITS, <$field>::neg, - |x| { - if x == 0 { - 0 - } else { - modulus - x - } - }, + BigUint::neg, ) } #[test] fn arithmetic_multiplication() { - let modulus = <$field>::ORDER; + let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( modulus, WORD_BITS, <$field>::mul, - |x, y| ((x as u128) * (y as u128) % (modulus as u128)) as u64, + BigUint::mul, ) } #[test] fn arithmetic_square() { - let modulus = <$field>::ORDER; + let modulus = <$field>::order(); crate::field::field_testing::run_unaryop_test_cases( modulus, WORD_BITS, |x: $field| x.square(), - |x| ((x as u128) * (x as u128) % (modulus as u128)) as u64, + |x| x * x, ) } @@ -232,12 +212,12 @@ macro_rules! test_arithmetic { fn inversion() { let zero = <$field>::ZERO; let one = <$field>::ONE; - let order = <$field>::ORDER; + let order = <$field>::order(); assert_eq!(zero.try_inverse(), None); - for &x in &[1, 2, 3, order - 3, order - 2, order - 1] { - let x = <$field>::from_canonical_u64(x); + for &x in &[BigUint::from(1u32), BigUint::from(2u32), BigUint::from(3u32), order - 3u32, order - 2u32, order - 1u32] { + let x = <$field>::from_canonical_biguint(x); let inv = x.inverse(); assert_eq!(x * inv, one); } @@ -266,10 +246,10 @@ macro_rules! test_arithmetic { #[test] fn negation() { let zero = <$field>::ZERO; - let order = <$field>::ORDER; + let order = <$field>::order(); - for &i in &[0, 1, 2, order - 2, order - 1] { - let i_f = <$field>::from_canonical_u64(i); + for &i in &[BigUint::from(0u32), BigUint::from(1u32), BigUint::from(2u32), order - 2u32, order - 1u32] { + let i_f = <$field>::from_canonical_biguint(i); assert_eq!(i_f + -i_f, zero); } } @@ -312,7 +292,7 @@ macro_rules! test_arithmetic { fn subtraction() { type F = $field; - let (a, b) = (F::from_canonical_u64((F::ORDER + 1) / 2), F::TWO); + let (a, b) = (F::from_canonical_biguint((F::order() + 1u32) / 2u32), F::TWO); let x = a * b; assert_eq!(x, F::ONE); assert_eq!(F::ZERO - x, F::NEG_ONE); diff --git a/src/fri/prover.rs b/src/fri/prover.rs index 76e7739c..b6fdd35b 100644 --- a/src/fri/prover.rs +++ b/src/fri/prover.rs @@ -115,7 +115,7 @@ fn fri_proof_of_work(current_hash: Hash, config: &FriConfig) -> F { ) .to_canonical_u64() .leading_zeros() - >= config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32 + >= config.proof_of_work_bits + (64 - F::order().bits()) as u32 }) .map(F::from_canonical_u64) .expect("Proof of work failed. This is highly unlikely!") diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index e6f8474f..1891c677 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -59,7 +59,7 @@ impl, const D: usize> CircuitBuilder { inputs.push(proof.pow_witness); let hash = self.hash_n_to_m(inputs, 1, false)[0]; - self.assert_leading_zeros(hash, config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32); + self.assert_leading_zeros(hash, config.proof_of_work_bits + (64 - F::order().bits()) as u32); } pub fn verify_fri_proof( diff --git a/src/fri/verifier.rs b/src/fri/verifier.rs index 712288fd..06f065c1 100644 --- a/src/fri/verifier.rs +++ b/src/fri/verifier.rs @@ -58,7 +58,7 @@ fn fri_verify_proof_of_work, const D: usize>( ); ensure!( hash.to_canonical_u64().leading_zeros() - >= config.proof_of_work_bits + (64 - F::ORDER.bits()) as u32, + >= config.proof_of_work_bits + (64 - F::order().bits()) as u32, "Invalid proof of work witness." ); From 7f92a3396467961864bb6fc0f3fa0cad95897ec2 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 13:05:40 -0700 Subject: [PATCH 06/25] cargo fmt --- src/field/cosets.rs | 1 + src/field/crandall_field.rs | 11 +++++++++-- src/field/extension_field/quadratic.rs | 9 ++++++++- src/field/extension_field/quartic.rs | 9 ++++++++- src/field/field.rs | 2 +- src/field/field_testing.rs | 23 ++++++++++++++++++++--- src/fri/recursive_verifier.rs | 5 ++++- 7 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/field/cosets.rs b/src/field/cosets.rs index d8dd27b4..5e297acc 100644 --- a/src/field/cosets.rs +++ b/src/field/cosets.rs @@ -1,4 +1,5 @@ use num_bigint::BigUint; + use crate::field::field::Field; /// Finds a set of shifts that result in unique cosets for the multiplicative subgroup of size diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index ce5a2b3a..2afd00c6 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -5,8 +5,8 @@ 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::Integer; +use num_bigint::BigUint; use rand::Rng; use serde::{Deserialize, Serialize}; @@ -248,7 +248,14 @@ impl Field for CrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_two : Vec<_> = n.to_u32_digits().iter().rev().take(2).pad_using(2, |_| &0u32).map(|x| *x as u64).collect(); + let last_two: Vec<_> = n + .to_u32_digits() + .iter() + .rev() + .take(2) + .pad_using(2, |_| &0u32) + .map(|x| *x as u64) + .collect(); let n_u64 = last_two[0] + (1u64 << 32) * last_two[1]; Self(n_u64) } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 4c734188..5424193c 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -91,7 +91,14 @@ impl Field for QuadraticCrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_four : Vec<_> = n.to_u32_digits().iter().rev().take(4).pad_using(4, |_| &0u32).map(|x| *x as u64).collect(); + let last_four: Vec<_> = n + .to_u32_digits() + .iter() + .rev() + .take(4) + .pad_using(4, |_| &0u32) + .map(|x| *x as u64) + .collect(); let last_u64 = last_four[0] + (1u64 << 32) * last_four[1]; let next_last_u64 = last_four[2] + (1u64 << 32) * last_four[3]; diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 8eb0d6fb..63d7ef75 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -124,7 +124,14 @@ impl Field for QuarticCrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_eight : Vec<_> = n.to_u32_digits().iter().rev().take(8).pad_using(8, |_| &0u32).map(|x| *x as u64).collect(); + let last_eight: Vec<_> = n + .to_u32_digits() + .iter() + .rev() + .take(8) + .pad_using(8, |_| &0u32) + .map(|x| *x as u64) + .collect(); let last_u64 = last_eight[0] + (1u64 << 32) * last_eight[1]; let next_last_u64 = last_eight[2] + (1u64 << 32) * last_eight[3]; let third_last_u64 = last_eight[4] + (1u64 << 32) * last_eight[5]; diff --git a/src/field/field.rs b/src/field/field.rs index ce4e52be..b69c8750 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -4,8 +4,8 @@ use std::hash::Hash; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -use num_bigint::BigUint; use num::{Integer, Zero}; +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 c30c641e..7447fae6 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -145,6 +145,7 @@ macro_rules! test_arithmetic { ($field:ty) => { mod arithmetic { use std::ops::{Add, Mul, Neg, Sub}; + use num_bigint::BigUint; use crate::field::field::Field; @@ -216,7 +217,14 @@ macro_rules! test_arithmetic { assert_eq!(zero.try_inverse(), None); - for &x in &[BigUint::from(1u32), BigUint::from(2u32), BigUint::from(3u32), order - 3u32, order - 2u32, order - 1u32] { + for &x in &[ + BigUint::from(1u32), + BigUint::from(2u32), + BigUint::from(3u32), + order - 3u32, + order - 2u32, + order - 1u32, + ] { let x = <$field>::from_canonical_biguint(x); let inv = x.inverse(); assert_eq!(x * inv, one); @@ -248,7 +256,13 @@ macro_rules! test_arithmetic { let zero = <$field>::ZERO; let order = <$field>::order(); - for &i in &[BigUint::from(0u32), BigUint::from(1u32), BigUint::from(2u32), order - 2u32, order - 1u32] { + for &i in &[ + BigUint::from(0u32), + BigUint::from(1u32), + BigUint::from(2u32), + order - 2u32, + order - 1u32, + ] { let i_f = <$field>::from_canonical_biguint(i); assert_eq!(i_f + -i_f, zero); } @@ -292,7 +306,10 @@ macro_rules! test_arithmetic { fn subtraction() { type F = $field; - let (a, b) = (F::from_canonical_biguint((F::order() + 1u32) / 2u32), F::TWO); + let (a, b) = ( + F::from_canonical_biguint((F::order() + 1u32) / 2u32), + F::TWO, + ); let x = a * b; assert_eq!(x, F::ONE); assert_eq!(F::ZERO - x, F::NEG_ONE); diff --git a/src/fri/recursive_verifier.rs b/src/fri/recursive_verifier.rs index 1891c677..4934a133 100644 --- a/src/fri/recursive_verifier.rs +++ b/src/fri/recursive_verifier.rs @@ -59,7 +59,10 @@ impl, const D: usize> CircuitBuilder { inputs.push(proof.pow_witness); let hash = self.hash_n_to_m(inputs, 1, false)[0]; - self.assert_leading_zeros(hash, config.proof_of_work_bits + (64 - F::order().bits()) as u32); + self.assert_leading_zeros( + hash, + config.proof_of_work_bits + (64 - F::order().bits()) as u32, + ); } pub fn verify_fri_proof( From 164bb7f5ca137aa3bc3d69aceec162ad728c8052 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 13:23:50 -0700 Subject: [PATCH 07/25] fixes --- src/field/crandall_field.rs | 4 +++ src/field/extension_field/quadratic.rs | 7 +++++ src/field/extension_field/quartic.rs | 14 ++++++++++ src/field/field.rs | 2 ++ src/field/field_testing.rs | 38 +++++++++++++++----------- 5 files changed, 49 insertions(+), 16 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 2afd00c6..3e84ae41 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -247,6 +247,10 @@ impl Field for CrandallField { Self(n) } + fn to_canonical_biguint(&self) -> BigUint { + BigUint::from(self.to_canonical_u64()) + } + fn from_canonical_biguint(n: BigUint) -> Self { let last_two: Vec<_> = n .to_u32_digits() diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 5424193c..3d58e34e 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -90,6 +90,13 @@ impl Field for QuadraticCrandallField { >::BaseField::from_canonical_u64(n).into() } + fn to_canonical_biguint(&self) -> BigUint { + let first = self.0[0].to_canonical_u64(); + let second = self.0[1].to_canonical_u64(); + let combined = second as u128 * (1u128 << 64) + first as u128; + BigUint::from(combined) + } + fn from_canonical_biguint(n: BigUint) -> Self { let last_four: Vec<_> = n .to_u32_digits() diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 63d7ef75..206d07c8 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -123,6 +123,20 @@ impl Field for QuarticCrandallField { >::BaseField::from_canonical_u64(n).into() } + fn to_canonical_biguint(&self) -> BigUint { + let first = self.0[0].to_canonical_u64(); + let second = self.0[1].to_canonical_u64(); + let third = self.0[2].to_canonical_u64(); + let fourth = self.0[2].to_canonical_u64(); + + let combined_first = second as u128 * (1u128 << 64) + first as u128; + let combined_second = fourth as u128 * (1u128 << 64) + third as u128; + + let combined = BigUint::from(combined_second) * (BigUint::from(1u32) << 128) + combined_first; + + combined + } + fn from_canonical_biguint(n: BigUint) -> Self { let last_eight: Vec<_> = n .to_u32_digits() diff --git a/src/field/field.rs b/src/field/field.rs index b69c8750..3f77fc1e 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -185,6 +185,8 @@ pub trait Field: Self::from_canonical_u64(n as u64) } + fn to_canonical_biguint(&self) -> BigUint; + fn from_canonical_biguint(n: BigUint) -> Self; fn rand_from_rng(rng: &mut R) -> Self; diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 7447fae6..44ed8d81 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -33,18 +33,22 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { // Inputs 'difference from' maximum value let diff_max = basic_inputs .iter() - .map(|&x| word_max - x) - .filter(|&x| BigUint::from(x) < modulus) + .map(|x| x.clone()) + .map(|x| word_max.clone() - x) + .filter(|x| x < &modulus) .collect(); // Inputs 'difference from' modulus value let diff_mod = basic_inputs .iter() - .filter(|&&x| BigUint::from(x) < modulus && x != BigUint::from(0u32)) - .map(|&x| modulus - x) + .map(|x| x.clone()) + .filter(|&x| x < modulus && x != BigUint::from(0u32)) + .map(|x| x.clone()) + .map(|x| modulus - x) .collect(); let basics = basic_inputs .into_iter() - .filter(|&x| BigUint::from(x) < modulus) + .map(|x| x.clone()) + .filter(|x| x < &modulus) .collect::>(); [basics, diff_max, diff_mod].concat() @@ -74,7 +78,8 @@ pub fn run_unaryop_test_cases( let expected: Vec<_> = inputs.iter().map(|&x| expected_op(x)).collect(); let output: Vec<_> = inputs .iter() - .map(|&x| op(F::from_canonical_biguint(x)).to_canonical_biguint()) + .map(|x| x.clone()) + .map(|x| op(F::from_canonical_biguint(x)).to_canonical_biguint()) .collect(); // Compare expected outputs with actual outputs for i in 0..inputs.len() { @@ -124,8 +129,9 @@ pub fn run_binaryop_test_cases( let output: Vec<_> = inputs .iter() .zip(shifted_inputs.clone()) - .map(|(&x, &y)| { - op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)).to_canonical_u64() + .map(|(x, y)| (x.clone(), y.clone())) + .map(|(x, y)| { + op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)).to_canonical_biguint() }) .collect(); @@ -205,7 +211,7 @@ macro_rules! test_arithmetic { modulus, WORD_BITS, |x: $field| x.square(), - |x| x * x, + |x| x.clone() * x, ) } @@ -217,13 +223,13 @@ macro_rules! test_arithmetic { assert_eq!(zero.try_inverse(), None); - for &x in &[ + for x in [ BigUint::from(1u32), BigUint::from(2u32), BigUint::from(3u32), - order - 3u32, - order - 2u32, - order - 1u32, + order.clone() - 3u32, + order.clone() - 2u32, + order.clone() - 1u32, ] { let x = <$field>::from_canonical_biguint(x); let inv = x.inverse(); @@ -256,12 +262,12 @@ macro_rules! test_arithmetic { let zero = <$field>::ZERO; let order = <$field>::order(); - for &i in &[ + for i in [ BigUint::from(0u32), BigUint::from(1u32), BigUint::from(2u32), - order - 2u32, - order - 1u32, + order.clone() - 2u32, + order.clone() - 1u32, ] { let i_f = <$field>::from_canonical_biguint(i); assert_eq!(i_f + -i_f, zero); From ff564861895081f402c6906c65193e207f2ca677 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 13:28:11 -0700 Subject: [PATCH 08/25] compiles --- src/field/field_testing.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 44ed8d81..a86a0587 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -41,9 +41,9 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { let diff_mod = basic_inputs .iter() .map(|x| x.clone()) - .filter(|&x| x < modulus && x != BigUint::from(0u32)) + .filter(|x| x.clone() < modulus.clone() && x.clone() != BigUint::from(0u32)) .map(|x| x.clone()) - .map(|x| modulus - x) + .map(|x| modulus.clone() - x) .collect(); let basics = basic_inputs .into_iter() @@ -75,7 +75,7 @@ pub fn run_unaryop_test_cases( ExpectedOp: Fn(BigUint) -> BigUint, { let inputs = test_inputs(modulus, word_bits); - let expected: Vec<_> = inputs.iter().map(|&x| expected_op(x)).collect(); + let expected: Vec<_> = inputs.iter().map(|x| expected_op(x.clone())).collect(); let output: Vec<_> = inputs .iter() .map(|x| x.clone()) From 3e00a5819fed65dd532ea94f6ccc07300947917e Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 14:12:33 -0700 Subject: [PATCH 09/25] fix: endian-ness --- src/field/crandall_field.rs | 5 ++--- src/field/extension_field/quadratic.rs | 7 +++---- src/field/extension_field/quartic.rs | 11 +++++------ 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 3e84ae41..1c57efa7 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -252,15 +252,14 @@ impl Field for CrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_two: Vec<_> = n + let smallest_two: Vec<_> = n .to_u32_digits() .iter() - .rev() .take(2) .pad_using(2, |_| &0u32) .map(|x| *x as u64) .collect(); - let n_u64 = last_two[0] + (1u64 << 32) * last_two[1]; + let n_u64 = smallest_two[0] + (1u64 << 32) * smallest_two[1]; Self(n_u64) } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 3d58e34e..a5b78ab6 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -98,16 +98,15 @@ impl Field for QuadraticCrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_four: Vec<_> = n + let smallest_four: Vec<_> = n .to_u32_digits() .iter() - .rev() .take(4) .pad_using(4, |_| &0u32) .map(|x| *x as u64) .collect(); - let last_u64 = last_four[0] + (1u64 << 32) * last_four[1]; - let next_last_u64 = last_four[2] + (1u64 << 32) * last_four[3]; + let last_u64 = smallest_four[0] + (1u64 << 32) * smallest_four[1]; + let next_last_u64 = smallest_four[2] + (1u64 << 32) * smallest_four[3]; Self([ >::BaseField::from_canonical_u64(last_u64), diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 206d07c8..39016533 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -138,18 +138,17 @@ impl Field for QuarticCrandallField { } fn from_canonical_biguint(n: BigUint) -> Self { - let last_eight: Vec<_> = n + let smallest_eight: Vec<_> = n .to_u32_digits() .iter() - .rev() .take(8) .pad_using(8, |_| &0u32) .map(|x| *x as u64) .collect(); - let last_u64 = last_eight[0] + (1u64 << 32) * last_eight[1]; - let next_last_u64 = last_eight[2] + (1u64 << 32) * last_eight[3]; - let third_last_u64 = last_eight[4] + (1u64 << 32) * last_eight[5]; - let fourth_last_u64 = last_eight[6] + (1u64 << 32) * last_eight[7]; + let last_u64 = smallest_eight[0] + (1u64 << 32) * smallest_eight[1]; + let next_last_u64 = smallest_eight[2] + (1u64 << 32) * smallest_eight[3]; + let third_last_u64 = smallest_eight[4] + (1u64 << 32) * smallest_eight[5]; + let fourth_last_u64 = smallest_eight[6] + (1u64 << 32) * smallest_eight[7]; Self([ >::BaseField::from_canonical_u64(last_u64), From b17dabefeb3354e8fc85fe641e36fd75909864b6 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 14:27:30 -0700 Subject: [PATCH 10/25] more fixes --- src/field/field_testing.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index a86a0587..7fcd1086 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -15,6 +15,7 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { let smalls: Vec<_> = (0..BIGGEST_SMALL).map(BigUint::from).collect(); // ... and close to MAX: MAX - x let word_max = (BigUint::from(1u32) << word_bits) - 1u32; + let multiple_words_max = (BigUint::from(1u32) << modwords * word_bits) - 1u32; let bigs = smalls.iter().map(|x| &word_max - x).collect(); let one_words = [smalls, bigs].concat(); // For each of the one word inputs above, create a new one at word i. @@ -34,7 +35,7 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { let diff_max = basic_inputs .iter() .map(|x| x.clone()) - .map(|x| word_max.clone() - x) + .map(|x| multiple_words_max.clone() - x) .filter(|x| x < &modulus) .collect(); // Inputs 'difference from' modulus value @@ -175,10 +176,16 @@ macro_rules! test_arithmetic { fn arithmetic_subtraction() { let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( - modulus, + modulus.clone(), WORD_BITS, <$field>::sub, - BigUint::sub, + |x, y| { + if x >= y { + x.clone() - y.clone() + } else { + modulus.clone() - y.clone() + x + } + }, ) } @@ -186,10 +193,16 @@ macro_rules! test_arithmetic { fn arithmetic_negation() { let modulus = <$field>::order(); crate::field::field_testing::run_unaryop_test_cases( - modulus, + modulus.clone(), WORD_BITS, <$field>::neg, - BigUint::neg, + |x| { + if x == BigUint::from(0u32) { + BigUint::from(0u32) + } else { + modulus.clone() - x.clone() + } + }, ) } From 292a28e6e31f7d88c7599f99cf0b77cdac4d9e0e Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 14:33:47 -0700 Subject: [PATCH 11/25] fixed tests --- src/field/extension_field/quartic.rs | 5 +++-- src/field/field_testing.rs | 15 ++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 39016533..51c0b1af 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -132,8 +132,9 @@ impl Field for QuarticCrandallField { let combined_first = second as u128 * (1u128 << 64) + first as u128; let combined_second = fourth as u128 * (1u128 << 64) + third as u128; - let combined = BigUint::from(combined_second) * (BigUint::from(1u32) << 128) + combined_first; - + let combined = + BigUint::from(combined_second) * (BigUint::from(1u32) << 128) + combined_first; + combined } diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 7fcd1086..4822024a 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -132,7 +132,8 @@ pub fn run_binaryop_test_cases( .zip(shifted_inputs.clone()) .map(|(x, y)| (x.clone(), y.clone())) .map(|(x, y)| { - op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)).to_canonical_biguint() + op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)) + .to_canonical_biguint() }) .collect(); @@ -165,10 +166,10 @@ macro_rules! test_arithmetic { fn arithmetic_addition() { let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( - modulus, + modulus.clone(), WORD_BITS, <$field>::add, - BigUint::add, + |x, y| (x.clone() + y.clone()) % modulus.clone(), ) } @@ -210,10 +211,10 @@ macro_rules! test_arithmetic { fn arithmetic_multiplication() { let modulus = <$field>::order(); crate::field::field_testing::run_binaryop_test_cases( - modulus, + modulus.clone(), WORD_BITS, <$field>::mul, - BigUint::mul, + |x, y| x.clone() * y.clone() % modulus.clone(), ) } @@ -221,10 +222,10 @@ macro_rules! test_arithmetic { fn arithmetic_square() { let modulus = <$field>::order(); crate::field::field_testing::run_unaryop_test_cases( - modulus, + modulus.clone(), WORD_BITS, |x: $field| x.square(), - |x| x.clone() * x, + |x| (x.clone() * x.clone()) % modulus.clone(), ) } From 59efe6a8fe819d3933cecf2e2e417b5df98ecab5 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 14:39:39 -0700 Subject: [PATCH 12/25] added test_arithmetic for extension fields --- src/field/extension_field/quadratic.rs | 3 +++ src/field/extension_field/quartic.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index a5b78ab6..d11f68e5 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -228,6 +228,7 @@ mod tests { use crate::field::extension_field::quadratic::QuadraticCrandallField; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; + use crate::test_arithmetic; #[test] fn test_add_neg_sub_mul() { @@ -298,4 +299,6 @@ mod tests { >::BaseField::POWER_OF_TWO_GENERATOR.into() ); } + + test_arithmetic!(crate::field::extension_field::quadratic::QuadraticCrandallField); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 51c0b1af..a2b33c00 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -291,6 +291,7 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; + use crate::test_arithmetic; fn exp_naive(x: F, power: u128) -> F { let mut current = x; @@ -388,4 +389,6 @@ mod tests { >::BaseField::POWER_OF_TWO_GENERATOR.into() ); } + + test_arithmetic!(crate::field::extension_field::quartic::QuarticCrandallField); } From 1322b8d0d2e900808c4b4edf876a9b5db9f45690 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Wed, 21 Jul 2021 14:59:14 -0700 Subject: [PATCH 13/25] fixes --- src/field/extension_field/quadratic.rs | 24 +++++-------- src/field/extension_field/quartic.rs | 50 +++++++++++++------------- 2 files changed, 33 insertions(+), 41 deletions(-) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index d11f68e5..491d06e6 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -91,26 +91,20 @@ impl Field for QuadraticCrandallField { } fn to_canonical_biguint(&self) -> BigUint { - let first = self.0[0].to_canonical_u64(); - let second = self.0[1].to_canonical_u64(); - let combined = second as u128 * (1u128 << 64) + first as u128; - BigUint::from(combined) + let first = self.0[0].to_canonical_biguint(); + let second = self.0[1].to_canonical_biguint(); + let combined = second * Self::CHARACTERISTIC + first; + + combined } fn from_canonical_biguint(n: BigUint) -> Self { - let smallest_four: Vec<_> = n - .to_u32_digits() - .iter() - .take(4) - .pad_using(4, |_| &0u32) - .map(|x| *x as u64) - .collect(); - let last_u64 = smallest_four[0] + (1u64 << 32) * smallest_four[1]; - let next_last_u64 = smallest_four[2] + (1u64 << 32) * smallest_four[3]; + let smaller = n.clone() % Self::CHARACTERISTIC; + let larger = n.clone() / Self::CHARACTERISTIC; Self([ - >::BaseField::from_canonical_u64(last_u64), - >::BaseField::from_canonical_u64(next_last_u64), + >::BaseField::from_canonical_biguint(smaller), + >::BaseField::from_canonical_biguint(larger), ]) } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index a2b33c00..c6d152a3 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -124,38 +124,36 @@ impl Field for QuarticCrandallField { } fn to_canonical_biguint(&self) -> BigUint { - let first = self.0[0].to_canonical_u64(); - let second = self.0[1].to_canonical_u64(); - let third = self.0[2].to_canonical_u64(); - let fourth = self.0[2].to_canonical_u64(); - - let combined_first = second as u128 * (1u128 << 64) + first as u128; - let combined_second = fourth as u128 * (1u128 << 64) + third as u128; - - let combined = - BigUint::from(combined_second) * (BigUint::from(1u32) << 128) + combined_first; - + let first = self.0[0].to_canonical_biguint(); + let second = self.0[1].to_canonical_biguint(); + let third = self.0[2].to_canonical_biguint(); + let fourth = self.0[3].to_canonical_biguint(); + + let mut combined = fourth; + combined *= Self::CHARACTERISTIC; + combined += third; + combined *= Self::CHARACTERISTIC; + combined += second; + combined *= Self::CHARACTERISTIC; + combined += first; + combined } fn from_canonical_biguint(n: BigUint) -> Self { - let smallest_eight: Vec<_> = n - .to_u32_digits() - .iter() - .take(8) - .pad_using(8, |_| &0u32) - .map(|x| *x as u64) - .collect(); - let last_u64 = smallest_eight[0] + (1u64 << 32) * smallest_eight[1]; - let next_last_u64 = smallest_eight[2] + (1u64 << 32) * smallest_eight[3]; - let third_last_u64 = smallest_eight[4] + (1u64 << 32) * smallest_eight[5]; - let fourth_last_u64 = smallest_eight[6] + (1u64 << 32) * smallest_eight[7]; + let first = n.clone() % Self::CHARACTERISTIC; + let mut remaining = n.clone() / Self::CHARACTERISTIC; + let second = remaining.clone() % Self::CHARACTERISTIC; + remaining = remaining / Self::CHARACTERISTIC; + let third = remaining.clone() % Self::CHARACTERISTIC; + remaining = remaining / Self::CHARACTERISTIC; + let fourth = remaining.clone() % Self::CHARACTERISTIC; Self([ - >::BaseField::from_canonical_u64(last_u64), - >::BaseField::from_canonical_u64(next_last_u64), - >::BaseField::from_canonical_u64(third_last_u64), - >::BaseField::from_canonical_u64(fourth_last_u64), + >::BaseField::from_canonical_biguint(first), + >::BaseField::from_canonical_biguint(second), + >::BaseField::from_canonical_biguint(third), + >::BaseField::from_canonical_biguint(fourth), ]) } From b65e792ff3ebb1b4a3c7a57e6404b265eeb90d59 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Jul 2021 11:58:29 +0200 Subject: [PATCH 14/25] - Remove useless rotation gadgets - rotate.rs -> select.rs - Added `select()` and `select_ext` - Optimize to use just one gate --- src/gadgets/arithmetic.rs | 20 ++--- src/gadgets/mod.rs | 2 +- src/gadgets/rotate.rs | 167 -------------------------------------- src/gadgets/select.rs | 76 +++++++++++++++++ 4 files changed, 85 insertions(+), 180 deletions(-) delete mode 100644 src/gadgets/rotate.rs create mode 100644 src/gadgets/select.rs diff --git a/src/gadgets/arithmetic.rs b/src/gadgets/arithmetic.rs index 6dcf1b3d..71dbf310 100644 --- a/src/gadgets/arithmetic.rs +++ b/src/gadgets/arithmetic.rs @@ -170,14 +170,12 @@ impl, const D: usize> CircuitBuilder { /// Exponentiate `base` to the power of `exponent`, given by its little-endian bits. pub fn exp_from_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target { let mut current = base; - let one_ext = self.one_extension(); - let mut product = self.one(); + let one = self.one(); + let mut product = one; for &bit in exponent_bits { - // TODO: Add base field select. - let current_ext = self.convert_to_ext(current); - let multiplicand = self.select(bit, current_ext, one_ext); - product = self.mul(product, multiplicand.0[0]); + let multiplicand = self.select(bit, current, one); + product = self.mul(product, multiplicand); current = self.mul(current, current); } @@ -189,14 +187,12 @@ impl, const D: usize> CircuitBuilder { /// Exponentiate `base` to the power of `2^bit_length-1-exponent`, given by its little-endian bits. pub fn exp_from_complement_bits(&mut self, base: Target, exponent_bits: &[Target]) -> Target { let mut current = base; - let one_ext = self.one_extension(); - let mut product = self.one(); + let one = self.one(); + let mut product = one; for &bit in exponent_bits { - let current_ext = self.convert_to_ext(current); - // TODO: Add base field select. - let multiplicand = self.select(bit, one_ext, current_ext); - product = self.mul(product, multiplicand.0[0]); + let multiplicand = self.select(bit, one, current); + product = self.mul(product, multiplicand); current = self.mul(current, current); } diff --git a/src/gadgets/mod.rs b/src/gadgets/mod.rs index 2f216870..4c4160e1 100644 --- a/src/gadgets/mod.rs +++ b/src/gadgets/mod.rs @@ -5,6 +5,6 @@ pub mod insert; pub mod interpolation; pub mod polynomial; pub mod range_check; -pub mod rotate; +pub mod select; pub mod split_base; pub(crate) mod split_join; diff --git a/src/gadgets/rotate.rs b/src/gadgets/rotate.rs deleted file mode 100644 index 67677795..00000000 --- a/src/gadgets/rotate.rs +++ /dev/null @@ -1,167 +0,0 @@ -use crate::circuit_builder::CircuitBuilder; -use crate::field::extension_field::target::ExtensionTarget; -use crate::field::extension_field::Extendable; -use crate::target::Target; -use crate::util::log2_ceil; - -impl, const D: usize> CircuitBuilder { - /// Selects `x` or `y` based on `b`, which is assumed to be binary. - /// In particular, this returns `if b { x } else { y }`. - /// Note: This does not range-check `b`. - // TODO: This uses 10 gates per call. If addends are added to `MulExtensionGate`, this will be - // reduced to 2 gates. We could also use a new degree 2 `SelectGate` for this. - // If `num_routed_wire` is larger than 26, we could batch two `select` in one gate. - pub fn select( - &mut self, - b: Target, - x: ExtensionTarget, - y: ExtensionTarget, - ) -> ExtensionTarget { - let b_y_minus_y = self.scalar_mul_sub_extension(b, y, y); - self.scalar_mul_sub_extension(b, x, b_y_minus_y) - } - - /// Left-rotates an array `k` times if `b=1` else return the same array. - pub fn rotate_left_fixed( - &mut self, - b: Target, - k: usize, - v: &[ExtensionTarget], - ) -> Vec> { - let len = v.len(); - debug_assert!(k < len, "Trying to rotate by more than the vector length."); - let mut res = Vec::new(); - - for i in 0..len { - res.push(self.select(b, v[(i + k) % len], v[i])); - } - - res - } - - /// Left-rotates an array `k` times if `b=1` else return the same array. - pub fn rotate_right_fixed( - &mut self, - b: Target, - k: usize, - v: &[ExtensionTarget], - ) -> Vec> { - let len = v.len(); - debug_assert!(k < len, "Trying to rotate by more than the vector length."); - let mut res = Vec::new(); - - for i in 0..len { - res.push(self.select(b, v[(len + i - k) % len], v[i])); - } - - res - } - - /// Left-rotates an vector by the `Target` having bits given in little-endian by `num_rotation_bits`. - pub fn rotate_left_from_bits( - &mut self, - num_rotation_bits: &[Target], - v: &[ExtensionTarget], - ) -> Vec> { - let mut v = v.to_vec(); - - for i in 0..num_rotation_bits.len() { - v = self.rotate_left_fixed(num_rotation_bits[i], 1 << i, &v); - } - - v - } - - pub fn rotate_right_from_bits( - &mut self, - num_rotation_bits: &[Target], - v: &[ExtensionTarget], - ) -> Vec> { - let mut v = v.to_vec(); - - for i in 0..num_rotation_bits.len() { - v = self.rotate_right_fixed(num_rotation_bits[i], 1 << i, &v); - } - - v - } - - /// Left-rotates an array by `num_rotation`. Assumes that `num_rotation` is range-checked to be - /// less than `2^len_bits`. - pub fn rotate_left( - &mut self, - num_rotation: Target, - v: &[ExtensionTarget], - ) -> Vec> { - let len_bits = log2_ceil(v.len()); - let bits = self.split_le(num_rotation, len_bits); - - self.rotate_left_from_bits(&bits, v) - } - - pub fn rotate_right( - &mut self, - num_rotation: Target, - v: &[ExtensionTarget], - ) -> Vec> { - let len_bits = log2_ceil(v.len()); - let bits = self.split_le(num_rotation, len_bits); - - self.rotate_right_from_bits(&bits, v) - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - - use super::*; - use crate::circuit_data::CircuitConfig; - use crate::field::crandall_field::CrandallField; - use crate::field::extension_field::quartic::QuarticCrandallField; - use crate::field::field::Field; - use crate::verifier::verify; - use crate::witness::PartialWitness; - - fn real_rotate( - num_rotation: usize, - v: &[ExtensionTarget], - ) -> Vec> { - let mut res = v.to_vec(); - res.rotate_left(num_rotation); - res - } - - fn test_rotate_given_len(len: usize) -> Result<()> { - type F = CrandallField; - type FF = QuarticCrandallField; - let config = CircuitConfig::large_config(); - let mut builder = CircuitBuilder::::new(config); - let v = (0..len) - .map(|_| builder.constant_extension(FF::rand())) - .collect::>(); - - for i in 0..len { - let it = builder.constant(F::from_canonical_usize(i)); - let rotated = real_rotate(i, &v); - let purported_rotated = builder.rotate_left(it, &v); - - for (x, y) in rotated.into_iter().zip(purported_rotated) { - builder.assert_equal_extension(x, y); - } - } - - let data = builder.build(); - let proof = data.prove(PartialWitness::new())?; - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_rotate() -> Result<()> { - for len in 1..5 { - test_rotate_given_len(len)?; - } - Ok(()) - } -} diff --git a/src/gadgets/select.rs b/src/gadgets/select.rs new file mode 100644 index 00000000..bbd36d76 --- /dev/null +++ b/src/gadgets/select.rs @@ -0,0 +1,76 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; +use crate::gates::arithmetic::ArithmeticExtensionGate; +use crate::target::Target; + +impl, const D: usize> CircuitBuilder { + /// Selects `x` or `y` based on `b`, which is assumed to be binary, i.e., this returns `if b { x } else { y }`. + /// This expression is gotten as `bx - (by-y)`, which can be computed with a single `ArithmeticExtensionGate`. + /// Note: This does not range-check `b`. + pub fn select_ext( + &mut self, + b: Target, + x: ExtensionTarget, + y: ExtensionTarget, + ) -> ExtensionTarget { + let b_ext = self.convert_to_ext(b); + let gate = self.num_gates(); + // Holds `by - y`. + let first_out = + ExtensionTarget::from_range(gate, ArithmeticExtensionGate::::wires_first_output()); + self.double_arithmetic_extension(F::ONE, F::NEG_ONE, b_ext, y, y, b_ext, x, first_out) + .1 + } + + /// See `select_ext`. + pub fn select(&mut self, b: Target, x: Target, y: Target) -> Target { + let x_ext = self.convert_to_ext(x); + let y_ext = self.convert_to_ext(y); + self.select_ext(b, x_ext, y_ext).to_target_array()[0] + } +} + +#[cfg(test)] +mod tests { + use anyhow::Result; + + use super::*; + use crate::circuit_data::CircuitConfig; + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::field::Field; + use crate::verifier::verify; + use crate::witness::PartialWitness; + + #[test] + fn test_select() -> Result<()> { + type F = CrandallField; + type FF = QuarticCrandallField; + let config = CircuitConfig::large_config(); + let mut builder = CircuitBuilder::::new(config); + let mut pw = PartialWitness::new(); + + let (x, y) = (FF::rand(), FF::rand()); + let xt = builder.add_virtual_extension_target(); + let yt = builder.add_virtual_extension_target(); + let truet = builder.add_virtual_target(); + let falset = builder.add_virtual_target(); + + pw.set_extension_target(xt, x); + pw.set_extension_target(yt, y); + pw.set_target(truet, F::ONE); + pw.set_target(falset, F::ZERO); + + let should_be_x = builder.select_ext(truet, xt, yt); + let should_be_y = builder.select_ext(falset, xt, yt); + + builder.assert_equal_extension(should_be_x, xt); + builder.assert_equal_extension(should_be_y, yt); + + let data = builder.build(); + let proof = data.prove(pw)?; + + verify(proof, &data.verifier_only, &data.common) + } +} From b68be576152f7d7414a845fdd085fa29061b3cbe Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Jul 2021 13:33:57 +0200 Subject: [PATCH 15/25] Simplify interpolation test --- src/gates/interpolation.rs | 28 ++++++---------------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 17d34e3a..d51685e7 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -313,31 +313,15 @@ mod tests { points: Vec, eval_point: FF, ) -> Vec { - let mut v = vec![F::ZERO; num_points * 5 + (coeffs.len() + 3) * D]; + let mut v = Vec::new(); + v.extend_from_slice(&points); for j in 0..num_points { - v[j] = points[j]; - } - for j in 0..num_points { - for i in 0..D { - v[num_points + D * j + i] = >::to_basefield_array( - &coeffs.eval(points[j].into()), - )[i]; - } - } - for i in 0..D { - v[num_points * 5 + i] = - >::to_basefield_array(&eval_point)[i]; - } - for i in 0..D { - v[num_points * 5 + D + i] = - >::to_basefield_array(&coeffs.eval(eval_point))[i]; + v.extend(coeffs.eval(points[j].into()).0); } + v.extend(eval_point.0); + v.extend(coeffs.eval(eval_point).0); for i in 0..coeffs.len() { - for (j, input) in - (0..D).zip(num_points * 5 + (2 + i) * D..num_points * 5 + (3 + i) * D) - { - v[input] = >::to_basefield_array(&coeffs.coeffs[i])[j]; - } + v.extend(coeffs.coeffs[i].0); } v.iter().map(|&x| x.into()).collect::>() } From 3a24e8f4c16afcb48a22f514e193d0661f7a7a37 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Thu, 22 Jul 2021 14:00:55 +0200 Subject: [PATCH 16/25] Manually implement `eval_unfiltered_base` for all gates --- src/gates/arithmetic.rs | 29 ++++++++++++++++++++-- src/gates/base_sum.rs | 16 +++++++++++- src/gates/constant.rs | 8 +++++- src/gates/gmimc.rs | 51 +++++++++++++++++++++++++++++++++++++- src/gates/insertion.rs | 40 +++++++++++++++++++++++++++++- src/gates/interpolation.rs | 26 ++++++++++++++++++- src/gates/noop.rs | 6 ++++- src/gates/public_input.rs | 9 ++++++- src/vars.rs | 11 +++++++- 9 files changed, 186 insertions(+), 10 deletions(-) diff --git a/src/gates/arithmetic.rs b/src/gates/arithmetic.rs index cf39e09b..a3739ee5 100644 --- a/src/gates/arithmetic.rs +++ b/src/gates/arithmetic.rs @@ -2,11 +2,11 @@ use std::ops::Range; use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::target::ExtensionTarget; -use crate::field::extension_field::Extendable; +use crate::field::extension_field::{Extendable, FieldExtension}; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::witness::PartialWitness; /// A gate which can a linear combination `c0*x*y+c1*z` twice with the same `x`. @@ -74,6 +74,31 @@ impl, const D: usize> Gate for ArithmeticExtensionGate constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let const_0 = vars.local_constants[0]; + let const_1 = vars.local_constants[1]; + + let first_multiplicand_0 = vars.get_local_ext(Self::wires_first_multiplicand_0()); + let first_multiplicand_1 = vars.get_local_ext(Self::wires_first_multiplicand_1()); + let first_addend = vars.get_local_ext(Self::wires_first_addend()); + let second_multiplicand_0 = vars.get_local_ext(Self::wires_second_multiplicand_0()); + let second_multiplicand_1 = vars.get_local_ext(Self::wires_second_multiplicand_1()); + let second_addend = vars.get_local_ext(Self::wires_second_addend()); + let first_output = vars.get_local_ext(Self::wires_first_output()); + let second_output = vars.get_local_ext(Self::wires_second_output()); + + let first_computed_output = first_multiplicand_0 * first_multiplicand_1 * const_0.into() + + first_addend * const_1.into(); + let second_computed_output = second_multiplicand_0 * second_multiplicand_1 * const_0.into() + + second_addend * const_1.into(); + + let mut constraints = (first_output - first_computed_output) + .to_basefield_array() + .to_vec(); + constraints.extend((second_output - second_computed_output).to_basefield_array()); + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/base_sum.rs b/src/gates/base_sum.rs index 8ad189ee..b6645959 100644 --- a/src/gates/base_sum.rs +++ b/src/gates/base_sum.rs @@ -8,7 +8,7 @@ use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::plonk_common::{reduce_with_powers, reduce_with_powers_recursive}; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::witness::PartialWitness; /// A gate which can decompose a number into base B little-endian limbs, @@ -57,6 +57,20 @@ impl, const D: usize, const B: usize> Gate for BaseSumGat constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let sum = vars.local_wires[Self::WIRE_SUM]; + let reversed_sum = vars.local_wires[Self::WIRE_REVERSED_SUM]; + let mut limbs = vars.local_wires[self.limbs()].to_vec(); + let computed_sum = reduce_with_powers(&limbs, F::from_canonical_usize(B)); + limbs.reverse(); + let computed_reversed_sum = reduce_with_powers(&limbs, F::from_canonical_usize(B)); + let mut constraints = vec![computed_sum - sum, computed_reversed_sum - reversed_sum]; + for limb in limbs { + constraints.push((0..B).map(|i| limb - F::from_canonical_usize(i)).product()); + } + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/constant.rs b/src/gates/constant.rs index 4049d058..4a5c4373 100644 --- a/src/gates/constant.rs +++ b/src/gates/constant.rs @@ -5,7 +5,7 @@ use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -33,6 +33,12 @@ impl, const D: usize> Gate for ConstantGate { vec![output - input] } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let input = vars.local_constants[Self::CONST_INPUT]; + let output = vars.local_wires[Self::WIRE_OUTPUT]; + vec![output - input] + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/gmimc.rs b/src/gates/gmimc.rs index 0404884b..12e43b3c 100644 --- a/src/gates/gmimc.rs +++ b/src/gates/gmimc.rs @@ -8,7 +8,7 @@ use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::gmimc::gmimc_automatic_constants; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -121,6 +121,55 @@ impl, const D: usize, const R: usize> Gate for GMiMCGate< constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let mut constraints = Vec::with_capacity(self.num_constraints()); + + // Assert that `swap` is binary. + let swap = vars.local_wires[Self::WIRE_SWAP]; + constraints.push(swap * (swap - F::ONE)); + + let old_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_OLD]; + let new_index_acc = vars.local_wires[Self::WIRE_INDEX_ACCUMULATOR_NEW]; + let computed_new_index_acc = F::TWO * old_index_acc + swap; + constraints.push(computed_new_index_acc - new_index_acc); + + let mut state = Vec::with_capacity(12); + for i in 0..4 { + let a = vars.local_wires[i]; + let b = vars.local_wires[i + 4]; + state.push(a + swap * (b - a)); + } + for i in 0..4 { + let a = vars.local_wires[i + 4]; + let b = vars.local_wires[i]; + state.push(a + swap * (b - a)); + } + for i in 8..12 { + state.push(vars.local_wires[i]); + } + + // Value that is implicitly added to each element. + // See https://affine.group/2020/02/starkware-challenge + let mut addition_buffer = F::ZERO; + + for r in 0..R { + let active = r % W; + let cubing_input = state[active] + addition_buffer + self.constants[r].into(); + let cubing_input_wire = vars.local_wires[Self::wire_cubing_input(r)]; + constraints.push(cubing_input - cubing_input_wire); + let f = cubing_input_wire.cube(); + addition_buffer += f; + state[active] -= f; + } + + for i in 0..W { + state[i] += addition_buffer; + constraints.push(state[i] - vars.local_wires[Self::wire_output(i)]); + } + + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/insertion.rs b/src/gates/insertion.rs index 1bc0b454..4bfe97a9 100644 --- a/src/gates/insertion.rs +++ b/src/gates/insertion.rs @@ -9,7 +9,7 @@ use crate::field::field::Field; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -114,6 +114,44 @@ impl, const D: usize> Gate for InsertionGate { constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let insertion_index = vars.local_wires[self.wires_insertion_index()]; + let list_items = (0..self.vec_size) + .map(|i| vars.get_local_ext(self.wires_original_list_item(i))) + .collect::>(); + let output_list_items = (0..=self.vec_size) + .map(|i| vars.get_local_ext(self.wires_output_list_item(i))) + .collect::>(); + let element_to_insert = vars.get_local_ext(self.wires_element_to_insert()); + + let mut constraints = Vec::new(); + let mut already_inserted = F::ZERO; + for r in 0..=self.vec_size { + let cur_index = F::from_canonical_usize(r); + let difference = cur_index - insertion_index; + let equality_dummy = vars.local_wires[self.wires_equality_dummy_for_round_r(r)]; + let insert_here = vars.local_wires[self.wires_insert_here_for_round_r(r)]; + + // The two equality constraints. + constraints.push(difference * equality_dummy - (F::ONE - insert_here)); + constraints.push(insert_here * difference); + + let mut new_item = element_to_insert * insert_here.into(); + if r > 0 { + new_item += list_items[r - 1] * already_inserted.into(); + } + already_inserted += insert_here; + if r < self.vec_size { + new_item += list_items[r] * (F::ONE - already_inserted).into(); + } + + // Output constraint. + constraints.extend((new_item - output_list_items[r]).to_basefield_array()); + } + + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 17d34e3a..ed04c322 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -10,8 +10,9 @@ use crate::field::interpolation::interpolant; use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{GeneratedValues, SimpleGenerator, WitnessGenerator}; +use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; use crate::wire::Wire; use crate::witness::PartialWitness; @@ -121,6 +122,29 @@ impl, const D: usize> Gate for InterpolationGate { constraints } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + let mut constraints = Vec::with_capacity(self.num_constraints()); + + let coeffs = (0..self.num_points) + .map(|i| vars.get_local_ext(self.wires_coeff(i))) + .collect(); + let interpolant = PolynomialCoeffs::new(coeffs); + + for i in 0..self.num_points { + let point = vars.local_wires[self.wire_point(i)]; + let value = vars.get_local_ext(self.wires_value(i)); + let computed_value = interpolant.eval(point.into()); + constraints.extend(&(value - computed_value).to_basefield_array()); + } + + let evaluation_point = vars.get_local_ext(self.wires_evaluation_point()); + let evaluation_value = vars.get_local_ext(self.wires_evaluation_value()); + let computed_evaluation_value = interpolant.eval(evaluation_point); + constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array()); + + constraints + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/noop.rs b/src/gates/noop.rs index a12df932..c27b22bf 100644 --- a/src/gates/noop.rs +++ b/src/gates/noop.rs @@ -3,7 +3,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::gates::gate::{Gate, GateRef}; use crate::generator::WitnessGenerator; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate which does nothing. pub struct NoopGate; @@ -23,6 +23,10 @@ impl, const D: usize> Gate for NoopGate { Vec::new() } + fn eval_unfiltered_base(&self, _vars: EvaluationVarsBase) -> Vec { + Vec::new() + } + fn eval_unfiltered_recursively( &self, _builder: &mut CircuitBuilder, diff --git a/src/gates/public_input.rs b/src/gates/public_input.rs index a86b78d5..e1ce9271 100644 --- a/src/gates/public_input.rs +++ b/src/gates/public_input.rs @@ -5,7 +5,7 @@ use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::Extendable; use crate::gates::gate::{Gate, GateRef}; use crate::generator::WitnessGenerator; -use crate::vars::{EvaluationTargets, EvaluationVars}; +use crate::vars::{EvaluationTargets, EvaluationVars, EvaluationVarsBase}; /// A gate whose first four wires will be equal to a hash of public inputs. pub struct PublicInputGate; @@ -32,6 +32,13 @@ impl, const D: usize> Gate for PublicInputGate { .collect() } + fn eval_unfiltered_base(&self, vars: EvaluationVarsBase) -> Vec { + Self::wires_public_inputs_hash() + .zip(vars.public_inputs_hash.elements) + .map(|(wire, hash_part)| vars.local_wires[wire] - hash_part) + .collect() + } + fn eval_unfiltered_recursively( &self, builder: &mut CircuitBuilder, diff --git a/src/vars.rs b/src/vars.rs index 8e98d41f..66ce2efb 100644 --- a/src/vars.rs +++ b/src/vars.rs @@ -3,7 +3,7 @@ use std::ops::Range; use crate::field::extension_field::algebra::ExtensionAlgebra; use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; -use crate::field::extension_field::Extendable; +use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::proof::{Hash, HashTarget}; @@ -37,6 +37,15 @@ impl<'a, F: Extendable, const D: usize> EvaluationVars<'a, F, D> { } impl<'a, F: Field> EvaluationVarsBase<'a, F> { + pub fn get_local_ext(&self, wire_range: Range) -> F::Extension + where + F: Extendable, + { + debug_assert_eq!(wire_range.len(), D); + let arr = self.local_wires[wire_range].try_into().unwrap(); + F::Extension::from_basefield_array(arr) + } + pub fn remove_prefix(&mut self, prefix: &[bool]) { self.local_constants = &self.local_constants[prefix.len()..]; } From 6bd197e9cf7927fd2d11e672b458f9a0c8001d69 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Thu, 22 Jul 2021 10:27:10 -0700 Subject: [PATCH 17/25] Observe public inputs (#119) * Observe public inputs * Observe the hash instead --- src/prover.rs | 3 ++- src/recursive_verifier.rs | 6 ++++-- src/verifier.rs | 3 ++- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/prover.rs b/src/prover.rs index 59b3cd3d..7d209667 100644 --- a/src/prover.rs +++ b/src/prover.rs @@ -78,9 +78,10 @@ pub(crate) fn prove, const D: usize>( ); let mut challenger = Challenger::new(); + // Observe the instance. - // TODO: Need to include public inputs as well. challenger.observe_hash(&common_data.circuit_digest); + challenger.observe_hash(&public_inputs_hash); challenger.observe_hash(&wires_commitment.merkle_tree.root); let betas = challenger.get_n_challenges(num_challenges); diff --git a/src/recursive_verifier.rs b/src/recursive_verifier.rs index 66b63e7f..0fe62a77 100644 --- a/src/recursive_verifier.rs +++ b/src/recursive_verifier.rs @@ -28,18 +28,20 @@ impl, const D: usize> CircuitBuilder { } = proof_with_pis; let one = self.one_extension(); - let public_inputs_hash = &self.hash_n_to_hash(public_inputs, true); - let num_challenges = inner_config.num_challenges; + let public_inputs_hash = &self.hash_n_to_hash(public_inputs, true); + let mut challenger = RecursiveChallenger::new(self); let (betas, gammas, alphas, zeta) = context!(self, "observe proof and generates challenges", { + // Observe the instance. let digest = HashTarget::from_vec( self.constants(&inner_common_data.circuit_digest.elements), ); challenger.observe_hash(&digest); + challenger.observe_hash(&public_inputs_hash); challenger.observe_hash(&proof.wires_root); let betas = challenger.get_n_challenges(self, num_challenges); diff --git a/src/verifier.rs b/src/verifier.rs index 878b630a..d8af4cb4 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -25,9 +25,10 @@ pub(crate) fn verify, const D: usize>( let public_inputs_hash = &hash_n_to_hash(public_inputs, true); let mut challenger = Challenger::new(); + // Observe the instance. - // TODO: Need to include public inputs as well. challenger.observe_hash(&common_data.circuit_digest); + challenger.observe_hash(&public_inputs_hash); challenger.observe_hash(&proof.wires_root); let betas = challenger.get_n_challenges(num_challenges); From 5d30124101e7951db4b0ec6afd1c3722f36c29ca Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 10:55:11 -0700 Subject: [PATCH 18/25] moved specific tests to prime_field_arithmetic --- src/field/crandall_field.rs | 4 +-- src/field/extension_field/quadratic.rs | 4 +-- src/field/extension_field/quartic.rs | 4 +-- src/field/field_testing.rs | 44 ++++++++++++++++---------- 4 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 1c57efa7..3946ead5 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -480,7 +480,7 @@ impl Frobenius<1> for CrandallField {} #[cfg(test)] mod tests { - use crate::test_arithmetic; + use crate::test_prime_field_arithmetic; - test_arithmetic!(crate::field::crandall_field::CrandallField); + test_prime_field_arithmetic!(crate::field::crandall_field::CrandallField); } diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 491d06e6..1b9c78a1 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -222,7 +222,7 @@ mod tests { use crate::field::extension_field::quadratic::QuadraticCrandallField; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; - use crate::test_arithmetic; + use crate::test_field_arithmetic; #[test] fn test_add_neg_sub_mul() { @@ -294,5 +294,5 @@ mod tests { ); } - test_arithmetic!(crate::field::extension_field::quadratic::QuadraticCrandallField); + test_field_arithmetic!(crate::field::extension_field::quadratic::QuadraticCrandallField); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index c6d152a3..15f90a5d 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -289,7 +289,7 @@ mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::{FieldExtension, Frobenius}; use crate::field::field::Field; - use crate::test_arithmetic; + use crate::test_field_arithmetic; fn exp_naive(x: F, power: u128) -> F { let mut current = x; @@ -388,5 +388,5 @@ mod tests { ); } - test_arithmetic!(crate::field::extension_field::quartic::QuarticCrandallField); + test_field_arithmetic!(crate::field::extension_field::quartic::QuarticCrandallField); } diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 4822024a..e2ae0fa7 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -149,9 +149,9 @@ pub fn run_binaryop_test_cases( } #[macro_export] -macro_rules! test_arithmetic { +macro_rules! test_prime_field_arithmetic { ($field:ty) => { - mod arithmetic { + mod prime_field_arithmetic { use std::ops::{Add, Mul, Neg, Sub}; use num_bigint::BigUint; @@ -161,7 +161,7 @@ macro_rules! test_arithmetic { // Can be 32 or 64; doesn't have to be computer's actual word // bits. Choosing 32 gives more tests... const WORD_BITS: usize = 32; - + #[test] fn arithmetic_addition() { let modulus = <$field>::order(); @@ -251,6 +251,30 @@ macro_rules! test_arithmetic { } } + #[test] + fn subtraction() { + type F = $field; + + let (a, b) = ( + F::from_canonical_biguint((F::order() + 1u32) / 2u32), + F::TWO, + ); + let x = a * b; + assert_eq!(x, F::ONE); + assert_eq!(F::ZERO - x, F::NEG_ONE); + } + } + }; +} + +#[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) @@ -322,19 +346,6 @@ macro_rules! test_arithmetic { } } - #[test] - fn subtraction() { - type F = $field; - - let (a, b) = ( - F::from_canonical_biguint((F::order() + 1u32) / 2u32), - F::TWO, - ); - let x = a * b; - assert_eq!(x, F::ONE); - assert_eq!(F::ZERO - x, F::NEG_ONE); - } - #[test] fn inverse_2exp() { // Just check consistency with try_inverse() @@ -351,3 +362,4 @@ macro_rules! test_arithmetic { } }; } + From b6e74b8244292cf156663a9deaf5157ad4310116 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 10:57:08 -0700 Subject: [PATCH 19/25] cargo fmt --- src/field/extension_field/quadratic.rs | 2 +- src/field/extension_field/quartic.rs | 4 ++-- src/field/field_testing.rs | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 1b9c78a1..48608f48 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -94,7 +94,7 @@ impl Field for QuadraticCrandallField { let first = self.0[0].to_canonical_biguint(); let second = self.0[1].to_canonical_biguint(); let combined = second * Self::CHARACTERISTIC + first; - + combined } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 15f90a5d..52452387 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -128,7 +128,7 @@ impl Field for QuarticCrandallField { let second = self.0[1].to_canonical_biguint(); let third = self.0[2].to_canonical_biguint(); let fourth = self.0[3].to_canonical_biguint(); - + let mut combined = fourth; combined *= Self::CHARACTERISTIC; combined += third; @@ -136,7 +136,7 @@ impl Field for QuarticCrandallField { combined += second; combined *= Self::CHARACTERISTIC; combined += first; - + combined } diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index e2ae0fa7..5ea6fb73 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -161,7 +161,7 @@ macro_rules! test_prime_field_arithmetic { // Can be 32 or 64; doesn't have to be computer's actual word // bits. Choosing 32 gives more tests... const WORD_BITS: usize = 32; - + #[test] fn arithmetic_addition() { let modulus = <$field>::order(); @@ -362,4 +362,3 @@ macro_rules! test_field_arithmetic { } }; } - From ffc90e902bacb1766ac0b6ecb43910a67b1d72c3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 13:08:14 -0700 Subject: [PATCH 20/25] exp_biguint test --- Cargo.toml | 1 - src/field/cosets.rs | 2 +- src/field/crandall_field.rs | 15 +- src/field/extension_field/quadratic.rs | 2 +- src/field/extension_field/quartic.rs | 12 +- src/field/field.rs | 2 +- src/field/field_testing.rs | 219 ++++++++++++++----------- 7 files changed, 132 insertions(+), 121 deletions(-) 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); - } - } - } - }; -} From 57da32fb82912f716091f823039c5602e5d6e94b Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 13:16:12 -0700 Subject: [PATCH 21/25] fixes to use references --- src/field/extension_field/mod.rs | 2 +- src/field/extension_field/quadratic.rs | 2 +- src/field/extension_field/quartic.rs | 2 +- src/field/extension_field/target.rs | 2 +- src/field/field.rs | 4 ++-- src/field/field_testing.rs | 4 ++-- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 6a927b04..7d706237 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -35,7 +35,7 @@ pub trait Frobenius: OEF { } let arr = self.to_basefield_array(); let k = (Self::BaseField::order() - 1u32) / (D as u64); - let z0 = Self::W.exp_biguint(k * count as u64); + let z0 = Self::W.exp_biguint(&(k * count as u64)); let mut res = [Self::BaseField::ZERO; D]; for (i, z) in z0.powers().take(D).enumerate() { res[i] = arr[i] * z; diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 156a71b3..5324ad2a 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -261,7 +261,7 @@ mod tests { type F = QuadraticCrandallField; let x = F::rand(); assert_eq!( - x.exp_biguint(>::BaseField::order()), + x.exp_biguint(&>::BaseField::order()), x.frobenius() ); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 7de88817..3c463026 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -342,7 +342,7 @@ mod tests { const D: usize = 4; let x = F::rand(); assert_eq!( - x.exp_biguint(>::BaseField::order()), + x.exp_biguint(&>::BaseField::order()), x.frobenius() ); for count in 2..D { diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 502ea896..6083e2c4 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -32,7 +32,7 @@ impl ExtensionTarget { } let arr = self.to_target_array(); let k = (F::order() - 1u32) / (D as u64); - let z0 = F::Extension::W.exp_biguint(k * count as u64); + let z0 = F::Extension::W.exp_biguint(&(k * count as u64)); let zs = z0 .powers() .take(D) diff --git a/src/field/field.rs b/src/field/field.rs index 4075d6d7..da9f94f0 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -220,7 +220,7 @@ pub trait Field: self.exp(power as u64) } - fn exp_biguint(&self, power: BigUint) -> Self { + fn exp_biguint(&self, power: &BigUint) -> Self { let digits = power.to_u32_digits(); let radix = 1u64 << 32; @@ -262,7 +262,7 @@ pub trait Field: let numerator = p.clone() + &p_minus_1 * n; if numerator.clone() % k == BigUint::zero() { let power = (numerator / k) % p_minus_1; - return self.exp_biguint(power); + return self.exp_biguint(&power); } } panic!( diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index 18e844e8..bbab0bc9 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -242,8 +242,8 @@ macro_rules! test_field_arithmetic { 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)); + assert_eq!(base.exp_biguint(&pow), base.exp_biguint(&big_pow)); + assert_ne!(base.exp_biguint(&pow), base.exp_biguint(&big_pow_wrong)); } #[test] From 3425bd00783f691555e3f81248d465abe2488d9f Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 13:26:38 -0700 Subject: [PATCH 22/25] replaced some clones with refs --- src/field/field_testing.rs | 53 +++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/src/field/field_testing.rs b/src/field/field_testing.rs index bbab0bc9..1d684975 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -1,4 +1,4 @@ -use num::bigint::BigUint; +use num::{bigint::BigUint, Zero}; use crate::field::field::Field; use crate::util::ceil_div_usize; @@ -34,21 +34,17 @@ pub fn test_inputs(modulus: BigUint, word_bits: usize) -> Vec { // Inputs 'difference from' maximum value let diff_max = basic_inputs .iter() - .map(|x| x.clone()) - .map(|x| multiple_words_max.clone() - x) + .map(|x| &multiple_words_max - x) .filter(|x| x < &modulus) .collect(); // Inputs 'difference from' modulus value let diff_mod = basic_inputs .iter() - .map(|x| x.clone()) - .filter(|x| x.clone() < modulus.clone() && x.clone() != BigUint::from(0u32)) - .map(|x| x.clone()) - .map(|x| modulus.clone() - x) + .filter(|&x| x < &modulus && !x.is_zero()) + .map(|x| &modulus - x) .collect(); let basics = basic_inputs .into_iter() - .map(|x| x.clone()) .filter(|x| x < &modulus) .collect::>(); [basics, diff_max, diff_mod].concat() @@ -79,7 +75,7 @@ pub fn run_unaryop_test_cases( let expected: Vec<_> = inputs.iter().map(|x| expected_op(x.clone())).collect(); let output: Vec<_> = inputs .iter() - .map(|x| x.clone()) + .cloned() .map(|x| op(F::from_canonical_biguint(x)).to_canonical_biguint()) .collect(); // Compare expected outputs with actual outputs @@ -130,9 +126,8 @@ pub fn run_binaryop_test_cases( let output: Vec<_> = inputs .iter() .zip(shifted_inputs.clone()) - .map(|(x, y)| (x.clone(), y.clone())) .map(|(x, y)| { - op(F::from_canonical_biguint(x), F::from_canonical_biguint(y)) + op(F::from_canonical_biguint(x.clone()), F::from_canonical_biguint(y.clone())) .to_canonical_biguint() }) .collect(); @@ -153,7 +148,7 @@ pub fn run_binaryop_test_cases( macro_rules! test_field_arithmetic { ($field:ty) => { mod field_arithmetic { - use num::bigint::BigUint; + use num::{bigint::BigUint, Zero, One} ; use rand::{thread_rng, Rng}; use crate::field::field::Field; @@ -184,11 +179,11 @@ macro_rules! test_field_arithmetic { let order = <$field>::order(); for i in [ - BigUint::from(0u32), - BigUint::from(1u32), + BigUint::zero(), + BigUint::one(), BigUint::from(2u32), - order.clone() - 2u32, - order.clone() - 1u32, + &order - 1u32, + &order - 2u32, ] { let i_f = <$field>::from_canonical_biguint(i); assert_eq!(i_f + -i_f, zero); @@ -269,7 +264,7 @@ macro_rules! test_prime_field_arithmetic { mod prime_field_arithmetic { use std::ops::{Add, Mul, Neg, Sub}; - use num::bigint::BigUint; + use num::{bigint::BigUint, Zero, One}; use crate::field::field::Field; @@ -284,7 +279,7 @@ macro_rules! test_prime_field_arithmetic { modulus.clone(), WORD_BITS, <$field>::add, - |x, y| (x.clone() + y.clone()) % modulus.clone(), + |x, y| (&x + &y) % &modulus, ) } @@ -297,9 +292,9 @@ macro_rules! test_prime_field_arithmetic { <$field>::sub, |x, y| { if x >= y { - x.clone() - y.clone() + &x - &y } else { - modulus.clone() - y.clone() + x + &modulus - &y + &x } }, ) @@ -313,10 +308,10 @@ macro_rules! test_prime_field_arithmetic { WORD_BITS, <$field>::neg, |x| { - if x == BigUint::from(0u32) { - BigUint::from(0u32) + if x.is_zero() { + BigUint::zero() } else { - modulus.clone() - x.clone() + &modulus - &x } }, ) @@ -329,7 +324,7 @@ macro_rules! test_prime_field_arithmetic { modulus.clone(), WORD_BITS, <$field>::mul, - |x, y| x.clone() * y.clone() % modulus.clone(), + |x, y| &x * &y % &modulus, ) } @@ -340,7 +335,7 @@ macro_rules! test_prime_field_arithmetic { modulus.clone(), WORD_BITS, |x: $field| x.square(), - |x| (x.clone() * x.clone()) % modulus.clone(), + |x| (&x * &x) % &modulus, ) } @@ -353,12 +348,12 @@ macro_rules! test_prime_field_arithmetic { assert_eq!(zero.try_inverse(), None); for x in [ - BigUint::from(1u32), + BigUint::one(), BigUint::from(2u32), BigUint::from(3u32), - order.clone() - 3u32, - order.clone() - 2u32, - order.clone() - 1u32, + &order - 3u32, + &order - 2u32, + &order - 1u32, ] { let x = <$field>::from_canonical_biguint(x); let inv = x.inverse(); From ff055b646632beb6feae7553c53e77658262464d Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 13:27:40 -0700 Subject: [PATCH 23/25] cargo fmt --- src/field/crandall_field.rs | 2 +- src/field/extension_field/quartic.rs | 2 +- src/field/field.rs | 2 +- src/field/field_testing.rs | 12 +++++++----- 4 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/field/crandall_field.rs b/src/field/crandall_field.rs index 54749531..051b0fd0 100644 --- a/src/field/crandall_field.rs +++ b/src/field/crandall_field.rs @@ -5,8 +5,8 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use itertools::Itertools; -use num::Integer; use num::bigint::BigUint; +use num::Integer; use rand::Rng; use serde::{Deserialize, Serialize}; diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 3c463026..f38f103a 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -4,8 +4,8 @@ use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use itertools::Itertools; -use num::traits::Pow; use num::bigint::BigUint; +use num::traits::Pow; use rand::Rng; use serde::{Deserialize, Serialize}; diff --git a/src/field/field.rs b/src/field/field.rs index da9f94f0..03f6bdf1 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -4,8 +4,8 @@ use std::hash::Hash; 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::{Integer, Zero}; 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 1d684975..ffab1d9d 100644 --- a/src/field/field_testing.rs +++ b/src/field/field_testing.rs @@ -127,8 +127,11 @@ pub fn run_binaryop_test_cases( .iter() .zip(shifted_inputs.clone()) .map(|(x, y)| { - op(F::from_canonical_biguint(x.clone()), F::from_canonical_biguint(y.clone())) - .to_canonical_biguint() + op( + F::from_canonical_biguint(x.clone()), + F::from_canonical_biguint(y.clone()), + ) + .to_canonical_biguint() }) .collect(); @@ -143,12 +146,11 @@ pub fn run_binaryop_test_cases( } } - #[macro_export] macro_rules! test_field_arithmetic { ($field:ty) => { mod field_arithmetic { - use num::{bigint::BigUint, Zero, One} ; + use num::{bigint::BigUint, One, Zero}; use rand::{thread_rng, Rng}; use crate::field::field::Field; @@ -264,7 +266,7 @@ macro_rules! test_prime_field_arithmetic { mod prime_field_arithmetic { use std::ops::{Add, Mul, Neg, Sub}; - use num::{bigint::BigUint, Zero, One}; + use num::{bigint::BigUint, One, Zero}; use crate::field::field::Field; From 9c287aac798750111dfb6b5762c69322b26d34e3 Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 14:12:49 -0700 Subject: [PATCH 24/25] fixed nits --- src/field/field.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/field/field.rs b/src/field/field.rs index 03f6bdf1..3e2d3680 100644 --- a/src/field/field.rs +++ b/src/field/field.rs @@ -246,7 +246,7 @@ pub trait Field: fn kth_root(&self, k: u64) -> Self { let p = Self::order().clone(); - let p_minus_1 = p.clone() - 1u32; + let p_minus_1 = &p - 1u32; debug_assert!( Self::is_monomial_permutation(k), "Not a permutation of this field" @@ -259,8 +259,8 @@ pub trait Field: // x^((p + n(p - 1))/k)^k = x, // implying that x^((p + n(p - 1))/k) is a k'th root of x. for n in 0..k { - let numerator = p.clone() + &p_minus_1 * n; - if numerator.clone() % k == BigUint::zero() { + let numerator = &p + &p_minus_1 * n; + if (&numerator % k).is_zero() { let power = (numerator / k) % p_minus_1; return self.exp_biguint(&power); } From 0af5c3bdb8729607125f020059d1f953b5fd18fa Mon Sep 17 00:00:00 2001 From: Nicholas Ward Date: Thu, 22 Jul 2021 14:49:24 -0700 Subject: [PATCH 25/25] addressed nit --- src/field/field.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field/field.rs b/src/field/field.rs index 3e2d3680..fd5f8ac1 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::bigint::BigUint; -use num::{Integer, Zero}; +use num::{Integer, One, Zero}; use rand::Rng; use serde::de::DeserializeOwned; use serde::Serialize; @@ -240,7 +240,7 @@ pub trait Field: match power { 0 => false, 1 => true, - _ => (Self::order() - 1u32).gcd(&BigUint::from(power)) == BigUint::from(1u32), + _ => (Self::order() - 1u32).gcd(&BigUint::from(power)).is_one(), } }