From 5678c7ebdac01ed82575eaedb8997d8b98d576f6 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 10:58:03 +0200 Subject: [PATCH 1/8] Added `ExtensionAlgebra` --- src/field/extension_field/algebra.rs | 153 +++++++++++++++++++++++++++ src/field/extension_field/mod.rs | 1 + src/gates/interpolation.rs | 11 +- src/vars.rs | 10 +- 4 files changed, 164 insertions(+), 11 deletions(-) create mode 100644 src/field/extension_field/algebra.rs diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs new file mode 100644 index 00000000..db80ce75 --- /dev/null +++ b/src/field/extension_field/algebra.rs @@ -0,0 +1,153 @@ +use crate::field::extension_field::{FieldExtension, OEF}; +use std::fmt::{Debug, Display, Formatter}; +use std::iter::{Product, Sum}; +use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; + +/// Let `F_D` be the extension `F[X]/(X^D-W)`. Then `ExtensionAlgebra` is the quotient `F_D[X]/(X^D-W)`. +/// It's a `D`-dimensional algebra over `F_D` useful to lift the multiplication over `F_D` to a multiplication over `(F_D)^D`. +#[derive(Copy, Clone)] +pub struct ExtensionAlgebra, const D: usize>([F; D]); + +impl, const D: usize> ExtensionAlgebra { + pub const ZERO: Self = Self([F::ZERO; D]); + + pub fn one() -> Self { + F::ONE.into() + } + + pub fn from_basefield_array(arr: [F; D]) -> Self { + Self(arr) + } + + pub fn to_basefield_array(self) -> [F; D] { + self.0 + } +} + +impl, const D: usize> From for ExtensionAlgebra { + fn from(x: F) -> Self { + let mut arr = [F::ZERO; D]; + arr[0] = x; + Self(arr) + } +} + +impl, const D: usize> Display for ExtensionAlgebra { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "({}) + ", self.0[0])?; + for i in 1..D - 1 { + write!(f, "({})*b^{} + ", self.0[i], i)?; + } + write!(f, "{}*b^{}", self.0[D - 1], D - 1) + } +} + +impl, const D: usize> Debug for ExtensionAlgebra { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + Display::fmt(self, f) + } +} + +impl, const D: usize> Neg for ExtensionAlgebra { + type Output = Self; + + #[inline] + fn neg(self) -> Self { + let mut arr = self.0; + arr.iter_mut().for_each(|x| *x = -*x); + Self(arr) + } +} + +impl, const D: usize> Add for ExtensionAlgebra { + type Output = Self; + + #[inline] + fn add(self, rhs: Self) -> Self { + let mut arr = self.0; + arr.iter_mut().zip(&rhs.0).for_each(|(x, &y)| *x += y); + Self(arr) + } +} + +impl, const D: usize> AddAssign for ExtensionAlgebra { + fn add_assign(&mut self, rhs: Self) { + *self = *self + rhs; + } +} + +impl, const D: usize> Sum for ExtensionAlgebra { + fn sum>(iter: I) -> Self { + iter.fold(Self::ZERO, |acc, x| acc + x) + } +} + +impl, const D: usize> Sub for ExtensionAlgebra { + type Output = Self; + + #[inline] + fn sub(self, rhs: Self) -> Self { + let mut arr = self.0; + arr.iter_mut().zip(&rhs.0).for_each(|(x, &y)| *x -= y); + Self(arr) + } +} + +impl, const D: usize> SubAssign for ExtensionAlgebra { + #[inline] + fn sub_assign(&mut self, rhs: Self) { + *self = *self - rhs; + } +} + +impl, const D: usize> Mul for ExtensionAlgebra { + type Output = Self; + + #[inline] + fn mul(self, rhs: Self) -> Self { + let mut res = [F::ZERO; D]; + let w = F::from_basefield(F::W); + for i in 0..D { + for j in 0..D { + res[(i + j) % D] += if i + j < D { + self.0[i] * rhs.0[j] + } else { + w * self.0[i] * rhs.0[i] + } + } + } + Self(res) + } +} + +impl, const D: usize> MulAssign for ExtensionAlgebra { + #[inline] + fn mul_assign(&mut self, rhs: Self) { + *self = *self * rhs; + } +} + +impl, const D: usize> Product for ExtensionAlgebra { + fn product>(iter: I) -> Self { + iter.fold(Self::one(), |acc, x| acc * x) + } +} + +/// A polynomial in coefficient form. +#[derive(Clone, Debug)] +pub struct PolynomialCoeffsAlgebra, const D: usize> { + pub(crate) coeffs: Vec>, +} + +impl, const D: usize> PolynomialCoeffsAlgebra { + pub fn new(coeffs: Vec>) -> Self { + PolynomialCoeffsAlgebra { coeffs } + } + + pub fn eval(&self, x: ExtensionAlgebra) -> ExtensionAlgebra { + self.coeffs + .iter() + .rev() + .fold(ExtensionAlgebra::ZERO, |acc, &c| acc * x + c) + } +} diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index 7e74be78..c5510ea1 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -1,5 +1,6 @@ use crate::field::field::Field; +pub mod algebra; pub mod quadratic; pub mod quartic; mod quartic_quartic; diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 53e0b7e7..3872b9ee 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use std::ops::Range; use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::lagrange::interpolant; @@ -111,19 +112,19 @@ where let mut constraints = Vec::with_capacity(self.num_constraints()); let coeffs = (0..self.num_points) - .map(|i| vars.get_local_ext_ext(self.wires_coeff(i))) + .map(|i| vars.get_local_ext_algebra(self.wires_coeff(i))) .collect(); - let interpolant = PolynomialCoeffs::new(coeffs); + let interpolant = PolynomialCoeffsAlgebra::new(coeffs); for i in 0..self.num_points { let point = vars.local_wires[self.wire_point(i)]; - let value = vars.get_local_ext_ext(self.wires_value(i)); + let value = vars.get_local_ext_algebra(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_ext(self.wires_evaluation_point()); - let evaluation_value = vars.get_local_ext_ext(self.wires_evaluation_value()); + let evaluation_point = vars.get_local_ext_algebra(self.wires_evaluation_point()); + let evaluation_value = vars.get_local_ext_algebra(self.wires_evaluation_value()); let computed_evaluation_value = interpolant.eval(evaluation_point); constraints.extend(&(evaluation_value - computed_evaluation_value).to_basefield_array()); diff --git a/src/vars.rs b/src/vars.rs index 88d0759a..1ac7935c 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::algebra::ExtensionAlgebra; use crate::field::extension_field::target::{ExtensionExtensionTarget, ExtensionTarget}; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::field::Field; @@ -18,16 +19,13 @@ pub struct EvaluationVarsBase<'a, F: Field> { } impl<'a, F: Extendable, const D: usize> EvaluationVars<'a, F, D> { - pub fn get_local_ext_ext( + pub fn get_local_ext_algebra( &self, wire_range: Range, - ) -> <>::Extension as Extendable>::Extension - where - F::Extension: Extendable, - { + ) -> ExtensionAlgebra { debug_assert_eq!(wire_range.len(), D); let arr = self.local_wires[wire_range].try_into().unwrap(); - <>::Extension as Extendable>::Extension::from_basefield_array(arr) + ExtensionAlgebra::from_basefield_array(arr) } } From d727f84a56f373fdb09b5ab07b1c1378da1efb78 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 11:18:21 +0200 Subject: [PATCH 2/8] Working test --- src/field/extension_field/algebra.rs | 4 +- src/gates/interpolation.rs | 68 ++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index db80ce75..7a4f43a3 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -38,7 +38,7 @@ impl, const D: usize> Display for ExtensionAlgebra { for i in 1..D - 1 { write!(f, "({})*b^{} + ", self.0[i], i)?; } - write!(f, "{}*b^{}", self.0[D - 1], D - 1) + write!(f, "({})*b^{}", self.0[D - 1], D - 1) } } @@ -112,7 +112,7 @@ impl, const D: usize> Mul for ExtensionAlgebra { res[(i + j) % D] += if i + j < D { self.0[i] * rhs.0[j] } else { - w * self.0[i] * rhs.0[i] + w * self.0[i] * rhs.0[j] } } } diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 3872b9ee..804b9310 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -282,9 +282,14 @@ mod tests { use std::marker::PhantomData; use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::quartic::QuarticCrandallField; + use crate::field::extension_field::FieldExtension; + use crate::field::field::Field; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::gates::interpolation::InterpolationGate; + use crate::polynomial::polynomial::PolynomialCoeffs; + use crate::vars::EvaluationVars; #[test] fn wire_indices() { @@ -311,4 +316,67 @@ mod tests { type F = CrandallField; test_low_degree(InterpolationGate::::new(4)); } + + #[test] + fn test_gate_constraint() { + type F = CrandallField; + type FF = QuarticCrandallField; + const D: usize = 4; + + /// Returns the local wires for an interpolation gate for given coeffs, points and eval point. + fn get_wires( + num_points: usize, + coeffs: PolynomialCoeffs, + points: Vec, + eval_point: FF, + ) -> Vec { + let mut v = vec![F::ZERO; num_points * 5 + (coeffs.len() + 3) * D]; + 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]; + } + 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.iter().map(|&x| x.into()).collect::>() + } + + /// Get a working row for InterpolationGate. + let coeffs = PolynomialCoeffs::new(vec![FF::rand(), FF::rand()]); + let points = vec![F::rand(), F::rand()]; + let eval_point = FF::rand(); + let gate = InterpolationGate:: { + num_points: 2, + _phantom: PhantomData, + }; + let vars = EvaluationVars { + local_constants: &[], + local_wires: &get_wires(2, coeffs, points, eval_point), + }; + + assert!( + gate.eval_unfiltered(vars.clone()) + .iter() + .all(|x| x.is_zero()), + "Gate constraints are not satisfied." + ); + } } From 070dc7c9f1bb81982e7910e380867d69fdd287b6 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 11:30:39 +0200 Subject: [PATCH 3/8] s/ext_ext/ext_algebra --- src/field/extension_field/algebra.rs | 2 +- src/field/extension_field/target.rs | 56 ++++++++++++++-------------- src/gadgets/polynomial.rs | 22 +++++------ src/gates/interpolation.rs | 15 ++++---- src/vars.rs | 8 ++-- 5 files changed, 50 insertions(+), 53 deletions(-) diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index 7a4f43a3..1cddb4c1 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -1,4 +1,4 @@ -use crate::field::extension_field::{FieldExtension, OEF}; +use crate::field::extension_field::OEF; use std::fmt::{Debug, Display, Formatter}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index 7198ebf6..d4603cbb 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -15,9 +15,9 @@ impl ExtensionTarget { /// `Target`s representing an element of an extension of an extension field. #[derive(Copy, Clone, Debug)] -pub struct ExtensionExtensionTarget(pub [ExtensionTarget; D]); +pub struct ExtensionAlgebraTarget(pub [ExtensionTarget; D]); -impl ExtensionExtensionTarget { +impl ExtensionAlgebraTarget { pub fn to_ext_target_array(&self) -> [ExtensionTarget; D] { self.0 } @@ -33,10 +33,10 @@ impl, const D: usize> CircuitBuilder { ExtensionTarget(parts) } - pub fn constant_ext_ext( + pub fn constant_ext_algebra( &mut self, c: <>::Extension as Extendable>::Extension, - ) -> ExtensionExtensionTarget + ) -> ExtensionAlgebraTarget where F::Extension: Extendable, { @@ -45,7 +45,7 @@ impl, const D: usize> CircuitBuilder { for i in 0..D { parts[i] = self.constant_extension(c_parts[i]); } - ExtensionExtensionTarget(parts) + ExtensionAlgebraTarget(parts) } pub fn zero_extension(&mut self) -> ExtensionTarget { @@ -60,11 +60,13 @@ impl, const D: usize> CircuitBuilder { self.constant_extension(F::Extension::TWO) } - pub fn zero_ext_ext(&mut self) -> ExtensionExtensionTarget + pub fn zero_ext_algebra(&mut self) -> ExtensionAlgebraTarget where F::Extension: Extendable, { - self.constant_ext_ext(<>::Extension as Extendable>::Extension::ZERO) + self.constant_ext_algebra( + <>::Extension as Extendable>::Extension::ZERO, + ) } pub fn add_extension( @@ -78,11 +80,11 @@ impl, const D: usize> CircuitBuilder { a } - pub fn add_ext_ext( + pub fn add_ext_algebra( &mut self, - mut a: ExtensionExtensionTarget, - b: ExtensionExtensionTarget, - ) -> ExtensionExtensionTarget { + mut a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { for i in 0..D { a.0[i] = self.add_extension(a.0[i], b.0[i]); } @@ -108,11 +110,11 @@ impl, const D: usize> CircuitBuilder { a } - pub fn sub_ext_ext( + pub fn sub_ext_algebra( &mut self, - mut a: ExtensionExtensionTarget, - b: ExtensionExtensionTarget, - ) -> ExtensionExtensionTarget { + mut a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { for i in 0..D { a.0[i] = self.sub_extension(a.0[i], b.0[i]); } @@ -138,29 +140,25 @@ impl, const D: usize> CircuitBuilder { ExtensionTarget(res) } - pub fn mul_ext_ext( + pub fn mul_ext_algebra( &mut self, - mut a: ExtensionExtensionTarget, - b: ExtensionExtensionTarget, - ) -> ExtensionExtensionTarget - where - F::Extension: Extendable, - { + mut a: ExtensionAlgebraTarget, + b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget { let mut res = [self.zero_extension(); D]; - let w = self - .constant_extension(<>::Extension as Extendable>::Extension::W); + let w = self.constant(F::Extension::W); for i in 0..D { for j in 0..D { let ai_bi = self.mul_extension(a.0[i], b.0[j]); res[(i + j) % D] = if i + j < D { self.add_extension(ai_bi, res[(i + j) % D]) } else { - let w_ai_bi = self.mul_extension(w, ai_bi); + let w_ai_bi = self.scalar_mul_ext(w, ai_bi); self.add_extension(w_ai_bi, res[(i + j) % D]) } } } - ExtensionExtensionTarget(res) + ExtensionAlgebraTarget(res) } pub fn mul_many_extension(&mut self, terms: &[ExtensionTarget]) -> ExtensionTarget { @@ -193,11 +191,11 @@ impl, const D: usize> CircuitBuilder { /// Returns `a * b`, where `b` is in the extension of the extension field, and `a` is in the /// extension field. - pub fn scalar_mul_ext_ext( + pub fn scalar_mul_ext_algebra( &mut self, a: ExtensionTarget, - mut b: ExtensionExtensionTarget, - ) -> ExtensionExtensionTarget + mut b: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget where F::Extension: Extendable, { diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index cac51452..8037f287 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -1,5 +1,5 @@ use crate::circuit_builder::CircuitBuilder; -use crate::field::extension_field::target::{ExtensionExtensionTarget, ExtensionTarget}; +use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; use crate::field::extension_field::Extendable; use crate::target::Target; @@ -33,22 +33,22 @@ impl PolynomialCoeffsExtTarget { } } -pub struct PolynomialCoeffsExtExtTarget(pub Vec>); +pub struct PolynomialCoeffsExtExtTarget(pub Vec>); impl PolynomialCoeffsExtExtTarget { pub fn eval_scalar( &self, builder: &mut CircuitBuilder, point: ExtensionTarget, - ) -> ExtensionExtensionTarget + ) -> ExtensionAlgebraTarget where F: Extendable, F::Extension: Extendable, { - let mut acc = builder.zero_ext_ext(); + let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { - let tmp = builder.scalar_mul_ext_ext(point, acc); - acc = builder.add_ext_ext(tmp, c); + let tmp = builder.scalar_mul_ext_algebra(point, acc); + acc = builder.add_ext_algebra(tmp, c); } acc } @@ -56,16 +56,16 @@ impl PolynomialCoeffsExtExtTarget { pub fn eval( &self, builder: &mut CircuitBuilder, - point: ExtensionExtensionTarget, - ) -> ExtensionExtensionTarget + point: ExtensionAlgebraTarget, + ) -> ExtensionAlgebraTarget where F: Extendable, F::Extension: Extendable, { - let mut acc = builder.zero_ext_ext(); + let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { - let tmp = builder.mul_ext_ext(point, acc); - acc = builder.add_ext_ext(tmp, c); + let tmp = builder.mul_ext_algebra(point, acc); + acc = builder.add_ext_algebra(tmp, c); } acc } diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 804b9310..0d3b8666 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -10,7 +10,6 @@ use crate::field::lagrange::interpolant; use crate::gadgets::polynomial::PolynomialCoeffsExtExtTarget; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; -use crate::polynomial::polynomial::PolynomialCoeffs; use crate::target::Target; use crate::vars::{EvaluationTargets, EvaluationVars}; use crate::wire::Wire; @@ -139,27 +138,27 @@ where let mut constraints = Vec::with_capacity(self.num_constraints()); let coeffs = (0..self.num_points) - .map(|i| vars.get_local_ext_ext(self.wires_coeff(i))) + .map(|i| vars.get_local_ext_algebra(self.wires_coeff(i))) .collect(); let interpolant = PolynomialCoeffsExtExtTarget(coeffs); for i in 0..self.num_points { let point = vars.local_wires[self.wire_point(i)]; - let value = vars.get_local_ext_ext(self.wires_value(i)); + let value = vars.get_local_ext_algebra(self.wires_value(i)); let computed_value = interpolant.eval_scalar(builder, point); constraints.extend( &builder - .sub_ext_ext(value, computed_value) + .sub_ext_algebra(value, computed_value) .to_ext_target_array(), ); } - let evaluation_point = vars.get_local_ext_ext(self.wires_evaluation_point()); - let evaluation_value = vars.get_local_ext_ext(self.wires_evaluation_value()); + let evaluation_point = vars.get_local_ext_algebra(self.wires_evaluation_point()); + let evaluation_value = vars.get_local_ext_algebra(self.wires_evaluation_value()); let computed_evaluation_value = interpolant.eval(builder, evaluation_point); constraints.extend( &builder - .sub_ext_ext(evaluation_value, computed_evaluation_value) + .sub_ext_algebra(evaluation_value, computed_evaluation_value) .to_ext_target_array(), ); @@ -359,7 +358,7 @@ mod tests { v.iter().map(|&x| x.into()).collect::>() } - /// Get a working row for InterpolationGate. + // Get a working row for InterpolationGate. let coeffs = PolynomialCoeffs::new(vec![FF::rand(), FF::rand()]); let points = vec![F::rand(), F::rand()]; let eval_point = FF::rand(); diff --git a/src/vars.rs b/src/vars.rs index 1ac7935c..74f15f23 100644 --- a/src/vars.rs +++ b/src/vars.rs @@ -2,8 +2,8 @@ use std::convert::TryInto; use std::ops::Range; use crate::field::extension_field::algebra::ExtensionAlgebra; -use crate::field::extension_field::target::{ExtensionExtensionTarget, ExtensionTarget}; -use crate::field::extension_field::{Extendable, FieldExtension}; +use crate::field::extension_field::target::{ExtensionAlgebraTarget, ExtensionTarget}; +use crate::field::extension_field::Extendable; use crate::field::field::Field; #[derive(Copy, Clone)] @@ -36,9 +36,9 @@ pub struct EvaluationTargets<'a, const D: usize> { } impl<'a, const D: usize> EvaluationTargets<'a, D> { - pub fn get_local_ext_ext(&self, wire_range: Range) -> ExtensionExtensionTarget { + pub fn get_local_ext_algebra(&self, wire_range: Range) -> ExtensionAlgebraTarget { debug_assert_eq!(wire_range.len(), D); let arr = self.local_wires[wire_range].try_into().unwrap(); - ExtensionExtensionTarget(arr) + ExtensionAlgebraTarget(arr) } } From 19a38682ab391beaaf29b04b91b9bc9dcfa490d8 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 12:49:45 +0200 Subject: [PATCH 4/8] Minor tweaks --- src/field/extension_field/algebra.rs | 2 +- src/field/extension_field/target.rs | 24 +++++++----------------- src/gadgets/polynomial.rs | 4 ++-- src/gates/interpolation.rs | 10 ++++++++-- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index 1cddb4c1..004e8dc1 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -3,7 +3,7 @@ use std::fmt::{Debug, Display, Formatter}; use std::iter::{Product, Sum}; use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; -/// Let `F_D` be the extension `F[X]/(X^D-W)`. Then `ExtensionAlgebra` is the quotient `F_D[X]/(X^D-W)`. +/// Let `F_D` be the optimal extension field `F[X]/(X^D-W)`. Then `ExtensionAlgebra` is the quotient `F_D[X]/(X^D-W)`. /// It's a `D`-dimensional algebra over `F_D` useful to lift the multiplication over `F_D` to a multiplication over `(F_D)^D`. #[derive(Copy, Clone)] pub struct ExtensionAlgebra, const D: usize>([F; D]); diff --git a/src/field/extension_field/target.rs b/src/field/extension_field/target.rs index d4603cbb..71e04360 100644 --- a/src/field/extension_field/target.rs +++ b/src/field/extension_field/target.rs @@ -1,4 +1,5 @@ use crate::circuit_builder::CircuitBuilder; +use crate::field::extension_field::algebra::ExtensionAlgebra; use crate::field::extension_field::{Extendable, FieldExtension, OEF}; use crate::field::field::Field; use crate::target::Target; @@ -35,11 +36,8 @@ impl, const D: usize> CircuitBuilder { pub fn constant_ext_algebra( &mut self, - c: <>::Extension as Extendable>::Extension, - ) -> ExtensionAlgebraTarget - where - F::Extension: Extendable, - { + c: ExtensionAlgebra, + ) -> ExtensionAlgebraTarget { let c_parts = c.to_basefield_array(); let mut parts = [self.zero_extension(); D]; for i in 0..D { @@ -60,13 +58,8 @@ impl, const D: usize> CircuitBuilder { self.constant_extension(F::Extension::TWO) } - pub fn zero_ext_algebra(&mut self) -> ExtensionAlgebraTarget - where - F::Extension: Extendable, - { - self.constant_ext_algebra( - <>::Extension as Extendable>::Extension::ZERO, - ) + pub fn zero_ext_algebra(&mut self) -> ExtensionAlgebraTarget { + self.constant_ext_algebra(ExtensionAlgebra::ZERO) } pub fn add_extension( @@ -142,7 +135,7 @@ impl, const D: usize> CircuitBuilder { pub fn mul_ext_algebra( &mut self, - mut a: ExtensionAlgebraTarget, + a: ExtensionAlgebraTarget, b: ExtensionAlgebraTarget, ) -> ExtensionAlgebraTarget { let mut res = [self.zero_extension(); D]; @@ -195,10 +188,7 @@ impl, const D: usize> CircuitBuilder { &mut self, a: ExtensionTarget, mut b: ExtensionAlgebraTarget, - ) -> ExtensionAlgebraTarget - where - F::Extension: Extendable, - { + ) -> ExtensionAlgebraTarget { for i in 0..D { b.0[i] = self.mul_extension(a, b.0[i]); } diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index 8037f287..1723a9bf 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -33,9 +33,9 @@ impl PolynomialCoeffsExtTarget { } } -pub struct PolynomialCoeffsExtExtTarget(pub Vec>); +pub struct PolynomialCoeffsExtAlgebraTarget(pub Vec>); -impl PolynomialCoeffsExtExtTarget { +impl PolynomialCoeffsExtAlgebraTarget { pub fn eval_scalar( &self, builder: &mut CircuitBuilder, diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 0d3b8666..af7535f1 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -7,7 +7,7 @@ use crate::field::extension_field::algebra::PolynomialCoeffsAlgebra; use crate::field::extension_field::target::ExtensionTarget; use crate::field::extension_field::{Extendable, FieldExtension}; use crate::field::lagrange::interpolant; -use crate::gadgets::polynomial::PolynomialCoeffsExtExtTarget; +use crate::gadgets::polynomial::PolynomialCoeffsExtAlgebraTarget; use crate::gates::gate::{Gate, GateRef}; use crate::generator::{SimpleGenerator, WitnessGenerator}; use crate::target::Target; @@ -140,7 +140,7 @@ where let coeffs = (0..self.num_points) .map(|i| vars.get_local_ext_algebra(self.wires_coeff(i))) .collect(); - let interpolant = PolynomialCoeffsExtExtTarget(coeffs); + let interpolant = PolynomialCoeffsExtAlgebraTarget(coeffs); for i in 0..self.num_points { let point = vars.local_wires[self.wire_point(i)]; @@ -280,15 +280,21 @@ where mod tests { use std::marker::PhantomData; + use crate::circuit_builder::CircuitBuilder; + use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::FieldExtension; use crate::field::field::Field; + use crate::fri::FriConfig; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::gates::interpolation::InterpolationGate; use crate::polynomial::polynomial::PolynomialCoeffs; + use crate::prover::PLONK_BLINDING; use crate::vars::EvaluationVars; + use crate::verifier::verify; + use crate::witness::PartialWitness; #[test] fn wire_indices() { From c674d6c1f650e49e70a37628cac206bd1ce353a5 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 12:53:04 +0200 Subject: [PATCH 5/8] Remove unused imports --- src/gates/interpolation.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index af7535f1..3f3ed8d7 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -280,21 +280,15 @@ where mod tests { use std::marker::PhantomData; - use crate::circuit_builder::CircuitBuilder; - use crate::circuit_data::CircuitConfig; use crate::field::crandall_field::CrandallField; use crate::field::extension_field::quartic::QuarticCrandallField; use crate::field::extension_field::FieldExtension; use crate::field::field::Field; - use crate::fri::FriConfig; use crate::gates::gate::Gate; use crate::gates::gate_testing::test_low_degree; use crate::gates::interpolation::InterpolationGate; use crate::polynomial::polynomial::PolynomialCoeffs; - use crate::prover::PLONK_BLINDING; use crate::vars::EvaluationVars; - use crate::verifier::verify; - use crate::witness::PartialWitness; #[test] fn wire_indices() { From 47da1ef68cafb24341e6bc9748d4cb7a1fd99ecd Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 14:01:47 +0200 Subject: [PATCH 6/8] Add MLE tests for algebras --- src/field/extension_field/algebra.rs | 98 ++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index 004e8dc1..97c3c12d 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -151,3 +151,101 @@ impl, const D: usize> PolynomialCoeffsAlgebra { .fold(ExtensionAlgebra::ZERO, |acc, &c| acc * x + c) } } + +#[cfg(test)] +mod tests { + use crate::field::crandall_field::CrandallField; + use crate::field::extension_field::algebra::ExtensionAlgebra; + use crate::field::extension_field::{Extendable, FieldExtension}; + use crate::field::field::Field; + use itertools::Itertools; + + /// Tests that the multiplication on the extension algebra lifts that of the field extension. + fn test_extension_algebra, const D: usize>() { + #[derive(Copy, Clone, Debug)] + enum ZeroOne { + Zero, + One, + } + + let to_field = |zo: &ZeroOne| match zo { + ZeroOne::Zero => F::ZERO, + ZeroOne::One => F::ONE, + }; + let to_fields = |x: &[ZeroOne], y: &[ZeroOne]| -> (F::Extension, F::Extension) { + let mut arr0 = [F::ZERO; D]; + let mut arr1 = [F::ZERO; D]; + arr0.copy_from_slice(&x.iter().map(to_field).collect::>()); + arr1.copy_from_slice(&y.iter().map(to_field).collect::>()); + ( + >::Extension::from_basefield_array(arr0), + >::Extension::from_basefield_array(arr1), + ) + }; + + // Standard MLE formula. + let selector = |xs: Vec, ts: &[F::Extension]| -> F::Extension { + (0..2 * D) + .map(|i| match xs[i] { + ZeroOne::Zero => F::Extension::ONE - ts[i], + ZeroOne::One => ts[i], + }) + .product() + }; + + let mul_mle = |ts: Vec| -> [F::Extension; D] { + let mut ans = [F::Extension::ZERO; D]; + for xs in (0..2 * D) + .map(|_| vec![ZeroOne::Zero, ZeroOne::One]) + .multi_cartesian_product() + { + let (a, b) = to_fields(&xs[..D], &xs[D..]); + let c = a * b; + let res = selector(xs, &ts); + for i in 0..D { + ans[i] += res * c.to_basefield_array()[i].into(); + } + } + ans + }; + + let ts = F::Extension::rand_vec(2 * D); + let mut arr0 = [F::Extension::ZERO; D]; + let mut arr1 = [F::Extension::ZERO; D]; + arr0.copy_from_slice(&ts[..D]); + arr1.copy_from_slice(&ts[D..]); + let x = ExtensionAlgebra::from_basefield_array(arr0); + let y = ExtensionAlgebra::from_basefield_array(arr1); + let z = x * y; + + dbg!(z.0, mul_mle(ts.clone())); + assert_eq!(z.0, mul_mle(ts)); + } + + mod base { + use super::*; + + #[test] + fn test_algebra() { + test_extension_algebra::(); + } + } + + mod quadratic { + use super::*; + + #[test] + fn test_algebra() { + test_extension_algebra::(); + } + } + + mod quartic { + use super::*; + + #[test] + fn test_algebra() { + test_extension_algebra::(); + } + } +} From db1ef913e03b3e3ccf1f478e4666b296fde1ba20 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 8 Jun 2021 10:08:17 -0700 Subject: [PATCH 7/8] Remove quartic_quartic --- src/field/extension_field/mod.rs | 1 - src/field/extension_field/quartic.rs | 7 +- src/field/extension_field/quartic_quartic.rs | 259 ------------------- src/gadgets/polynomial.rs | 2 - src/gates/interpolation.rs | 10 - 5 files changed, 1 insertion(+), 278 deletions(-) delete mode 100644 src/field/extension_field/quartic_quartic.rs diff --git a/src/field/extension_field/mod.rs b/src/field/extension_field/mod.rs index c5510ea1..60d2b2e1 100644 --- a/src/field/extension_field/mod.rs +++ b/src/field/extension_field/mod.rs @@ -3,7 +3,6 @@ use crate::field::field::Field; pub mod algebra; pub mod quadratic; pub mod quartic; -mod quartic_quartic; pub mod target; /// Optimal extension field trait. diff --git a/src/field/extension_field/quartic.rs b/src/field/extension_field/quartic.rs index 6bd8ac55..2acac183 100644 --- a/src/field/extension_field/quartic.rs +++ b/src/field/extension_field/quartic.rs @@ -6,8 +6,7 @@ use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssi use rand::Rng; use crate::field::crandall_field::CrandallField; -use crate::field::extension_field::quartic_quartic::QuarticQuarticCrandallField; -use crate::field::extension_field::{Extendable, FieldExtension, OEF}; +use crate::field::extension_field::{FieldExtension, OEF}; use crate::field::field::Field; /// A quartic extension of `CrandallField`. @@ -239,10 +238,6 @@ impl DivAssign for QuarticCrandallField { } } -impl Extendable<4> for QuarticCrandallField { - type Extension = QuarticQuarticCrandallField; -} - #[cfg(test)] mod tests { use crate::field::extension_field::quartic::QuarticCrandallField; diff --git a/src/field/extension_field/quartic_quartic.rs b/src/field/extension_field/quartic_quartic.rs deleted file mode 100644 index 62fad962..00000000 --- a/src/field/extension_field/quartic_quartic.rs +++ /dev/null @@ -1,259 +0,0 @@ -use crate::field::crandall_field::CrandallField; -use crate::field::extension_field::quartic::QuarticCrandallField; -use crate::field::extension_field::{FieldExtension, OEF}; -use crate::field::field::Field; -use rand::Rng; -use std::fmt::{Debug, Display, Formatter}; -use std::hash::Hash; -use std::iter::{Product, Sum}; -use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; - -/// A quartic extension of `QuarticCrandallField`. -#[derive(Copy, Clone, Eq, PartialEq, Hash)] -pub struct QuarticQuarticCrandallField(pub(crate) [QuarticCrandallField; 4]); - -impl OEF<4> for QuarticQuarticCrandallField { - // Verifiable in Sage with - // p = 2^64 - 9 * 2^28 + 1 - // F = GF(p) - // PR_F. = PolynomialRing(F) - // assert (x^4 - 3).is_irreducible() - // F4. = F.extension(x^4 - 3) - // PR_F4. = PolynomialRing(F4) - // assert (x^4 - y).is_irreducible() - // F44. = F4.extension(x^4 - y) - const W: QuarticCrandallField = QuarticCrandallField([ - CrandallField(0), - CrandallField(1), - CrandallField(0), - CrandallField(0), - ]); -} - -impl FieldExtension<4> for QuarticQuarticCrandallField { - type BaseField = QuarticCrandallField; - - fn to_basefield_array(&self) -> [Self::BaseField; 4] { - self.0 - } - - fn from_basefield_array(arr: [Self::BaseField; 4]) -> Self { - Self(arr) - } - - fn from_basefield(x: Self::BaseField) -> Self { - x.into() - } -} - -impl From<>::BaseField> for QuarticQuarticCrandallField { - fn from(x: >::BaseField) -> Self { - Self([ - x, - >::BaseField::ZERO, - >::BaseField::ZERO, - >::BaseField::ZERO, - ]) - } -} - -impl Field for QuarticQuarticCrandallField { - const ZERO: Self = Self([QuarticCrandallField::ZERO; 4]); - const ONE: Self = Self([ - QuarticCrandallField::ONE, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - ]); - const TWO: Self = Self([ - QuarticCrandallField::TWO, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - ]); - const NEG_ONE: Self = Self([ - QuarticCrandallField::NEG_ONE, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - ]); - - // Does not fit in 64-bits. - const ORDER: u64 = 0; - const TWO_ADICITY: usize = 32; - const MULTIPLICATIVE_GROUP_GENERATOR: Self = Self([ - QuarticCrandallField([ - CrandallField(7562951059982399618), - CrandallField(16734862117167184487), - CrandallField(8532193866847630013), - CrandallField(15462716295551021898), - ]), - QuarticCrandallField([ - CrandallField(16143979237658148445), - CrandallField(12004617499933809221), - CrandallField(11826153143854535879), - CrandallField(14780824604953232397), - ]), - QuarticCrandallField([ - CrandallField(12779077039546101185), - CrandallField(15745975127331074164), - CrandallField(4297791107105154033), - CrandallField(5966855376644799108), - ]), - QuarticCrandallField([ - CrandallField(1942992936904935291), - CrandallField(6041097781717465159), - CrandallField(16875726992388585780), - CrandallField(17742746479895474446), - ]), - ]); - const POWER_OF_TWO_GENERATOR: Self = Self([ - QuarticCrandallField::ZERO, - QuarticCrandallField([ - CrandallField::ZERO, - CrandallField::ZERO, - CrandallField::ZERO, - CrandallField(6809469153480715254), - ]), - QuarticCrandallField::ZERO, - QuarticCrandallField::ZERO, - ]); - - fn try_inverse(&self) -> Option { - todo!() - } - - fn to_canonical_u64(&self) -> u64 { - panic!("Doesn't fit!") - } - - fn from_canonical_u64(n: u64) -> Self { - >::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), - ]) - } -} - -impl Display for QuarticQuarticCrandallField { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!( - f, - "({}) + ({})*b + ({})*b^2 + ({})*b^3", - self.0[0], self.0[1], self.0[2], self.0[3] - ) - } -} - -impl Debug for QuarticQuarticCrandallField { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - Display::fmt(self, f) - } -} - -impl Neg for QuarticQuarticCrandallField { - type Output = Self; - - #[inline] - fn neg(self) -> Self { - Self([-self.0[0], -self.0[1], -self.0[2], -self.0[3]]) - } -} - -impl Add for QuarticQuarticCrandallField { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self { - Self([ - self.0[0] + rhs.0[0], - self.0[1] + rhs.0[1], - self.0[2] + rhs.0[2], - self.0[3] + rhs.0[3], - ]) - } -} - -impl AddAssign for QuarticQuarticCrandallField { - fn add_assign(&mut self, rhs: Self) { - *self = *self + rhs; - } -} - -impl Sum for QuarticQuarticCrandallField { - fn sum>(iter: I) -> Self { - iter.fold(Self::ZERO, |acc, x| acc + x) - } -} - -impl Sub for QuarticQuarticCrandallField { - type Output = Self; - - #[inline] - fn sub(self, rhs: Self) -> Self { - Self([ - self.0[0] - rhs.0[0], - self.0[1] - rhs.0[1], - self.0[2] - rhs.0[2], - self.0[3] - rhs.0[3], - ]) - } -} - -impl SubAssign for QuarticQuarticCrandallField { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - *self = *self - rhs; - } -} - -impl Mul for QuarticQuarticCrandallField { - type Output = Self; - - #[inline] - fn mul(self, rhs: Self) -> Self { - let Self([a0, a1, a2, a3]) = self; - let Self([b0, b1, b2, b3]) = rhs; - - 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]) - } -} - -impl MulAssign for QuarticQuarticCrandallField { - #[inline] - fn mul_assign(&mut self, rhs: Self) { - *self = *self * rhs; - } -} - -impl Product for QuarticQuarticCrandallField { - fn product>(iter: I) -> Self { - iter.fold(Self::ONE, |acc, x| acc * x) - } -} - -impl Div for QuarticQuarticCrandallField { - type Output = Self; - - #[allow(clippy::suspicious_arithmetic_impl)] - fn div(self, rhs: Self) -> Self::Output { - self * rhs.inverse() - } -} - -impl DivAssign for QuarticQuarticCrandallField { - fn div_assign(&mut self, rhs: Self) { - *self = *self / rhs; - } -} diff --git a/src/gadgets/polynomial.rs b/src/gadgets/polynomial.rs index 1723a9bf..543be834 100644 --- a/src/gadgets/polynomial.rs +++ b/src/gadgets/polynomial.rs @@ -43,7 +43,6 @@ impl PolynomialCoeffsExtAlgebraTarget { ) -> ExtensionAlgebraTarget where F: Extendable, - F::Extension: Extendable, { let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { @@ -60,7 +59,6 @@ impl PolynomialCoeffsExtAlgebraTarget { ) -> ExtensionAlgebraTarget where F: Extendable, - F::Extension: Extendable, { let mut acc = builder.zero_ext_algebra(); for &c in self.0.iter().rev() { diff --git a/src/gates/interpolation.rs b/src/gates/interpolation.rs index 3f3ed8d7..d2412967 100644 --- a/src/gates/interpolation.rs +++ b/src/gates/interpolation.rs @@ -22,16 +22,12 @@ use crate::witness::PartialWitness; /// given point. #[derive(Clone, Debug)] pub(crate) struct InterpolationGate, const D: usize> -where - F::Extension: Extendable, { num_points: usize, _phantom: PhantomData, } impl, const D: usize> InterpolationGate -where - F::Extension: Extendable, { pub fn new(num_points: usize) -> GateRef { let gate = Self { @@ -100,8 +96,6 @@ where } impl, const D: usize> Gate for InterpolationGate -where - F::Extension: Extendable, { fn id(&self) -> String { format!("{:?}", self, D) @@ -200,8 +194,6 @@ where } struct InterpolationGenerator, const D: usize> -where - F::Extension: Extendable, { gate_index: usize, gate: InterpolationGate, @@ -209,8 +201,6 @@ where } impl, const D: usize> SimpleGenerator for InterpolationGenerator -where - F::Extension: Extendable, { fn dependencies(&self) -> Vec { let local_target = |input| { From f9652114356b32b072b0035ace73c06abbbbb147 Mon Sep 17 00:00:00 2001 From: wborgeaud Date: Tue, 8 Jun 2021 19:36:30 +0200 Subject: [PATCH 8/8] Use Daniel's `fmt` --- src/field/extension_field/algebra.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/field/extension_field/algebra.rs b/src/field/extension_field/algebra.rs index 97c3c12d..eac0bbd8 100644 --- a/src/field/extension_field/algebra.rs +++ b/src/field/extension_field/algebra.rs @@ -34,11 +34,11 @@ impl, const D: usize> From for ExtensionAlgebra { impl, const D: usize> Display for ExtensionAlgebra { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "({}) + ", self.0[0])?; - for i in 1..D - 1 { - write!(f, "({})*b^{} + ", self.0[i], i)?; + write!(f, "({})", self.0[0])?; + for i in 1..D { + write!(f, " + ({})*b^{}", self.0[i], i)?; } - write!(f, "({})*b^{}", self.0[D - 1], D - 1) + Ok(()) } }