diff --git a/src/commitment_scheme/kzg10/key.rs b/src/commitment_scheme/kzg10/key.rs index 78430198..82078b79 100644 --- a/src/commitment_scheme/kzg10/key.rs +++ b/src/commitment_scheme/kzg10/key.rs @@ -225,15 +225,15 @@ pub struct OpeningKey { /// The generator of G2. #[cfg_attr(feature = "rkyv-impl", omit_bounds)] pub(crate) h: G2Affine, - /// \beta times the above generator of G2. + /// 'x' times the above generator of G2. #[cfg_attr(feature = "rkyv-impl", omit_bounds)] - pub(crate) beta_h: G2Affine, + pub(crate) x_h: G2Affine, /// The generator of G2, prepared for use in pairings. #[cfg_attr(feature = "rkyv-impl", omit_bounds)] pub(crate) prepared_h: G2Prepared, - /// \beta times the above generator of G2, prepared for use in pairings. + /// 'x' times the above generator of G2, prepared for use in pairings. #[cfg_attr(feature = "rkyv-impl", omit_bounds)] - pub(crate) prepared_beta_h: G2Prepared, + pub(crate) prepared_x_h: G2Prepared, } impl Serializable<{ G1Affine::SIZE + G2Affine::SIZE * 2 }> for OpeningKey { @@ -246,7 +246,7 @@ impl Serializable<{ G1Affine::SIZE + G2Affine::SIZE * 2 }> for OpeningKey { // This can't fail therefore we don't care about the Result nor use it. writer.write(&self.g.to_bytes()); writer.write(&self.h.to_bytes()); - writer.write(&self.beta_h.to_bytes()); + writer.write(&self.x_h.to_bytes()); buf } @@ -262,24 +262,21 @@ impl Serializable<{ G1Affine::SIZE + G2Affine::SIZE * 2 }> for OpeningKey { } impl OpeningKey { - pub(crate) fn new( - g: G1Affine, - h: G2Affine, - beta_h: G2Affine, - ) -> OpeningKey { + pub(crate) fn new(g: G1Affine, h: G2Affine, x_h: G2Affine) -> OpeningKey { let prepared_h = G2Prepared::from(h); - let prepared_beta_h = G2Prepared::from(beta_h); + let prepared_x_h = G2Prepared::from(x_h); OpeningKey { g, h, - beta_h, + x_h, prepared_h, - prepared_beta_h, + prepared_x_h, } } /// Checks whether a batch of polynomials evaluated at different points, /// returned their specified value. + #[allow(dead_code)] pub(crate) fn batch_check( &self, points: &[BlsScalar], @@ -313,7 +310,7 @@ impl OpeningKey { let affine_total_c = G1Affine::from(total_c); let pairing = dusk_bls12_381::multi_miller_loop(&[ - (&affine_total_w, &self.prepared_beta_h), + (&affine_total_w, &self.prepared_x_h), (&affine_total_c, &self.prepared_h), ]) .final_exponentiation(); @@ -343,7 +340,7 @@ mod test { - (op_key.g * proof.evaluated_point)) .into(); - let inner_b: G2Affine = (op_key.beta_h - (op_key.h * point)).into(); + let inner_b: G2Affine = (op_key.x_h - (op_key.h * point)).into(); let prepared_inner_b = G2Prepared::from(-inner_b); let pairing = dusk_bls12_381::multi_miller_loop(&[ diff --git a/src/commitment_scheme/kzg10/proof.rs b/src/commitment_scheme/kzg10/proof.rs index 1fae715a..58fffb63 100644 --- a/src/commitment_scheme/kzg10/proof.rs +++ b/src/commitment_scheme/kzg10/proof.rs @@ -34,6 +34,7 @@ pub(crate) mod alloc { /// Proof that multiple polynomials were correctly evaluated at a point `z`, /// each producing their respective evaluated points p_i(z). #[derive(Debug)] + #[allow(dead_code)] pub(crate) struct AggregateProof { /// This is a commitment to the aggregated witness polynomial. pub(crate) commitment_to_witness: Commitment, @@ -45,6 +46,7 @@ pub(crate) mod alloc { pub(crate) commitments_to_polynomials: Vec, } + #[allow(dead_code)] impl AggregateProof { /// Initializes an `AggregatedProof` with the commitment to the witness. pub(crate) fn with_witness(witness: Commitment) -> AggregateProof { diff --git a/src/commitment_scheme/kzg10/srs.rs b/src/commitment_scheme/kzg10/srs.rs index 55a18595..709df97c 100644 --- a/src/commitment_scheme/kzg10/srs.rs +++ b/src/commitment_scheme/kzg10/srs.rs @@ -230,7 +230,7 @@ mod test { assert_eq!(got_pp.commit_key.powers_of_g, pp.commit_key.powers_of_g); assert_eq!(got_pp.opening_key.g, pp.opening_key.g); assert_eq!(got_pp.opening_key.h, pp.opening_key.h); - assert_eq!(got_pp.opening_key.beta_h, pp.opening_key.beta_h); + assert_eq!(got_pp.opening_key.x_h, pp.opening_key.x_h); } #[test] @@ -245,6 +245,6 @@ mod test { assert_eq!(pp.commit_key, pp_p.commit_key); assert_eq!(pp.opening_key.g, pp_p.opening_key.g); assert_eq!(pp.opening_key.h, pp_p.opening_key.h); - assert_eq!(pp.opening_key.beta_h, pp_p.opening_key.beta_h); + assert_eq!(pp.opening_key.x_h, pp_p.opening_key.x_h); } } diff --git a/src/compiler/prover.rs b/src/compiler/prover.rs index b3d29eff..68bf956b 100644 --- a/src/compiler/prover.rs +++ b/src/compiler/prover.rs @@ -515,15 +515,14 @@ impl Prover { ); let w_z_chall_comm = self.commit_key.commit(&aggregate_witness)?; - // compute the shifted challenge 'v' - let v_challenge_shifted = - transcript.challenge_scalar(b"v_challenge_shifted"); + // compute the shifted challenge 'v_w' + let v_w_challenge = transcript.challenge_scalar(b"v_w_challenge"); // compute the shifted opening proof polynomial 'W_zw(X)' let shifted_aggregate_witness = CommitKey::compute_aggregate_witness( &[z_poly, a_w_poly, b_w_poly, d_w_poly], &(z_challenge * domain.group_gen), - &v_challenge_shifted, + &v_w_challenge, ); let w_z_chall_w_comm = self.commit_key.commit(&shifted_aggregate_witness)?; diff --git a/src/proof_system/proof.rs b/src/proof_system/proof.rs index 10a39030..10111aa8 100644 --- a/src/proof_system/proof.rs +++ b/src/proof_system/proof.rs @@ -12,6 +12,11 @@ use crate::commitment_scheme::Commitment; use dusk_bytes::{DeserializableSlice, Serializable}; +#[cfg(feature = "std")] +use rayon::prelude::*; + +const V_MAX_DEGREE: usize = 7; + #[cfg(feature = "rkyv-impl")] use crate::util::check_field; #[cfg(feature = "rkyv-impl")] @@ -172,6 +177,7 @@ impl Serializable<{ 11 * Commitment::SIZE + ProofEvaluations::SIZE }> } #[cfg(feature = "alloc")] +#[allow(unused_imports)] pub(crate) mod alloc { use super::*; use crate::{ @@ -185,7 +191,7 @@ pub(crate) mod alloc { #[rustfmt::skip] use ::alloc::vec::Vec; use dusk_bls12_381::{ - multiscalar_mul::msm_variable_base, BlsScalar, G1Affine, + multiscalar_mul::msm_variable_base, BlsScalar, G1Affine, G1Projective, }; use merlin::Transcript; #[cfg(feature = "std")] @@ -193,6 +199,7 @@ pub(crate) mod alloc { impl Proof { /// Performs the verification of a [`Proof`] returning a boolean result. + #[allow(non_snake_case)] pub(crate) fn verify( &self, verifier_key: &VerifierKey, @@ -280,6 +287,14 @@ pub(crate) mod alloc { transcript.append_scalar(b"q_r_eval", &self.evaluations.q_r_eval); let v_challenge = transcript.challenge_scalar(b"v_challenge"); + let v_w_challenge = transcript.challenge_scalar(b"v_w_challenge"); + + // Add commitment to openings to transcript + transcript.append_commitment(b"w_z", &self.w_z_chall_comm); + transcript.append_commitment(b"w_z_w", &self.w_z_chall_w_comm); + + // Compute the challenge 'u' + let u_challenge = transcript.challenge_scalar(b"u_challenge"); // Compute zero polynomial evaluated at challenge `z` let z_h_eval = domain.evaluate_vanishing_polynomial(&z_challenge); @@ -291,26 +306,31 @@ pub(crate) mod alloc { &z_challenge, ); - // Compute linearization commitment - let r_comm = self.compute_linearization_commitment( - &alpha, - &beta, - &gamma, - ( - &range_sep_challenge, - &logic_sep_challenge, - &fixed_base_sep_challenge, - &var_base_sep_challenge, - ), - &z_challenge, - l1_eval, - verifier_key, - &domain, - ); + // Compute '[D]_1' + let D = self + .compute_linearization_commitment( + &alpha, + &beta, + &gamma, + ( + &range_sep_challenge, + &logic_sep_challenge, + &fixed_base_sep_challenge, + &var_base_sep_challenge, + ), + &z_challenge, + &u_challenge, + l1_eval, + verifier_key, + &domain, + ) + .0; + // Evaluate public inputs let pi_eval = compute_barycentric_eval(pub_inputs, &z_challenge, &domain); + // Compute r_0 let r_0_eval = pi_eval - l1_eval * alpha.square() - alpha @@ -326,70 +346,119 @@ pub(crate) mod alloc { * (self.evaluations.d_eval + gamma) * self.evaluations.z_eval; - // Commitment Scheme - // Now we delegate computation to the commitment scheme by batch - // checking two proofs The `AggregateProof`, which is a - // proof that all the necessary polynomials evaluated at - // challenge `z` are correct and a `SingleProof` which - // is proof that the permutation polynomial evaluated at the shifted - // root of unity is correct + // Coefficients to compute [E]_1 + let mut v_coeffs_E = vec![v_challenge]; - // Compose the Aggregated Proof - // - let mut aggregate_proof = - AggregateProof::with_witness(self.w_z_chall_comm); - aggregate_proof.add_part((-r_0_eval, r_comm)); - aggregate_proof.add_part((self.evaluations.a_eval, self.a_comm)); - aggregate_proof.add_part((self.evaluations.b_eval, self.b_comm)); - aggregate_proof.add_part((self.evaluations.c_eval, self.c_comm)); - aggregate_proof.add_part((self.evaluations.d_eval, self.d_comm)); - aggregate_proof.add_part(( + // Compute the powers of the v_challenge + for i in 1..V_MAX_DEGREE { + v_coeffs_E.push(v_coeffs_E[i - 1] * v_challenge); + } + + // Compute the powers of the v_challenge multiplied by u_challenge + v_coeffs_E.push(v_w_challenge * u_challenge); + v_coeffs_E.push(v_coeffs_E[V_MAX_DEGREE] * v_w_challenge); + v_coeffs_E.push(v_coeffs_E[V_MAX_DEGREE + 1] * v_w_challenge); + + // Coefficients to compute [F]_1 + let mut v_coeffs_F = v_coeffs_E[..V_MAX_DEGREE].to_vec(); + + // As we include the shifted coefficients when computing [F]_1, + // we group them to save scalar multiplications when multiplying + // by [a]_1, [b]_1, and [d]_1 + v_coeffs_F[0] += v_coeffs_E[V_MAX_DEGREE]; + v_coeffs_F[1] += v_coeffs_E[V_MAX_DEGREE + 1]; + v_coeffs_F[3] += v_coeffs_E[V_MAX_DEGREE + 2]; + + // Commitments to compute [F]_1 + let F_comms = vec![ + self.a_comm.0, + self.b_comm.0, + self.c_comm.0, + self.d_comm.0, + verifier_key.permutation.s_sigma_1.0, + verifier_key.permutation.s_sigma_2.0, + verifier_key.permutation.s_sigma_3.0, + ]; + + // Compute '[F]_1' in single-core + #[cfg(not(feature = "std"))] + let mut F: G1Projective = F_comms + .iter() + .zip(v_coeffs_F.iter()) + .map(|(poly, coeff)| poly * coeff) + .sum(); + + // Compute '[F]_1' in multi-core + #[cfg(feature = "std")] + let mut F: G1Projective = F_comms + .par_iter() + .zip(v_coeffs_F.par_iter()) + .map(|(poly, coeff)| poly * coeff) + .sum(); + + // [F]_1 = [D]_1 + (v)[a]_1 + (v^2)[b]_1 + (v^3)[c]_1 + (v^4)[d]_1 + + // + (v^5)[s_sigma_1]_1 + (v^6)[s_sigma_2]_1 + (v^7)[s_sigma_3]_1 + + // + (u * v_w)[a]_1 + (u * v_w^2)[b]_1 + (u * v_w^3)[d]_1 + F += D; + + // Evaluations to compute [E]_1 + let E_evals = vec![ + self.evaluations.a_eval, + self.evaluations.b_eval, + self.evaluations.c_eval, + self.evaluations.d_eval, self.evaluations.s_sigma_1_eval, - verifier_key.permutation.s_sigma_1, - )); - aggregate_proof.add_part(( self.evaluations.s_sigma_2_eval, - verifier_key.permutation.s_sigma_2, - )); - aggregate_proof.add_part(( self.evaluations.s_sigma_3_eval, - verifier_key.permutation.s_sigma_3, - )); - // Flatten proof with opening challenge - let flattened_proof_a = aggregate_proof.flatten(&v_challenge); - - // Compose the shifted aggregate proof - let mut shifted_aggregate_proof = - AggregateProof::with_witness(self.w_z_chall_w_comm); - shifted_aggregate_proof - .add_part((self.evaluations.z_eval, self.z_comm)); - shifted_aggregate_proof - .add_part((self.evaluations.a_next_eval, self.a_comm)); - shifted_aggregate_proof - .add_part((self.evaluations.b_next_eval, self.b_comm)); - shifted_aggregate_proof - .add_part((self.evaluations.d_next_eval, self.d_comm)); - - let v_challenge_shifted = - transcript.challenge_scalar(b"v_challenge_shifted"); - let flattened_proof_b = - shifted_aggregate_proof.flatten(&v_challenge_shifted); + self.evaluations.a_next_eval, + self.evaluations.b_next_eval, + self.evaluations.d_next_eval, + ]; + + // Compute '[E]_1' = (-r_0 + (v)a + (v^2)b + (v^3)c + (v^4)d + + // + (v^5)s_sigma_1 + (v^6)s_sigma_2 + (v^7)s_sigma_3 + + // + (u)z_w + (u * v_w)a_w + (u * v_w^2)b_w + (u * v_w^3)d_w) + let mut E: BlsScalar = E_evals + .iter() + .zip(v_coeffs_E.iter()) + .map(|(eval, coeff)| eval * coeff) + .sum(); + E += -r_0_eval + (u_challenge * self.evaluations.z_eval); + + let E = E * opening_key.g; + + // Compute the G_1 element of the first pairing: + // [W_z]_1 + u * [W_zw]_1 + // + // Note that we negate this value to be able to subtract + // the pairings later on, using the multi Miller loop + let left = G1Affine::from( + -(self.w_z_chall_comm.0 + + u_challenge * self.w_z_chall_w_comm.0), + ); - // Add commitment to openings to transcript - transcript.append_commitment(b"w_z", &self.w_z_chall_comm); - transcript.append_commitment(b"w_z_w", &self.w_z_chall_w_comm); + // Compute the G_1 element of the second pairing: + // z * [W_z]_1 + (u * z * w) * [W_zw]_1 + [F]_1 - [E]_1 + let right = G1Affine::from( + z_challenge * self.w_z_chall_comm.0 + + (u_challenge * z_challenge * domain.group_gen) + * self.w_z_chall_w_comm.0 + + F + - E, + ); - // Batch check - if opening_key - .batch_check( - &[z_challenge, (z_challenge * domain.group_gen)], - &[flattened_proof_a, flattened_proof_b], - transcript, - ) - .is_err() - { + // Compute the two pairings and subtract them + let pairing = dusk_bls12_381::multi_miller_loop(&[ + (&left, &opening_key.prepared_x_h), + (&right, &opening_key.prepared_h), + ]) + .final_exponentiation(); + + // Return 'ProofVerificationError' if the two + // pairings are not equal, continue otherwise + if pairing != dusk_bls12_381::Gt::identity() { return Err(Error::ProofVerificationError); - } + }; Ok(()) } @@ -408,6 +477,7 @@ pub(crate) mod alloc { var_base_sep_challenge, ): (&BlsScalar, &BlsScalar, &BlsScalar, &BlsScalar), z_challenge: &BlsScalar, + u_challenge: &BlsScalar, l1_eval: BlsScalar, verifier_key: &VerifierKey, domain: &EvaluationDomain, @@ -454,6 +524,7 @@ pub(crate) mod alloc { &mut points, &self.evaluations, z_challenge, + u_challenge, (alpha, beta, gamma), &l1_eval, self.z_comm.0, diff --git a/src/proof_system/widget/permutation/verifierkey.rs b/src/proof_system/widget/permutation/verifierkey.rs index e143069f..f5c21e5f 100644 --- a/src/proof_system/widget/permutation/verifierkey.rs +++ b/src/proof_system/widget/permutation/verifierkey.rs @@ -48,6 +48,7 @@ mod alloc { points: &mut Vec, evaluations: &ProofEvaluations, z_challenge: &BlsScalar, + u_challenge: &BlsScalar, (alpha, beta, gamma): (&BlsScalar, &BlsScalar, &BlsScalar), l1_eval: &BlsScalar, z_comm: G1Affine, @@ -77,7 +78,7 @@ mod alloc { // l1(z) * alpha^2 let r = l1_eval * alpha_sq; - scalars.push(x + r); + scalars.push(x + r + u_challenge); points.push(z_comm); // -1 * (a_eval + beta * sigma_1_eval + gamma)