From eab053b5e0f2748376cafc02be4cb21f063c1bf8 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Wed, 24 Jan 2024 14:36:24 -0800 Subject: [PATCH] Rename mlkzg and remove redundant transcript absorbs (#299) * rename and add some clarifying notes * remove redundant transcript absorbs Credit: adr1anh --- examples/and.rs | 4 +- examples/minroot.rs | 4 +- src/lib.rs | 4 +- src/provider/{mlkzg.rs => hyperkzg.rs} | 55 +++++++++----------------- src/provider/mod.rs | 2 +- 5 files changed, 25 insertions(+), 44 deletions(-) rename src/provider/{mlkzg.rs => hyperkzg.rs} (93%) diff --git a/examples/and.rs b/examples/and.rs index 20daa112..07cc12ab 100644 --- a/examples/and.rs +++ b/examples/and.rs @@ -9,7 +9,7 @@ use ff::Field; use ff::{PrimeField, PrimeFieldBits}; use flate2::{write::ZlibEncoder, Compression}; use nova_snark::{ - provider::{mlkzg::Bn256EngineKZG, GrumpkinEngine}, + provider::{hyperkzg::Bn256EngineKZG, GrumpkinEngine}, traits::{ circuit::{StepCircuit, TrivialCircuit}, snark::RelaxedR1CSSNARKTrait, @@ -22,7 +22,7 @@ use std::time::Instant; type E1 = Bn256EngineKZG; type E2 = GrumpkinEngine; -type EE1 = nova_snark::provider::mlkzg::EvaluationEngine; +type EE1 = nova_snark::provider::hyperkzg::EvaluationEngine; type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine; type S1 = nova_snark::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK type S2 = nova_snark::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK diff --git a/examples/minroot.rs b/examples/minroot.rs index cfc05739..97f11265 100644 --- a/examples/minroot.rs +++ b/examples/minroot.rs @@ -5,7 +5,7 @@ use bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError}; use ff::Field; use flate2::{write::ZlibEncoder, Compression}; use nova_snark::{ - provider::{mlkzg::Bn256EngineKZG, GrumpkinEngine}, + provider::{hyperkzg::Bn256EngineKZG, GrumpkinEngine}, traits::{ circuit::{StepCircuit, TrivialCircuit}, snark::RelaxedR1CSSNARKTrait, @@ -18,7 +18,7 @@ use std::time::Instant; type E1 = Bn256EngineKZG; type E2 = GrumpkinEngine; -type EE1 = nova_snark::provider::mlkzg::EvaluationEngine; +type EE1 = nova_snark::provider::hyperkzg::EvaluationEngine; type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine; type S1 = nova_snark::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK type S2 = nova_snark::spartan::snark::RelaxedR1CSSNARK; // non-preprocessing SNARK diff --git a/src/lib.rs b/src/lib.rs index 0110ffdb..f35b8074 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -846,7 +846,7 @@ mod tests { use super::*; use crate::{ provider::{ - mlkzg::Bn256EngineKZG, pedersen::CommitmentKeyExtTrait, traits::DlogGroup, Bn256Engine, + hyperkzg::Bn256EngineKZG, pedersen::CommitmentKeyExtTrait, traits::DlogGroup, Bn256Engine, GrumpkinEngine, PallasEngine, Secp256k1Engine, Secq256k1Engine, VestaEngine, }, traits::{circuit::TrivialCircuit, evaluation::EvaluationEngineTrait, snark::default_ck_hint}, @@ -1214,7 +1214,7 @@ mod tests { test_ivc_nontrivial_with_spark_compression_with::< Bn256EngineKZG, GrumpkinEngine, - provider::mlkzg::EvaluationEngine<_>, + provider::hyperkzg::EvaluationEngine<_>, EE<_>, >(); } diff --git a/src/provider/mlkzg.rs b/src/provider/hyperkzg.rs similarity index 93% rename from src/provider/mlkzg.rs rename to src/provider/hyperkzg.rs index d9602288..1698f991 100644 --- a/src/provider/mlkzg.rs +++ b/src/provider/hyperkzg.rs @@ -1,4 +1,10 @@ -//! This module implements Nova's evaluation engine using multilinear KZG +//! This module implements Nova's evaluation engine using `HyperKZG`, a KZG-based polynomial commitment for multilinear polynomials +//! HyperKZG is based on the transformation from univariate PCS to multilinear PCS in the Gemini paper (section 2.4.2 in https://eprint.iacr.org/2022/420.pdf). +//! However, there are some key differences: +//! (1) HyperKZG works with multilinear polynomials represented in evaluation form (rather than in coefficient form in Gemini's transformation). +//! This means that Spartan's polynomial IOP can use commit to its polynomials as-is without incurring any interpolations or FFTs. +//! (2) HyperKZG is specialized to use KZG as the univariate commitment scheme, so it includes several optimizations (both during the transformation of multilinear-to-univariate claims +//! and within the KZG commitment scheme implementation itself). #![allow(non_snake_case)] use crate::{ errors::NovaError, @@ -294,14 +300,7 @@ where { // This impl block defines helper functions that are not a part of // EvaluationEngineTrait, but that we will use to implement the trait methods. - fn compute_challenge( - C: &G1, - y: &E::Scalar, - com: &[G1], - transcript: &mut ::TE, - ) -> E::Scalar { - transcript.absorb(b"C", C); - transcript.absorb(b"y", y); + fn compute_challenge(com: &[G1], transcript: &mut ::TE) -> E::Scalar { transcript.absorb(b"c", &com.to_vec().as_slice()); transcript.squeeze(b"c").unwrap() @@ -309,14 +308,7 @@ where // Compute challenge q = Hash(vk, C0, ..., C_{k-1}, u0, ...., u_{t-1}, // (f_i(u_j))_{i=0..k-1,j=0..t-1}) - fn get_batch_challenge( - C: &[G1], - u: &[E::Scalar], - v: &[Vec], - transcript: &mut ::TE, - ) -> E::Scalar { - transcript.absorb(b"C", &C.to_vec().as_slice()); - transcript.absorb(b"u", &u.to_vec().as_slice()); + fn get_batch_challenge(v: &[Vec], transcript: &mut ::TE) -> E::Scalar { transcript.absorb( b"v", &v.iter() @@ -338,12 +330,7 @@ where q_powers } - fn verifier_second_challenge( - C_B: &G1, - W: &[G1], - transcript: &mut ::TE, - ) -> E::Scalar { - transcript.absorb(b"C_b", C_B); + fn verifier_second_challenge(W: &[G1], transcript: &mut ::TE) -> E::Scalar { transcript.absorb(b"W", &W.to_vec().as_slice()); transcript.squeeze(b"d").unwrap() @@ -473,7 +460,7 @@ where } } - let q = Self::get_batch_challenge(C, u, &v, transcript); + let q = Self::get_batch_challenge(&v, transcript); let B = kzg_compute_batch_polynomial(f, q); // Now open B at u0, ..., u_{t-1} @@ -483,15 +470,9 @@ where w.push(wi); } - // Compute the commitment to the batched polynomial B(X) - let q_powers = Self::batch_challenge_powers(q, k); - let C_B = (::group(&C[0]) - + E::GE::vartime_multiscalar_mul(&q_powers[1..k], &C[1..k])) - .preprocessed(); - // The prover computes the challenge to keep the transcript in the same // state as that of the verifier - let _d_0 = Self::verifier_second_challenge(&C_B, &w, transcript); + let _d_0 = Self::verifier_second_challenge(&w, transcript); (w, v) }; @@ -530,9 +511,9 @@ where .collect(); // Phase 2 - // We do not need to add x to the transcript, because in our context x was - // obtained from the transcript. - let r = Self::compute_challenge(&C.comm.preprocessed(), eval, &com, transcript); + // We do not need to add x to the transcript, because in our context x was obtained from the transcript. + // We also do not need to absorb `C` and `eval` as they are already absorbed by the transcript by the caller + let r = Self::compute_challenge(&com, transcript); let u = vec![r, -r, r * r]; // Phase 3 -- create response @@ -567,7 +548,7 @@ where let k = C.len(); let t = u.len(); - let q = Self::get_batch_challenge(C, u, v, transcript); + let q = Self::get_batch_challenge(v, transcript); let q_powers = Self::batch_challenge_powers(q, k); // 1, q, q^2, ..., q^(k-1) // Compute the commitment to the batched polynomial B(X) @@ -584,7 +565,7 @@ where }) .collect::>(); - let d_0 = Self::verifier_second_challenge(&C_B, W, transcript); + let d_0 = Self::verifier_second_challenge(W, transcript); let d = [d_0, d_0 * d_0]; // Shorthand to convert from preprocessed G1 elements to non-preprocessed @@ -629,7 +610,7 @@ where // we do not need to add x to the transcript, because in our context x was // obtained from the transcript - let r = Self::compute_challenge(&C.comm.preprocessed(), y, &com, transcript); + let r = Self::compute_challenge(&com, transcript); if r == E::Scalar::ZERO || C.comm == E::GE::zero() { return Err(NovaError::ProofVerifyError); diff --git a/src/provider/mod.rs b/src/provider/mod.rs index b2739cec..e0d6ce24 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -1,8 +1,8 @@ //! This module implements Nova's traits using the following several different combinations // public modules to be used as an evaluation engine with Spartan +pub mod hyperkzg; pub mod ipa_pc; -pub mod mlkzg; // crate-public modules, made crate-public mostly for tests pub(crate) mod bn256_grumpkin;