From 7d8daa5d0560daae8aca87f13bd90260e7ea84ef Mon Sep 17 00:00:00 2001 From: Sean Bowe Date: Tue, 29 Sep 2020 16:56:21 -0600 Subject: [PATCH] Refactor h_eval computation into separate, more functional code. Co-authored-by: str4d --- src/plonk/verifier.rs | 173 +++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 78 deletions(-) diff --git a/src/plonk/verifier.rs b/src/plonk/verifier.rs index de910432..4ee3e378 100644 --- a/src/plonk/verifier.rs +++ b/src/plonk/verifier.rs @@ -63,7 +63,10 @@ impl<'a, C: CurveAffine> Proof { // Sample x_3 challenge, which is used to ensure the circuit is // satisfied with high probability. let x_3: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); - let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]); + + // This check ensures the circuit is satisfied so long as the polynomial + // commitments open to the correct values. + self.check_hx(params, vk, x_0, x_1, x_2, x_3)?; // Hash together all the openings provided by the prover into a new // transcript on the scalar field. @@ -86,83 +89,6 @@ impl<'a, C: CurveAffine> Proof { C::Base::from_bytes(&(transcript_scalar.squeeze()).to_bytes()).unwrap(); transcript.absorb(transcript_scalar_point); - // Evaluate the circuit using the custom gates provided - let mut h_eval = C::Scalar::zero(); - for poly in vk.cs.gates.iter() { - h_eval *= &x_2; - - let evaluation: C::Scalar = poly.evaluate( - &|index| self.fixed_evals[index], - &|index| self.advice_evals[index], - &|index| self.aux_evals[index], - &|a, b| a + &b, - &|a, b| a * &b, - &|a, scalar| a * &scalar, - ); - - h_eval += &evaluation; - } - - // First element in each permutation product should be 1 - // l_0(X) * (1 - z(X)) = 0 - { - // TODO: bubble this error up - let denominator = (x_3 - &C::Scalar::one()).invert().unwrap(); - - for eval in self.permutation_product_evals.iter() { - h_eval *= &x_2; - - let mut tmp = denominator; // 1 / (x_3 - 1) - tmp *= &(x_3n - &C::Scalar::one()); // (x_3^n - 1) / (x_3 - 1) - tmp *= &vk.domain.get_barycentric_weight(); // l_0(x_3) - tmp *= &(C::Scalar::one() - &eval); // l_0(X) * (1 - z(X)) - - h_eval += &tmp; - } - } - - // z(X) \prod (p(X) + \beta s_i(X) + \gamma) - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma) - for (permutation_index, wires) in vk.cs.permutations.iter().enumerate() { - h_eval *= &x_2; - - let mut left = self.permutation_product_evals[permutation_index]; - for (advice_eval, permutation_eval) in wires - .iter() - .map(|&wire| self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]) - .zip(self.permutation_evals[permutation_index].iter()) - { - left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1); - } - - let mut right = self.permutation_product_inv_evals[permutation_index]; - let mut current_delta = x_0 * &x_3; - for advice_eval in wires - .iter() - .map(|&wire| self.advice_evals[vk.cs.get_advice_query_index(wire, 0)]) - { - right *= &(advice_eval + ¤t_delta + &x_1); - current_delta *= &C::Scalar::DELTA; - } - - h_eval += &left; - h_eval -= &right; - } - - // Compute the expected h(x) value - let mut expected_h_eval = C::Scalar::zero(); - let mut cur = C::Scalar::one(); - for eval in &self.h_evals { - expected_h_eval += &(cur * eval); - cur *= &x_3n; - } - - if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) { - return Err(Error::ConstraintSystemFailure); - } - - // We are now convinced the circuit is satisfied so long as the - // polynomial commitments open to the correct values. - // Sample x_4 for compressing openings at the same points together let x_4: C::Scalar = get_challenge_scalar(Challenge(transcript.squeeze().get_lower_128())); @@ -293,4 +219,95 @@ impl<'a, C: CurveAffine> Proof { .verify(params, msm, &mut transcript, x_6, commitment_msm, msm_eval) .map_err(|_| Error::OpeningError) } + + /// Checks that this proof's h_evals are correct, and thus that all of the + /// rules are satisfied. + fn check_hx( + &self, + params: &'a Params, + vk: &VerifyingKey, + x_0: C::Scalar, + x_1: C::Scalar, + x_2: C::Scalar, + x_3: C::Scalar, + ) -> Result<(), Error> { + // x_3^n + let x_3n = x_3.pow(&[params.n as u64, 0, 0, 0]); + + // TODO: bubble this error up + // l_0(x_3) + let l_0 = (x_3 - &C::Scalar::one()).invert().unwrap() // 1 / (x_3 - 1) + * &(x_3n - &C::Scalar::one()) // (x_3^n - 1) / (x_3 - 1) + * &vk.domain.get_barycentric_weight(); // l_0(x_3) + + // Compute the expected value of h(x_3) + let h_eval = std::iter::empty() + // Evaluate the circuit using the custom gates provided + .chain(vk.cs.gates.iter().map(|poly| { + poly.evaluate( + &|index| self.fixed_evals[index], + &|index| self.advice_evals[index], + &|index| self.aux_evals[index], + &|a, b| a + &b, + &|a, b| a * &b, + &|a, scalar| a * &scalar, + ) + })) + // l_0(X) * (1 - z(X)) = 0 + .chain( + self.permutation_product_evals + .iter() + .map(|product_eval| l_0 * &(C::Scalar::one() - &product_eval)), + ) + // z(X) \prod (p(X) + \beta s_i(X) + \gamma) + // - z(omega^{-1} X) \prod (p(X) + \delta^i \beta X + \gamma) + .chain( + vk.cs + .permutations + .iter() + .zip(self.permutation_evals.iter()) + .zip(self.permutation_product_evals.iter()) + .zip(self.permutation_product_inv_evals.iter()) + .map( + |(((wires, permutation_evals), product_eval), product_inv_eval)| { + let mut left = *product_eval; + for (advice_eval, permutation_eval) in wires + .iter() + .map(|&wire| { + self.advice_evals[vk.cs.get_advice_query_index(wire, 0)] + }) + .zip(permutation_evals.iter()) + { + left *= &(advice_eval + &(x_0 * permutation_eval) + &x_1); + } + + let mut right = *product_inv_eval; + let mut current_delta = x_0 * &x_3; + for advice_eval in wires.iter().map(|&wire| { + self.advice_evals[vk.cs.get_advice_query_index(wire, 0)] + }) { + right *= &(advice_eval + ¤t_delta + &x_1); + current_delta *= &C::Scalar::DELTA; + } + + left - &right + }, + ), + ) + .fold(C::Scalar::zero(), |h_eval, v| h_eval * &x_2 + &v); + + // Compute the expected h(x_3) value + let mut expected_h_eval = C::Scalar::zero(); + let mut cur = C::Scalar::one(); + for eval in &self.h_evals { + expected_h_eval += &(cur * eval); + cur *= &x_3n; + } + + if h_eval != (expected_h_eval * &(x_3n - &C::Scalar::one())) { + return Err(Error::ConstraintSystemFailure); + } + + Ok(()) + } }