From 57e5a85bd15bd4616343767dfe2b55f91f9a6b0c Mon Sep 17 00:00:00 2001 From: Mara Mihali Date: Fri, 16 Dec 2022 18:34:57 +0200 Subject: [PATCH 1/6] make eq_extension public and fix github actions --- .github/workflows/ci.yml | 1 + src/multilinear_pc/mod.rs | 9 +++------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0f4be64a..0238476f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,7 @@ on: - master env: RUST_BACKTRACE: 1 + RUSTFLAGS: "--emit asm -C llvm-args=-x86-asm-syntax=intel" jobs: style: diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index 6d001639..3782643c 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -147,11 +147,8 @@ impl MultilinearPC { .into_iter() .map(|x| x.into_bigint()) .collect(); - let g_product = ::msm_bigint( - &ck.powers_of_g[0], - scalars.as_slice(), - ) - .into_affine(); + let g_product = + VariableBaseMSM::multi_scalar_mul(&ck.powers_of_g[0], scalars.as_slice()).into_affine(); Commitment { nv, g_product } } @@ -253,7 +250,7 @@ fn remove_dummy_variable(poly: &[F], pad: usize) -> Vec { /// generate eq(t,x), a product of multilinear polynomials with fixed t. /// eq(a,b) is takes extensions of a,b in {0,1}^num_vars such that if a and b in {0,1}^num_vars are equal /// then this polynomial evaluates to 1. -fn eq_extension(t: &[F]) -> Vec> { +pub fn eq_extension(t: &[F]) -> Vec> { let dim = t.len(); let mut result = Vec::new(); for i in 0..dim { From 61967360d4ec7ed861e555b86a5bd280d7fa83a4 Mon Sep 17 00:00:00 2001 From: Mara Mihali Date: Wed, 25 Jan 2023 11:20:37 +0000 Subject: [PATCH 2/6] add parallel iterators --- src/lib.rs | 5 ++--- src/multilinear_pc/mod.rs | 42 +++++++++++++++++++++++++++------------ 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 068906bf..8cc99a1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,9 +5,8 @@ #![deny(stable_features, unreachable_pub, non_shorthand_field_patterns)] #![deny(unused_attributes, unused_mut)] #![deny(missing_docs)] -#![deny(unused_imports)] -#![deny(renamed_and_removed_lints, stable_features, unused_allocation)] -#![deny(unused_comparisons, bare_trait_objects, unused_must_use, const_err)] +#![deny(stable_features, unused_allocation)] +#![deny(unused_comparisons, bare_trait_objects, unused_must_use)] #![forbid(unsafe_code)] #[allow(unused)] diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index 3782643c..cd3212b6 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -13,7 +13,10 @@ use ark_std::ops::Mul; use ark_std::rand::RngCore; use ark_std::vec::Vec; use ark_std::UniformRand; - +use rayon::prelude::*; +use std::thread; +// use rayon::iter::ParallelIterator; +// use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator}; /// data structures used by multilinear extension commitment scheme pub mod data_structures; @@ -45,8 +48,8 @@ impl MultilinearPC { if i != 0 { let mul = eq.pop_back().unwrap().evaluations; base = base - .into_iter() - .zip(mul.into_iter()) + .into_par_iter() + .zip(mul.into_par_iter()) .map(|(a, b)| a * &b) .collect(); } @@ -144,8 +147,8 @@ impl MultilinearPC { let nv = polynomial.num_vars(); let scalars: Vec<_> = polynomial .to_evaluations() - .into_iter() - .map(|x| x.into_bigint()) + .into_par_iter() + .map(|x| x.into_repr()) .collect(); let g_product = VariableBaseMSM::multi_scalar_mul(&ck.powers_of_g[0], scalars.as_slice()).into_affine(); @@ -169,15 +172,22 @@ impl MultilinearPC { for i in 0..nv { let k = nv - i; let point_at_k = point[i]; - q[k] = (0..(1 << (k - 1))).map(|_| E::Fr::zero()).collect(); - r[k - 1] = (0..(1 << (k - 1))).map(|_| E::Fr::zero()).collect(); + q[k] = (0..(1 << (k - 1))) + .into_par_iter() + .map(|_| E::Fr::zero()) + .collect(); + r[k - 1] = (0..(1 << (k - 1))) + .into_par_iter() + .map(|_| E::Fr::zero()) + .collect(); for b in 0..(1 << (k - 1)) { q[k][b] = r[k][(b << 1) + 1] - &r[k][b << 1]; r[k - 1][b] = r[k][b << 1] * &(E::Fr::one() - &point_at_k) + &(r[k][(b << 1) + 1] * &point_at_k); } let scalars: Vec<_> = (0..(1 << k)) - .map(|x| q[k][x >> 1].into_bigint()) // fine + .into_par_iter() + .map(|x| q[k][x >> 1].into_repr()) // fine .collect(); let pi_h = @@ -186,7 +196,12 @@ impl MultilinearPC { proofs.push(pi_h); } - Proof { proofs } + let proofs = thread_handles + .into_par_iter() + .map(|h| h.join().unwrap()) + .collect(); + + Proof { proofs: proofs } } /// Verifies that `value` is the evaluation at `x` of the polynomial @@ -210,24 +225,25 @@ impl MultilinearPC { let g_mul: Vec = FixedBase::msm(scalar_size, window_size, &g_table, point); let pairing_lefts: Vec<_> = (0..vk.nv) + .into_par_iter() .map(|i| vk.g_mask_random[i].into_projective() - &g_mul[i]) .collect(); let pairing_lefts: Vec = E::G1Projective::batch_normalization_into_affine(&pairing_lefts); let pairing_lefts: Vec = pairing_lefts - .into_iter() + .into_par_iter() .map(|x| E::G1Prepared::from(x)) .collect(); let pairing_rights: Vec = proof .proofs - .iter() + .par_iter() .map(|x| E::G2Prepared::from(*x)) .collect(); let pairings: Vec<_> = pairing_lefts - .into_iter() - .zip(pairing_rights.into_iter()) + .into_par_iter() + .zip(pairing_rights.into_par_iter()) .collect(); let right = E::product_of_pairings(pairings.iter()); left == right From 710d6656a8f79fcbccc0a4d4f498d9b6fb3b40e9 Mon Sep 17 00:00:00 2001 From: Mara Mihali Date: Thu, 26 Jan 2023 10:34:46 +0000 Subject: [PATCH 3/6] add support for commitment in g2 --- src/multilinear_pc/data_structures.rs | 18 +++ src/multilinear_pc/mod.rs | 156 +++++++++++++++++++++++++- 2 files changed, 173 insertions(+), 1 deletion(-) diff --git a/src/multilinear_pc/data_structures.rs b/src/multilinear_pc/data_structures.rs index e52ef66b..f3ebfc5f 100644 --- a/src/multilinear_pc/data_structures.rs +++ b/src/multilinear_pc/data_structures.rs @@ -23,6 +23,8 @@ pub struct UniversalParams { pub h: E::G2Affine, /// g^randomness pub g_mask: Vec, + //h^randomness + pub h_mask: Vec, } /// Public Parameter used by prover @@ -51,6 +53,8 @@ pub struct VerifierKey { pub h: E::G2Affine, /// g^t1, g^t2, ... pub g_mask_random: Vec, + // h^t1, h^t2,... + pub h_mask_random: Vec, } #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] @@ -63,8 +67,22 @@ pub struct Commitment { } #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +pub struct Commitment_G2 { + /// number of variables + pub nv: usize, + /// product of g as described by the vRAM paper + pub h_product: E::G2Affine, +} + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq, Eq)] /// proof of opening pub struct Proof { /// Evaluation of quotients pub proofs: Vec, } + +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq, Eq)] +pub struct Proof_G1 { + /// Evaluation of quotients + pub proofs: Vec, +} diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index cd3212b6..2e21fdff 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -1,3 +1,6 @@ +use self::data_structures::{Commitment_G2, Proof_G1}; + +use super::timer::Timer; use crate::multilinear_pc::data_structures::{ Commitment, CommitterKey, Proof, UniversalParams, VerifierKey, }; @@ -102,15 +105,28 @@ impl MultilinearPC { &t, )) }; + + let h_mask = { + let window_size = FixedBaseMSM::get_mul_window_size(num_vars); + let h_table = + FixedBaseMSM::get_window_table(scalar_bits, window_size, h.into_projective()); + E::G2Projective::batch_normalization_into_affine(&FixedBaseMSM::multi_scalar_mul( + scalar_bits, + window_size, + &h_table, + &t, + )) + }; // end_timer!(vp_generation_timer); UniversalParams { num_vars, g, - g_mask, h, powers_of_g, powers_of_h, + g_mask, + h_mask, } } @@ -135,6 +151,7 @@ impl MultilinearPC { g: params.g, h: params.h, g_mask_random: (¶ms.g_mask[to_reduce..]).to_vec(), + h_mask_random: (¶ms.h_mask[to_reduce..]).to_vec(), }; (ck, vk) } @@ -155,6 +172,21 @@ impl MultilinearPC { Commitment { nv, g_product } } + pub fn commit_g2( + ck: &CommitterKey, + polynomial: &impl MultilinearExtension, + ) -> Commitment_G2 { + let nv = polynomial.num_vars(); + let scalars: Vec<_> = polynomial + .to_evaluations() + .into_iter() + .map(|x| x.into_repr()) + .collect(); + let h_product = + VariableBaseMSM::multi_scalar_mul(&ck.powers_of_h[0], scalars.as_slice()).into_affine(); + Commitment_G2 { nv, h_product } + } + /// On input a polynomial `p` and a point `point`, outputs a proof for the same. pub fn open( ck: &CommitterKey, @@ -204,8 +236,102 @@ impl MultilinearPC { Proof { proofs: proofs } } + pub fn open_g1( + ck: &CommitterKey, + polynomial: &impl MultilinearExtension, + point: &[E::Fr], + ) -> Proof_G1 { + assert_eq!(polynomial.num_vars(), ck.nv, "Invalid size of polynomial"); + let nv = polynomial.num_vars(); + let mut r: Vec> = (0..nv + 1).map(|_| Vec::new()).collect(); + let mut q: Vec> = (0..nv + 1).map(|_| Vec::new()).collect(); + + r[nv] = polynomial.to_evaluations(); + + let mut thread_handles = vec![]; + let proofs: Vec<_> = vec![E::G1Affine::zero(); nv]; + + let mut i = 0; + for mut p in proofs { + let k = nv - i; + let point_at_k = point[i]; + q[k] = (0..(1 << (k - 1))).map(|_| E::Fr::zero()).collect(); + r[k - 1] = (0..(1 << (k - 1))).map(|_| E::Fr::zero()).collect(); + for b in 0..(1 << (k - 1)) { + q[k][b] = r[k][(b << 1) + 1] - &r[k][b << 1]; + r[k - 1][b] = r[k][b << 1] * &(E::Fr::one() - &point_at_k) + + &(r[k][(b << 1) + 1] * &point_at_k); + } + let scalars: Vec<_> = (0..(1 << k)) + .map(|x| q[k][x >> 1].into_repr()) // fine + .collect(); + let pg = ck.powers_of_g[i].clone(); + thread_handles.push(thread::spawn(move || { + p = VariableBaseMSM::multi_scalar_mul(&pg, &scalars).into_affine(); + p + })); + + i = i + 1; + } + + let proofs = thread_handles + .into_iter() + .map(|g| g.join().unwrap()) + .collect(); + + Proof_G1 { proofs: proofs } + } + /// Verifies that `value` is the evaluation at `x` of the polynomial /// committed inside `comm`. + pub fn check_2<'a>( + vk: &VerifierKey, + commitment: &Commitment_G2, + point: &[E::Fr], + value: E::Fr, + proof: &Proof_G1, + ) -> bool { + let left = E::pairing( + vk.g, + commitment.h_product.into_projective() - &vk.h.mul(value), + ); + // println!("left is {:?}", left); + + let scalar_size = E::Fr::size_in_bits(); + let window_size = FixedBaseMSM::get_mul_window_size(vk.nv); + + let h_table = + FixedBaseMSM::get_window_table(scalar_size, window_size, vk.h.into_projective()); + let h_mul: Vec = + FixedBaseMSM::multi_scalar_mul(scalar_size, window_size, &h_table, point); + + let pairing_rights: Vec<_> = (0..vk.nv) + .into_iter() + .map(|i| vk.h_mask_random[i].into_projective() - &h_mul[i]) + .collect(); + let pairing_rights: Vec = + E::G2Projective::batch_normalization_into_affine(&pairing_rights); + let pairing_rights: Vec = pairing_rights + .into_iter() + .map(|x| E::G2Prepared::from(x)) + .collect(); + + let pairing_lefts: Vec = proof + .proofs + .iter() + .map(|x| E::G1Prepared::from(*x)) + .collect(); + + let pairings: Vec<_> = pairing_lefts + .into_iter() + .zip(pairing_rights.into_iter()) + .collect(); + let right = E::product_of_pairings(pairings.iter()); + // println!("right is {:?}", right); + + left == right + } + pub fn check<'a>( vk: &VerifierKey, commitment: &Commitment, @@ -313,6 +439,34 @@ mod tests { assert!(result); } + fn test_polynomial_g2( + uni_params: &UniversalParams, + poly: &impl MultilinearExtension, + rng: &mut R, + ) { + let nv = poly.num_vars(); + assert_ne!(nv, 0); + let (ck, vk) = MultilinearPC::::trim(&uni_params, nv); + let point: Vec<_> = (0..nv).map(|_| Fr::rand(rng)).collect(); + let com = MultilinearPC::commit_g2(&ck, poly); + let proof = MultilinearPC::open_g1(&ck, poly, &point); + + let value = poly.evaluate(&point).unwrap(); + let result = MultilinearPC::check_2(&vk, &com, &point, value, &proof); + assert!(result); + } + + #[test] + fn test() { + let mut rng = test_rng(); + + // normal polynomials + let uni_params = MultilinearPC::setup(2, &mut rng); + + let poly1 = DenseMultilinearExtension::rand(2, &mut rng); + test_polynomial_g2(&uni_params, &poly1, &mut rng); + } + #[test] fn setup_commit_verify_correct_polynomials() { let mut rng = test_rng(); From 03cb4f3a5ace71bab5121cf9100079b744a11313 Mon Sep 17 00:00:00 2001 From: nikkolasg Date: Fri, 3 Feb 2023 13:36:51 +0100 Subject: [PATCH 4/6] adding documentation --- src/multilinear_pc/data_structures.rs | 8 +++++--- src/multilinear_pc/mod.rs | 4 ++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/multilinear_pc/data_structures.rs b/src/multilinear_pc/data_structures.rs index f3ebfc5f..104c5ed8 100644 --- a/src/multilinear_pc/data_structures.rs +++ b/src/multilinear_pc/data_structures.rs @@ -23,7 +23,7 @@ pub struct UniversalParams { pub h: E::G2Affine, /// g^randomness pub g_mask: Vec, - //h^randomness + /// h^randomness pub h_mask: Vec, } @@ -53,12 +53,12 @@ pub struct VerifierKey { pub h: E::G2Affine, /// g^t1, g^t2, ... pub g_mask_random: Vec, - // h^t1, h^t2,... + /// h^t1, h^t2,... pub h_mask_random: Vec, } #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] -/// commitment +/// PST commitment on the G1 group pub struct Commitment { /// number of variables pub nv: usize, @@ -67,6 +67,7 @@ pub struct Commitment { } #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +/// PST Commitment on the G2 group pub struct Commitment_G2 { /// number of variables pub nv: usize, @@ -82,6 +83,7 @@ pub struct Proof { } #[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug, PartialEq, Eq)] +/// PST Proof of opening on G1 (so commitment is on G2) pub struct Proof_G1 { /// Evaluation of quotients pub proofs: Vec, diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index 2e21fdff..540756d1 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -172,6 +172,8 @@ impl MultilinearPC { Commitment { nv, g_product } } + /// commit the given polynomial using the G2 group as a basis + /// That means the opening will be in G1. pub fn commit_g2( ck: &CommitterKey, polynomial: &impl MultilinearExtension, @@ -236,6 +238,7 @@ impl MultilinearPC { Proof { proofs: proofs } } + /// Create PST opening proof in G1 (with a commitment on G2) pub fn open_g1( ck: &CommitterKey, polynomial: &impl MultilinearExtension, @@ -332,6 +335,7 @@ impl MultilinearPC { left == right } + /// Check a polynomial opening proof in G2 and commitment on G1 pub fn check<'a>( vk: &VerifierKey, commitment: &Commitment, From e6678e90f2ee90f00acd74c84ec0f716049fffcc Mon Sep 17 00:00:00 2001 From: nikkolasg Date: Sun, 5 Feb 2023 21:46:46 +0100 Subject: [PATCH 5/6] all tests pass - remove deadlock --- src/multilinear_pc/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index 48a91dc8..31fd0f4d 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -209,15 +209,16 @@ impl MultilinearPC { .collect(); let ph = ck.powers_of_h[i].clone(); + debug_assert!(ph.len() == scalars.len()); thread_handles.push(thread::spawn(move || { ::msm(&ph, &scalars[..]) .unwrap() .into_affine() })); } - + print!("Waiting for threads to finish..."); let proofs = thread_handles - .into_par_iter() + .into_iter() .map(|h| h.join().unwrap()) .collect(); @@ -282,7 +283,6 @@ impl MultilinearPC { proof: &ProofG1, ) -> bool { let left = E::pairing(vk.g, commitment.h_product.into_group() - &vk.h.mul(value)); - // println!("left is {:?}", left); let scalar_size = ::MODULUS_BIT_SIZE; let window_size = FixedBase::get_mul_window_size(vk.nv); @@ -306,7 +306,6 @@ impl MultilinearPC { .collect(); let right = E::multi_pairing(pairing_lefts, pairing_rights); - // println!("right is {:?}", right); left == right } @@ -426,7 +425,6 @@ mod tests { let value = poly.evaluate(&point).unwrap(); let result = MultilinearPC::check_2(&vk, &com, &point, value, &proof); - println!("result: {}", result); assert!(result); } From 693cff5b8b0f69c8e25a78ac253273955122f850 Mon Sep 17 00:00:00 2001 From: Mara Mihali Date: Tue, 7 Feb 2023 17:16:35 +0000 Subject: [PATCH 6/6] remove unnecessary parallel iterators --- src/multilinear_pc/mod.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/multilinear_pc/mod.rs b/src/multilinear_pc/mod.rs index 31fd0f4d..8a562f5f 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -191,11 +191,11 @@ impl MultilinearPC { let k = nv - i; let point_at_k = point[i]; q[k] = (0..(1 << (k - 1))) - .into_par_iter() + .into_iter() .map(|_| E::ScalarField::zero()) .collect(); r[k - 1] = (0..(1 << (k - 1))) - .into_par_iter() + .into_iter() .map(|_| E::ScalarField::zero()) .collect(); for b in 0..(1 << (k - 1)) { @@ -204,7 +204,7 @@ impl MultilinearPC { + &(r[k][(b << 1) + 1] * &point_at_k); } let scalars: Vec<_> = (0..(1 << k)) - .into_par_iter() + .into_iter() .map(|x| q[k][x >> 1]) // fine .collect(); @@ -296,7 +296,7 @@ impl MultilinearPC { .map(|i| vk.h_mask_random[i].into_group() - &h_mul[i]) .collect(); let pairing_rights: Vec = E::G2::normalize_batch(&pairing_rights) - .into_par_iter() + .into_iter() .map(|p| E::G2Prepared::from(p)) .collect(); let pairing_lefts: Vec = proof @@ -327,18 +327,18 @@ impl MultilinearPC { let g_mul: Vec = FixedBase::msm(scalar_size, window_size, &g_table, point); let pairing_lefts: Vec<_> = (0..vk.nv) - .into_par_iter() + .into_iter() .map(|i| vk.g_mask_random[i].into_group() - &g_mul[i]) .collect(); let pairing_lefts: Vec = E::G1::normalize_batch(&pairing_lefts); let pairing_lefts: Vec = pairing_lefts - .into_par_iter() + .into_iter() .map(|x| E::G1Prepared::from(x)) .collect(); let pairing_rights: Vec = proof .proofs - .par_iter() + .iter() .map(|x| E::G2Prepared::from(*x)) .collect(); @@ -429,7 +429,7 @@ mod tests { } #[test] - fn test_poly() { + fn test_commit_on_g2_short() { let mut rng = test_rng(); // normal polynomials @@ -439,6 +439,17 @@ mod tests { test_polynomial_g2(&uni_params, &poly1, &mut rng); } + #[test] + fn test_commit_on_g2_long() { + let mut rng = test_rng(); + + // normal polynomials + let uni_params = MultilinearPC::setup(10, &mut rng); + + let poly1 = DenseMultilinearExtension::rand(10, &mut rng); + test_polynomial_g2(&uni_params, &poly1, &mut rng); + } + #[test] fn setup_commit_verify_correct_polynomials() { let mut rng = test_rng();