diff --git a/src/multilinear_pc/data_structures.rs b/src/multilinear_pc/data_structures.rs index fc287b9..104c5ed 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,10 +53,12 @@ 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)] -/// commitment +/// PST commitment on the G1 group pub struct Commitment { /// number of variables pub nv: usize, @@ -62,9 +66,25 @@ pub struct Commitment { pub g_product: E::G1Affine, } +#[derive(CanonicalSerialize, CanonicalDeserialize, Clone, Debug)] +/// PST Commitment on the G2 group +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)] +/// 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 c8b0e59..61b35ba 100644 --- a/src/multilinear_pc/mod.rs +++ b/src/multilinear_pc/mod.rs @@ -1,3 +1,5 @@ +use self::data_structures::{Commitment_G2, Proof_G1}; + use super::timer::Timer; use crate::multilinear_pc::data_structures::{ Commitment, CommitterKey, Proof, UniversalParams, VerifierKey, @@ -96,15 +98,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, } } @@ -129,6 +144,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) } @@ -141,7 +157,7 @@ impl MultilinearPC { let nv = polynomial.num_vars(); let scalars: Vec<_> = polynomial .to_evaluations() - .into_par_iter() + .into_iter() .map(|x| x.into_repr()) .collect(); let g_product = @@ -149,6 +165,23 @@ 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, + ) -> 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, @@ -173,11 +206,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::Fr::zero()) .collect(); r[k - 1] = (0..(1 << (k - 1))) - .into_par_iter() + .into_iter() .map(|_| E::Fr::zero()) .collect(); for b in 0..(1 << (k - 1)) { @@ -186,7 +219,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].into_repr()) // fine .collect(); let ph = ck.powers_of_h[i].clone(); @@ -204,21 +237,117 @@ impl MultilinearPC { } let proofs = thread_handles - .into_par_iter() + .into_iter() .map(|h| h.join().unwrap()) .collect(); // let res = s - // .into_par_iter() - // .zip(ck.powers_of_h.clone().into_par_iter()) + // .into_iter() + // .zip(ck.powers_of_h.clone().into_iter()) // .map(|(si, hi)| VariableBaseMSM::multi_scalar_mul(&hi, &si).into_affine()) // .collect::>(); // print!("{:?}", res); Proof { proofs: proofs } } + /// Create PST opening proof in G1 (with a commitment on G2) + 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 + } + + /// Check a polynomial opening proof in G2 and commitment on G1 pub fn check<'a>( vk: &VerifierKey, commitment: &Commitment, @@ -241,13 +370,13 @@ impl MultilinearPC { FixedBaseMSM::multi_scalar_mul(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_projective() - &g_mul[i]) .collect(); let pairing_lefts: Vec = E::G1Projective::batch_normalization_into_affine(&pairing_lefts); let pairing_lefts: Vec = pairing_lefts - .into_par_iter() + .into_iter() .map(|x| E::G1Prepared::from(x)) .collect(); @@ -258,8 +387,8 @@ impl MultilinearPC { .collect(); let pairings: Vec<_> = pairing_lefts - .into_par_iter() - .zip(pairing_rights.into_par_iter()) + .into_iter() + .zip(pairing_rights.into_iter()) .collect(); let right = E::product_of_pairings(pairings.iter()); // println!("right is {:?}", right); @@ -331,6 +460,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();