diff --git a/src/plonk/keygen.rs b/src/plonk/keygen.rs index 5df667a..c04fd42 100644 --- a/src/plonk/keygen.rs +++ b/src/plonk/keygen.rs @@ -76,6 +76,17 @@ where .max() .unwrap_or(1); + // The lookup argument also serves alongside the gates and must be accounted + // for. + degree = std::cmp::max( + degree, + cs.lookups + .iter() + .map(|l| l.required_degree()) + .max() + .unwrap_or(1), + ); + // Account for each gate to ensure our quotient polynomial is the // correct degree and that our extended domain is the right size. for poly in cs.gates.iter() { diff --git a/src/plonk/lookup.rs b/src/plonk/lookup.rs index 640faef..7d588d0 100644 --- a/src/plonk/lookup.rs +++ b/src/plonk/lookup.rs @@ -18,6 +18,24 @@ impl Argument { table_columns: table_columns.to_vec(), } } + + pub(crate) fn required_degree(&self) -> usize { + assert_eq!(self.input_columns.len(), self.table_columns.len()); + + // degree 2: + // l_0(X) * (1 - z'(X)) = 0 + // + // degree 3: + // z'(X) (a'(X) + \beta) (s'(X) + \gamma) + // - z'(\omega^{-1} X) (\theta^{m-1} a_0(X) + ... + a_{m-1}(X) + \beta) (\theta^{m-1} s_0(X) + ... + s_{m-1}(X) + \gamma) + // + // degree 2: + // l_0(X) * (a'(X) - s'(X)) = 0 + // + // degree 2: + // (a′(X)−s′(X))⋅(a′(X)−a′(\omega{-1} X)) = 0 + 3 + } } #[derive(Clone, Debug)] diff --git a/src/plonk/permutation.rs b/src/plonk/permutation.rs index deda02b..0de904c 100644 --- a/src/plonk/permutation.rs +++ b/src/plonk/permutation.rs @@ -24,8 +24,18 @@ impl Argument { pub(crate) fn required_degree(&self) -> usize { // The permutation argument will serve alongside the gates, so must be - // accounted for. - self.columns.len() + 1 + // accounted for. There are constraints of degree 2 regardless of the + // number of columns involved. (It doesn't make sense to make a + // permutation argument with zero columns but to be rigorous we account + // for it here.) + + // degree 2: + // l_0(X) * (1 - z(X)) = 0 + // + // degree columns + 1 + // z(X) \prod (p(X) + \beta s_i(X) + \gamma) + // - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma) + std::cmp::max(self.columns.len() + 1, 2) } } diff --git a/src/plonk/vanishing/verifier.rs b/src/plonk/vanishing/verifier.rs index e86cb62..f50ddd9 100644 --- a/src/plonk/vanishing/verifier.rs +++ b/src/plonk/vanishing/verifier.rs @@ -9,10 +9,14 @@ use crate::{ }; impl Proof { - pub(in crate::plonk) fn check_lengths(&self, _vk: &VerifyingKey) -> Result<(), Error> { - // TODO: check h_evals + pub(in crate::plonk) fn check_lengths(&self, vk: &VerifyingKey) -> Result<(), Error> { + if self.h_commitments.len() != self.h_evals.len() { + return Err(Error::IncompatibleParams); + } - // TODO: check h_commitments + if self.h_commitments.len() != vk.domain.get_quotient_poly_degree() { + return Err(Error::IncompatibleParams); + } Ok(()) } diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index bc21231..11de2b8 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -182,6 +182,8 @@ impl<'a, C: CurveAffine> Proof { .map(|p| p.check_lengths(vk)) .transpose()?; + self.vanishing.check_lengths(vk)?; + if self.lookups.len() != vk.cs.lookups.len() { return Err(Error::IncompatibleParams); } diff --git a/src/poly/domain.rs b/src/poly/domain.rs index 022a67c..c6358ac 100644 --- a/src/poly/domain.rs +++ b/src/poly/domain.rs @@ -382,4 +382,9 @@ impl EvaluationDomain { pub fn get_barycentric_weight(&self) -> G::Scalar { self.barycentric_weight } + + /// Gets the quotient polynomial's degree (as a multiple of n) + pub fn get_quotient_poly_degree(&self) -> usize { + self.quotient_poly_degree as usize + } }