From e92ea87572b1dec3229c32fc554aca69c47255e1 Mon Sep 17 00:00:00 2001 From: xevisalle Date: Thu, 8 Aug 2024 14:49:52 +0200 Subject: [PATCH] Boost the verifier --- CHANGELOG.md | 2 + README.md | 2 +- src/proof_system/proof.rs | 111 ++++++++++++++++++++------------------ 3 files changed, 63 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70d05fc5..5454b74c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Modify the prover to match the paper [#831] - Modify the verifier to match the paper [#831] - Rename some variables to match the paper [#831] +- Modify the parallelization to have a faster verifier [#834] ### Removed @@ -592,6 +593,7 @@ is necessary since `rkyv/validation` was required as a bound. - Proof system module. +[#834]: https://github.com/dusk-network/plonk/issues/834 [#831]: https://github.com/dusk-network/plonk/issues/831 [#819]: https://github.com/dusk-network/plonk/issues/819 [#818]: https://github.com/dusk-network/plonk/issues/818 diff --git a/README.md b/README.md index 4cc6acc3..e4c39bbe 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ as the documentation regarding the data structures that it exports. To check thi Benchmarks taken on `Apple M1`, for a circuit-size of `2^16` constraints: - Proving time: `7.871s` -- Verification time: `3.732ms` **(This time does not vary depending on the circuit-size.)** +- Verification time: `2.821ms` **(This time does not vary depending on the circuit-size.)** For more results, please run `cargo bench` to get a full report of benchmarks in respect of constraint numbers. diff --git a/src/proof_system/proof.rs b/src/proof_system/proof.rs index e434eb28..285e8947 100644 --- a/src/proof_system/proof.rs +++ b/src/proof_system/proof.rs @@ -358,18 +358,34 @@ pub(crate) mod alloc { 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(); + // 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, + self.evaluations.s_sigma_2_eval, + self.evaluations.s_sigma_3_eval, + self.evaluations.a_w_eval, + self.evaluations.b_w_eval, + self.evaluations.d_w_eval, + ]; - // 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]; + // Compute E = (-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_scalar: BlsScalar = E_evals + .iter() + .zip(v_coeffs_E.iter()) + .map(|(eval, coeff)| eval * coeff) + .sum(); + E_scalar += -r_0_eval + (u_challenge * self.evaluations.z_eval); - // Commitments to compute [F]_1 - let F_comms = vec![ + // We group all the remaining scalar multiplications in the + // verification process, with the purpose of + // parallelizing them + let scalarmuls_points = vec![ self.a_comm.0, self.b_comm.0, self.c_comm.0, @@ -377,54 +393,51 @@ pub(crate) mod alloc { verifier_key.permutation.s_sigma_1.0, verifier_key.permutation.s_sigma_2.0, verifier_key.permutation.s_sigma_3.0, + opening_key.g, + self.w_z_chall_w_comm.0, + self.w_z_chall_comm.0, + self.w_z_chall_w_comm.0, ]; - // Compute '[F]_1' in single-core + let mut scalarmuls_scalars = 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 + scalarmuls_scalars[0] += v_coeffs_E[V_MAX_DEGREE]; + scalarmuls_scalars[1] += v_coeffs_E[V_MAX_DEGREE + 1]; + scalarmuls_scalars[3] += v_coeffs_E[V_MAX_DEGREE + 2]; + + scalarmuls_scalars.push(E_scalar); + scalarmuls_scalars.push(u_challenge); + scalarmuls_scalars.push(z_challenge); + scalarmuls_scalars + .push(u_challenge * z_challenge * domain.group_gen); + + // Compute the scalar multiplications in single-core #[cfg(not(feature = "std"))] - let mut F: G1Projective = F_comms + let scalarmuls: Vec = scalarmuls_points .iter() - .zip(v_coeffs_F.iter()) - .map(|(poly, coeff)| poly * coeff) - .sum(); + .zip(scalarmuls_scalars.iter()) + .map(|(point, scalar)| point * scalar) + .collect(); - // Compute '[F]_1' in multi-core + // Compute the scalar multiplications in multi-core #[cfg(feature = "std")] - let mut F: G1Projective = F_comms + let scalarmuls: Vec = scalarmuls_points .par_iter() - .zip(v_coeffs_F.par_iter()) - .map(|(poly, coeff)| poly * coeff) - .sum(); + .zip(scalarmuls_scalars.par_iter()) + .map(|(point, scalar)| point * scalar) + .collect(); // [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 + let mut F: G1Projective = scalarmuls[..V_MAX_DEGREE].iter().sum(); 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, - self.evaluations.s_sigma_2_eval, - self.evaluations.s_sigma_3_eval, - self.evaluations.a_w_eval, - self.evaluations.b_w_eval, - self.evaluations.d_w_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; + // [E]_1 = E * G + let E = scalarmuls[V_MAX_DEGREE]; // Compute the G_1 element of the first pairing: // [W_z]_1 + u * [W_zw]_1 @@ -432,17 +445,13 @@ pub(crate) mod alloc { // 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), + -(self.w_z_chall_comm.0 + scalarmuls[V_MAX_DEGREE + 1]), ); // 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 + scalarmuls[V_MAX_DEGREE + 2] + scalarmuls[V_MAX_DEGREE + 3] + F - E, );