From 66d6f3c338cc27b072b1f40e804f3d9cba9b9786 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 14:12:08 +0200 Subject: [PATCH 1/6] Remove useless Qua(d)r(a)ticFieldExtension traits --- src/bin/bench_ldes.rs | 2 +- src/field/extension_field/mod.rs | 61 +++++++-------- src/field/extension_field/quadratic.rs | 97 ++++++++++-------------- src/field/extension_field/quartic.rs | 100 +++++++++---------------- 4 files changed, 101 insertions(+), 159 deletions(-) diff --git a/src/bin/bench_ldes.rs b/src/bin/bench_ldes.rs index 1fb02d65..0413b296 100644 --- a/src/bin/bench_ldes.rs +++ b/src/bin/bench_ldes.rs @@ -12,7 +12,7 @@ type F = CrandallField; // from wire polynomials which "store" the outputs of S-boxes in our Poseidon gate. const NUM_LDES: usize = 8 + 8 + 3 + 86 + 3 + 8; -const DEGREE: usize = 1 << 14; +const DEGREE: usize = 1 << 13; const RATE_BITS: usize = 3; diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 67329c3c..122c9416 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -1,10 +1,31 @@ -use crate::field::extension_field::quadratic::QuadraticFieldExtension; -use crate::field::extension_field::quartic::QuarticFieldExtension; use crate::field::field::Field; pub mod quadratic; pub mod quartic; +/// Optimal extension field trait. +/// A degree `d` field extension is optimal if there exists a base field element `W`, +/// such that the extension is `F[X]/(X^d-W)`. +pub trait OEF: FieldExtension { + // Element W of BaseField, such that `X^d - W` is irreducible over BaseField. + const W: Self::BaseField; + + /// Frobenius automorphisms: x -> x^p, where p is the order of BaseField. + fn frobenius(&self) -> Self { + let arr = self.to_basefield_array(); + let k = (Self::BaseField::ORDER - 1) / (D as u64); + let z0 = Self::W.exp(k); + let mut z = Self::BaseField::ONE; + let mut res = [Self::BaseField::ZERO; D]; + for i in 0..D { + res[i] = arr[i] * z; + z *= z0; + } + + Self::from_basefield_array(res) + } +} + pub trait Extendable: Sized { type Extension: Field + FieldExtension + From; } @@ -21,6 +42,10 @@ pub trait FieldExtension: Field { fn from_basefield_array(arr: [Self::BaseField; D]) -> Self; fn from_basefield(x: Self::BaseField) -> Self; + + fn is_in_basefield(&self) -> bool { + self.to_basefield_array()[1..].iter().all(|x| x.is_zero()) + } } impl FieldExtension<1> for F { @@ -39,38 +64,6 @@ impl FieldExtension<1> for F { } } -impl FieldExtension<2> for FE { - type BaseField = FE::BaseField; - - fn to_basefield_array(&self) -> [Self::BaseField; 2] { - self.to_canonical_representation() - } - - fn from_basefield_array(arr: [Self::BaseField; 2]) -> Self { - Self::from_canonical_representation(arr) - } - - fn from_basefield(x: Self::BaseField) -> Self { - x.into() - } -} - -impl FieldExtension<4> for FE { - type BaseField = FE::BaseField; - - fn to_basefield_array(&self) -> [Self::BaseField; 4] { - self.to_canonical_representation() - } - - fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self { - Self::from_canonical_representation(arr) - } - - fn from_basefield(x: Self::BaseField) -> Self { - x.into() - } -} - /// Flatten the slice by sending every extension field element to its D-sized canonical representation. pub fn flatten(l: &[F::Extension]) -> Vec where diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 25b42e49..4fc60423 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -1,66 +1,49 @@ +use crate::circuit_builder::CircuitBuilder; use crate::field::crandall_field::CrandallField; +use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; +use crate::target::Target; use rand::Rng; use std::fmt::{Debug, Display, Formatter}; use std::hash::{Hash, Hasher}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -pub trait QuadraticFieldExtension: - Field + From<::BaseField> -{ - type BaseField: Field; - - // Element W of BaseField, such that `X^2 - W` is irreducible over BaseField. - const W: Self::BaseField; - - fn to_canonical_representation(&self) -> [Self::BaseField; 2]; - - fn from_canonical_representation(v: [Self::BaseField; 2]) -> Self; - - fn is_in_basefield(&self) -> bool { - self.to_canonical_representation()[1..] - .iter() - .all(|x| x.is_zero()) - } - - /// Frobenius automorphisms: x -> x^p, where p is the order of BaseField. - fn frobenius(&self) -> Self { - let [a0, a1] = self.to_canonical_representation(); - let k = (Self::BaseField::ORDER - 1) / 2; - let z = Self::W.exp(k); - - Self::from_canonical_representation([a0, a1 * z]) - } -} - #[derive(Copy, Clone)] pub struct QuadraticCrandallField([CrandallField; 2]); -impl QuadraticFieldExtension for QuadraticCrandallField { - type BaseField = CrandallField; +impl OEF<2> for QuadraticCrandallField { // Verifiable in Sage with // ``R. = GF(p)[]; assert (x^2 -3).is_irreducible()`. - const W: Self::BaseField = CrandallField(3); + const W: CrandallField = CrandallField(3); +} - fn to_canonical_representation(&self) -> [Self::BaseField; 2] { +impl FieldExtension<2> for QuadraticCrandallField { + type BaseField = CrandallField; + + fn to_basefield_array(&self) -> [Self::BaseField; 2] { self.0 } - fn from_canonical_representation(v: [Self::BaseField; 2]) -> Self { - Self(v) + fn from_basefield_array(arr: [Self::BaseField; 2]) -> Self { + Self(arr) + } + + fn from_basefield(x: Self::BaseField) -> Self { + x.into() } } -impl From<::BaseField> for QuadraticCrandallField { - fn from(x: ::BaseField) -> Self { - Self([x, ::BaseField::ZERO]) +impl From<>::BaseField> for QuadraticCrandallField { + fn from(x: >::BaseField) -> Self { + Self([x, >::BaseField::ZERO]) } } impl PartialEq for QuadraticCrandallField { fn eq(&self, other: &Self) -> bool { - self.to_canonical_representation() == other.to_canonical_representation() + FieldExtension::<2>::to_basefield_array(self) + == FieldExtension::<2>::to_basefield_array(other) } } @@ -68,7 +51,7 @@ impl Eq for QuadraticCrandallField {} impl Hash for QuadraticCrandallField { fn hash(&self, state: &mut H) { - for l in &self.to_canonical_representation() { + for l in &FieldExtension::<2>::to_basefield_array(self) { Hash::hash(l, state); } } @@ -101,7 +84,7 @@ impl Field for QuadraticCrandallField { let a_pow_r_minus_1 = self.frobenius(); let a_pow_r = a_pow_r_minus_1 * *self; - debug_assert!(a_pow_r.is_in_basefield()); + debug_assert!(FieldExtension::<2>::is_in_basefield(&a_pow_r)); Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into()) } @@ -111,16 +94,13 @@ impl Field for QuadraticCrandallField { } fn from_canonical_u64(n: u64) -> Self { - Self([ - ::BaseField::from_canonical_u64(n), - ::BaseField::ZERO, - ]) + >::BaseField::from_canonical_u64(n).into() } fn rand_from_rng(rng: &mut R) -> Self { Self([ - ::BaseField::rand_from_rng(rng), - ::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), ]) } } @@ -226,11 +206,16 @@ impl DivAssign for QuadraticCrandallField { } } +pub struct ExtensionTarget(pub [Target; 2]); + +// impl CircuitBuilder { +// fn mul +// } + #[cfg(test)] mod tests { - use crate::field::extension_field::quadratic::{ - QuadraticCrandallField, QuadraticFieldExtension, - }; + use crate::field::extension_field::quadratic::QuadraticCrandallField; + use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; #[test] @@ -241,10 +226,7 @@ mod tests { let z = F::rand(); assert_eq!(x + (-x), F::ZERO); assert_eq!(-x, F::ZERO - x); - assert_eq!( - x + x, - x * ::BaseField::TWO.into() - ); + assert_eq!(x + x, x * >::BaseField::TWO.into()); assert_eq!(x * (-x), -x.square()); assert_eq!(x + y, y + x); assert_eq!(x * y, y * x); @@ -273,7 +255,7 @@ mod tests { type F = QuadraticCrandallField; let x = F::rand(); assert_eq!( - x.exp(::BaseField::ORDER), + x.exp(>::BaseField::ORDER), x.frobenius() ); } @@ -300,10 +282,9 @@ mod tests { F::POWER_OF_TWO_GENERATOR ); assert_eq!( - F::POWER_OF_TWO_GENERATOR.exp( - 1 << (F::TWO_ADICITY - ::BaseField::TWO_ADICITY) - ), - ::BaseField::POWER_OF_TWO_GENERATOR.into() + F::POWER_OF_TWO_GENERATOR + .exp(1 << (F::TWO_ADICITY - >::BaseField::TWO_ADICITY)), + >::BaseField::POWER_OF_TWO_GENERATOR.into() ); } } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 121e4c67..c69e365d 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -1,4 +1,5 @@ use crate::field::crandall_field::CrandallField; +use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; use rand::Rng; use std::fmt::{Debug, Display, Formatter}; @@ -6,72 +7,46 @@ use std::hash::{Hash, Hasher}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -pub trait QuarticFieldExtension: Field + From<::BaseField> { - type BaseField: Field; - - // Element W of BaseField, such that `X^4 - W` is irreducible over BaseField. - const W: Self::BaseField; - - fn to_canonical_representation(&self) -> [Self::BaseField; 4]; - - fn from_canonical_representation(v: [Self::BaseField; 4]) -> Self; - - fn is_in_basefield(&self) -> bool { - self.to_canonical_representation()[1..] - .iter() - .all(|x| x.is_zero()) - } - - /// Frobenius automorphisms: x -> x^p, where p is the order of BaseField. - fn frobenius(&self) -> Self { - let [a0, a1, a2, a3] = self.to_canonical_representation(); - let k = (Self::BaseField::ORDER - 1) / 4; - let z0 = Self::W.exp(k); - let mut z = Self::BaseField::ONE; - let b0 = a0 * z; - z *= z0; - let b1 = a1 * z; - z *= z0; - let b2 = a2 * z; - z *= z0; - let b3 = a3 * z; - - Self::from_canonical_representation([b0, b1, b2, b3]) - } -} - #[derive(Copy, Clone)] pub struct QuarticCrandallField([CrandallField; 4]); -impl QuarticFieldExtension for QuarticCrandallField { - type BaseField = CrandallField; +impl OEF<4> for QuarticCrandallField { // Verifiable in Sage with // ``R. = GF(p)[]; assert (x^4 -3).is_irreducible()`. - const W: Self::BaseField = CrandallField(3); + const W: CrandallField = CrandallField(3); +} - fn to_canonical_representation(&self) -> [Self::BaseField; 4] { +impl FieldExtension<4> for QuarticCrandallField { + type BaseField = CrandallField; + + fn to_basefield_array(&self) -> [Self::BaseField; 4] { self.0 } - fn from_canonical_representation(v: [Self::BaseField; 4]) -> Self { - Self(v) + fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self { + Self(arr) + } + + fn from_basefield(x: Self::BaseField) -> Self { + x.into() } } -impl From<::BaseField> for QuarticCrandallField { - fn from(x: ::BaseField) -> Self { +impl From<>::BaseField> for QuarticCrandallField { + fn from(x: >::BaseField) -> Self { Self([ x, - ::BaseField::ZERO, - ::BaseField::ZERO, - ::BaseField::ZERO, + >::BaseField::ZERO, + >::BaseField::ZERO, + >::BaseField::ZERO, ]) } } impl PartialEq for QuarticCrandallField { fn eq(&self, other: &Self) -> bool { - self.to_canonical_representation() == other.to_canonical_representation() + FieldExtension::<4>::to_basefield_array(self) + == FieldExtension::<4>::to_basefield_array(other) } } @@ -79,7 +54,7 @@ impl Eq for QuarticCrandallField {} impl Hash for QuarticCrandallField { fn hash(&self, state: &mut H) { - for l in &self.to_canonical_representation() { + for l in &FieldExtension::<4>::to_basefield_array(self) { Hash::hash(l, state); } } @@ -136,7 +111,7 @@ impl Field for QuarticCrandallField { let a_pow_p3_plus_p2 = a_pow_p_plus_1.frobenius().frobenius(); let a_pow_r_minus_1 = a_pow_p3_plus_p2 * a_pow_p; let a_pow_r = a_pow_r_minus_1 * *self; - debug_assert!(a_pow_r.is_in_basefield()); + debug_assert!(FieldExtension::<4>::is_in_basefield(&a_pow_r)); Some(a_pow_r_minus_1 * a_pow_r.0[0].inverse().into()) } @@ -146,20 +121,15 @@ impl Field for QuarticCrandallField { } fn from_canonical_u64(n: u64) -> Self { - Self([ - ::BaseField::from_canonical_u64(n), - ::BaseField::ZERO, - ::BaseField::ZERO, - ::BaseField::ZERO, - ]) + >::BaseField::from_canonical_u64(n).into() } fn rand_from_rng(rng: &mut R) -> Self { Self([ - ::BaseField::rand_from_rng(rng), - ::BaseField::rand_from_rng(rng), - ::BaseField::rand_from_rng(rng), - ::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), + >::BaseField::rand_from_rng(rng), ]) } } @@ -283,7 +253,8 @@ impl DivAssign for QuarticCrandallField { #[cfg(test)] mod tests { - use crate::field::extension_field::quartic::{QuarticCrandallField, QuarticFieldExtension}; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; fn exp_naive(x: F, power: u128) -> F { @@ -307,10 +278,7 @@ mod tests { let z = F::rand(); assert_eq!(x + (-x), F::ZERO); assert_eq!(-x, F::ZERO - x); - assert_eq!( - x + x, - x * ::BaseField::TWO.into() - ); + assert_eq!(x + x, x * >::BaseField::TWO.into()); assert_eq!(x * (-x), -x.square()); assert_eq!(x + y, y + x); assert_eq!(x * y, y * x); @@ -339,7 +307,7 @@ mod tests { type F = QuarticCrandallField; let x = F::rand(); assert_eq!( - exp_naive(x, ::BaseField::ORDER as u128), + exp_naive(x, >::BaseField::ORDER as u128), x.frobenius() ); } @@ -374,8 +342,8 @@ mod tests { ); assert_eq!( F::POWER_OF_TWO_GENERATOR - .exp(1 << (F::TWO_ADICITY - ::BaseField::TWO_ADICITY)), - ::BaseField::POWER_OF_TWO_GENERATOR.into() + .exp(1 << (F::TWO_ADICITY - >::BaseField::TWO_ADICITY)), + >::BaseField::POWER_OF_TWO_GENERATOR.into() ); } } From 655bcd8eac3a236f0a13dc6ca16402d459be01cb Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 15:31:52 +0200 Subject: [PATCH 2/6] Minor --- src/field/extension_field/quadratic.rs | 6 ------ src/field/extension_field/target.rs | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 src/field/extension_field/target.rs diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index 4fc60423..ac910278 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -206,12 +206,6 @@ impl DivAssign for QuadraticCrandallField { } } -pub struct ExtensionTarget(pub [Target; 2]); - -// impl CircuitBuilder { -// fn mul -// } - #[cfg(test)] mod tests { use crate::field::extension_field::quadratic::QuadraticCrandallField; diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs new file mode 100644 index 00000000..32111f7f --- /dev/null +++ b/src/field/extension_field/target.rs @@ -0,0 +1,14 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::field::Field; +use crate::target::Target; + +pub struct ExtensionTarget([Target; D]); + +impl CircuitBuilder { + pub fn mul_extension(a: ExtensionTarget, b: ExtensionTarget) -> () + where + F: Extendable, + { + } +} From b64a5fab46865bcacc0f49109ccb66ad278147a7 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 16:36:21 +0200 Subject: [PATCH 3/6] Addition and multiplication for ExtensionTarget --- src/field/extension_field/mod.rs | 7 ++---- src/field/extension_field/target.rs | 36 +++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 122c9416..10a577db 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -2,6 +2,7 @@ use crate::field::field::Field; pub mod quadratic; pub mod quartic; +pub mod target; /// Optimal extension field trait. /// A degree `d` field extension is optimal if there exists a base field element `W`, @@ -27,11 +28,7 @@ pub trait OEF: FieldExtension { } pub trait Extendable: Sized { - type Extension: Field + FieldExtension + From; -} - -impl Extendable<1> for F { - type Extension = Self; + type Extension: Field + FieldExtension + OEF + From; } pub trait FieldExtension: Field { diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 32111f7f..6ca84a24 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -1,14 +1,46 @@ use crate::circuit_builder::CircuitBuilder; -use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::extension_field::{Extendable, FieldExtension, OEF}; use crate::field::field::Field; use crate::target::Target; +#[derive(Copy, Clone, Debug)] pub struct ExtensionTarget([Target; D]); impl CircuitBuilder { - pub fn mul_extension(a: ExtensionTarget, b: ExtensionTarget) -> () + pub fn add_extension( + &mut self, + mut a: ExtensionTarget, + b: ExtensionTarget, + ) -> ExtensionTarget where F: Extendable, { + for i in 0..D { + a.0[i] = self.add(a.0[i], b.0[i]); + } + a + } + + pub fn mul_extension( + &mut self, + a: ExtensionTarget, + b: ExtensionTarget, + ) -> ExtensionTarget + where + F: Extendable, + { + let w = self.constant(F::Extension::W); + let mut res = [self.zero(); D]; + for i in 0..D { + for j in 0..D { + res[(i + j) % D] = if i + j < D { + self.mul_add(a.0[i], b.0[j], res[(i + j) % D]) + } else { + let tmp = self.mul_add(a.0[i], b.0[j], res[(i + j) % D]); + self.mul(w, tmp) + } + } + } + ExtensionTarget(res) } } From 4f6e9fb2e031d4147e24e85da5cf9b35032e9ce8 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 17:31:55 +0200 Subject: [PATCH 4/6] Recursive evaluation for interpolation gate. --- src/field/extension_field/target.rs | 44 ++++++++++++++++++++++++++++- src/gadgets/mod.rs | 1 + src/gadgets/polynomial.rs | 35 +++++++++++++++++++++++ src/gates/interpolation.rs | 30 +++++++++++++++++++- src/vars.rs | 9 ++++++ 5 files changed, 117 insertions(+), 2 deletions(-) create mode 100644 src/gadgets/polynomial.rs diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 6ca84a24..28429c1a 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -4,9 +4,22 @@ use crate::field::field::Field; use crate::target::Target; #[derive(Copy, Clone, Debug)] -pub struct ExtensionTarget([Target; D]); +pub struct ExtensionTarget(pub [Target; D]); + +impl ExtensionTarget { + pub fn to_target_array(&self) -> [Target; D] { + self.0 + } +} impl CircuitBuilder { + pub fn zero_ext(&mut self) -> ExtensionTarget + where + F: Extendable, + { + ExtensionTarget([self.zero(); D]) + } + pub fn add_extension( &mut self, mut a: ExtensionTarget, @@ -21,6 +34,20 @@ impl CircuitBuilder { a } + pub fn sub_extension( + &mut self, + mut a: ExtensionTarget, + b: ExtensionTarget, + ) -> ExtensionTarget + where + F: Extendable, + { + for i in 0..D { + a.0[i] = self.sub(a.0[i], b.0[i]); + } + a + } + pub fn mul_extension( &mut self, a: ExtensionTarget, @@ -43,4 +70,19 @@ impl CircuitBuilder { } ExtensionTarget(res) } + + /// Returns a*b where `b` is in the extension field and `a` is in the base field. + pub fn scalar_mul( + &mut self, + a: Target, + mut b: ExtensionTarget, + ) -> ExtensionTarget + where + F: Extendable, + { + for i in 0..D { + b.0[i] = self.mul(a, b.0[i]); + } + b + } } diff --git a/src/gadgets/mod.rs b/src/gadgets/mod.rs index ed84207e..9a6a728e 100644 --- a/src/gadgets/mod.rs +++ b/src/gadgets/mod.rs @@ -1,3 +1,4 @@ pub mod arithmetic; pub mod hash; +pub mod polynomial; pub(crate) mod split_join; diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs new file mode 100644 index 00000000..05427038 --- /dev/null +++ b/src/gadgets/polynomial.rs @@ -0,0 +1,35 @@ +use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::target::ExtensionTarget; +use crate::field::extension_field::Extendable; +use crate::field::field::Field; +use crate::target::Target; + +pub struct PolynomialCoeffsTarget(pub Vec>); + +impl PolynomialCoeffsTarget { + pub fn eval_scalar>( + &self, + builder: &mut CircuitBuilder, + point: Target, + ) -> ExtensionTarget { + let mut acc = builder.zero_ext(); + for &c in self.0.iter().rev() { + let tmp = builder.scalar_mul(point, acc); + acc = builder.add_extension(tmp, c); + } + acc + } + + pub fn eval>( + &self, + builder: &mut CircuitBuilder, + point: ExtensionTarget, + ) -> ExtensionTarget { + let mut acc = builder.zero_ext(); + for &c in self.0.iter().rev() { + let tmp = builder.mul_extension(point, acc); + acc = builder.add_extension(tmp, c); + } + acc + } +} diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index adc7055d..a1b9ddd5 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -6,6 +6,7 @@ use crate::circuit_builder::CircuitBuilder; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::field::lagrange::interpolant; +use crate::gadgets::polynomial::PolynomialCoeffsTarget; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::polynomial::polynomial::PolynomialCoeffs; @@ -125,7 +126,34 @@ impl, const D: usize> Gate for InterpolationGate, vars: EvaluationTargets, ) -> Vec { - todo!() + 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 = PolynomialCoeffsTarget(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_scalar(builder, point); + constraints.extend( + &builder + .sub_extension(value, computed_value) + .to_target_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(builder, evaluation_point); + constraints.extend( + &builder + .sub_extension(evaluation_value, computed_evaluation_value) + .to_target_array(), + ); + + constraints } fn generators( diff --git a/src/vars.rs b/src/vars.rs index 7c0afab9..aa8a3561 100644 --- a/src/vars.rs +++ b/src/vars.rs @@ -1,6 +1,7 @@ use std::convert::TryInto; use std::ops::Range; +use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; use crate::target::Target; @@ -27,3 +28,11 @@ pub struct EvaluationTargets<'a> { pub(crate) local_constants: &'a [Target], pub(crate) local_wires: &'a [Target], } + +impl<'a> EvaluationTargets<'a> { + pub fn get_local_ext(&self, wire_range: Range) -> ExtensionTarget { + debug_assert_eq!(wire_range.len(), D); + let arr = self.local_wires[wire_range].try_into().unwrap(); + ExtensionTarget(arr) + } +} From c9309eb27b4caf4f781ecf4fb1ff7a6b4e5705bf Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 17:40:26 +0200 Subject: [PATCH 5/6] Minor --- src/bin/bench_ldes.rs | 2 +- src/field/extension_field/mod.rs | 1 + src/field/extension_field/target.rs | 2 +- src/gadgets/polynomial.rs | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/bench_ldes.rs b/src/bin/bench_ldes.rs index 0413b296..1fb02d65 100644 --- a/src/bin/bench_ldes.rs +++ b/src/bin/bench_ldes.rs @@ -12,7 +12,7 @@ type F = CrandallField; // from wire polynomials which "store" the outputs of S-boxes in our Poseidon gate. const NUM_LDES: usize = 8 + 8 + 3 + 86 + 3 + 8; -const DEGREE: usize = 1 << 13; +const DEGREE: usize = 1 << 14; const RATE_BITS: usize = 3; diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 10a577db..89263916 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -7,6 +7,7 @@ pub mod target; /// Optimal extension field trait. /// A degree `d` field extension is optimal if there exists a base field element `W`, /// such that the extension is `F[X]/(X^d-W)`. +#[allow(clippy::upper_case_acronyms)] pub trait OEF: FieldExtension { // Element W of BaseField, such that `X^d - W` is irreducible over BaseField. const W: Self::BaseField; diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 28429c1a..861baaf5 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -13,7 +13,7 @@ impl ExtensionTarget { } impl CircuitBuilder { - pub fn zero_ext(&mut self) -> ExtensionTarget + pub fn zero_extension(&mut self) -> ExtensionTarget where F: Extendable, { diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index 05427038..64bf4ca3 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -12,7 +12,7 @@ impl PolynomialCoeffsTarget { builder: &mut CircuitBuilder, point: Target, ) -> ExtensionTarget { - let mut acc = builder.zero_ext(); + let mut acc = builder.zero_extension(); for &c in self.0.iter().rev() { let tmp = builder.scalar_mul(point, acc); acc = builder.add_extension(tmp, c); @@ -25,7 +25,7 @@ impl PolynomialCoeffsTarget { builder: &mut CircuitBuilder, point: ExtensionTarget, ) -> ExtensionTarget { - let mut acc = builder.zero_ext(); + let mut acc = builder.zero_extension(); for &c in self.0.iter().rev() { let tmp = builder.mul_extension(point, acc); acc = builder.add_extension(tmp, c); From a11d2ed36be044162fa3bf8fda7208dbda51ac92 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Mon, 24 May 2021 22:04:06 +0200 Subject: [PATCH 6/6] Fixes based on PR comments --- src/field/extension_field/mod.rs | 10 +++++++++- src/field/extension_field/quadratic.rs | 8 +++----- src/field/extension_field/quartic.rs | 12 ++++++------ src/field/extension_field/target.rs | 4 ++-- 4 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 89263916..46c99f11 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -28,8 +28,16 @@ pub trait OEF: FieldExtension { } } +impl OEF<1> for F { + const W: Self::BaseField = F::ZERO; +} + pub trait Extendable: Sized { - type Extension: Field + FieldExtension + OEF + From; + type Extension: Field + OEF + From; +} + +impl Extendable<1> for F { + type Extension = F; } pub trait FieldExtension: Field { diff --git a/src/field/extension_field/quadratic.rs b/src/field/extension_field/quadratic.rs index ac910278..fc74ec88 100644 --- a/src/field/extension_field/quadratic.rs +++ b/src/field/extension_field/quadratic.rs @@ -1,8 +1,6 @@ -use crate::circuit_builder::CircuitBuilder; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; -use crate::target::Target; use rand::Rng; use std::fmt::{Debug, Display, Formatter}; use std::hash::{Hash, Hasher}; @@ -82,7 +80,7 @@ impl Field for QuadraticCrandallField { return None; } - let a_pow_r_minus_1 = self.frobenius(); + let a_pow_r_minus_1 = OEF::<2>::frobenius(self); let a_pow_r = a_pow_r_minus_1 * *self; debug_assert!(FieldExtension::<2>::is_in_basefield(&a_pow_r)); @@ -171,7 +169,7 @@ impl Mul for QuadraticCrandallField { let Self([a0, a1]) = self; let Self([b0, b1]) = rhs; - let c0 = a0 * b0 + Self::W * a1 * b1; + let c0 = a0 * b0 + >::W * a1 * b1; let c1 = a0 * b1 + a1 * b0; Self([c0, c1]) @@ -250,7 +248,7 @@ mod tests { let x = F::rand(); assert_eq!( x.exp(>::BaseField::ORDER), - x.frobenius() + OEF::<2>::frobenius(&x) ); } diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index c69e365d..f1791d0e 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -106,9 +106,9 @@ impl Field for QuarticCrandallField { return None; } - let a_pow_p = self.frobenius(); + let a_pow_p = OEF::<4>::frobenius(self); let a_pow_p_plus_1 = a_pow_p * *self; - let a_pow_p3_plus_p2 = a_pow_p_plus_1.frobenius().frobenius(); + let a_pow_p3_plus_p2 = OEF::<4>::frobenius(&OEF::<4>::frobenius(&a_pow_p_plus_1)); let a_pow_r_minus_1 = a_pow_p3_plus_p2 * a_pow_p; let a_pow_r = a_pow_r_minus_1 * *self; debug_assert!(FieldExtension::<4>::is_in_basefield(&a_pow_r)); @@ -214,9 +214,9 @@ impl Mul for QuarticCrandallField { let Self([a0, a1, a2, a3]) = self; let Self([b0, b1, b2, b3]) = rhs; - let c0 = a0 * b0 + Self::W * (a1 * b3 + a2 * b2 + a3 * b1); - let c1 = a0 * b1 + a1 * b0 + Self::W * (a2 * b3 + a3 * b2); - let c2 = a0 * b2 + a1 * b1 + a2 * b0 + Self::W * a3 * b3; + let c0 = a0 * b0 + >::W * (a1 * b3 + a2 * b2 + a3 * b1); + let c1 = a0 * b1 + a1 * b0 + >::W * (a2 * b3 + a3 * b2); + let c2 = a0 * b2 + a1 * b1 + a2 * b0 + >::W * a3 * b3; let c3 = a0 * b3 + a1 * b2 + a2 * b1 + a3 * b0; Self([c0, c1, c2, c3]) @@ -308,7 +308,7 @@ mod tests { let x = F::rand(); assert_eq!( exp_naive(x, >::BaseField::ORDER as u128), - x.frobenius() + OEF::<4>::frobenius(&x) ); } diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 861baaf5..1927e0d1 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -63,8 +63,8 @@ impl CircuitBuilder { res[(i + j) % D] = if i + j < D { self.mul_add(a.0[i], b.0[j], res[(i + j) % D]) } else { - let tmp = self.mul_add(a.0[i], b.0[j], res[(i + j) % D]); - self.mul(w, tmp) + let tmp = self.mul(a.0[i], b.0[j]); + self.mul_add(w, tmp, res[(i + j) % D]) } } }