From fe13834e237d6b8b631b8d15896422ab6277a1ee Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 11:46:36 -0700 Subject: [PATCH 01/24] not quite there... annoying transcript stuff --- src/provider/hyrax_pc.rs | 312 ++++++++++++++++++++++++++++++++++++++ src/provider/ipa_pc.rs | 4 +- src/provider/mod.rs | 1 + src/spartan/polynomial.rs | 37 +++++ 4 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 src/provider/hyrax_pc.rs diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs new file mode 100644 index 0000000..02e6796 --- /dev/null +++ b/src/provider/hyrax_pc.rs @@ -0,0 +1,312 @@ +//! This module implements the Hyrax polynomial commitment scheme +#![allow(clippy::too_many_arguments)] +use crate::{ + errors::SpartanError, + provider::ipa_pc::{InnerProductArgument, InnerProductInstance, InnerProductWitness}, + provider::pedersen::CommitmentKeyExtTrait, + spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, + traits::{ + commitment::{ + CommitmentEngineTrait, CommitmentTrait + }, + Group, TranscriptEngineTrait, TranscriptReprTrait, + }, + Commitment, CommitmentKey,CompressedCommitment +}; +use ff::Field; +use rayon::prelude::*; + +/// Structure that holds Poly Commits +#[derive(Debug)] +pub struct PolyCommit { + /// Commitment + pub comm: Vec>, +} + +/// Hyrax PC generators and functions to commit and prove evaluation +pub struct HyraxPC { + gens_v: CommitmentKey, // generator for vectors + gens_s: CommitmentKey, // generator for scalars (eval) +} + +impl TranscriptReprTrait for PolyCommit { + fn to_transcript_bytes(&self) -> Vec { + let mut v = Vec::new(); + v.append(&mut b"poly_commitment_begin".to_vec()); + + for c in &self.comm { + v.append(&mut c.to_transcrypt_bytes()); + } + + v.append(&mut b"poly_commitment_end".to_vec()); + v + } +} + + +impl HyraxPC +where + G: Group, + CommitmentKey: CommitmentKeyExtTrait, +{ + /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly + pub fn new(num_vars: usize, label: &'static [u8]) -> Self { + let (_left, right) = EqPolynomial::::compute_factored_lens(num_vars); + let gens_v = G::CE::setup(label, (2usize).pow(right as u32)); + let gens_s = G::CE::setup(b"gens_s", 1); + HyraxPC { gens_v, gens_s } + } + + fn commit_inner( + &self, + poly: &MultilinearPolynomial, + L_size: usize, + ) -> PolyCommit { + let R_size = poly.len() / L_size; + + assert_eq!(L_size * R_size, poly.len()); + + let comm = (0..L_size) + .into_par_iter() + .map(|i| { + G::CE::commit( + &self.gens_v, + &poly.get_Z()[R_size * i..R_size * (i + 1)], + ) + .compress() + }) + .collect(); + + PolyCommit { comm } + } + + /// Commits to a multilinear polynomial and returns commitment and blind + pub fn commit( + &self, + poly: &MultilinearPolynomial, + ) -> PolyCommit { + let n = poly.len(); + let ell = poly.get_num_vars(); + assert_eq!(n, (2usize).pow(ell as u32)); + + let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(ell); + let L_size = (2usize).pow(left_num_vars as u32); + let R_size = (2usize).pow(right_num_vars as u32); + assert_eq!(L_size * R_size, n); + + self.commit_inner(poly, L_size) + } + + /// Proves the evaluation of polynomial at a random point r + pub fn prove_eval( + &self, + poly: &MultilinearPolynomial, // defined as vector Z + poly_com: &PolyCommit, + r: &[G::Scalar], // point at which the polynomial is evaluated + Zr: &G::Scalar, // evaluation of poly(r) + transcript: &mut G::TE, + ) -> Result< + ( + InnerProductArgument, + InnerProductWitness, + ), + SpartanError, + > { + transcript.absorb(b"protocol-name", b"polynomial evaluation proof"); + transcript.absorb(b"poly_com", &poly_com); + + // assert vectors are of the right size + assert_eq!(poly.get_num_vars(), r.len()); + + let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(r.len()); + let L_size = (2usize).pow(left_num_vars as u32); + let R_size = (2usize).pow(right_num_vars as u32); + + // compute the L and R vectors (these depend only on the public challenge r so they are public) + let eq = EqPolynomial::new(r.to_vec()); + let (L, R) = eq.compute_factored_evals(); + assert_eq!(L.len(), L_size); + assert_eq!(R.len(), R_size); + + // compute the vector underneath L*Z + // compute vector-matrix product between L and Z viewed as a matrix + let LZ = poly.bound(&L); + + // Translation between this stuff and IPA + // LZ = x_vec + // LZ_blind = r_x + // Zr = y + // blind_Zr = r_y + // R = a_vec + + // Commit to LZ and Zr + let com_LZ = G::CE::commit(&self.gens_v, &LZ); + //let com_Zr = G::CE::commit(&self.gens_s, &[*Zr]); + + // a dot product argument (IPA) of size R_size + let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, Zr); + let ipa_witness = InnerProductWitness::::new(&LZ); + let ipa = InnerProductArgument::::prove( + &self.gens_v, + &self.gens_s, + &ipa_instance, + &ipa_witness, + transcript, + )?; + + Ok((ipa, ipa_witness)) + } + + /// Verifies the proof showing the evaluation of a committed polynomial at a random point + pub fn verify_eval( + &self, + r: &[G::Scalar], // point at which the polynomial was evaluated + poly_com: &PolyCommit, + Zr: &G::Scalar, + ipa: &InnerProductArgument, + transcript: &mut G::TE, + ) -> Result<(), SpartanError> { + transcript.append_message(b"protocol-name", b"polynomial evaluation proof"); + poly_com.append_to_transcript(b"poly_com", transcript); + + // compute L and R + let eq = EqPolynomial::new(r.to_vec()); + let (L, R) = eq.compute_factored_evals(); + + // compute a weighted sum of commitments and L + let gens: CommitmentKey = + CommitmentKey::::reinterpret_commitments_as_ck(&poly_com.comm)?; + + let com_LZ = G::CE::commit(&gens, &L); // computes MSM of commitment and L + + let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, Zr); + + ipa.verify( + &self.gens_v, + &self.gens_s, + L.len(), + &ipa_instance, + transcript, + ) + } +} + +#[cfg(test)] +mod tests { + use super::*; + type G = pasta_curves::pallas::Point; + use crate::traits::TranscriptEngineTrait; + use rand::rngs::OsRng; + + fn inner_product(a: &[T], b: &[T]) -> T + where + T: Field + Send + Sync, + { + assert_eq!(a.len(), b.len()); + (0..a.len()) + .into_par_iter() + .map(|i| a[i] * b[i]) + .reduce(|| T::ZERO, |x, y| x + y) + } + + fn evaluate_with_LR( + Z: &[::Scalar], + r: &[::Scalar], + ) -> ::Scalar { + let eq = EqPolynomial::new(r.to_vec()); + let (L, R) = eq.compute_factored_evals(); + + let ell = r.len(); + // ensure ell is even + assert!(ell % 2 == 0); + + // compute n = 2^\ell + let n = (2usize).pow(ell as u32); + + // compute m = sqrt(n) = 2^{\ell/2} + let m = (n as f64).sqrt() as usize; + + // compute vector-matrix product between L and Z viewed as a matrix + let LZ = (0..m) + .map(|i| { + (0..m) + .map(|j| L[j] * Z[j * m + i]) + .fold(::Scalar::ZERO, |acc, item| acc + item) + }) + .collect::::Scalar>>(); + + // compute dot product between LZ and R + inner_product(&LZ, &R) + } + + fn to_scalar(x: usize) -> ::Scalar { + (0..x) + .map(|_i| ::Scalar::ONE) + .fold(::Scalar::ZERO, |acc, item| acc + item) + } + + #[test] + fn check_polynomial_evaluation() { + // Z = [1, 2, 1, 4] + let Z = vec![to_scalar(1), to_scalar(2), to_scalar(1), to_scalar(4)]; + + // r = [4,3] + let r = vec![to_scalar(4), to_scalar(3)]; + + let eval_with_LR = evaluate_with_LR(&Z, &r); + let poly = MultilinearPolynomial::new(Z); + + let eval = poly.evaluate(&r); + assert_eq!(eval, to_scalar(28)); + assert_eq!(eval_with_LR, eval); + } + + #[test] + fn check_hyrax_pc_commit() { + let Z = vec![to_scalar(1), to_scalar(2), to_scalar(1), to_scalar(4)]; + + let poly = MultilinearPolynomial::new(Z); + + // Public stuff + let num_vars = 2; + assert_eq!(num_vars, poly.get_num_vars()); + let r = vec![to_scalar(4), to_scalar(3)]; // r = [4,3] + + // Prover actions + let eval = poly.evaluate(&r); + assert_eq!(eval, to_scalar(28)); + + let prover_gens = HyraxPC::new(num_vars, b"poly_test"); + let poly_comm = prover_gens.commit(&poly); + + let mut prover_transcript = G::TE::new(b"example"); + + let blind_eval = ::Scalar::random(&mut OsRng); + + let (ipa_proof, _ipa_witness, comm_eval): (InnerProductArgument, InnerProductWitness, _) = + prover_gens + .prove_eval( + &poly, + &poly_comm, + &r, + &eval, + &blind_eval, + &mut prover_transcript, + ) + .unwrap(); + + // Verifier actions + + let verifier_gens = HyraxPC::new(num_vars, b"poly_test"); + let mut verifier_transcript = G::TE::new(b"example"); + + let res = verifier_gens.verify_eval( + &r, + &poly_comm, + &comm_eval, + &ipa_proof, + &mut verifier_transcript, + ); + assert!(res.is_ok()); + } +} diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 413ae47..0ae1874 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -119,7 +119,7 @@ pub struct InnerProductInstance { } impl InnerProductInstance { - fn new(comm_a_vec: &Commitment, b_vec: &[G::Scalar], c: &G::Scalar) -> Self { + pub fn new(comm_a_vec: &Commitment, b_vec: &[G::Scalar], c: &G::Scalar) -> Self { InnerProductInstance { comm_a_vec: *comm_a_vec, b_vec: b_vec.to_vec(), @@ -144,7 +144,7 @@ struct InnerProductWitness { } impl InnerProductWitness { - fn new(a_vec: &[G::Scalar]) -> Self { + pub fn new(a_vec: &[G::Scalar]) -> Self { InnerProductWitness { a_vec: a_vec.to_vec(), } diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 2ef0027..f9532b6 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -10,6 +10,7 @@ pub mod keccak; pub mod pasta; pub mod pedersen; pub mod secp_secq; +pub mod hyrax_pc; use ff::PrimeField; use pasta_curves::{self, arithmetic::CurveAffine, group::Group as AnotherGroup}; diff --git a/src/spartan/polynomial.rs b/src/spartan/polynomial.rs index 18387f1..eb8572c 100644 --- a/src/spartan/polynomial.rs +++ b/src/spartan/polynomial.rs @@ -44,6 +44,20 @@ impl EqPolynomial { } evals } + + pub fn compute_factored_lens(ell: usize) -> (usize, usize) { + (ell / 2, ell - ell / 2) + } + + pub fn compute_factored_evals(&self) -> (Vec, Vec) { + let ell = self.r.len(); + let (left_num_vars, _right_num_vars) = EqPolynomial::::compute_factored_lens(ell); + + let L = EqPolynomial::new(self.r[..left_num_vars].to_vec()).evals(); + let R = EqPolynomial::new(self.r[left_num_vars..ell].to_vec()).evals(); + + (L, R) + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -65,10 +79,33 @@ impl MultilinearPolynomial { self.num_vars } + pub fn get_Z(&self) -> &[Scalar] { + &self.Z + } + pub fn len(&self) -> usize { self.Z.len() } + pub fn is_empty(&self) -> bool { + self.Z.len() == 0 + } + + pub fn bound(&self, L: &[Scalar]) -> Vec { + let (left_num_vars, right_num_vars) = + EqPolynomial::::compute_factored_lens(self.num_vars); + let L_size = (2_usize).pow(left_num_vars as u32); + let R_size = (2_usize).pow(right_num_vars as u32); + + (0..R_size) + .map(|i| { + (0..L_size) + .map(|j| L[j] * self.Z[j * R_size + i]) + .fold(Scalar::zero(), |x, y| x + y) + }) + .collect() + } + pub fn bound_poly_var_top(&mut self, r: &Scalar) { let n = self.len() / 2; From e2f1762cc32fe9af86fde86053564c6f8ec4d302 Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 12:11:38 -0700 Subject: [PATCH 02/24] small stuff --- src/provider/ipa_pc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 0ae1874..dc0c86c 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -139,7 +139,8 @@ impl TranscriptReprTrait for InnerProductInstance { } } -struct InnerProductWitness { +/// An inner product witness consists the vector `a`. +pub struct InnerProductWitness { a_vec: Vec, } From a7f688298fa01a492f1c76f48335826552ac3b19 Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 12:11:55 -0700 Subject: [PATCH 03/24] small stuff --- src/spartan/polynomial.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/spartan/polynomial.rs b/src/spartan/polynomial.rs index eb8572c..04d1565 100644 --- a/src/spartan/polynomial.rs +++ b/src/spartan/polynomial.rs @@ -101,7 +101,7 @@ impl MultilinearPolynomial { .map(|i| { (0..L_size) .map(|j| L[j] * self.Z[j * R_size + i]) - .fold(Scalar::zero(), |x, y| x + y) + .fold(Scalar::ZERO, |x, y| x + y) }) .collect() } From 6fdf48cd6202bac893b201176bb328912d21caf0 Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 12:13:54 -0700 Subject: [PATCH 04/24] some progress --- src/provider/hyrax_pc.rs | 2 +- src/provider/ipa_pc.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 02e6796..a8af6f5 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -13,7 +13,6 @@ use crate::{ }, Commitment, CommitmentKey,CompressedCommitment }; -use ff::Field; use rayon::prelude::*; /// Structure that holds Poly Commits @@ -193,6 +192,7 @@ where #[cfg(test)] mod tests { + use ff::Field; use super::*; type G = pasta_curves::pallas::Point; use crate::traits::TranscriptEngineTrait; diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index dc0c86c..ce25a46 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -170,7 +170,7 @@ where b"IPA" } - fn prove( + pub fn prove( ck: &CommitmentKey, ck_c: &CommitmentKey, U: &InnerProductInstance, @@ -282,7 +282,7 @@ where }) } - fn verify( + pub fn verify( &self, ck: &CommitmentKey, ck_c: &CommitmentKey, From aa172407d5ef0dea3e63240b4486a3ba1c31f338 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Thu, 27 Jul 2023 12:48:14 -0700 Subject: [PATCH 05/24] fix transcript --- src/provider/hyrax_pc.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index a8af6f5..27fd1ca 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -3,7 +3,7 @@ use crate::{ errors::SpartanError, provider::ipa_pc::{InnerProductArgument, InnerProductInstance, InnerProductWitness}, - provider::pedersen::CommitmentKeyExtTrait, + provider::pedersen::{CommitmentKeyExtTrait,CompressedCommitment}, spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, traits::{ commitment::{ @@ -11,7 +11,7 @@ use crate::{ }, Group, TranscriptEngineTrait, TranscriptReprTrait, }, - Commitment, CommitmentKey,CompressedCommitment + CommitmentKey }; use rayon::prelude::*; @@ -34,7 +34,7 @@ impl TranscriptReprTrait for PolyCommit { v.append(&mut b"poly_commitment_begin".to_vec()); for c in &self.comm { - v.append(&mut c.to_transcrypt_bytes()); + v.append(&mut c.to_transcript_bytes()); } v.append(&mut b"poly_commitment_end".to_vec()); @@ -111,8 +111,7 @@ where ), SpartanError, > { - transcript.absorb(b"protocol-name", b"polynomial evaluation proof"); - transcript.absorb(b"poly_com", &poly_com); + transcript.absorb(b"poly_com", poly_com); // assert vectors are of the right size assert_eq!(poly.get_num_vars(), r.len()); @@ -165,8 +164,7 @@ where ipa: &InnerProductArgument, transcript: &mut G::TE, ) -> Result<(), SpartanError> { - transcript.append_message(b"protocol-name", b"polynomial evaluation proof"); - poly_com.append_to_transcript(b"poly_com", transcript); + transcript.absorb(b"poly_com", poly_com); // compute L and R let eq = EqPolynomial::new(r.to_vec()); From e41cb22b878c7c7c6451f71859977864a295b18d Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Thu, 27 Jul 2023 12:55:37 -0700 Subject: [PATCH 06/24] add doc, use generic types --- src/provider/hyrax_pc.rs | 51 +++++++++++----------------------------- src/provider/ipa_pc.rs | 4 ++++ src/provider/mod.rs | 1 + 3 files changed, 19 insertions(+), 37 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 27fd1ca..07bb667 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -3,15 +3,13 @@ use crate::{ errors::SpartanError, provider::ipa_pc::{InnerProductArgument, InnerProductInstance, InnerProductWitness}, - provider::pedersen::{CommitmentKeyExtTrait,CompressedCommitment}, + provider::pedersen::CommitmentKeyExtTrait, spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, traits::{ - commitment::{ - CommitmentEngineTrait, CommitmentTrait - }, + commitment::{CommitmentEngineTrait, CommitmentTrait}, Group, TranscriptEngineTrait, TranscriptReprTrait, }, - CommitmentKey + CommitmentKey, CompressedCommitment, }; use rayon::prelude::*; @@ -24,7 +22,7 @@ pub struct PolyCommit { /// Hyrax PC generators and functions to commit and prove evaluation pub struct HyraxPC { - gens_v: CommitmentKey, // generator for vectors + gens_v: CommitmentKey, // generator for vectors gens_s: CommitmentKey, // generator for scalars (eval) } @@ -42,7 +40,6 @@ impl TranscriptReprTrait for PolyCommit { } } - impl HyraxPC where G: Group, @@ -56,34 +53,21 @@ where HyraxPC { gens_v, gens_s } } - fn commit_inner( - &self, - poly: &MultilinearPolynomial, - L_size: usize, - ) -> PolyCommit { + fn commit_inner(&self, poly: &MultilinearPolynomial, L_size: usize) -> PolyCommit { let R_size = poly.len() / L_size; assert_eq!(L_size * R_size, poly.len()); let comm = (0..L_size) .into_par_iter() - .map(|i| { - G::CE::commit( - &self.gens_v, - &poly.get_Z()[R_size * i..R_size * (i + 1)], - ) - .compress() - }) + .map(|i| G::CE::commit(&self.gens_v, &poly.get_Z()[R_size * i..R_size * (i + 1)]).compress()) .collect(); PolyCommit { comm } } /// Commits to a multilinear polynomial and returns commitment and blind - pub fn commit( - &self, - poly: &MultilinearPolynomial, - ) -> PolyCommit { + pub fn commit(&self, poly: &MultilinearPolynomial) -> PolyCommit { let n = poly.len(); let ell = poly.get_num_vars(); assert_eq!(n, (2usize).pow(ell as u32)); @@ -101,16 +85,10 @@ where &self, poly: &MultilinearPolynomial, // defined as vector Z poly_com: &PolyCommit, - r: &[G::Scalar], // point at which the polynomial is evaluated - Zr: &G::Scalar, // evaluation of poly(r) + r: &[G::Scalar], // point at which the polynomial is evaluated + Zr: &G::Scalar, // evaluation of poly(r) transcript: &mut G::TE, - ) -> Result< - ( - InnerProductArgument, - InnerProductWitness, - ), - SpartanError, - > { + ) -> Result<(InnerProductArgument, InnerProductWitness), SpartanError> { transcript.absorb(b"poly_com", poly_com); // assert vectors are of the right size @@ -138,7 +116,7 @@ where // R = a_vec // Commit to LZ and Zr - let com_LZ = G::CE::commit(&self.gens_v, &LZ); + let com_LZ = G::CE::commit(&self.gens_v, &LZ); //let com_Zr = G::CE::commit(&self.gens_s, &[*Zr]); // a dot product argument (IPA) of size R_size @@ -160,7 +138,7 @@ where &self, r: &[G::Scalar], // point at which the polynomial was evaluated poly_com: &PolyCommit, - Zr: &G::Scalar, + Zr: &G::Scalar, ipa: &InnerProductArgument, transcript: &mut G::TE, ) -> Result<(), SpartanError> { @@ -171,8 +149,7 @@ where let (L, R) = eq.compute_factored_evals(); // compute a weighted sum of commitments and L - let gens: CommitmentKey = - CommitmentKey::::reinterpret_commitments_as_ck(&poly_com.comm)?; + let gens: CommitmentKey = CommitmentKey::::reinterpret_commitments_as_ck(&poly_com.comm)?; let com_LZ = G::CE::commit(&gens, &L); // computes MSM of commitment and L @@ -190,8 +167,8 @@ where #[cfg(test)] mod tests { - use ff::Field; use super::*; + use ff::Field; type G = pasta_curves::pallas::Point; use crate::traits::TranscriptEngineTrait; use rand::rngs::OsRng; diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index ce25a46..aa9ba4b 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -119,6 +119,7 @@ pub struct InnerProductInstance { } impl InnerProductInstance { + /// Creates a new inner product instance pub fn new(comm_a_vec: &Commitment, b_vec: &[G::Scalar], c: &G::Scalar) -> Self { InnerProductInstance { comm_a_vec: *comm_a_vec, @@ -145,6 +146,7 @@ pub struct InnerProductWitness { } impl InnerProductWitness { + /// Creates a new inner product witness pub fn new(a_vec: &[G::Scalar]) -> Self { InnerProductWitness { a_vec: a_vec.to_vec(), @@ -170,6 +172,7 @@ where b"IPA" } + /// Proves an inner product relationship pub fn prove( ck: &CommitmentKey, ck_c: &CommitmentKey, @@ -282,6 +285,7 @@ where }) } + /// Verifies an inner product relationship pub fn verify( &self, ck: &CommitmentKey, diff --git a/src/provider/mod.rs b/src/provider/mod.rs index f9532b6..4a99a1c 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -5,6 +5,7 @@ //! `EvaluationEngine` with an IPA-based polynomial evaluation argument pub mod bn256_grumpkin; +pub mod hyrax_pc; pub mod ipa_pc; pub mod keccak; pub mod pasta; From 035a191230cf0d3db5f58cf250cb2ee8a08d19da Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 12:43:28 -0700 Subject: [PATCH 07/24] local tests passing --- src/provider/hyrax_pc.rs | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 07bb667..2839c4e 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -171,7 +171,6 @@ mod tests { use ff::Field; type G = pasta_curves::pallas::Point; use crate::traits::TranscriptEngineTrait; - use rand::rngs::OsRng; fn inner_product(a: &[T], b: &[T]) -> T where @@ -254,34 +253,19 @@ mod tests { let prover_gens = HyraxPC::new(num_vars, b"poly_test"); let poly_comm = prover_gens.commit(&poly); - let mut prover_transcript = G::TE::new(b"example"); + let mut prover_transcript = ::TE::new(b"example"); - let blind_eval = ::Scalar::random(&mut OsRng); - - let (ipa_proof, _ipa_witness, comm_eval): (InnerProductArgument, InnerProductWitness, _) = - prover_gens - .prove_eval( - &poly, - &poly_comm, - &r, - &eval, - &blind_eval, - &mut prover_transcript, - ) - .unwrap(); + let (ipa_proof, _ipa_witness): (InnerProductArgument, InnerProductWitness) = prover_gens + .prove_eval(&poly, &poly_comm, &r, &eval, &mut prover_transcript) + .unwrap(); // Verifier actions let verifier_gens = HyraxPC::new(num_vars, b"poly_test"); - let mut verifier_transcript = G::TE::new(b"example"); - - let res = verifier_gens.verify_eval( - &r, - &poly_comm, - &comm_eval, - &ipa_proof, - &mut verifier_transcript, - ); + let mut verifier_transcript = ::TE::new(b"example"); + + let res = + verifier_gens.verify_eval(&r, &poly_comm, &eval, &ipa_proof, &mut verifier_transcript); assert!(res.is_ok()); } } From a2734dca4dba63835024b01273928cb0c7b584c4 Mon Sep 17 00:00:00 2001 From: Sebastian Angel Date: Thu, 27 Jul 2023 14:13:02 -0700 Subject: [PATCH 08/24] evaluation engine --- src/provider/hyrax_pc.rs | 260 +++++++++++++++++++++++++-------------- 1 file changed, 165 insertions(+), 95 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 2839c4e..c02ecb5 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -7,99 +7,97 @@ use crate::{ spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, + evaluation::EvaluationEngineTrait, Group, TranscriptEngineTrait, TranscriptReprTrait, }, CommitmentKey, CompressedCommitment, }; use rayon::prelude::*; +use serde::{Deserialize, Serialize}; +use std::marker::PhantomData; -/// Structure that holds Poly Commits -#[derive(Debug)] -pub struct PolyCommit { - /// Commitment - pub comm: Vec>, + +/// Provides an implementation of the hyrax key +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxProverKey { + ck_s: CommitmentKey, } -/// Hyrax PC generators and functions to commit and prove evaluation -pub struct HyraxPC { - gens_v: CommitmentKey, // generator for vectors - gens_s: CommitmentKey, // generator for scalars (eval) +/// Provides an implementation of the hyrax key +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxVerifierKey { + ck_v: CommitmentKey, + ck_s: CommitmentKey, } -impl TranscriptReprTrait for PolyCommit { - fn to_transcript_bytes(&self) -> Vec { - let mut v = Vec::new(); - v.append(&mut b"poly_commitment_begin".to_vec()); - for c in &self.comm { - v.append(&mut c.to_transcript_bytes()); - } - v.append(&mut b"poly_commitment_end".to_vec()); - v - } +/// Provides an implementation of a polynomial evaluation argument +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxEvaluationArgument { + ipa: InnerProductArgument, +} + + +/// Provides an implementation of a polynomial evaluation engine using Hyrax PC +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxEvaluationEngine { + _p: PhantomData, } -impl HyraxPC + +impl EvaluationEngineTrait for HyraxEvaluationEngine where G: Group, CommitmentKey: CommitmentKeyExtTrait, { - /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly - pub fn new(num_vars: usize, label: &'static [u8]) -> Self { - let (_left, right) = EqPolynomial::::compute_factored_lens(num_vars); - let gens_v = G::CE::setup(label, (2usize).pow(right as u32)); - let gens_s = G::CE::setup(b"gens_s", 1); - HyraxPC { gens_v, gens_s } - } - - fn commit_inner(&self, poly: &MultilinearPolynomial, L_size: usize) -> PolyCommit { - let R_size = poly.len() / L_size; - - assert_eq!(L_size * R_size, poly.len()); - - let comm = (0..L_size) - .into_par_iter() - .map(|i| G::CE::commit(&self.gens_v, &poly.get_Z()[R_size * i..R_size * (i + 1)]).compress()) - .collect(); - - PolyCommit { comm } + type CE = G::CE; + type ProverKey = HyraxProverKey; + type VerifierKey = HyraxVerifierKey; + type EvaluationArgument = HyraxEvaluationArgument; + + fn setup( + ck: &>::CommitmentKey, + ) -> (Self::ProverKey, Self::VerifierKey) { + let pk = HyraxProverKey:: { + ck_s: G::CE::setup(b"hyrax", 1), + }; + + let vk = HyraxVerifierKey:: { + ck_v: ck.clone(), + ck_s: G::CE::setup(b"hyrax", 1), + }; + + (pk, vk) } - /// Commits to a multilinear polynomial and returns commitment and blind - pub fn commit(&self, poly: &MultilinearPolynomial) -> PolyCommit { - let n = poly.len(); - let ell = poly.get_num_vars(); - assert_eq!(n, (2usize).pow(ell as u32)); - - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(ell); - let L_size = (2usize).pow(left_num_vars as u32); - let R_size = (2usize).pow(right_num_vars as u32); - assert_eq!(L_size * R_size, n); - - self.commit_inner(poly, L_size) - } - - /// Proves the evaluation of polynomial at a random point r - pub fn prove_eval( - &self, - poly: &MultilinearPolynomial, // defined as vector Z - poly_com: &PolyCommit, - r: &[G::Scalar], // point at which the polynomial is evaluated - Zr: &G::Scalar, // evaluation of poly(r) + fn prove( + ck: &CommitmentKey, + pk: &Self::ProverKey, transcript: &mut G::TE, - ) -> Result<(InnerProductArgument, InnerProductWitness), SpartanError> { - transcript.absorb(b"poly_com", poly_com); - + comm: &PolyCommit, + poly: &[G::Scalar], + point: &[G::Scalar], + eval: &G::Scalar, + ) -> Result { + + transcript.absorb(b"poly_com", comm); + + let poly_m = MultilinearPolynomial::::new(poly); + // assert vectors are of the right size - assert_eq!(poly.get_num_vars(), r.len()); + assert_eq!(poly_m.get_num_vars(), point.len()); - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(r.len()); + let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(point.len()); let L_size = (2usize).pow(left_num_vars as u32); let R_size = (2usize).pow(right_num_vars as u32); - // compute the L and R vectors (these depend only on the public challenge r so they are public) - let eq = EqPolynomial::new(r.to_vec()); + // compute the L and R vectors (these depend only on the public challenge point so they are public) + let eq = EqPolynomial::new(point.to_vec()); let (L, R) = eq.compute_factored_evals(); assert_eq!(L.len(), L_size); assert_eq!(R.len(), R_size); @@ -108,56 +106,48 @@ where // compute vector-matrix product between L and Z viewed as a matrix let LZ = poly.bound(&L); - // Translation between this stuff and IPA - // LZ = x_vec - // LZ_blind = r_x - // Zr = y - // blind_Zr = r_y - // R = a_vec - - // Commit to LZ and Zr - let com_LZ = G::CE::commit(&self.gens_v, &LZ); - //let com_Zr = G::CE::commit(&self.gens_s, &[*Zr]); + // Commit to LZ + let com_LZ = G::CE::commit(ck, &LZ); // a dot product argument (IPA) of size R_size - let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, Zr); + let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); let ipa_witness = InnerProductWitness::::new(&LZ); let ipa = InnerProductArgument::::prove( - &self.gens_v, - &self.gens_s, + ck, + &pk.ck_s, &ipa_instance, &ipa_witness, transcript, )?; - Ok((ipa, ipa_witness)) + Ok(HyraxEvaluationArgument { ipa }) } - /// Verifies the proof showing the evaluation of a committed polynomial at a random point - pub fn verify_eval( - &self, - r: &[G::Scalar], // point at which the polynomial was evaluated - poly_com: &PolyCommit, - Zr: &G::Scalar, - ipa: &InnerProductArgument, + fn verify( + vk: &Self::VerifierKey, transcript: &mut G::TE, + comm: &PolyCommit, + point: &[G::Scalar], + eval: &G::Scalar, + arg: &Self::EvaluationArgument, ) -> Result<(), SpartanError> { - transcript.absorb(b"poly_com", poly_com); + + transcript.absorb(b"poly_com", comm); // compute L and R - let eq = EqPolynomial::new(r.to_vec()); + let eq = EqPolynomial::new(point.to_vec()); let (L, R) = eq.compute_factored_evals(); // compute a weighted sum of commitments and L - let gens: CommitmentKey = CommitmentKey::::reinterpret_commitments_as_ck(&poly_com.comm)?; + let gens: CommitmentKey = CommitmentKey::::reinterpret_commitments_as_ck(&comm.comm)?; let com_LZ = G::CE::commit(&gens, &L); // computes MSM of commitment and L - let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, Zr); + let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); - ipa.verify( - &self.gens_v, - &self.gens_s, + arg.ipa.verify( + &vk.ck_v, + &vk.ck_s, L.len(), &ipa_instance, transcript, @@ -165,6 +155,86 @@ where } } +/// Structure that holds Poly Commits +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct PolyCommit { + /// Commitment + pub comm: Vec>, +} + + +impl CommitmentTrait for PolyCommit { + type CompressedCommitment = PolyCommit; + + fn compress(&self) -> Self::CompressedCommitment { + self + } + + fn to_coordinates(&self) -> (G::Base, G::Base, bool) { + unimplemented!() + } + + + fn decompress(c: &Self::CompressedCommitment) -> Result { + Ok(c) + } +} + +/// Provides a commitment engine +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct HyraxCommitmentEngine { + _p: PhantomData, +} + +impl CommitmentEngineTrait for HyraxCommitmentEngine { + type CommitmentKey = CommitmentKey; + type Commitment = PolyCommit; + + /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly + fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { + let (_left, right) = EqPolynomial::::compute_factored_lens(n); + let gens_v = G::CE::setup(label, (2usize).pow(right as u32)); + Self::CommitmentKey { + ck: gens_v, + _p: Default::default(), + } + } + + fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { + let poly = MultilinearPolynomial::new(v); + let n = poly.len(); + let ell = poly.get_num_vars(); + assert_eq!(n, (2usize).pow(ell as u32)); + + let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(ell); + let L_size = (2usize).pow(left_num_vars as u32); + let R_size = (2usize).pow(right_num_vars as u32); + assert_eq!(L_size * R_size, n); + + let comm = (0..L_size) + .into_par_iter() + .map(|i| G::CE::commit(ck, &poly.get_Z()[R_size * i..R_size * (i + 1)]).compress()) + .collect(); + + PolyCommit { comm } + } +} + +impl TranscriptReprTrait for PolyCommit { + fn to_transcript_bytes(&self) -> Vec { + let mut v = Vec::new(); + v.append(&mut b"poly_commitment_begin".to_vec()); + + for c in &self.comm { + v.append(&mut c.to_transcript_bytes()); + } + + v.append(&mut b"poly_commitment_end".to_vec()); + v + } +} + #[cfg(test)] mod tests { use super::*; From 6ce34f21a623c6609e7eea1c23a6093125875c69 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Thu, 27 Jul 2023 15:30:26 -0700 Subject: [PATCH 09/24] fix trait requirements, except for one --- src/provider/hyrax_pc.rs | 336 ++++++++++++++++++++++++++------------- src/provider/pedersen.rs | 4 - src/traits/commitment.rs | 4 - 3 files changed, 224 insertions(+), 120 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index c02ecb5..dcdb9d2 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -3,19 +3,224 @@ use crate::{ errors::SpartanError, provider::ipa_pc::{InnerProductArgument, InnerProductInstance, InnerProductWitness}, - provider::pedersen::CommitmentKeyExtTrait, + provider::pedersen::{ + Commitment as PedersenCommitment, CommitmentEngine as PedersenCommitmentEngine, + CommitmentKey as PedersenCommitmentKey, CommitmentKeyExtTrait, + }, spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, evaluation::EvaluationEngineTrait, Group, TranscriptEngineTrait, TranscriptReprTrait, }, - CommitmentKey, CompressedCommitment, + Commitment, CommitmentKey, }; +use core::ops::{Add, AddAssign, Mul, MulAssign}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; +/// Structure that holds Poly Commits +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct PolyCommit { + /// Commitment + comm: Vec>, + is_default: bool, +} + +impl Default for PolyCommit { + fn default() -> Self { + PolyCommit { + comm: vec![], + is_default: true, + } + } +} + +impl CommitmentTrait for PolyCommit { + type CompressedCommitment = PolyCommit; + + fn compress(&self) -> Self::CompressedCommitment { + *self + } + + fn decompress(c: &Self::CompressedCommitment) -> Result { + Ok(*c) + } +} + +impl MulAssign for PolyCommit { + fn mul_assign(&mut self, scalar: G::Scalar) { + let result = (self as &PolyCommit) + .comm + .iter() + .map(|c| c * &scalar) + .collect(); + *self = PolyCommit { + comm: result, + is_default: self.is_default, + }; + } +} + +impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a PolyCommit { + type Output = PolyCommit; + fn mul(self, scalar: &'b G::Scalar) -> PolyCommit { + let result = self.comm.iter().map(|c| c * &scalar).collect(); + PolyCommit { + comm: result, + is_default: self.is_default, + } + } +} + +impl Mul for PolyCommit { + type Output = PolyCommit; + + fn mul(self, scalar: G::Scalar) -> PolyCommit { + let result = self.comm.iter().map(|c| c * &scalar).collect(); + PolyCommit { + comm: result, + is_default: self.is_default, + } + } +} + +impl<'b, G: Group> AddAssign<&'b PolyCommit> for PolyCommit { + fn add_assign(&mut self, other: &'b PolyCommit) { + if self.is_default { + *self = other.clone(); + } else if other.is_default { + return; + } else { + let result = (self as &PolyCommit) + .comm + .iter() + .zip(other.comm.iter()) + .map(|(a, b)| a + b) + .collect(); + *self = PolyCommit { + comm: result, + is_default: self.is_default, + }; + } + } +} + +impl<'a, 'b, G: Group> Add<&'b PolyCommit> for &'a PolyCommit { + type Output = PolyCommit; + fn add(self, other: &'b PolyCommit) -> PolyCommit { + if self.is_default { + return other.clone(); + } else if other.is_default { + return self.clone(); + } else { + let result = self + .comm + .iter() + .zip(other.comm.iter()) + .map(|(a, b)| a + b) + .collect(); + PolyCommit { + comm: result, + is_default: self.is_default, + } + } + } +} + +macro_rules! define_add_variants { + (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty, Output = $out:ty) => { + impl<'b, G: $g> Add<&'b $rhs> for $lhs { + type Output = $out; + fn add(self, rhs: &'b $rhs) -> $out { + &self + rhs + } + } + + impl<'a, G: $g> Add<$rhs> for &'a $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + self + &rhs + } + } + + impl Add<$rhs> for $lhs { + type Output = $out; + fn add(self, rhs: $rhs) -> $out { + &self + &rhs + } + } + }; +} + +macro_rules! define_add_assign_variants { + (G = $g:path, LHS = $lhs:ty, RHS = $rhs:ty) => { + impl AddAssign<$rhs> for $lhs { + fn add_assign(&mut self, rhs: $rhs) { + *self += &rhs; + } + } + }; +} + +define_add_assign_variants!(G = Group, LHS = PolyCommit, RHS = PolyCommit); +define_add_variants!(G = Group, LHS = PolyCommit, RHS = PolyCommit, Output = PolyCommit); + +/// Provides a commitment engine +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct HyraxCommitmentEngine { + _p: PhantomData, +} + +impl CommitmentEngineTrait for HyraxCommitmentEngine { + type CommitmentKey = PedersenCommitmentKey; + type Commitment = PolyCommit; + + /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly + fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { + let (_left, right) = EqPolynomial::::compute_factored_lens(n); + PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)) + } + + fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { + let poly = MultilinearPolynomial::new(v.to_vec()); + let n = poly.len(); + let ell = poly.get_num_vars(); + assert_eq!(n, (2usize).pow(ell as u32)); + + let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(ell); + let L_size = (2usize).pow(left_num_vars as u32); + let R_size = (2usize).pow(right_num_vars as u32); + assert_eq!(L_size * R_size, n); + + let comm = (0..L_size) + .collect::>() + .into_par_iter() + .map(|i| PedersenCommitmentEngine::commit(ck, &poly.get_Z()[R_size * i..R_size * (i + 1)])) + .collect(); + + PolyCommit { + comm, + is_default: false, + } + } +} + +impl TranscriptReprTrait for PolyCommit { + fn to_transcript_bytes(&self) -> Vec { + let mut v = Vec::new(); + v.append(&mut b"poly_commitment_begin".to_vec()); + + for c in &self.comm { + v.append(&mut c.to_transcript_bytes()); + } + + v.append(&mut b"poly_commitment_end".to_vec()); + v + } +} /// Provides an implementation of the hyrax key #[derive(Clone, Debug, Serialize, Deserialize)] @@ -32,8 +237,6 @@ pub struct HyraxVerifierKey { ck_s: CommitmentKey, } - - /// Provides an implementation of a polynomial evaluation argument #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] @@ -41,7 +244,6 @@ pub struct HyraxEvaluationArgument { ipa: InnerProductArgument, } - /// Provides an implementation of a polynomial evaluation engine using Hyrax PC #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] @@ -49,7 +251,6 @@ pub struct HyraxEvaluationEngine { _p: PhantomData, } - impl EvaluationEngineTrait for HyraxEvaluationEngine where G: Group, @@ -79,20 +280,20 @@ where ck: &CommitmentKey, pk: &Self::ProverKey, transcript: &mut G::TE, - comm: &PolyCommit, + comm: &Commitment, poly: &[G::Scalar], point: &[G::Scalar], eval: &G::Scalar, ) -> Result { - transcript.absorb(b"poly_com", comm); - - let poly_m = MultilinearPolynomial::::new(poly); - + + let poly_m = MultilinearPolynomial::::new(poly.to_vec()); + // assert vectors are of the right size assert_eq!(poly_m.get_num_vars(), point.len()); - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(point.len()); + let (left_num_vars, right_num_vars) = + EqPolynomial::::compute_factored_lens(point.len()); let L_size = (2usize).pow(left_num_vars as u32); let R_size = (2usize).pow(right_num_vars as u32); @@ -104,21 +305,16 @@ where // compute the vector underneath L*Z // compute vector-matrix product between L and Z viewed as a matrix - let LZ = poly.bound(&L); + let LZ = poly_m.bound(&L); - // Commit to LZ + // Commit to LZ let com_LZ = G::CE::commit(ck, &LZ); // a dot product argument (IPA) of size R_size let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); let ipa_witness = InnerProductWitness::::new(&LZ); - let ipa = InnerProductArgument::::prove( - ck, - &pk.ck_s, - &ipa_instance, - &ipa_witness, - transcript, - )?; + let ipa = + InnerProductArgument::::prove(ck, &pk.ck_s, &ipa_instance, &ipa_witness, transcript)?; Ok(HyraxEvaluationArgument { ipa }) } @@ -126,12 +322,11 @@ where fn verify( vk: &Self::VerifierKey, transcript: &mut G::TE, - comm: &PolyCommit, + comm: &Commitment, point: &[G::Scalar], eval: &G::Scalar, arg: &Self::EvaluationArgument, ) -> Result<(), SpartanError> { - transcript.absorb(b"poly_com", comm); // compute L and R @@ -139,99 +334,16 @@ where let (L, R) = eq.compute_factored_evals(); // compute a weighted sum of commitments and L - let gens: CommitmentKey = CommitmentKey::::reinterpret_commitments_as_ck(&comm.comm)?; + let gens: PedersenCommitmentKey = + PedersenCommitmentKey::::reinterpret_commitments_as_ck(&comm.comm)?; - let com_LZ = G::CE::commit(&gens, &L); // computes MSM of commitment and L + let com_LZ = PedersenCommitmentEngine::commit(&gens, &L); // computes MSM of commitment and L let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); - arg.ipa.verify( - &vk.ck_v, - &vk.ck_s, - L.len(), - &ipa_instance, - transcript, - ) - } -} - -/// Structure that holds Poly Commits -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(bound = "")] -pub struct PolyCommit { - /// Commitment - pub comm: Vec>, -} - - -impl CommitmentTrait for PolyCommit { - type CompressedCommitment = PolyCommit; - - fn compress(&self) -> Self::CompressedCommitment { - self - } - - fn to_coordinates(&self) -> (G::Base, G::Base, bool) { - unimplemented!() - } - - - fn decompress(c: &Self::CompressedCommitment) -> Result { - Ok(c) - } -} - -/// Provides a commitment engine -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct HyraxCommitmentEngine { - _p: PhantomData, -} - -impl CommitmentEngineTrait for HyraxCommitmentEngine { - type CommitmentKey = CommitmentKey; - type Commitment = PolyCommit; - - /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly - fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { - let (_left, right) = EqPolynomial::::compute_factored_lens(n); - let gens_v = G::CE::setup(label, (2usize).pow(right as u32)); - Self::CommitmentKey { - ck: gens_v, - _p: Default::default(), - } - } - - fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { - let poly = MultilinearPolynomial::new(v); - let n = poly.len(); - let ell = poly.get_num_vars(); - assert_eq!(n, (2usize).pow(ell as u32)); - - let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(ell); - let L_size = (2usize).pow(left_num_vars as u32); - let R_size = (2usize).pow(right_num_vars as u32); - assert_eq!(L_size * R_size, n); - - let comm = (0..L_size) - .into_par_iter() - .map(|i| G::CE::commit(ck, &poly.get_Z()[R_size * i..R_size * (i + 1)]).compress()) - .collect(); - - PolyCommit { comm } - } -} - -impl TranscriptReprTrait for PolyCommit { - fn to_transcript_bytes(&self) -> Vec { - let mut v = Vec::new(); - v.append(&mut b"poly_commitment_begin".to_vec()); - - for c in &self.comm { - v.append(&mut c.to_transcript_bytes()); - } - - v.append(&mut b"poly_commitment_end".to_vec()); - v + arg + .ipa + .verify(&vk.ck_v, &vk.ck_s, L.len(), &ipa_instance, transcript) } } diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index 3d687b4..b659cda 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -43,10 +43,6 @@ impl CommitmentTrait for Commitment { } } - fn to_coordinates(&self) -> (G::Base, G::Base, bool) { - self.comm.to_coordinates() - } - fn decompress(c: &Self::CompressedCommitment) -> Result { let comm = c.comm.decompress(); if comm.is_none() { diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 2b13b6e..5599e09 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -40,7 +40,6 @@ impl ScalarMul for T where T: Mul: Clone - + Copy + Debug + Default + PartialEq @@ -68,9 +67,6 @@ pub trait CommitmentTrait: /// Compresses self into a compressed commitment fn compress(&self) -> Self::CompressedCommitment; - /// Returns the coordinate representation of the commitment - fn to_coordinates(&self) -> (G::Base, G::Base, bool); - /// Decompresses a compressed commitment into a commitment fn decompress(c: &Self::CompressedCommitment) -> Result; } From aa07afcfa0aef4719706e9be42b6e5d6a602e4e7 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 11:55:59 -0700 Subject: [PATCH 10/24] checkpoint --- src/provider/hyrax_pc.rs | 142 ++++++++++++++++++++++++++------------- src/provider/ipa_pc.rs | 98 +++++++++++++++++---------- src/provider/pedersen.rs | 73 +++++++++++++++----- src/traits/commitment.rs | 1 + 4 files changed, 219 insertions(+), 95 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index dcdb9d2..b189aa1 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -5,7 +5,8 @@ use crate::{ provider::ipa_pc::{InnerProductArgument, InnerProductInstance, InnerProductWitness}, provider::pedersen::{ Commitment as PedersenCommitment, CommitmentEngine as PedersenCommitmentEngine, - CommitmentKey as PedersenCommitmentKey, CommitmentKeyExtTrait, + CommitmentEngineExtTrait, CommitmentKey as PedersenCommitmentKey, + CompressedCommitment as PedersenCompressedCommitment, }, spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, traits::{ @@ -20,87 +21,113 @@ use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; -/// Structure that holds Poly Commits +/// A type that holds commitment generators for Hyrax commitments +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxCommitmentKey { + ck: PedersenCommitmentKey, + _p: PhantomData, +} + +/// Structure that holds commitments #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(bound = "")] -pub struct PolyCommit { - /// Commitment +pub struct HyraxCommitment { comm: Vec>, is_default: bool, } -impl Default for PolyCommit { +/// Structure that holds compressed commitments +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +#[serde(bound = "")] +pub struct HyraxCompressedCommitment { + comm: Vec>, + is_default: bool, +} + +impl Default for HyraxCommitment { fn default() -> Self { - PolyCommit { + HyraxCommitment { comm: vec![], is_default: true, } } } -impl CommitmentTrait for PolyCommit { - type CompressedCommitment = PolyCommit; +impl CommitmentTrait for HyraxCommitment { + type CompressedCommitment = HyraxCompressedCommitment; fn compress(&self) -> Self::CompressedCommitment { - *self + HyraxCompressedCommitment { + comm: self.comm.iter().map(|c| c.compress()).collect::>(), + is_default: self.is_default, + } } fn decompress(c: &Self::CompressedCommitment) -> Result { - Ok(*c) + let comm = c + .comm + .iter() + .map(|c| as CommitmentTrait>::decompress(c)) + .collect::, _>>()?; + Ok(HyraxCommitment { + comm, + is_default: c.is_default, + }) } } -impl MulAssign for PolyCommit { +impl MulAssign for HyraxCommitment { fn mul_assign(&mut self, scalar: G::Scalar) { - let result = (self as &PolyCommit) + let result = (self as &HyraxCommitment) .comm .iter() .map(|c| c * &scalar) .collect(); - *self = PolyCommit { + *self = HyraxCommitment { comm: result, is_default: self.is_default, }; } } -impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a PolyCommit { - type Output = PolyCommit; - fn mul(self, scalar: &'b G::Scalar) -> PolyCommit { +impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a HyraxCommitment { + type Output = HyraxCommitment; + fn mul(self, scalar: &'b G::Scalar) -> HyraxCommitment { let result = self.comm.iter().map(|c| c * &scalar).collect(); - PolyCommit { + HyraxCommitment { comm: result, is_default: self.is_default, } } } -impl Mul for PolyCommit { - type Output = PolyCommit; +impl Mul for HyraxCommitment { + type Output = HyraxCommitment; - fn mul(self, scalar: G::Scalar) -> PolyCommit { + fn mul(self, scalar: G::Scalar) -> HyraxCommitment { let result = self.comm.iter().map(|c| c * &scalar).collect(); - PolyCommit { + HyraxCommitment { comm: result, is_default: self.is_default, } } } -impl<'b, G: Group> AddAssign<&'b PolyCommit> for PolyCommit { - fn add_assign(&mut self, other: &'b PolyCommit) { +impl<'b, G: Group> AddAssign<&'b HyraxCommitment> for HyraxCommitment { + fn add_assign(&mut self, other: &'b HyraxCommitment) { if self.is_default { *self = other.clone(); } else if other.is_default { return; } else { - let result = (self as &PolyCommit) + let result = (self as &HyraxCommitment) .comm .iter() .zip(other.comm.iter()) .map(|(a, b)| a + b) .collect(); - *self = PolyCommit { + *self = HyraxCommitment { comm: result, is_default: self.is_default, }; @@ -108,9 +135,9 @@ impl<'b, G: Group> AddAssign<&'b PolyCommit> for PolyCommit { } } -impl<'a, 'b, G: Group> Add<&'b PolyCommit> for &'a PolyCommit { - type Output = PolyCommit; - fn add(self, other: &'b PolyCommit) -> PolyCommit { +impl<'a, 'b, G: Group> Add<&'b HyraxCommitment> for &'a HyraxCommitment { + type Output = HyraxCommitment; + fn add(self, other: &'b HyraxCommitment) -> HyraxCommitment { if self.is_default { return other.clone(); } else if other.is_default { @@ -122,7 +149,7 @@ impl<'a, 'b, G: Group> Add<&'b PolyCommit> for &'a PolyCommit { .zip(other.comm.iter()) .map(|(a, b)| a + b) .collect(); - PolyCommit { + HyraxCommitment { comm: result, is_default: self.is_default, } @@ -165,8 +192,8 @@ macro_rules! define_add_assign_variants { }; } -define_add_assign_variants!(G = Group, LHS = PolyCommit, RHS = PolyCommit); -define_add_variants!(G = Group, LHS = PolyCommit, RHS = PolyCommit, Output = PolyCommit); +define_add_assign_variants!(G = Group, LHS = HyraxCommitment, RHS = HyraxCommitment); +define_add_variants!(G = Group, LHS = HyraxCommitment, RHS = HyraxCommitment, Output = HyraxCommitment); /// Provides a commitment engine #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] @@ -175,13 +202,17 @@ pub struct HyraxCommitmentEngine { } impl CommitmentEngineTrait for HyraxCommitmentEngine { - type CommitmentKey = PedersenCommitmentKey; - type Commitment = PolyCommit; + type CommitmentKey = HyraxCommitmentKey; + type Commitment = HyraxCommitment; /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { let (_left, right) = EqPolynomial::::compute_factored_lens(n); - PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)) + let ck = PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)); + HyraxCommitmentKey { + ck, + _p: Default::default(), + } } fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { @@ -198,17 +229,33 @@ impl CommitmentEngineTrait for HyraxCommitmentEngine { let comm = (0..L_size) .collect::>() .into_par_iter() - .map(|i| PedersenCommitmentEngine::commit(ck, &poly.get_Z()[R_size * i..R_size * (i + 1)])) + .map(|i| { + PedersenCommitmentEngine::commit(&ck.ck, &poly.get_Z()[R_size * i..R_size * (i + 1)]) + }) .collect(); - PolyCommit { + HyraxCommitment { comm, is_default: false, } } } -impl TranscriptReprTrait for PolyCommit { +impl TranscriptReprTrait for HyraxCommitment { + fn to_transcript_bytes(&self) -> Vec { + let mut v = Vec::new(); + v.append(&mut b"poly_commitment_begin".to_vec()); + + for c in &self.comm { + v.append(&mut c.to_transcript_bytes()); + } + + v.append(&mut b"poly_commitment_end".to_vec()); + v + } +} + +impl TranscriptReprTrait for HyraxCompressedCommitment { fn to_transcript_bytes(&self) -> Vec { let mut v = Vec::new(); v.append(&mut b"poly_commitment_begin".to_vec()); @@ -253,8 +300,7 @@ pub struct HyraxEvaluationEngine { impl EvaluationEngineTrait for HyraxEvaluationEngine where - G: Group, - CommitmentKey: CommitmentKeyExtTrait, + G: Group>, { type CE = G::CE; type ProverKey = HyraxProverKey; @@ -308,13 +354,18 @@ where let LZ = poly_m.bound(&L); // Commit to LZ - let com_LZ = G::CE::commit(ck, &LZ); + let com_LZ = PedersenCommitmentEngine::commit(&ck.ck, &LZ); // a dot product argument (IPA) of size R_size let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); let ipa_witness = InnerProductWitness::::new(&LZ); - let ipa = - InnerProductArgument::::prove(ck, &pk.ck_s, &ipa_instance, &ipa_witness, transcript)?; + let ipa = InnerProductArgument::::prove( + &ck.ck, + &pk.ck_s.ck, + &ipa_instance, + &ipa_witness, + transcript, + )?; Ok(HyraxEvaluationArgument { ipa }) } @@ -334,16 +385,15 @@ where let (L, R) = eq.compute_factored_evals(); // compute a weighted sum of commitments and L - let gens: PedersenCommitmentKey = - PedersenCommitmentKey::::reinterpret_commitments_as_ck(&comm.comm)?; + let ck = PedersenCommitmentEngine::reinterpret_commitments_as_ck(&comm.comm); - let com_LZ = PedersenCommitmentEngine::commit(&gens, &L); // computes MSM of commitment and L + let com_LZ = PedersenCommitmentEngine::commit(&ck, &L); // computes MSM of commitment and L let ipa_instance = InnerProductInstance::::new(&com_LZ, &R, eval); arg .ipa - .verify(&vk.ck_v, &vk.ck_s, L.len(), &ipa_instance, transcript) + .verify(&vk.ck_v.ck, &vk.ck_s.ck, L.len(), &ipa_instance, transcript) } } diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index aa9ba4b..ee65524 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -2,14 +2,23 @@ #![allow(clippy::too_many_arguments)] use crate::{ errors::SpartanError, +<<<<<<< HEAD provider::pedersen::CommitmentKeyExtTrait, spartan::polys::eq::EqPolynomial, +======= + provider::pedersen::{ + Commitment as PedersenCommitment, CommitmentEngine as PedersenCommitmentEngine, + CommitmentEngineExtTrait, CommitmentKey as PedersenCommitmentKey, + CompressedCommitment as PedersenCompressedCommitment, + }, + spartan::polynomial::EqPolynomial, +>>>>>>> checkpoint traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, evaluation::EvaluationEngineTrait, Group, TranscriptEngineTrait, TranscriptReprTrait, }, - Commitment, CommitmentKey, CompressedCommitment, CE, + Commitment, CommitmentKey, }; use core::iter; use ff::Field; @@ -113,14 +122,14 @@ where /// An inner product instance consists of a commitment to a vector `a` and another vector `b` /// and the claim that c = . pub struct InnerProductInstance { - comm_a_vec: Commitment, + comm_a_vec: PedersenCommitment, b_vec: Vec, c: G::Scalar, } impl InnerProductInstance { /// Creates a new inner product instance - pub fn new(comm_a_vec: &Commitment, b_vec: &[G::Scalar], c: &G::Scalar) -> Self { + pub fn new(comm_a_vec: &PedersenCommitment, b_vec: &[G::Scalar], c: &G::Scalar) -> Self { InnerProductInstance { comm_a_vec: *comm_a_vec, b_vec: b_vec.to_vec(), @@ -158,31 +167,36 @@ impl InnerProductWitness { #[derive(Clone, Debug, Serialize, Deserialize)] #[serde(bound = "")] pub struct InnerProductArgument { - L_vec: Vec>, - R_vec: Vec>, + L_vec: Vec>, + R_vec: Vec>, a_hat: G::Scalar, } +<<<<<<< HEAD impl InnerProductArgument where G: Group, CommitmentKey: CommitmentKeyExtTrait, { const fn protocol_name() -> &'static [u8] { +======= +impl InnerProductArgument { + fn protocol_name() -> &'static [u8] { +>>>>>>> checkpoint b"IPA" } /// Proves an inner product relationship pub fn prove( - ck: &CommitmentKey, - ck_c: &CommitmentKey, + ck: &PedersenCommitmentKey, + ck_c: &PedersenCommitmentKey, U: &InnerProductInstance, W: &InnerProductWitness, transcript: &mut G::TE, ) -> Result { transcript.dom_sep(Self::protocol_name()); - let (ck, _) = ck.split_at(U.b_vec.len()); + let (ck, _) = PedersenCommitmentEngine::::split_at(ck, U.b_vec.len()); if U.b_vec.len() != W.a_vec.len() { return Err(SpartanError::InvalidInputLength); @@ -193,31 +207,31 @@ where // sample a random base for commiting to the inner product let r = transcript.squeeze(b"r")?; - let ck_c = ck_c.scale(&r); + let ck_c = PedersenCommitmentEngine::::scale(ck_c, &r); // a closure that executes a step of the recursive inner product argument let prove_inner = |a_vec: &[G::Scalar], b_vec: &[G::Scalar], - ck: &CommitmentKey, + ck: &PedersenCommitmentKey, transcript: &mut G::TE| -> Result< ( - CompressedCommitment, - CompressedCommitment, + PedersenCompressedCommitment, + PedersenCompressedCommitment, Vec, Vec, - CommitmentKey, + PedersenCommitmentKey, ), SpartanError, > { let n = a_vec.len(); - let (ck_L, ck_R) = ck.split_at(n / 2); + let (ck_L, ck_R) = PedersenCommitmentEngine::split_at(ck, n / 2); let c_L = inner_product(&a_vec[0..n / 2], &b_vec[n / 2..n]); let c_R = inner_product(&a_vec[n / 2..n], &b_vec[0..n / 2]); - let L = CE::::commit( - &ck_R.combine(&ck_c), + let L = PedersenCommitmentEngine::commit( + &PedersenCommitmentEngine::combine(&ck_R, &ck_c), &a_vec[0..n / 2] .iter() .chain(iter::once(&c_L)) @@ -225,8 +239,8 @@ where .collect::>(), ) .compress(); - let R = CE::::commit( - &ck_L.combine(&ck_c), + let R = PedersenCommitmentEngine::commit( + &PedersenCommitmentEngine::combine(&ck_L, &ck_c), &a_vec[n / 2..n] .iter() .chain(iter::once(&c_R)) @@ -254,14 +268,14 @@ where .map(|(b_L, b_R)| *b_L * r_inverse + r * *b_R) .collect::>(); - let ck_folded = ck.fold(&r_inverse, &r); + let ck_folded = PedersenCommitmentEngine::fold(&ck, &r_inverse, &r); Ok((L, R, a_vec_folded, b_vec_folded, ck_folded)) }; // two vectors to hold the logarithmic number of group elements - let mut L_vec: Vec> = Vec::new(); - let mut R_vec: Vec> = Vec::new(); + let mut L_vec: Vec> = Vec::new(); + let mut R_vec: Vec> = Vec::new(); // we create mutable copies of vectors and generators let mut a_vec = W.a_vec.to_vec(); @@ -288,13 +302,13 @@ where /// Verifies an inner product relationship pub fn verify( &self, - ck: &CommitmentKey, - ck_c: &CommitmentKey, + ck: &PedersenCommitmentKey, + ck_c: &PedersenCommitmentKey, n: usize, U: &InnerProductInstance, transcript: &mut G::TE, ) -> Result<(), SpartanError> { - let (ck, _) = ck.split_at(U.b_vec.len()); + let (ck, _) = PedersenCommitmentEngine::split_at(&ck, U.b_vec.len()); transcript.dom_sep(Self::protocol_name()); if U.b_vec.len() != n @@ -310,9 +324,9 @@ where // sample a random base for commiting to the inner product let r = transcript.squeeze(b"r")?; - let ck_c = ck_c.scale(&r); + let ck_c = PedersenCommitmentEngine::scale(&ck_c, &r); - let P = U.comm_a_vec + CE::::commit(&ck_c, &[U.c]); + let P = U.comm_a_vec + PedersenCommitmentEngine::::commit(&ck_c, &[U.c]); let batch_invert = |v: &[G::Scalar]| -> Result, SpartanError> { let mut products = vec![G::Scalar::ZERO; v.len()]; @@ -379,21 +393,32 @@ where }; let ck_hat = { - let c = CE::::commit(&ck, &s).compress(); - CommitmentKey::::reinterpret_commitments_as_ck(&[c])? + let c = PedersenCommitmentEngine::::commit(&ck, &s); + PedersenCommitmentEngine::::reinterpret_commitments_as_ck(&[c]) }; let b_hat = inner_product(&U.b_vec, &s); let P_hat = { let ck_folded = { - let ck_L = CommitmentKey::::reinterpret_commitments_as_ck(&self.L_vec)?; - let ck_R = CommitmentKey::::reinterpret_commitments_as_ck(&self.R_vec)?; - let ck_P = CommitmentKey::::reinterpret_commitments_as_ck(&[P.compress()])?; - ck_L.combine(&ck_R).combine(&ck_P) + let L_vec_decomp = self + .L_vec + .iter() + .map(|L| PedersenCommitment::::decompress(&L)) + .collect::, _>>()?; + let R_vec_decomp = self + .R_vec + .iter() + .map(|R| PedersenCommitment::::decompress(&R)) + .collect::, _>>()?; + + let ck_L = PedersenCommitmentEngine::::reinterpret_commitments_as_ck(&L_vec_decomp); + let ck_R = PedersenCommitmentEngine::::reinterpret_commitments_as_ck(&R_vec_decomp); + let ck_P = PedersenCommitmentEngine::::reinterpret_commitments_as_ck(&[P]); + PedersenCommitmentEngine::combine(&PedersenCommitmentEngine::combine(&ck_L, &ck_R), &ck_P) }; - CE::::commit( + PedersenCommitmentEngine::::commit( &ck_folded, &r_square .iter() @@ -404,7 +429,12 @@ where ) }; - if P_hat == CE::::commit(&ck_hat.combine(&ck_c), &[self.a_hat, self.a_hat * b_hat]) { + if P_hat + == PedersenCommitmentEngine::::commit( + &PedersenCommitmentEngine::combine(&ck_hat, &ck_c), + &[self.a_hat, self.a_hat * b_hat], + ) + { Ok(()) } else { Err(SpartanError::InvalidIPA) diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index b659cda..c0ba178 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -24,7 +24,7 @@ pub struct CommitmentKey { #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)] #[serde(bound = "")] pub struct Commitment { - pub(crate) comm: G, + comm: G, } /// A type that holds a compressed commitment @@ -186,17 +186,16 @@ impl CommitmentEngineTrait for CommitmentEngine { /// A trait listing properties of a commitment key that can be managed in a divide-and-conquer fashion pub trait CommitmentKeyExtTrait { /// Splits the commitment key into two pieces at a specified point - fn split_at(&self, n: usize) -> (Self, Self) - where - Self: Sized; + fn split_at(ck: &Self::CommitmentKey, n: usize) -> (Self::CommitmentKey, Self::CommitmentKey); /// Combines two commitment keys into one - fn combine(&self, other: &Self) -> Self; + fn combine(ck: &Self::CommitmentKey, other: &Self::CommitmentKey) -> Self::CommitmentKey; /// Folds the two commitment keys into one using the provided weights - fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> Self; + fn fold(ck: &Self::CommitmentKey, w1: &G::Scalar, w2: &G::Scalar) -> Self::CommitmentKey; /// Scales the commitment key using the provided scalar +<<<<<<< HEAD fn scale(&self, r: &G::Scalar) -> Self; /// Reinterprets commitments as commitment keys @@ -215,25 +214,49 @@ impl>> CommitmentKeyExtTrait for Commitment }, CommitmentKey { ck: self.ck[n..].to_vec(), +======= + fn scale(ck: &Self::CommitmentKey, r: &G::Scalar) -> Self::CommitmentKey; + + /// Reinterprets the commitments as a commitment key + fn reinterpret_commitments_as_ck(commitments: &[Self::Commitment]) -> Self::CommitmentKey; +} + +impl CommitmentEngineExtTrait for CommitmentEngine { + fn split_at(ck: &Self::CommitmentKey, n: usize) -> (Self::CommitmentKey, Self::CommitmentKey) { + ( + CommitmentKey { + ck: ck.ck[0..n].to_vec(), + _p: Default::default(), + }, + CommitmentKey { + ck: ck.ck[n..].to_vec(), + _p: Default::default(), +>>>>>>> checkpoint }, ) } - fn combine(&self, other: &CommitmentKey) -> CommitmentKey { + fn combine(ck: &Self::CommitmentKey, other: &Self::CommitmentKey) -> Self::CommitmentKey { let ck = { - let mut c = self.ck.clone(); + let mut c = ck.ck.clone(); c.extend(other.ck.clone()); c }; +<<<<<<< HEAD CommitmentKey { ck } +======= + Self::CommitmentKey { + ck, + _p: Default::default(), + } +>>>>>>> checkpoint } - // combines the left and right halves of `self` using `w1` and `w2` as the weights - fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentKey { + fn fold(ck: &Self::CommitmentKey, w1: &G::Scalar, w2: &G::Scalar) -> Self::CommitmentKey { let w = vec![*w1, *w2]; - let (L, R) = self.split_at(self.ck.len() / 2); + let (L, R) = Self::split_at(ck, ck.ck.len() / 2); - let ck = (0..self.ck.len() / 2) + let ck = (0..ck.ck.len() / 2) .into_par_iter() .map(|i| { let bases = [L.ck[i].clone(), R.ck[i].clone()].to_vec(); @@ -241,18 +264,25 @@ impl>> CommitmentKeyExtTrait for Commitment }) .collect(); +<<<<<<< HEAD CommitmentKey { ck } +======= + Self::CommitmentKey { + ck, + _p: Default::default(), + } +>>>>>>> checkpoint } - /// Scales each element in `self` by `r` - fn scale(&self, r: &G::Scalar) -> Self { - let ck_scaled = self + fn scale(ck: &Self::CommitmentKey, r: &G::Scalar) -> Self::CommitmentKey { + let ck_scaled = ck .ck .clone() .into_par_iter() .map(|g| G::vartime_multiscalar_mul(&[*r], &[g]).preprocessed()) .collect(); +<<<<<<< HEAD CommitmentKey { ck: ck_scaled } } @@ -267,5 +297,18 @@ impl>> CommitmentKeyExtTrait for Commitment .map(|i| d[i].comm.preprocessed()) .collect(); Ok(CommitmentKey { ck }) +======= + Self::CommitmentKey { + ck: ck_scaled, + _p: Default::default(), + } + } + + fn reinterpret_commitments_as_ck(commitments: &[Self::Commitment]) -> Self::CommitmentKey { + Self::CommitmentKey { + ck: commitments.iter().map(|c| c.comm.preprocessed()).collect(), + _p: Default::default(), + } +>>>>>>> checkpoint } } diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index 5599e09..e15a803 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -40,6 +40,7 @@ impl ScalarMul for T where T: Mul: Clone + + Copy + Debug + Default + PartialEq From 1251d2317d2e5246ac309ddb46c54bb52a12d0a6 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 12:09:06 -0700 Subject: [PATCH 11/24] remove Copy requirement on commitment type --- src/r1cs.rs | 10 +-- src/spartan/mod.rs | 8 ++- src/spartan/polynomial.rs | 4 -- src/spartan/ppsnark.rs | 140 +++++++++++++++++++++----------------- src/spartan/snark.rs | 12 ++-- src/traits/commitment.rs | 1 - 6 files changed, 93 insertions(+), 82 deletions(-) diff --git a/src/r1cs.rs b/src/r1cs.rs index 86c71ce..f4736e7 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -378,7 +378,7 @@ impl R1CSInstance { Err(SpartanError::InvalidInputLength) } else { Ok(R1CSInstance { - comm_W: *comm_W, + comm_W: comm_W.clone(), X: X.to_owned(), }) } @@ -471,7 +471,7 @@ impl RelaxedR1CSInstance { instance: &R1CSInstance, ) -> RelaxedR1CSInstance { let mut r_instance = RelaxedR1CSInstance::default(ck, S); - r_instance.comm_W = instance.comm_W; + r_instance.comm_W = instance.comm_W.clone(); r_instance.u = G::Scalar::ONE; r_instance.X = instance.X.clone(); r_instance @@ -483,7 +483,7 @@ impl RelaxedR1CSInstance { X: &[G::Scalar], ) -> RelaxedR1CSInstance { RelaxedR1CSInstance { - comm_W: *comm_W, + comm_W: comm_W.clone(), comm_E: Commitment::::default(), u: G::Scalar::ONE, X: X.to_vec(), @@ -507,8 +507,8 @@ impl RelaxedR1CSInstance { .zip(X2) .map(|(a, b)| *a + *r * *b) .collect::>(); - let comm_W = *comm_W_1 + *comm_W_2 * *r; - let comm_E = *comm_E_1 + *comm_T * *r; + let comm_W = comm_W_1.clone() + comm_W_2.clone() * *r; + let comm_E = comm_E_1.clone() + comm_T.clone() * *r; let u = *u1 + *r; Ok(RelaxedR1CSInstance { diff --git a/src/spartan/mod.rs b/src/spartan/mod.rs index d8ae008..c0d223f 100644 --- a/src/spartan/mod.rs +++ b/src/spartan/mod.rs @@ -84,7 +84,11 @@ impl PolyEvalInstance { .map(|u| { let mut x = vec![G::Scalar::ZERO; ell - u.x.len()]; x.extend(u.x.clone()); - PolyEvalInstance { c: u.c, x, e: u.e } + PolyEvalInstance { + c: u.c.clone(), + x, + e: u.e, + } }) .collect() } else { @@ -107,7 +111,7 @@ impl PolyEvalInstance { let c = c_vec .iter() .zip(powers_of_s.iter()) - .map(|(c, p)| *c * *p) + .map(|(c, p)| c.clone() * *p) .fold(Commitment::::default(), |acc, item| acc + item); PolyEvalInstance { diff --git a/src/spartan/polynomial.rs b/src/spartan/polynomial.rs index 04d1565..7a6d14e 100644 --- a/src/spartan/polynomial.rs +++ b/src/spartan/polynomial.rs @@ -87,10 +87,6 @@ impl MultilinearPolynomial { self.Z.len() } - pub fn is_empty(&self) -> bool { - self.Z.len() == 0 - } - pub fn bound(&self, L: &[Scalar]) -> Vec { let (left_num_vars, right_num_vars) = EqPolynomial::::compute_factored_lens(self.num_vars); diff --git a/src/spartan/ppsnark.rs b/src/spartan/ppsnark.rs index 4eefd3c..f9bcacd 100644 --- a/src/spartan/ppsnark.rs +++ b/src/spartan/ppsnark.rs @@ -112,15 +112,15 @@ pub struct R1CSShapeSparkCommitment { impl TranscriptReprTrait for R1CSShapeSparkCommitment { fn to_transcript_bytes(&self) -> Vec { [ - self.comm_row, - self.comm_col, - self.comm_val_A, - self.comm_val_B, - self.comm_val_C, - self.comm_row_read_ts, - self.comm_row_audit_ts, - self.comm_col_read_ts, - self.comm_col_audit_ts, + self.comm_row.clone(), + self.comm_col.clone(), + self.comm_val_A.clone(), + self.comm_val_B.clone(), + self.comm_val_C.clone(), + self.comm_row_read_ts.clone(), + self.comm_row_audit_ts.clone(), + self.comm_col_read_ts.clone(), + self.comm_col_audit_ts.clone(), ] .as_slice() .to_transcript_bytes() @@ -232,15 +232,15 @@ impl R1CSShapeSparkRepr { R1CSShapeSparkCommitment { N: self.row.len(), - comm_row: comm_vec[0], - comm_col: comm_vec[1], - comm_val_A: comm_vec[2], - comm_val_B: comm_vec[3], - comm_val_C: comm_vec[4], - comm_row_read_ts: comm_vec[5], - comm_row_audit_ts: comm_vec[6], - comm_col_read_ts: comm_vec[7], - comm_col_audit_ts: comm_vec[8], + comm_row: comm_vec[0].clone(), + comm_col: comm_vec[1].clone(), + comm_val_A: comm_vec[2].clone(), + comm_val_B: comm_vec[3].clone(), + comm_val_C: comm_vec[4].clone(), + comm_row_read_ts: comm_vec[5].clone(), + comm_row_audit_ts: comm_vec[6].clone(), + comm_col_read_ts: comm_vec[7].clone(), + comm_col_audit_ts: comm_vec[8].clone(), } } @@ -951,7 +951,10 @@ impl> RelaxedR1CSSNARKTrait for Relaxe || rayon::join(|| G::CE::commit(&pk.ck, &Bz), || G::CE::commit(&pk.ck, &Cz)), ); - transcript.absorb(b"c", &[comm_Az, comm_Bz, comm_Cz].as_slice()); + transcript.absorb( + b"c", + &[comm_Az.clone(), comm_Bz.clone(), comm_Cz.clone()].as_slice(), + ); // number of rounds of the satisfiability sum-check let num_rounds_sat = pk.S_repr.N.log_2(); @@ -998,13 +1001,16 @@ impl> RelaxedR1CSSNARKTrait for Relaxe &[eval_Az_at_tau, eval_Bz_at_tau, eval_Cz_at_tau].as_slice(), ); // absorb commitments to E_row and E_col in the transcript - transcript.absorb(b"e", &vec![comm_E_row, comm_E_col].as_slice()); + transcript.absorb( + b"e", + &vec![comm_E_row.clone(), comm_E_col.clone()].as_slice(), + ); // add claims about Az, Bz, and Cz to be checked later // since all the three polynomials are opened at tau, // we can combine them into a single polynomial opened at tau let eval_vec = vec![eval_Az_at_tau, eval_Bz_at_tau, eval_Cz_at_tau]; - let comm_vec = vec![comm_Az, comm_Bz, comm_Cz]; + let comm_vec = vec![comm_Az.clone(), comm_Bz.clone(), comm_Cz.clone()]; let poly_vec = vec![&Az, &Bz, &Cz]; transcript.absorb(b"e", &eval_vec.as_slice()); // c_vec is already in the transcript let c = transcript.squeeze(b"c")?; @@ -1213,7 +1219,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe .comm_output_vec .iter() .zip(powers_of_rho.iter()) - .map(|(c, r_i)| *c * *r_i) + .map(|(c, r_i)| c.clone() * *r_i) .fold(Commitment::::default(), |acc, item| acc + item); let weighted_sum = |W: &[Vec], s: &[G::Scalar]| -> Vec { @@ -1241,7 +1247,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe p: poly_output.clone(), }, PolyEvalInstance { - c: comm_output, + c: comm_output.clone(), x: r_sat.clone(), e: eval_output, }, @@ -1258,7 +1264,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe p: poly_output.clone(), }, PolyEvalInstance { - c: comm_output, + c: comm_output.clone(), x, e: product, }, @@ -1268,7 +1274,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe w_u_vec.push(( PolyEvalWitness { p: poly_output }, PolyEvalInstance { - c: comm_output, + c: comm_output.clone(), x: rand_ext[1..].to_vec(), e: eval_output2, }, @@ -1337,14 +1343,14 @@ impl> RelaxedR1CSSNARKTrait for Relaxe eval_col_audit_ts, ]; let comm_vec = [ - pk.S_comm.comm_row, - pk.S_comm.comm_row_read_ts, - comm_E_row, - pk.S_comm.comm_row_audit_ts, - pk.S_comm.comm_col, - pk.S_comm.comm_col_read_ts, - comm_E_col, - pk.S_comm.comm_col_audit_ts, + pk.S_comm.comm_row.clone(), + pk.S_comm.comm_row_read_ts.clone(), + comm_E_row.clone(), + pk.S_comm.comm_row_audit_ts.clone(), + pk.S_comm.comm_col.clone(), + pk.S_comm.comm_col_read_ts.clone(), + comm_E_col.clone(), + pk.S_comm.comm_col_audit_ts.clone(), ]; let poly_vec = [ &pk.S_repr.row, @@ -1365,7 +1371,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe w_u_vec.push(( PolyEvalWitness { p: W.W }, PolyEvalInstance { - c: U.comm_W, + c: U.comm_W.clone(), x: r_prod_unpad[1..].to_vec(), e: eval_W, }, @@ -1376,15 +1382,15 @@ impl> RelaxedR1CSSNARKTrait for Relaxe eval_Az, eval_Bz, eval_Cz, eval_E, eval_E_row, eval_E_col, eval_val_A, eval_val_B, eval_val_C, ]; let comm_vec = [ - comm_Az, - comm_Bz, - comm_Cz, - U.comm_E, - comm_E_row, - comm_E_col, - pk.S_comm.comm_val_A, - pk.S_comm.comm_val_B, - pk.S_comm.comm_val_C, + comm_Az.clone(), + comm_Bz.clone(), + comm_Cz.clone(), + U.comm_E.clone(), + comm_E_row.clone(), + comm_E_col.clone(), + pk.S_comm.comm_val_A.clone(), + pk.S_comm.comm_val_B.clone(), + pk.S_comm.comm_val_C.clone(), ]; let poly_vec = [ &Az, @@ -1460,7 +1466,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_joint = u_vec_padded .iter() .zip(powers_of_gamma.iter()) - .map(|(u, g_i)| u.c * *g_i) + .map(|(u, g_i)| u.c.clone() * *g_i) .fold(Commitment::::default(), |acc, item| acc + item); let poly_joint = PolyEvalWitness::weighted_sum(&w_vec_padded, &powers_of_gamma); let eval_joint = claims_batch_left @@ -1551,7 +1557,10 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_E_row = Commitment::::decompress(&self.comm_E_row)?; let comm_E_col = Commitment::::decompress(&self.comm_E_col)?; - transcript.absorb(b"c", &[comm_Az, comm_Bz, comm_Cz].as_slice()); + transcript.absorb( + b"c", + &[comm_Az.clone(), comm_Bz.clone(), comm_Cz.clone()].as_slice(), + ); let num_rounds_sat = vk.S_comm.N.log_2(); let tau = (0..num_rounds_sat) @@ -1568,7 +1577,10 @@ impl> RelaxedR1CSSNARKTrait for Relaxe .as_slice(), ); - transcript.absorb(b"e", &vec![comm_E_row, comm_E_col].as_slice()); + transcript.absorb( + b"e", + &vec![comm_E_row.clone(), comm_E_col.clone()].as_slice(), + ); // add claims about Az, Bz, and Cz to be checked later // since all the three polynomials are opened at tau, @@ -1578,7 +1590,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe self.eval_Bz_at_tau, self.eval_Cz_at_tau, ]; - let comm_vec = vec![comm_Az, comm_Bz, comm_Cz]; + let comm_vec = vec![comm_Az.clone(), comm_Bz.clone(), comm_Cz.clone()]; transcript.absorb(b"e", &eval_vec.as_slice()); // c_vec is already in the transcript let c = transcript.squeeze(b"c")?; let u = PolyEvalInstance::batch(&comm_vec, &tau, &eval_vec, &c); @@ -1729,7 +1741,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_output = comm_output_vec .iter() .zip(powers_of_rho.iter()) - .map(|(c, r_i)| *c * *r_i) + .map(|(c, r_i)| c.clone() * *r_i) .fold(Commitment::::default(), |acc, item| acc + item); let eval_output2 = self @@ -1741,7 +1753,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // eval_output = output(r_sat) u_vec.push(PolyEvalInstance { - c: comm_output, + c: comm_output.clone(), x: r_sat.clone(), e: eval_output, }); @@ -1753,7 +1765,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe x }; u_vec.push(PolyEvalInstance { - c: comm_output, + c: comm_output.clone(), x, e: product, }); @@ -1795,14 +1807,14 @@ impl> RelaxedR1CSSNARKTrait for Relaxe self.eval_col_audit_ts, ]; let comm_vec = [ - vk.S_comm.comm_row, - vk.S_comm.comm_row_read_ts, - comm_E_row, - vk.S_comm.comm_row_audit_ts, - vk.S_comm.comm_col, - vk.S_comm.comm_col_read_ts, - comm_E_col, - vk.S_comm.comm_col_audit_ts, + vk.S_comm.comm_row.clone(), + vk.S_comm.comm_row_read_ts.clone(), + comm_E_row.clone(), + vk.S_comm.comm_row_audit_ts.clone(), + vk.S_comm.comm_col.clone(), + vk.S_comm.comm_col_read_ts.clone(), + comm_E_col.clone(), + vk.S_comm.comm_col_audit_ts.clone(), ]; let u = PolyEvalInstance::batch(&comm_vec, &r_prod, &eval_vec, &c); @@ -1847,7 +1859,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe }; u_vec.push(PolyEvalInstance { - c: U.comm_W, + c: U.comm_W.clone(), x: r_prod_unpad[1..].to_vec(), e: self.eval_W, }); @@ -1936,12 +1948,12 @@ impl> RelaxedR1CSSNARKTrait for Relaxe comm_Az, comm_Bz, comm_Cz, - U.comm_E, + U.comm_E.clone(), comm_E_row, comm_E_col, - vk.S_comm.comm_val_A, - vk.S_comm.comm_val_B, - vk.S_comm.comm_val_C, + vk.S_comm.comm_val_A.clone(), + vk.S_comm.comm_val_B.clone(), + vk.S_comm.comm_val_C.clone(), ]; transcript.absorb(b"e", &eval_vec.as_slice()); // c_vec is already in the transcript let c = transcript.squeeze(b"c")?; @@ -1993,7 +2005,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_joint = u_vec_padded .iter() .zip(powers_of_gamma.iter()) - .map(|(u, g_i)| u.c * *g_i) + .map(|(u, g_i)| u.c.clone() * *g_i) .fold(Commitment::::default(), |acc, item| acc + item); let eval_joint = self .evals_batch_arr diff --git a/src/spartan/snark.rs b/src/spartan/snark.rs index a1ad696..157aab3 100644 --- a/src/spartan/snark.rs +++ b/src/spartan/snark.rs @@ -271,7 +271,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe w_u_vec.push(( PolyEvalWitness { p: W.W.clone() }, PolyEvalInstance { - c: U.comm_W, + c: U.comm_W.clone(), x: r_y[1..].to_vec(), e: eval_W, }, @@ -280,7 +280,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe w_u_vec.push(( PolyEvalWitness { p: W.E }, PolyEvalInstance { - c: U.comm_E, + c: U.comm_E.clone(), x: r_x, e: eval_E, }, @@ -343,7 +343,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_joint = u_vec_padded .iter() .zip(powers_of_gamma.iter()) - .map(|(u, g_i)| u.c * *g_i) + .map(|(u, g_i)| u.c.clone() * *g_i) .fold(Commitment::::default(), |acc, item| acc + item); let poly_joint = PolyEvalWitness::weighted_sum(&w_vec_padded, &powers_of_gamma); let eval_joint = claims_batch_left @@ -486,12 +486,12 @@ impl> RelaxedR1CSSNARKTrait for Relaxe // add claims about W and E polynomials let u_vec: Vec> = vec![ PolyEvalInstance { - c: U.comm_W, + c: U.comm_W.clone(), x: r_y[1..].to_vec(), e: self.eval_W, }, PolyEvalInstance { - c: U.comm_E, + c: U.comm_E.clone(), x: r_x, e: self.eval_E, }, @@ -542,7 +542,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe let comm_joint = u_vec_padded .iter() .zip(powers_of_gamma.iter()) - .map(|(u, g_i)| u.c * *g_i) + .map(|(u, g_i)| u.c.clone() * *g_i) .fold(Commitment::::default(), |acc, item| acc + item); let eval_joint = self .evals_batch diff --git a/src/traits/commitment.rs b/src/traits/commitment.rs index e15a803..5599e09 100644 --- a/src/traits/commitment.rs +++ b/src/traits/commitment.rs @@ -40,7 +40,6 @@ impl ScalarMul for T where T: Mul: Clone - + Copy + Debug + Default + PartialEq From 8c99733a6a599285452e76950de2b6d0acbebb20 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 12:37:54 -0700 Subject: [PATCH 12/24] fix an issue --- src/lib.rs | 18 ++--- src/provider/bn256_grumpkin.rs | 140 +++++++++++++++++++++++++++++++++ src/provider/hyrax_pc.rs | 113 ++------------------------ src/provider/pasta.rs | 4 +- src/provider/pedersen.rs | 4 + 5 files changed, 161 insertions(+), 118 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5a60502..7d84715 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -151,27 +151,27 @@ mod tests { } #[test] - fn test_snark() { + fn test_snark_hyrax_pc() { type G = pasta_curves::pallas::Point; - type EE = crate::provider::ipa_pc::EvaluationEngine; + type EE = crate::provider::hyrax_pc::HyraxEvaluationEngine; type S = crate::spartan::snark::RelaxedR1CSSNARK; - type Spp = crate::spartan::ppsnark::RelaxedR1CSSNARK; + //type Spp = crate::spartan::ppsnark::RelaxedR1CSSNARK; test_snark_with::(); - test_snark_with::(); + //test_snark_with::(); type G2 = bn256::Point; - type EE2 = crate::provider::ipa_pc::EvaluationEngine; + type EE2 = crate::provider::hyrax_pc::HyraxEvaluationEngine; type S2 = crate::spartan::snark::RelaxedR1CSSNARK; - type S2pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; + //type S2pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; test_snark_with::(); - test_snark_with::(); + //test_snark_with::(); type G3 = secp256k1::Point; type EE3 = crate::provider::ipa_pc::EvaluationEngine; type S3 = crate::spartan::snark::RelaxedR1CSSNARK; - type S3pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; + //type S3pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; test_snark_with::(); - test_snark_with::(); + //test_snark_with::(); } fn test_snark_with>() { diff --git a/src/provider/bn256_grumpkin.rs b/src/provider/bn256_grumpkin.rs index eb3fc9f..4cc2640 100644 --- a/src/provider/bn256_grumpkin.rs +++ b/src/provider/bn256_grumpkin.rs @@ -36,6 +36,146 @@ pub mod grumpkin { }; } +<<<<<<< HEAD +======= +// This implementation behaves in ways specific to the bn256/grumpkin curves in: +// - to_coordinates, +// - vartime_multiscalar_mul, where it does not call into accelerated implementations. +macro_rules! impl_traits { + ( + $name:ident, + $name_compressed:ident, + $name_curve:ident, + $name_curve_affine:ident, + $order_str:literal + ) => { + impl Group for $name::Point { + type Base = $name::Base; + type Scalar = $name::Scalar; + type CompressedGroupElement = $name_compressed; + type PreprocessedGroupElement = $name::Affine; + type TE = Keccak256Transcript; + type CE = HyraxCommitmentEngine; + + fn vartime_multiscalar_mul( + scalars: &[Self::Scalar], + bases: &[Self::PreprocessedGroupElement], + ) -> Self { + cpu_best_multiexp(scalars, bases) + } + + fn preprocessed(&self) -> Self::PreprocessedGroupElement { + self.to_affine() + } + + fn compress(&self) -> Self::CompressedGroupElement { + self.to_bytes() + } + + fn from_label(label: &'static [u8], n: usize) -> Vec { + let mut shake = Shake256::default(); + shake.update(label); + let mut reader = shake.finalize_xof(); + let mut uniform_bytes_vec = Vec::new(); + for _ in 0..n { + let mut uniform_bytes = [0u8; 32]; + reader.read_exact(&mut uniform_bytes).unwrap(); + uniform_bytes_vec.push(uniform_bytes); + } + let gens_proj: Vec<$name_curve> = (0..n) + .collect::>() + .into_par_iter() + .map(|i| { + let hash = $name_curve::hash_to_curve("from_uniform_bytes"); + hash(&uniform_bytes_vec[i]) + }) + .collect(); + + let num_threads = rayon::current_num_threads(); + if gens_proj.len() > num_threads { + let chunk = (gens_proj.len() as f64 / num_threads as f64).ceil() as usize; + (0..num_threads) + .collect::>() + .into_par_iter() + .map(|i| { + let start = i * chunk; + let end = if i == num_threads - 1 { + gens_proj.len() + } else { + core::cmp::min((i + 1) * chunk, gens_proj.len()) + }; + if end > start { + let mut gens = vec![$name_curve_affine::identity(); end - start]; + ::batch_normalize(&gens_proj[start..end], &mut gens); + gens + } else { + vec![] + } + }) + .collect::>>() + .into_par_iter() + .flatten() + .collect() + } else { + let mut gens = vec![$name_curve_affine::identity(); n]; + ::batch_normalize(&gens_proj, &mut gens); + gens + } + } + + fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) { + let coordinates = self.to_affine().coordinates(); + if coordinates.is_some().unwrap_u8() == 1 + // The bn256/grumpkin convention is to define and return the identity point's affine encoding (not None) + && (Self::PreprocessedGroupElement::identity() != self.to_affine()) + { + (*coordinates.unwrap().x(), *coordinates.unwrap().y(), false) + } else { + (Self::Base::zero(), Self::Base::zero(), true) + } + } + + fn get_curve_params() -> (Self::Base, Self::Base, BigInt) { + let A = $name::Point::a(); + let B = $name::Point::b(); + let order = BigInt::from_str_radix($order_str, 16).unwrap(); + + (A, B, order) + } + + fn zero() -> Self { + $name::Point::identity() + } + + fn get_generator() -> Self { + $name::Point::generator() + } + } + + impl PrimeFieldExt for $name::Scalar { + fn from_uniform(bytes: &[u8]) -> Self { + let bytes_arr: [u8; 64] = bytes.try_into().unwrap(); + $name::Scalar::from_uniform_bytes(&bytes_arr) + } + } + + impl TranscriptReprTrait for $name_compressed { + fn to_transcript_bytes(&self) -> Vec { + self.as_ref().to_vec() + } + } + + impl CompressedGroup for $name_compressed { + type GroupElement = $name::Point; + + fn decompress(&self) -> Option<$name::Point> { + Some($name_curve::from_bytes(&self).unwrap()) + } + } + }; +} + +>>>>>>> fix an issue impl TranscriptReprTrait for grumpkin::Base { fn to_transcript_bytes(&self) -> Vec { self.to_repr().to_vec() diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index b189aa1..8576032 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -8,7 +8,10 @@ use crate::{ CommitmentEngineExtTrait, CommitmentKey as PedersenCommitmentKey, CompressedCommitment as PedersenCompressedCommitment, }, - spartan::polynomial::{EqPolynomial, MultilinearPolynomial}, + spartan::{ + math::Math, + polynomial::{EqPolynomial, MultilinearPolynomial}, + }, traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, evaluation::EvaluationEngineTrait, @@ -207,7 +210,8 @@ impl CommitmentEngineTrait for HyraxCommitmentEngine { /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { - let (_left, right) = EqPolynomial::::compute_factored_lens(n); + let num_vars = n.next_power_of_two().log_2() as usize; + let (_left, right) = EqPolynomial::::compute_factored_lens(num_vars); let ck = PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)); HyraxCommitmentKey { ck, @@ -396,108 +400,3 @@ where .verify(&vk.ck_v.ck, &vk.ck_s.ck, L.len(), &ipa_instance, transcript) } } - -#[cfg(test)] -mod tests { - use super::*; - use ff::Field; - type G = pasta_curves::pallas::Point; - use crate::traits::TranscriptEngineTrait; - - fn inner_product(a: &[T], b: &[T]) -> T - where - T: Field + Send + Sync, - { - assert_eq!(a.len(), b.len()); - (0..a.len()) - .into_par_iter() - .map(|i| a[i] * b[i]) - .reduce(|| T::ZERO, |x, y| x + y) - } - - fn evaluate_with_LR( - Z: &[::Scalar], - r: &[::Scalar], - ) -> ::Scalar { - let eq = EqPolynomial::new(r.to_vec()); - let (L, R) = eq.compute_factored_evals(); - - let ell = r.len(); - // ensure ell is even - assert!(ell % 2 == 0); - - // compute n = 2^\ell - let n = (2usize).pow(ell as u32); - - // compute m = sqrt(n) = 2^{\ell/2} - let m = (n as f64).sqrt() as usize; - - // compute vector-matrix product between L and Z viewed as a matrix - let LZ = (0..m) - .map(|i| { - (0..m) - .map(|j| L[j] * Z[j * m + i]) - .fold(::Scalar::ZERO, |acc, item| acc + item) - }) - .collect::::Scalar>>(); - - // compute dot product between LZ and R - inner_product(&LZ, &R) - } - - fn to_scalar(x: usize) -> ::Scalar { - (0..x) - .map(|_i| ::Scalar::ONE) - .fold(::Scalar::ZERO, |acc, item| acc + item) - } - - #[test] - fn check_polynomial_evaluation() { - // Z = [1, 2, 1, 4] - let Z = vec![to_scalar(1), to_scalar(2), to_scalar(1), to_scalar(4)]; - - // r = [4,3] - let r = vec![to_scalar(4), to_scalar(3)]; - - let eval_with_LR = evaluate_with_LR(&Z, &r); - let poly = MultilinearPolynomial::new(Z); - - let eval = poly.evaluate(&r); - assert_eq!(eval, to_scalar(28)); - assert_eq!(eval_with_LR, eval); - } - - #[test] - fn check_hyrax_pc_commit() { - let Z = vec![to_scalar(1), to_scalar(2), to_scalar(1), to_scalar(4)]; - - let poly = MultilinearPolynomial::new(Z); - - // Public stuff - let num_vars = 2; - assert_eq!(num_vars, poly.get_num_vars()); - let r = vec![to_scalar(4), to_scalar(3)]; // r = [4,3] - - // Prover actions - let eval = poly.evaluate(&r); - assert_eq!(eval, to_scalar(28)); - - let prover_gens = HyraxPC::new(num_vars, b"poly_test"); - let poly_comm = prover_gens.commit(&poly); - - let mut prover_transcript = ::TE::new(b"example"); - - let (ipa_proof, _ipa_witness): (InnerProductArgument, InnerProductWitness) = prover_gens - .prove_eval(&poly, &poly_comm, &r, &eval, &mut prover_transcript) - .unwrap(); - - // Verifier actions - - let verifier_gens = HyraxPC::new(num_vars, b"poly_test"); - let mut verifier_transcript = ::TE::new(b"example"); - - let res = - verifier_gens.verify_eval(&r, &poly_comm, &eval, &ipa_proof, &mut verifier_transcript); - assert!(res.is_ok()); - } -} diff --git a/src/provider/pasta.rs b/src/provider/pasta.rs index 9a40f01..75d8614 100644 --- a/src/provider/pasta.rs +++ b/src/provider/pasta.rs @@ -1,6 +1,6 @@ //! This module implements the Spartan traits for `pallas::Point`, `pallas::Scalar`, `vesta::Point`, `vesta::Scalar`. use crate::{ - provider::{cpu_best_multiexp, keccak::Keccak256Transcript, pedersen::CommitmentEngine}, + provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; @@ -58,7 +58,7 @@ macro_rules! impl_traits { type CompressedGroupElement = $name_compressed; type PreprocessedGroupElement = $name::Affine; type TE = Keccak256Transcript; - type CE = CommitmentEngine; + type CE = HyraxCommitmentEngine; #[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))] fn vartime_multiscalar_mul( diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index c0ba178..7b1c36c 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -176,6 +176,10 @@ impl CommitmentEngineTrait for CommitmentEngine { } fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { + if ck.ck.len() < v.len() { + println!("commitment key length: {}", ck.ck.len()); + println!("v length: {}", v.len()); + } assert!(ck.ck.len() >= v.len()); Commitment { comm: G::vartime_multiscalar_mul(v, &ck.ck[..v.len()]), From ddb1e08154576e7d00594801f06b5504df137d00 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 13:30:37 -0700 Subject: [PATCH 13/24] test passes --- src/lib.rs | 1 - src/provider/hyrax_pc.rs | 20 ++++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7d84715..7b9e059 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -162,7 +162,6 @@ mod tests { type G2 = bn256::Point; type EE2 = crate::provider::hyrax_pc::HyraxEvaluationEngine; type S2 = crate::spartan::snark::RelaxedR1CSSNARK; - //type S2pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; test_snark_with::(); //test_snark_with::(); diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 8576032..4683a35 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -20,6 +20,10 @@ use crate::{ Commitment, CommitmentKey, }; use core::ops::{Add, AddAssign, Mul, MulAssign}; +use itertools::{ + EitherOrBoth::{Both, Left, Right}, + Itertools, +}; use rayon::prelude::*; use serde::{Deserialize, Serialize}; use std::marker::PhantomData; @@ -127,8 +131,12 @@ impl<'b, G: Group> AddAssign<&'b HyraxCommitment> for HyraxCommitment { let result = (self as &HyraxCommitment) .comm .iter() - .zip(other.comm.iter()) - .map(|(a, b)| a + b) + .zip_longest(other.comm.iter()) + .map(|x| match x { + Both(a, b) => a + b, + Left(a) => a.clone(), + Right(b) => b.clone(), + }) .collect(); *self = HyraxCommitment { comm: result, @@ -149,8 +157,12 @@ impl<'a, 'b, G: Group> Add<&'b HyraxCommitment> for &'a HyraxCommitment { let result = self .comm .iter() - .zip(other.comm.iter()) - .map(|(a, b)| a + b) + .zip_longest(other.comm.iter()) + .map(|x| match x { + Both(a, b) => a + b, + Left(a) => a.clone(), + Right(b) => b.clone(), + }) .collect(); HyraxCommitment { comm: result, From b19c5ffbf01f8148d163cc1a1ac7c0b0d1d1ae98 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 13:34:18 -0700 Subject: [PATCH 14/24] fix clippy warnings --- src/provider/hyrax_pc.rs | 16 ++++++++-------- src/provider/ipa_pc.rs | 10 +++++----- src/spartan/ppsnark.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 4683a35..39223b5 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -101,7 +101,7 @@ impl MulAssign for HyraxCommitment { impl<'a, 'b, G: Group> Mul<&'b G::Scalar> for &'a HyraxCommitment { type Output = HyraxCommitment; fn mul(self, scalar: &'b G::Scalar) -> HyraxCommitment { - let result = self.comm.iter().map(|c| c * &scalar).collect(); + let result = self.comm.iter().map(|c| c * scalar).collect(); HyraxCommitment { comm: result, is_default: self.is_default, @@ -134,8 +134,8 @@ impl<'b, G: Group> AddAssign<&'b HyraxCommitment> for HyraxCommitment { .zip_longest(other.comm.iter()) .map(|x| match x { Both(a, b) => a + b, - Left(a) => a.clone(), - Right(b) => b.clone(), + Left(a) => *a, + Right(b) => *b, }) .collect(); *self = HyraxCommitment { @@ -150,9 +150,9 @@ impl<'a, 'b, G: Group> Add<&'b HyraxCommitment> for &'a HyraxCommitment { type Output = HyraxCommitment; fn add(self, other: &'b HyraxCommitment) -> HyraxCommitment { if self.is_default { - return other.clone(); + other.clone() } else if other.is_default { - return self.clone(); + self.clone() } else { let result = self .comm @@ -160,8 +160,8 @@ impl<'a, 'b, G: Group> Add<&'b HyraxCommitment> for &'a HyraxCommitment { .zip_longest(other.comm.iter()) .map(|x| match x { Both(a, b) => a + b, - Left(a) => a.clone(), - Right(b) => b.clone(), + Left(a) => *a, + Right(b) => *b, }) .collect(); HyraxCommitment { @@ -222,7 +222,7 @@ impl CommitmentEngineTrait for HyraxCommitmentEngine { /// Derives generators for Hyrax PC, where num_vars is the number of variables in multilinear poly fn setup(label: &'static [u8], n: usize) -> Self::CommitmentKey { - let num_vars = n.next_power_of_two().log_2() as usize; + let num_vars = n.next_power_of_two().log_2(); let (_left, right) = EqPolynomial::::compute_factored_lens(num_vars); let ck = PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)); HyraxCommitmentKey { diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index ee65524..4c8da83 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -268,7 +268,7 @@ impl InnerProductArgument { .map(|(b_L, b_R)| *b_L * r_inverse + r * *b_R) .collect::>(); - let ck_folded = PedersenCommitmentEngine::fold(&ck, &r_inverse, &r); + let ck_folded = PedersenCommitmentEngine::fold(ck, &r_inverse, &r); Ok((L, R, a_vec_folded, b_vec_folded, ck_folded)) }; @@ -308,7 +308,7 @@ impl InnerProductArgument { U: &InnerProductInstance, transcript: &mut G::TE, ) -> Result<(), SpartanError> { - let (ck, _) = PedersenCommitmentEngine::split_at(&ck, U.b_vec.len()); + let (ck, _) = PedersenCommitmentEngine::split_at(ck, U.b_vec.len()); transcript.dom_sep(Self::protocol_name()); if U.b_vec.len() != n @@ -324,7 +324,7 @@ impl InnerProductArgument { // sample a random base for commiting to the inner product let r = transcript.squeeze(b"r")?; - let ck_c = PedersenCommitmentEngine::scale(&ck_c, &r); + let ck_c = PedersenCommitmentEngine::scale(ck_c, &r); let P = U.comm_a_vec + PedersenCommitmentEngine::::commit(&ck_c, &[U.c]); @@ -404,12 +404,12 @@ impl InnerProductArgument { let L_vec_decomp = self .L_vec .iter() - .map(|L| PedersenCommitment::::decompress(&L)) + .map(|L| PedersenCommitment::::decompress(L)) .collect::, _>>()?; let R_vec_decomp = self .R_vec .iter() - .map(|R| PedersenCommitment::::decompress(&R)) + .map(|R| PedersenCommitment::::decompress(R)) .collect::, _>>()?; let ck_L = PedersenCommitmentEngine::::reinterpret_commitments_as_ck(&L_vec_decomp); diff --git a/src/spartan/ppsnark.rs b/src/spartan/ppsnark.rs index f9bcacd..98d6023 100644 --- a/src/spartan/ppsnark.rs +++ b/src/spartan/ppsnark.rs @@ -1274,7 +1274,7 @@ impl> RelaxedR1CSSNARKTrait for Relaxe w_u_vec.push(( PolyEvalWitness { p: poly_output }, PolyEvalInstance { - c: comm_output.clone(), + c: comm_output, x: rand_ext[1..].to_vec(), e: eval_output2, }, From ef280eb6973d3aa559d7e4fc6bb93bc5514fe7cd Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 28 Jul 2023 16:04:44 -0700 Subject: [PATCH 15/24] reduce ck size --- src/r1cs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/r1cs.rs b/src/r1cs.rs index f4736e7..c018f20 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -66,8 +66,7 @@ impl R1CS { let S = S.pad(); // pad the shape before computing the commitment key let num_cons = S.num_cons; let num_vars = S.num_vars; - let total_nz = S.A.len() + S.B.len() + S.C.len(); - G::CE::setup(b"ck", max(max(num_cons, num_vars), total_nz)) + G::CE::setup(b"ck", max(num_cons, num_vars)) } } From ca87bf2e5aa1a15d75c6e6f4f2f95ac137183db5 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 4 Aug 2023 10:32:31 -0700 Subject: [PATCH 16/24] pad shape and witness when created --- src/bellpepper/r1cs.rs | 3 +-- src/errors.rs | 3 +++ src/lib.rs | 8 ++++++++ src/provider/hyrax_pc.rs | 3 ++- src/provider/ipa_pc.rs | 2 +- src/r1cs.rs | 25 ++++++++++++++++++------- 6 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/bellpepper/r1cs.rs b/src/bellpepper/r1cs.rs index 62806a0..cf6e740 100644 --- a/src/bellpepper/r1cs.rs +++ b/src/bellpepper/r1cs.rs @@ -41,8 +41,7 @@ where let X = &self.input_assignment[1..]; let comm_W = W.commit(ck); - - let instance = R1CSInstance::::new(shape, &comm_W, X)?; + let instance = R1CSInstance::::new(&shape, &comm_W, X)?; Ok((instance, W)) } diff --git a/src/errors.rs b/src/errors.rs index 07ff508..e49d2b4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -50,4 +50,7 @@ pub enum SpartanError { /// returned when the consistency with public IO and assignment used fails #[error("IncorrectWitness")] IncorrectWitness, + /// returned when the library encounters an internal error + #[error("InternalError")] + InternalError, } diff --git a/src/lib.rs b/src/lib.rs index 7b9e059..14036c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -128,6 +128,7 @@ mod tests { let y = AllocatedNum::alloc(cs.namespace(|| "y"), || { Ok(x_cu.get_value().unwrap() + x.get_value().unwrap() + F::from(5u64)) })?; + let z = AllocatedNum::alloc(cs.namespace(|| "z"), || Ok(F::from(1u64)))?; cs.enforce( || "y = x^3 + x + 5", @@ -144,6 +145,13 @@ mod tests { |lc| lc + y.get_variable(), ); + cs.enforce( + || "z = 1", + |lc| lc + z.get_variable(), + |lc| lc + CS::one() - z.get_variable(), + |lc| lc, + ); + let _ = y.inputize(cs.namespace(|| "output")); Ok(()) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 39223b5..74c52b2 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -362,6 +362,7 @@ where // compute the L and R vectors (these depend only on the public challenge point so they are public) let eq = EqPolynomial::new(point.to_vec()); let (L, R) = eq.compute_factored_evals(); + assert_eq!(L.len(), L_size); assert_eq!(R.len(), R_size); @@ -409,6 +410,6 @@ where arg .ipa - .verify(&vk.ck_v.ck, &vk.ck_s.ck, L.len(), &ipa_instance, transcript) + .verify(&vk.ck_v.ck, &vk.ck_s.ck, R.len(), &ipa_instance, transcript) } } diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index 4c8da83..dc2816e 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -339,7 +339,7 @@ impl InnerProductArgument { // we can compute an inversion only if acc is non-zero if acc == G::Scalar::ZERO { - return Err(SpartanError::InvalidInputLength); + return Err(SpartanError::InternalError); } // compute the inverse once for all entries diff --git a/src/r1cs.rs b/src/r1cs.rs index c018f20..02fa13d 100644 --- a/src/r1cs.rs +++ b/src/r1cs.rs @@ -111,14 +111,17 @@ impl R1CSShape { return Err(SpartanError::InvalidIndex); } - Ok(R1CSShape { + let shape = R1CSShape { num_cons, num_vars, num_io, A: A.to_owned(), B: B.to_owned(), C: C.to_owned(), - }) + }; + + // pad the shape + Ok(shape.pad()) } // Checks regularity conditions on the R1CSShape, required in Spartan-class SNARKs @@ -353,11 +356,19 @@ impl R1CSShape { impl R1CSWitness { /// A method to create a witness object using a vector of scalars pub fn new(S: &R1CSShape, W: &[G::Scalar]) -> Result, SpartanError> { - if S.num_vars != W.len() { - Err(SpartanError::InvalidWitnessLength) - } else { - Ok(R1CSWitness { W: W.to_owned() }) - } + let w = R1CSWitness { W: W.to_owned() }; + Ok(w.pad(S)) + } + + /// Pads the provided witness to the correct length + pub fn pad(&self, S: &R1CSShape) -> R1CSWitness { + let W = { + let mut W = self.W.clone(); + W.extend(vec![G::Scalar::ZERO; S.num_vars - W.len()]); + W + }; + + Self { W } } /// Commits to the witness using the supplied generators From a80aa1510d11eb490a001f7352407b22723b03c1 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 4 Aug 2023 10:46:25 -0700 Subject: [PATCH 17/24] fix clippy --- src/bellpepper/r1cs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bellpepper/r1cs.rs b/src/bellpepper/r1cs.rs index cf6e740..158670c 100644 --- a/src/bellpepper/r1cs.rs +++ b/src/bellpepper/r1cs.rs @@ -41,7 +41,7 @@ where let X = &self.input_assignment[1..]; let comm_W = W.commit(ck); - let instance = R1CSInstance::::new(&shape, &comm_W, X)?; + let instance = R1CSInstance::::new(shape, &comm_W, X)?; Ok((instance, W)) } From b1de20de124a075d9c07d9db43125fd47ba06e0d Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Tue, 29 Aug 2023 13:06:15 -0700 Subject: [PATCH 18/24] port sha256 bench from nova --- Cargo.toml | 4 ++ benches/sha256.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) create mode 100644 benches/sha256.rs diff --git a/Cargo.toml b/Cargo.toml index 89994ef..8657bb5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,10 @@ cfg-if = "1.0.0" sha2 = "0.10.7" proptest = "1.2.0" +[[bench]] +name = "sha256" +harness = false + [features] default = [] # Compiles in portable mode, w/o ISA extensions => binary can be executed on all systems. diff --git a/benches/sha256.rs b/benches/sha256.rs new file mode 100644 index 0000000..e28ee56 --- /dev/null +++ b/benches/sha256.rs @@ -0,0 +1,153 @@ +//! Benchmarks Spartan's prover for proving SHA-256 with varying sized messages. +//! This code invokes a hand-written SHA-256 gadget from bellman/bellperson. +//! It also uses code from bellman/bellperson to compare circuit-generated digest with sha2 crate's output +#![allow(non_snake_case)] +use bellperson::gadgets::{sha256::sha256, Assignment}; +use bellperson::{gadgets::{ + boolean::{AllocatedBit, Boolean}, + num::{AllocatedNum, Num}}, + Circuit,ConstraintSystem, SynthesisError, +}; +use core::time::Duration; +use criterion::*; +use ff::{PrimeField, PrimeFieldBits}; +use spartan2::{traits::Group,SNARK}; +use sha2::{Digest, Sha256}; +use std::marker::PhantomData; + +type G = pasta_curves::pallas::Point; +type EE = spartan2::provider::hyrax_pc::HyraxEvaluationEngine; +type S = spartan2::spartan::snark::RelaxedR1CSSNARK; + +#[derive(Clone, Debug)] +struct Sha256Circuit { + preimage: Vec, + _p: PhantomData, +} + +impl Sha256Circuit { + pub fn new(preimage: Vec) -> Self { + Self { + preimage, + _p: PhantomData, + } + } +} + +impl Circuit for Sha256Circuit { + fn synthesize>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + let bit_values: Vec<_> = self + .preimage + .clone() + .into_iter() + .flat_map(|byte| (0..8).map(move |i| (byte >> i) & 1u8 == 1u8)) + .map(Some) + .collect(); + assert_eq!(bit_values.len(), self.preimage.len() * 8); + + let preimage_bits = bit_values + .into_iter() + .enumerate() + .map(|(i, b)| AllocatedBit::alloc(cs.namespace(|| format!("preimage bit {i}")), b)) + .map(|b| b.map(Boolean::from)) + .collect::, _>>()?; + + let hash_bits = sha256(cs.namespace(|| "sha256"), &preimage_bits)?; + + for (i, hash_bits) in hash_bits.chunks(256_usize).enumerate() { + let mut num = Num::::zero(); + let mut coeff = Scalar::ONE; + for bit in hash_bits { + num = num.add_bool_with_coeff(CS::one(), bit, coeff); + + coeff = coeff.double(); + } + + let hash = AllocatedNum::alloc(cs.namespace(|| format!("input {i}")), || { + Ok(*num.get_value().get()?) + })?; + + // num * 1 = hash + cs.enforce( + || format!("packing constraint {i}"), + |_| num.lc(Scalar::ONE), + |lc| lc + CS::one(), + |lc| lc + hash.get_variable(), + ); + } + + // sanity check with the hasher + let mut hasher = Sha256::new(); + hasher.update(&self.preimage); + let hash_result = hasher.finalize(); + + let mut s = hash_result + .iter() + .flat_map(|&byte| (0..8).rev().map(move |i| (byte >> i) & 1u8 == 1u8)); + + for b in hash_bits { + match b { + Boolean::Is(b) => { + assert!(s.next().unwrap() == b.get_value().unwrap()); + } + Boolean::Not(b) => { + assert!(s.next().unwrap() != b.get_value().unwrap()); + } + Boolean::Constant(_b) => { + panic!("Can't reach here") + } + } + } + Ok(()) + } +} + +criterion_group! { +name = snark; +config = Criterion::default().warm_up_time(Duration::from_millis(3000)); +targets = bench_snark +} + +criterion_main!(snark); + +fn bench_snark(c: &mut Criterion) { + // Test vectors + let circuits = vec![ + Sha256Circuit::new(vec![0u8; 1 << 6]), + Sha256Circuit::new(vec![0u8; 1 << 7]), + Sha256Circuit::new(vec![0u8; 1 << 8]), + Sha256Circuit::new(vec![0u8; 1 << 9]), + Sha256Circuit::new(vec![0u8; 1 << 10]), + Sha256Circuit::new(vec![0u8; 1 << 11]), + Sha256Circuit::new(vec![0u8; 1 << 12]), + Sha256Circuit::new(vec![0u8; 1 << 13]), + Sha256Circuit::new(vec![0u8; 1 << 14]), + Sha256Circuit::new(vec![0u8; 1 << 15]), + Sha256Circuit::new(vec![0u8; 1 << 16]), + ]; + + for circuit in circuits { + let mut group = c.benchmark_group(format!( + "SpartanProve-Sha256-message-len-{}", + circuit.preimage.len() + )); + group.sample_size(10); + + // produce keys + let (pk, _vk) = + SNARK::::Scalar>>::setup(circuit.clone()).unwrap(); + + group.bench_function("Prove", |b| { + let res = b.iter(|| { + SNARK::::Scalar>>::prove( + black_box(&pk), + black_box(circuit.clone()), + ); + }); + }); + group.finish(); + } +} From 31ee0860787735aae11c8479f32a2782f4ac6ab1 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 29 Sep 2023 13:54:03 -0700 Subject: [PATCH 19/24] fix bench --- Cargo.toml | 3 ++- benches/sha256.rs | 17 +++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8657bb5..9a95822 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,9 @@ license-file = "LICENSE" keywords = ["zkSNARKs", "cryptography", "proofs"] [dependencies] -bellpepper-core = "0.2.1" ff = { version = "0.13.0", features = ["derive"] } +bellpepper-core = { version="0.2.0", default-features = false } +bellpepper = { version="0.2.0", default-features = false } digest = "0.10" sha3 = "0.10" rayon = "1.7" diff --git a/benches/sha256.rs b/benches/sha256.rs index e28ee56..f3c5187 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -2,17 +2,17 @@ //! This code invokes a hand-written SHA-256 gadget from bellman/bellperson. //! It also uses code from bellman/bellperson to compare circuit-generated digest with sha2 crate's output #![allow(non_snake_case)] -use bellperson::gadgets::{sha256::sha256, Assignment}; -use bellperson::{gadgets::{ +use bellpepper::gadgets::{sha256::sha256, Assignment}; +use bellpepper_core::{ boolean::{AllocatedBit, Boolean}, - num::{AllocatedNum, Num}}, - Circuit,ConstraintSystem, SynthesisError, + num::{AllocatedNum, Num}, + Circuit, ConstraintSystem, SynthesisError, }; use core::time::Duration; use criterion::*; use ff::{PrimeField, PrimeFieldBits}; -use spartan2::{traits::Group,SNARK}; use sha2::{Digest, Sha256}; +use spartan2::{traits::Group, SNARK}; use std::marker::PhantomData; type G = pasta_curves::pallas::Point; @@ -35,10 +35,7 @@ impl Sha256Circuit { } impl Circuit for Sha256Circuit { - fn synthesize>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { + fn synthesize>(self, cs: &mut CS) -> Result<(), SynthesisError> { let bit_values: Vec<_> = self .preimage .clone() @@ -141,7 +138,7 @@ fn bench_snark(c: &mut Criterion) { SNARK::::Scalar>>::setup(circuit.clone()).unwrap(); group.bench_function("Prove", |b| { - let res = b.iter(|| { + let _res = b.iter(|| { SNARK::::Scalar>>::prove( black_box(&pk), black_box(circuit.clone()), From 1df4caba62511d12376cb83a8e78c1d815c6a667 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 29 Sep 2023 13:56:12 -0700 Subject: [PATCH 20/24] remove unneeded Phantom --- src/provider/hyrax_pc.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 74c52b2..270795a 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -33,7 +33,6 @@ use std::marker::PhantomData; #[serde(bound = "")] pub struct HyraxCommitmentKey { ck: PedersenCommitmentKey, - _p: PhantomData, } /// Structure that holds commitments @@ -227,7 +226,6 @@ impl CommitmentEngineTrait for HyraxCommitmentEngine { let ck = PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)); HyraxCommitmentKey { ck, - _p: Default::default(), } } From ce0cf51d356eccbc13bb0dd0a57e0132d2f9f15d Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 29 Sep 2023 14:41:15 -0700 Subject: [PATCH 21/24] resolve conflicts --- src/lib.rs | 2 +- src/provider/bn256_grumpkin.rs | 142 +------------------------------ src/provider/hyrax_pc.rs | 8 +- src/provider/ipa_pc.rs | 22 +---- src/provider/mod.rs | 3 +- src/provider/pedersen.rs | 68 ++------------- src/provider/secp_secq.rs | 2 +- src/spartan/polys/eq.rs | 16 ++++ src/spartan/polys/multilinear.rs | 25 +++++- src/traits/evaluation.rs | 3 + 10 files changed, 58 insertions(+), 233 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 14036c3..62c39d8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -174,7 +174,7 @@ mod tests { //test_snark_with::(); type G3 = secp256k1::Point; - type EE3 = crate::provider::ipa_pc::EvaluationEngine; + type EE3 = crate::provider::hyrax_pc::HyraxEvaluationEngine; type S3 = crate::spartan::snark::RelaxedR1CSSNARK; //type S3pp = crate::spartan::ppsnark::RelaxedR1CSSNARK; test_snark_with::(); diff --git a/src/provider/bn256_grumpkin.rs b/src/provider/bn256_grumpkin.rs index 4cc2640..3386d16 100644 --- a/src/provider/bn256_grumpkin.rs +++ b/src/provider/bn256_grumpkin.rs @@ -1,7 +1,7 @@ //! This module implements the Spartan traits for `bn256::Point`, `bn256::Scalar`, `grumpkin::Point`, `grumpkin::Scalar`. use crate::{ impl_traits, - provider::{cpu_best_multiexp, keccak::Keccak256Transcript, pedersen::CommitmentEngine}, + provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; @@ -36,146 +36,6 @@ pub mod grumpkin { }; } -<<<<<<< HEAD -======= -// This implementation behaves in ways specific to the bn256/grumpkin curves in: -// - to_coordinates, -// - vartime_multiscalar_mul, where it does not call into accelerated implementations. -macro_rules! impl_traits { - ( - $name:ident, - $name_compressed:ident, - $name_curve:ident, - $name_curve_affine:ident, - $order_str:literal - ) => { - impl Group for $name::Point { - type Base = $name::Base; - type Scalar = $name::Scalar; - type CompressedGroupElement = $name_compressed; - type PreprocessedGroupElement = $name::Affine; - type TE = Keccak256Transcript; - type CE = HyraxCommitmentEngine; - - fn vartime_multiscalar_mul( - scalars: &[Self::Scalar], - bases: &[Self::PreprocessedGroupElement], - ) -> Self { - cpu_best_multiexp(scalars, bases) - } - - fn preprocessed(&self) -> Self::PreprocessedGroupElement { - self.to_affine() - } - - fn compress(&self) -> Self::CompressedGroupElement { - self.to_bytes() - } - - fn from_label(label: &'static [u8], n: usize) -> Vec { - let mut shake = Shake256::default(); - shake.update(label); - let mut reader = shake.finalize_xof(); - let mut uniform_bytes_vec = Vec::new(); - for _ in 0..n { - let mut uniform_bytes = [0u8; 32]; - reader.read_exact(&mut uniform_bytes).unwrap(); - uniform_bytes_vec.push(uniform_bytes); - } - let gens_proj: Vec<$name_curve> = (0..n) - .collect::>() - .into_par_iter() - .map(|i| { - let hash = $name_curve::hash_to_curve("from_uniform_bytes"); - hash(&uniform_bytes_vec[i]) - }) - .collect(); - - let num_threads = rayon::current_num_threads(); - if gens_proj.len() > num_threads { - let chunk = (gens_proj.len() as f64 / num_threads as f64).ceil() as usize; - (0..num_threads) - .collect::>() - .into_par_iter() - .map(|i| { - let start = i * chunk; - let end = if i == num_threads - 1 { - gens_proj.len() - } else { - core::cmp::min((i + 1) * chunk, gens_proj.len()) - }; - if end > start { - let mut gens = vec![$name_curve_affine::identity(); end - start]; - ::batch_normalize(&gens_proj[start..end], &mut gens); - gens - } else { - vec![] - } - }) - .collect::>>() - .into_par_iter() - .flatten() - .collect() - } else { - let mut gens = vec![$name_curve_affine::identity(); n]; - ::batch_normalize(&gens_proj, &mut gens); - gens - } - } - - fn to_coordinates(&self) -> (Self::Base, Self::Base, bool) { - let coordinates = self.to_affine().coordinates(); - if coordinates.is_some().unwrap_u8() == 1 - // The bn256/grumpkin convention is to define and return the identity point's affine encoding (not None) - && (Self::PreprocessedGroupElement::identity() != self.to_affine()) - { - (*coordinates.unwrap().x(), *coordinates.unwrap().y(), false) - } else { - (Self::Base::zero(), Self::Base::zero(), true) - } - } - - fn get_curve_params() -> (Self::Base, Self::Base, BigInt) { - let A = $name::Point::a(); - let B = $name::Point::b(); - let order = BigInt::from_str_radix($order_str, 16).unwrap(); - - (A, B, order) - } - - fn zero() -> Self { - $name::Point::identity() - } - - fn get_generator() -> Self { - $name::Point::generator() - } - } - - impl PrimeFieldExt for $name::Scalar { - fn from_uniform(bytes: &[u8]) -> Self { - let bytes_arr: [u8; 64] = bytes.try_into().unwrap(); - $name::Scalar::from_uniform_bytes(&bytes_arr) - } - } - - impl TranscriptReprTrait for $name_compressed { - fn to_transcript_bytes(&self) -> Vec { - self.as_ref().to_vec() - } - } - - impl CompressedGroup for $name_compressed { - type GroupElement = $name::Point; - - fn decompress(&self) -> Option<$name::Point> { - Some($name_curve::from_bytes(&self).unwrap()) - } - } - }; -} - ->>>>>>> fix an issue impl TranscriptReprTrait for grumpkin::Base { fn to_transcript_bytes(&self) -> Vec { self.to_repr().to_vec() diff --git a/src/provider/hyrax_pc.rs b/src/provider/hyrax_pc.rs index 270795a..5dfbfa6 100644 --- a/src/provider/hyrax_pc.rs +++ b/src/provider/hyrax_pc.rs @@ -10,7 +10,7 @@ use crate::{ }, spartan::{ math::Math, - polynomial::{EqPolynomial, MultilinearPolynomial}, + polys::{eq::EqPolynomial, multilinear::MultilinearPolynomial}, }, traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, @@ -224,9 +224,7 @@ impl CommitmentEngineTrait for HyraxCommitmentEngine { let num_vars = n.next_power_of_two().log_2(); let (_left, right) = EqPolynomial::::compute_factored_lens(num_vars); let ck = PedersenCommitmentEngine::setup(label, (2usize).pow(right as u32)); - HyraxCommitmentKey { - ck, - } + HyraxCommitmentKey { ck } } fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment { @@ -322,7 +320,7 @@ where type EvaluationArgument = HyraxEvaluationArgument; fn setup( - ck: &>::CommitmentKey, + ck: &<::CE as CommitmentEngineTrait>::CommitmentKey, ) -> (Self::ProverKey, Self::VerifierKey) { let pk = HyraxProverKey:: { ck_s: G::CE::setup(b"hyrax", 1), diff --git a/src/provider/ipa_pc.rs b/src/provider/ipa_pc.rs index dc2816e..64b8648 100644 --- a/src/provider/ipa_pc.rs +++ b/src/provider/ipa_pc.rs @@ -2,17 +2,12 @@ #![allow(clippy::too_many_arguments)] use crate::{ errors::SpartanError, -<<<<<<< HEAD - provider::pedersen::CommitmentKeyExtTrait, - spartan::polys::eq::EqPolynomial, -======= provider::pedersen::{ Commitment as PedersenCommitment, CommitmentEngine as PedersenCommitmentEngine, CommitmentEngineExtTrait, CommitmentKey as PedersenCommitmentKey, CompressedCommitment as PedersenCompressedCommitment, }, - spartan::polynomial::EqPolynomial, ->>>>>>> checkpoint + spartan::polys::eq::EqPolynomial, traits::{ commitment::{CommitmentEngineTrait, CommitmentTrait}, evaluation::EvaluationEngineTrait, @@ -49,9 +44,9 @@ pub struct EvaluationEngine { impl EvaluationEngineTrait for EvaluationEngine where - G: Group, - CommitmentKey: CommitmentKeyExtTrait, + G: Group>, { + type CE = G::CE; type ProverKey = ProverKey; type VerifierKey = VerifierKey; type EvaluationArgument = InnerProductArgument; @@ -172,17 +167,8 @@ pub struct InnerProductArgument { a_hat: G::Scalar, } -<<<<<<< HEAD -impl InnerProductArgument -where - G: Group, - CommitmentKey: CommitmentKeyExtTrait, -{ - const fn protocol_name() -> &'static [u8] { -======= impl InnerProductArgument { - fn protocol_name() -> &'static [u8] { ->>>>>>> checkpoint + const fn protocol_name() -> &'static [u8] { b"IPA" } diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 4a99a1c..5d68710 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -11,7 +11,6 @@ pub mod keccak; pub mod pasta; pub mod pedersen; pub mod secp_secq; -pub mod hyrax_pc; use ff::PrimeField; use pasta_curves::{self, arithmetic::CurveAffine, group::Group as AnotherGroup}; @@ -161,7 +160,7 @@ macro_rules! impl_traits { type CompressedGroupElement = $name_compressed; type PreprocessedGroupElement = $name::Affine; type TE = Keccak256Transcript; - type CE = CommitmentEngine; + type CE = HyraxCommitmentEngine; fn vartime_multiscalar_mul( scalars: &[Self::Scalar], diff --git a/src/provider/pedersen.rs b/src/provider/pedersen.rs index 7b1c36c..c7e72b7 100644 --- a/src/provider/pedersen.rs +++ b/src/provider/pedersen.rs @@ -187,8 +187,8 @@ impl CommitmentEngineTrait for CommitmentEngine { } } -/// A trait listing properties of a commitment key that can be managed in a divide-and-conquer fashion -pub trait CommitmentKeyExtTrait { +/// Additional extensions on the commitment engine +pub trait CommitmentEngineExtTrait: CommitmentEngineTrait { /// Splits the commitment key into two pieces at a specified point fn split_at(ck: &Self::CommitmentKey, n: usize) -> (Self::CommitmentKey, Self::CommitmentKey); @@ -199,26 +199,6 @@ pub trait CommitmentKeyExtTrait { fn fold(ck: &Self::CommitmentKey, w1: &G::Scalar, w2: &G::Scalar) -> Self::CommitmentKey; /// Scales the commitment key using the provided scalar -<<<<<<< HEAD - fn scale(&self, r: &G::Scalar) -> Self; - - /// Reinterprets commitments as commitment keys - fn reinterpret_commitments_as_ck( - c: &[<<::CE as CommitmentEngineTrait>::Commitment as CommitmentTrait>::CompressedCommitment], - ) -> Result - where - Self: Sized; -} - -impl>> CommitmentKeyExtTrait for CommitmentKey { - fn split_at(&self, n: usize) -> (CommitmentKey, CommitmentKey) { - ( - CommitmentKey { - ck: self.ck[0..n].to_vec(), - }, - CommitmentKey { - ck: self.ck[n..].to_vec(), -======= fn scale(ck: &Self::CommitmentKey, r: &G::Scalar) -> Self::CommitmentKey; /// Reinterprets the commitments as a commitment key @@ -230,12 +210,9 @@ impl CommitmentEngineExtTrait for CommitmentEngine { ( CommitmentKey { ck: ck.ck[0..n].to_vec(), - _p: Default::default(), }, CommitmentKey { ck: ck.ck[n..].to_vec(), - _p: Default::default(), ->>>>>>> checkpoint }, ) } @@ -246,14 +223,7 @@ impl CommitmentEngineExtTrait for CommitmentEngine { c.extend(other.ck.clone()); c }; -<<<<<<< HEAD - CommitmentKey { ck } -======= - Self::CommitmentKey { - ck, - _p: Default::default(), - } ->>>>>>> checkpoint + Self::CommitmentKey { ck } } fn fold(ck: &Self::CommitmentKey, w1: &G::Scalar, w2: &G::Scalar) -> Self::CommitmentKey { @@ -268,14 +238,7 @@ impl CommitmentEngineExtTrait for CommitmentEngine { }) .collect(); -<<<<<<< HEAD - CommitmentKey { ck } -======= - Self::CommitmentKey { - ck, - _p: Default::default(), - } ->>>>>>> checkpoint + Self::CommitmentKey { ck } } fn scale(ck: &Self::CommitmentKey, r: &G::Scalar) -> Self::CommitmentKey { @@ -286,33 +249,12 @@ impl CommitmentEngineExtTrait for CommitmentEngine { .map(|g| G::vartime_multiscalar_mul(&[*r], &[g]).preprocessed()) .collect(); -<<<<<<< HEAD - CommitmentKey { ck: ck_scaled } - } - - /// reinterprets a vector of commitments as a set of generators - fn reinterpret_commitments_as_ck(c: &[CompressedCommitment]) -> Result { - let d = (0..c.len()) - .into_par_iter() - .map(|i| Commitment::::decompress(&c[i])) - .collect::>, SpartanError>>()?; - let ck = (0..d.len()) - .into_par_iter() - .map(|i| d[i].comm.preprocessed()) - .collect(); - Ok(CommitmentKey { ck }) -======= - Self::CommitmentKey { - ck: ck_scaled, - _p: Default::default(), - } + Self::CommitmentKey { ck: ck_scaled } } fn reinterpret_commitments_as_ck(commitments: &[Self::Commitment]) -> Self::CommitmentKey { Self::CommitmentKey { ck: commitments.iter().map(|c| c.comm.preprocessed()).collect(), - _p: Default::default(), } ->>>>>>> checkpoint } } diff --git a/src/provider/secp_secq.rs b/src/provider/secp_secq.rs index 7247f67..9126941 100644 --- a/src/provider/secp_secq.rs +++ b/src/provider/secp_secq.rs @@ -1,7 +1,7 @@ //! This module implements the Spartan traits for secp::Point, secp::Scalar, secq::Point, secq::Scalar. use crate::{ impl_traits, - provider::{cpu_best_multiexp, keccak::Keccak256Transcript, pedersen::CommitmentEngine}, + provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; diff --git a/src/spartan/polys/eq.rs b/src/spartan/polys/eq.rs index 22ef1a1..492128e 100644 --- a/src/spartan/polys/eq.rs +++ b/src/spartan/polys/eq.rs @@ -65,6 +65,22 @@ impl EqPolynomial { evals } + + /// Computes the lengths of the left and right halves of the `EqPolynomial`'s vector `r`. + pub fn compute_factored_lens(ell: usize) -> (usize, usize) { + (ell / 2, ell - ell / 2) + } + + /// Computes the left and right halves of the `EqPolynomial`. + pub fn compute_factored_evals(&self) -> (Vec, Vec) { + let ell = self.r.len(); + let (left_num_vars, _right_num_vars) = EqPolynomial::::compute_factored_lens(ell); + + let L = EqPolynomial::new(self.r[..left_num_vars].to_vec()).evals(); + let R = EqPolynomial::new(self.r[left_num_vars..ell].to_vec()).evals(); + + (L, R) + } } #[cfg(test)] diff --git a/src/spartan/polys/multilinear.rs b/src/spartan/polys/multilinear.rs index 9ed128d..b60035f 100644 --- a/src/spartan/polys/multilinear.rs +++ b/src/spartan/polys/multilinear.rs @@ -117,14 +117,35 @@ impl MultilinearPolynomial { } new_poly } + + /// Returns the evaluations of the polynomial. + pub fn get_Z(&self) -> &[Scalar] { + &self.Z + } + + /// Bounds the polynomial's top variables using the given scalars. + pub fn bound(&self, L: &[Scalar]) -> Vec { + let (left_num_vars, right_num_vars) = + EqPolynomial::::compute_factored_lens(self.num_vars); + let L_size = (2_usize).pow(left_num_vars as u32); + let R_size = (2_usize).pow(right_num_vars as u32); + + (0..R_size) + .map(|i| { + (0..L_size) + .map(|j| L[j] * self.Z[j * R_size + i]) + .fold(Scalar::ZERO, |x, y| x + y) + }) + .collect() + } } impl Index for MultilinearPolynomial { type Output = Scalar; #[inline(always)] - fn index(&self, _index: usize) -> &Scalar { - &(self.Z[_index]) + fn index(&self, index: usize) -> &Scalar { + &(self.Z[index]) } } diff --git a/src/traits/evaluation.rs b/src/traits/evaluation.rs index 9657d4a..f91ee19 100644 --- a/src/traits/evaluation.rs +++ b/src/traits/evaluation.rs @@ -9,6 +9,9 @@ use serde::{Deserialize, Serialize}; /// A trait that ties different pieces of the commitment evaluation together pub trait EvaluationEngineTrait: Clone + Send + Sync { + /// A type that holds the associated commitment engine + type CE: CommitmentEngineTrait; + /// A type that holds the prover key type ProverKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>; From 63f563643ee81112082113535df22503599d8c91 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Fri, 29 Sep 2023 14:49:18 -0700 Subject: [PATCH 22/24] fix clippy --- benches/sha256.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/sha256.rs b/benches/sha256.rs index f3c5187..bfeb0c7 100644 --- a/benches/sha256.rs +++ b/benches/sha256.rs @@ -138,8 +138,8 @@ fn bench_snark(c: &mut Criterion) { SNARK::::Scalar>>::setup(circuit.clone()).unwrap(); group.bench_function("Prove", |b| { - let _res = b.iter(|| { - SNARK::::Scalar>>::prove( + b.iter(|| { + let _ = SNARK::::Scalar>>::prove( black_box(&pk), black_box(circuit.clone()), ); From dbda00441f374b7ee7240229c4057355789cd093 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Wed, 10 Jan 2024 12:01:26 -0800 Subject: [PATCH 23/24] update halo2curves; expose asm feature --- Cargo.toml | 7 +- src/provider/bn256_grumpkin.rs | 3 +- src/provider/mod.rs | 130 +-------------------------------- src/provider/pasta.rs | 7 +- src/provider/secp_secq.rs | 3 +- 5 files changed, 15 insertions(+), 135 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 9a95822..2fa0d9e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,16 +32,20 @@ flate2 = "1.0" bitvec = "1.0" byteorder = "1.4.3" thiserror = "1.0" -halo2curves = { version = "0.4.0", features = ["derive_serde"] } group = "0.13.0" once_cell = "1.18.0" [target.'cfg(any(target_arch = "x86_64", target_arch = "aarch64"))'.dependencies] pasta-msm = { version = "0.1.4" } +[target.'cfg(not(target_arch = "wasm32"))'.dependencies] +halo2curves = { version = "0.5.0", features = ["bits", "derive_serde"] } + + [target.wasm32-unknown-unknown.dependencies] # see https://github.com/rust-random/rand/pull/948 getrandom = { version = "0.2.0", default-features = false, features = ["js"] } +halo2curves = { version = "0.5.0", default-features = false, features = ["bits", "derive_serde"] } [dev-dependencies] criterion = { version = "0.4", features = ["html_reports"] } @@ -58,6 +62,7 @@ harness = false [features] default = [] +asm = ["halo2curves/asm"] # Compiles in portable mode, w/o ISA extensions => binary can be executed on all systems. portable = ["pasta-msm/portable"] flamegraph = ["pprof/flamegraph", "pprof/criterion"] diff --git a/src/provider/bn256_grumpkin.rs b/src/provider/bn256_grumpkin.rs index 3386d16..8f20997 100644 --- a/src/provider/bn256_grumpkin.rs +++ b/src/provider/bn256_grumpkin.rs @@ -1,7 +1,7 @@ //! This module implements the Spartan traits for `bn256::Point`, `bn256::Scalar`, `grumpkin::Point`, `grumpkin::Scalar`. use crate::{ impl_traits, - provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, + provider::{hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; @@ -21,6 +21,7 @@ use halo2curves::bn256::{ use halo2curves::grumpkin::{ G1Affine as GrumpkinAffine, G1Compressed as GrumpkinCompressed, G1 as GrumpkinPoint, }; +use halo2curves::msm::best_multiexp; /// Re-exports that give access to the standard aliases used in the code base, for bn256 pub mod bn256 { diff --git a/src/provider/mod.rs b/src/provider/mod.rs index 5d68710..9891b91 100644 --- a/src/provider/mod.rs +++ b/src/provider/mod.rs @@ -12,134 +12,6 @@ pub mod pasta; pub mod pedersen; pub mod secp_secq; -use ff::PrimeField; -use pasta_curves::{self, arithmetic::CurveAffine, group::Group as AnotherGroup}; - -/// Native implementation of fast multiexp -/// Adapted from zcash/halo2 -fn cpu_multiexp_serial(coeffs: &[C::Scalar], bases: &[C], acc: &mut C::Curve) { - let coeffs: Vec<_> = coeffs.iter().map(|a| a.to_repr()).collect(); - - let c = if bases.len() < 4 { - 1 - } else if bases.len() < 32 { - 3 - } else { - (f64::from(bases.len() as u32)).ln().ceil() as usize - }; - - fn get_at(segment: usize, c: usize, bytes: &F::Repr) -> usize { - let skip_bits = segment * c; - let skip_bytes = skip_bits / 8; - - if skip_bytes >= 32 { - return 0; - } - - let mut v = [0; 8]; - for (v, o) in v.iter_mut().zip(bytes.as_ref()[skip_bytes..].iter()) { - *v = *o; - } - - let mut tmp = u64::from_le_bytes(v); - tmp >>= skip_bits - (skip_bytes * 8); - tmp %= 1 << c; - - tmp as usize - } - - let segments = (256 / c) + 1; - - for current_segment in (0..segments).rev() { - for _ in 0..c { - *acc = acc.double(); - } - - #[derive(Clone, Copy)] - enum Bucket { - None, - Affine(C), - Projective(C::Curve), - } - - impl Bucket { - fn add_assign(&mut self, other: &C) { - *self = match *self { - Bucket::None => Bucket::Affine(*other), - Bucket::Affine(a) => Bucket::Projective(a + *other), - Bucket::Projective(mut a) => { - a += *other; - Bucket::Projective(a) - } - } - } - - fn add(self, mut other: C::Curve) -> C::Curve { - match self { - Bucket::None => other, - Bucket::Affine(a) => { - other += a; - other - } - Bucket::Projective(a) => other + a, - } - } - } - - let mut buckets: Vec> = vec![Bucket::None; (1 << c) - 1]; - - for (coeff, base) in coeffs.iter().zip(bases.iter()) { - let coeff = get_at::(current_segment, c, coeff); - if coeff != 0 { - buckets[coeff - 1].add_assign(base); - } - } - - // Summation by parts - // e.g. 3a + 2b + 1c = a + - // (a) + b + - // ((a) + b) + c - let mut running_sum = C::Curve::identity(); - for exp in buckets.into_iter().rev() { - running_sum = exp.add(running_sum); - *acc += &running_sum; - } - } -} - -/// Performs a multi-exponentiation operation without GPU acceleration. -/// -/// This function will panic if coeffs and bases have a different length. -/// -/// This will use multithreading if beneficial. -/// Adapted from zcash/halo2 -pub(crate) fn cpu_best_multiexp(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve { - assert_eq!(coeffs.len(), bases.len()); - - let num_threads = rayon::current_num_threads(); - if coeffs.len() > num_threads { - let chunk = coeffs.len() / num_threads; - let num_chunks = coeffs.chunks(chunk).len(); - let mut results = vec![C::Curve::identity(); num_chunks]; - rayon::scope(|scope| { - for ((coeffs, bases), acc) in coeffs - .chunks(chunk) - .zip(bases.chunks(chunk)) - .zip(results.iter_mut()) - { - scope.spawn(move |_| { - cpu_multiexp_serial(coeffs, bases, acc); - }); - } - }); - results.iter().fold(C::Curve::identity(), |a, b| a + b) - } else { - let mut acc = C::Curve::identity(); - cpu_multiexp_serial(coeffs, bases, &mut acc); - acc - } -} - /// Curve ops /// This implementation behaves in ways specific to the halo2curves suite of curves in: // - to_coordinates, @@ -166,7 +38,7 @@ macro_rules! impl_traits { scalars: &[Self::Scalar], bases: &[Self::PreprocessedGroupElement], ) -> Self { - cpu_best_multiexp(scalars, bases) + best_multiexp(scalars, bases) } fn preprocessed(&self) -> Self::PreprocessedGroupElement { diff --git a/src/provider/pasta.rs b/src/provider/pasta.rs index 75d8614..fb0ddea 100644 --- a/src/provider/pasta.rs +++ b/src/provider/pasta.rs @@ -1,10 +1,11 @@ //! This module implements the Spartan traits for `pallas::Point`, `pallas::Scalar`, `vesta::Point`, `vesta::Scalar`. use crate::{ - provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, + provider::{hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; use ff::{FromUniformBytes, PrimeField}; +use halo2curves::msm::best_multiexp; use num_bigint::BigInt; use num_traits::Num; use pasta_curves::{ @@ -68,7 +69,7 @@ macro_rules! impl_traits { if scalars.len() >= 128 { pasta_msm::$name(bases, scalars) } else { - cpu_best_multiexp(scalars, bases) + best_multiexp(scalars, bases) } } @@ -77,7 +78,7 @@ macro_rules! impl_traits { scalars: &[Self::Scalar], bases: &[Self::PreprocessedGroupElement], ) -> Self { - cpu_best_multiexp(scalars, bases) + best_multiexp(scalars, bases) } fn preprocessed(&self) -> Self::PreprocessedGroupElement { diff --git a/src/provider/secp_secq.rs b/src/provider/secp_secq.rs index 9126941..571969d 100644 --- a/src/provider/secp_secq.rs +++ b/src/provider/secp_secq.rs @@ -1,12 +1,13 @@ //! This module implements the Spartan traits for secp::Point, secp::Scalar, secq::Point, secq::Scalar. use crate::{ impl_traits, - provider::{cpu_best_multiexp, hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, + provider::{hyrax_pc::HyraxCommitmentEngine, keccak::Keccak256Transcript}, traits::{CompressedGroup, Group, PrimeFieldExt, TranscriptReprTrait}, }; use digest::{ExtendableOutput, Update}; use ff::{FromUniformBytes, PrimeField}; use group::{cofactor::CofactorCurveAffine, Curve, Group as AnotherGroup, GroupEncoding}; +use halo2curves::msm::best_multiexp; use halo2curves::secp256k1::{Secp256k1, Secp256k1Affine, Secp256k1Compressed}; use halo2curves::secq256k1::{Secq256k1, Secq256k1Affine, Secq256k1Compressed}; use num_bigint::BigInt; From 854f47f35e08eb4f4d0fe4735cea658192ea02f5 Mon Sep 17 00:00:00 2001 From: Srinath Setty Date: Wed, 10 Jan 2024 12:41:15 -0800 Subject: [PATCH 24/24] fix clippy --- src/provider/keccak.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/provider/keccak.rs b/src/provider/keccak.rs index 119478e..849ae30 100644 --- a/src/provider/keccak.rs +++ b/src/provider/keccak.rs @@ -155,7 +155,7 @@ mod tests { fn test_keccak_example() { let mut hasher = Keccak256::new(); hasher.update(0xffffffff_u32.to_le_bytes()); - let output: [u8; 32] = hasher.finalize().try_into().unwrap(); + let output: [u8; 32] = hasher.finalize().into(); assert_eq!( hex::encode(output), "29045a592007d0c246ef02c2223570da9522d0cf0f73282c79a1bc8f0bb2c238"