From 8edea23c2f0190a83545ce6047df28dd5900082c Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 31 Oct 2023 08:02:44 +0100 Subject: [PATCH] Add Pedersen::{commit,open,verify} MSM error handling (#34) --- src/folding/hypernova/cccs.rs | 10 ++++----- src/folding/hypernova/lcccs.rs | 14 ++++++------- src/folding/hypernova/nimfs.rs | 25 ++++++++++++----------- src/folding/hypernova/utils.rs | 4 ++-- src/folding/nova/circuits.rs | 6 +++--- src/folding/nova/mod.rs | 10 ++++----- src/folding/nova/nifs.rs | 27 +++++++++++++------------ src/lib.rs | 6 ++++-- src/pedersen.rs | 37 +++++++++++++++++++++++++--------- 9 files changed, 80 insertions(+), 59 deletions(-) diff --git a/src/folding/hypernova/cccs.rs b/src/folding/hypernova/cccs.rs index 3a00d32..1ece619 100644 --- a/src/folding/hypernova/cccs.rs +++ b/src/folding/hypernova/cccs.rs @@ -38,18 +38,18 @@ impl CCS { rng: &mut R, pedersen_params: &PedersenParams, z: &[C::ScalarField], - ) -> (CCCS, Witness) { + ) -> Result<(CCCS, Witness), Error> { let w: Vec = z[(1 + self.l)..].to_vec(); let r_w = C::ScalarField::rand(rng); - let C = Pedersen::::commit(pedersen_params, &w, &r_w); + let C = Pedersen::::commit(pedersen_params, &w, &r_w)?; - ( + Ok(( CCCS:: { C, x: z[1..(1 + self.l)].to_vec(), }, Witness:: { w, r_w }, - ) + )) } /// Computes q(x) = \sum^q c_i * \prod_{j \in S_i} ( \sum_{y \in {0,1}^s'} M_j(x, y) * z(y) ) @@ -109,7 +109,7 @@ impl CCCS { ) -> Result<(), Error> { // check that C is the commitment of w. Notice that this is not verifying a Pedersen // opening, but checking that the Commmitment comes from committing to the witness. - if self.C != Pedersen::commit(pedersen_params, &w.w, &w.r_w) { + if self.C != Pedersen::commit(pedersen_params, &w.w, &w.r_w)? { return Err(Error::NotSatisfied); } diff --git a/src/folding/hypernova/lcccs.rs b/src/folding/hypernova/lcccs.rs index e136475..d107ddf 100644 --- a/src/folding/hypernova/lcccs.rs +++ b/src/folding/hypernova/lcccs.rs @@ -40,15 +40,15 @@ impl CCS { rng: &mut R, pedersen_params: &PedersenParams, z: &[C::ScalarField], - ) -> (LCCCS, Witness) { + ) -> Result<(LCCCS, Witness), Error> { let w: Vec = z[(1 + self.l)..].to_vec(); let r_w = C::ScalarField::rand(rng); - let C = Pedersen::commit(pedersen_params, &w, &r_w); + let C = Pedersen::commit(pedersen_params, &w, &r_w)?; let r_x: Vec = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect(); let v = self.compute_v_j(z, &r_x); - ( + Ok(( LCCCS:: { C, u: C::ScalarField::one(), @@ -57,7 +57,7 @@ impl CCS { v, }, Witness:: { w, r_w }, - ) + )) } } @@ -94,7 +94,7 @@ impl LCCCS { ) -> Result<(), Error> { // check that C is the commitment of w. Notice that this is not verifying a Pedersen // opening, but checking that the Commmitment comes from committing to the witness. - if self.C != Pedersen::commit(pedersen_params, &w.w, &w.r_w) { + if self.C != Pedersen::commit(pedersen_params, &w.w, &w.r_w)? { return Err(Error::NotSatisfied); } @@ -129,7 +129,7 @@ pub mod tests { ccs.check_relation(&z.clone()).unwrap(); let pedersen_params = Pedersen::::new_params(&mut rng, ccs.n - ccs.l - 1); - let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z); + let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap(); // with our test vector comming from R1CS, v should have length 3 assert_eq!(lcccs.v.len(), 3); @@ -160,7 +160,7 @@ pub mod tests { let pedersen_params = Pedersen::::new_params(&mut rng, ccs.n - ccs.l - 1); // Compute v_j with the right z - let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z); + let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap(); // with our test vector comming from R1CS, v should have length 3 assert_eq!(lcccs.v.len(), 3); diff --git a/src/folding/hypernova/nimfs.rs b/src/folding/hypernova/nimfs.rs index da44514..3f9e882 100644 --- a/src/folding/hypernova/nimfs.rs +++ b/src/folding/hypernova/nimfs.rs @@ -373,8 +373,8 @@ pub mod tests { #[test] fn test_fold() { let ccs = get_test_ccs(); - let z1 = get_test_z(3); - let z2 = get_test_z(4); + let z1 = get_test_z::(3); + let z2 = get_test_z::(4); ccs.check_relation(&z1).unwrap(); ccs.check_relation(&z2).unwrap(); @@ -386,8 +386,8 @@ pub mod tests { let pedersen_params = Pedersen::::new_params(&mut rng, ccs.n - ccs.l - 1); - let (lcccs, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1); - let (cccs, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z2); + let (lcccs, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap(); + let (cccs, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z2).unwrap(); lcccs.check_relation(&pedersen_params, &ccs, &w1).unwrap(); cccs.check_relation(&pedersen_params, &ccs, &w2).unwrap(); @@ -420,9 +420,9 @@ pub mod tests { let z_2 = get_test_z(4); // Create the LCCCS instance out of z_1 - let (running_instance, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z_1); + let (running_instance, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap(); // Create the CCCS instance out of z_2 - let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2); + let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap(); // Prover's transcript let mut transcript_p = IOPTranscript::::new(b"multifolding"); @@ -471,7 +471,8 @@ pub mod tests { // LCCCS witness let z_1 = get_test_z(2); - let (mut running_instance, mut w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z_1); + let (mut running_instance, mut w1) = + ccs.to_lcccs(&mut rng, &pedersen_params, &z_1).unwrap(); let mut transcript_p = IOPTranscript::::new(b"multifolding"); let mut transcript_v = IOPTranscript::::new(b"multifolding"); @@ -486,7 +487,7 @@ pub mod tests { let z_2 = get_test_z(i); println!("z_2 {:?}", z_2); // DBG - let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2); + let (new_instance, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z_2).unwrap(); // run the prover side of the multifolding let (proof, folded_lcccs, folded_witness) = NIMFS::::prove( @@ -550,7 +551,7 @@ pub mod tests { let mut lcccs_instances = Vec::new(); let mut w_lcccs = Vec::new(); for z_i in z_lcccs.iter() { - let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i); + let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap(); lcccs_instances.push(running_instance); w_lcccs.push(w); } @@ -558,7 +559,7 @@ pub mod tests { let mut cccs_instances = Vec::new(); let mut w_cccs = Vec::new(); for z_i in z_cccs.iter() { - let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i); + let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap(); cccs_instances.push(new_instance); w_cccs.push(w); } @@ -640,7 +641,7 @@ pub mod tests { let mut lcccs_instances = Vec::new(); let mut w_lcccs = Vec::new(); for z_i in z_lcccs.iter() { - let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i); + let (running_instance, w) = ccs.to_lcccs(&mut rng, &pedersen_params, z_i).unwrap(); lcccs_instances.push(running_instance); w_lcccs.push(w); } @@ -648,7 +649,7 @@ pub mod tests { let mut cccs_instances = Vec::new(); let mut w_cccs = Vec::new(); for z_i in z_cccs.iter() { - let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i); + let (new_instance, w) = ccs.to_cccs(&mut rng, &pedersen_params, z_i).unwrap(); cccs_instances.push(new_instance); w_cccs.push(w); } diff --git a/src/folding/hypernova/utils.rs b/src/folding/hypernova/utils.rs index 23bd50f..6974c5e 100644 --- a/src/folding/hypernova/utils.rs +++ b/src/folding/hypernova/utils.rs @@ -269,7 +269,7 @@ pub mod tests { // Initialize a multifolding object let pedersen_params = Pedersen::new_params(&mut rng, ccs.n - ccs.l - 1); - let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1); + let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap(); let sigmas_thetas = compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime); @@ -312,7 +312,7 @@ pub mod tests { // Initialize a multifolding object let pedersen_params = Pedersen::new_params(&mut rng, ccs.n - ccs.l - 1); - let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1); + let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap(); let mut sum_v_j_gamma = Fr::zero(); for j in 0..lcccs_instance.v.len() { diff --git a/src/folding/nova/circuits.rs b/src/folding/nova/circuits.rs index b33ae45..484c2bb 100644 --- a/src/folding/nova/circuits.rs +++ b/src/folding/nova/circuits.rs @@ -424,8 +424,8 @@ mod tests { let pedersen_params = Pedersen::::new_params(&mut rng, r1cs.A.n_rows); // compute committed instances - let ci1 = w1.commit(&pedersen_params, x1.clone()); - let ci2 = w2.commit(&pedersen_params, x2.clone()); + let ci1 = w1.commit(&pedersen_params, x1.clone()).unwrap(); + let ci2 = w2.commit(&pedersen_params, x2.clone()).unwrap(); // get challenge from transcript let poseidon_config = poseidon_test_config::(); @@ -695,7 +695,7 @@ mod tests { // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we // assign them directly to w_i, u_i. w_i = Witness::::new(w_i1.clone(), r1cs.A.n_rows); - u_i = w_i.commit(&pedersen_params, vec![u_i1_x]); + u_i = w_i.commit(&pedersen_params, vec![u_i1_x]).unwrap(); check_instance_relation(&r1cs, &w_i, &u_i).unwrap(); check_instance_relation(&r1cs, &W_i1, &U_i1).unwrap(); diff --git a/src/folding/nova/mod.rs b/src/folding/nova/mod.rs index b196a69..46de311 100644 --- a/src/folding/nova/mod.rs +++ b/src/folding/nova/mod.rs @@ -92,18 +92,18 @@ where &self, params: &PedersenParams, x: Vec, - ) -> CommittedInstance { + ) -> Result, Error> { let mut cmE = C::zero(); if !is_zero_vec::(&self.E) { - cmE = Pedersen::commit(params, &self.E, &self.rE); + cmE = Pedersen::commit(params, &self.E, &self.rE)?; } - let cmW = Pedersen::commit(params, &self.W, &self.rW); - CommittedInstance { + let cmW = Pedersen::commit(params, &self.W, &self.rW)?; + Ok(CommittedInstance { cmE, u: C::ScalarField::one(), cmW, x, - } + }) } } diff --git a/src/folding/nova/nifs.rs b/src/folding/nova/nifs.rs index e3d7609..06c8f5d 100644 --- a/src/folding/nova/nifs.rs +++ b/src/folding/nova/nifs.rs @@ -103,7 +103,7 @@ where // compute cross terms let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2)?; let rT = C::ScalarField::one(); // use 1 as rT since we don't need hiding property for cm(T) - let cmT = Pedersen::commit(pedersen_params, &T, &rT); + let cmT = Pedersen::commit(pedersen_params, &T, &rT)?; // fold witness let w3 = NIFS::::fold_witness(r, w1, w2, &T, rT)?; @@ -170,12 +170,9 @@ where // cm_proofs should have length 3: [cmE_proof, cmW_proof, cmT_proof] return Err(Error::NotExpectedLength); } - if !Pedersen::verify(pedersen_params, tr, ci.cmE, cm_proofs[0].clone()) - || !Pedersen::verify(pedersen_params, tr, ci.cmW, cm_proofs[1].clone()) - || !Pedersen::verify(pedersen_params, tr, cmT, cm_proofs[2].clone()) - { - return Err(Error::CommitmentVerificationFail); - } + Pedersen::verify(pedersen_params, tr, ci.cmE, cm_proofs[0].clone())?; + Pedersen::verify(pedersen_params, tr, ci.cmW, cm_proofs[1].clone())?; + Pedersen::verify(pedersen_params, tr, cmT, cm_proofs[2].clone())?; Ok(()) } } @@ -210,7 +207,9 @@ pub mod tests { // dummy instance, witness and public inputs zeroes let w_dummy = Witness::::new(vec![Fr::zero(); w1.len()], r1cs.A.n_rows); - let mut u_dummy = w_dummy.commit(&pedersen_params, vec![Fr::zero(); x1.len()]); + let mut u_dummy = w_dummy + .commit(&pedersen_params, vec![Fr::zero(); x1.len()]) + .unwrap(); u_dummy.u = Fr::zero(); let w_i = w_dummy.clone(); @@ -250,8 +249,8 @@ pub mod tests { let r = Fr::rand(&mut rng); // folding challenge would come from the transcript // compute committed instances - let ci1 = w1.commit(&pedersen_params, x1.clone()); - let ci2 = w2.commit(&pedersen_params, x2.clone()); + let ci1 = w1.commit(&pedersen_params, x1.clone()).unwrap(); + let ci2 = w2.commit(&pedersen_params, x2.clone()).unwrap(); // NIFS.P let (w3, ci3_aux, T, cmT) = @@ -273,7 +272,7 @@ pub mod tests { // check that folded commitments from folded instance (ci) are equal to folding the // use folded rE, rW to commit w3 - let ci3_expected = w3.commit(&pedersen_params, ci3.x.clone()); + let ci3_expected = w3.commit(&pedersen_params, ci3.x.clone()).unwrap(); assert_eq!(ci3_expected.cmE, ci3.cmE); assert_eq!(ci3_expected.cmW, ci3.cmW); @@ -322,7 +321,8 @@ pub mod tests { // prepare the running instance let mut running_instance_w = Witness::::new(w.clone(), r1cs.A.n_rows); - let mut running_committed_instance = running_instance_w.commit(&pedersen_params, x); + let mut running_committed_instance = + running_instance_w.commit(&pedersen_params, x).unwrap(); assert!(check_relaxed_r1cs( &r1cs, &z, @@ -336,7 +336,8 @@ pub mod tests { let incomming_instance_z = get_test_z(i + 4); let (w, x) = r1cs.split_z(&incomming_instance_z); let incomming_instance_w = Witness::::new(w.clone(), r1cs.A.n_rows); - let incomming_committed_instance = incomming_instance_w.commit(&pedersen_params, x); + let incomming_committed_instance = + incomming_instance_w.commit(&pedersen_params, x).unwrap(); assert!(check_relaxed_r1cs( &r1cs, &incomming_instance_z.clone(), diff --git a/src/lib.rs b/src/lib.rs index c9daa1f..3560eb3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,10 @@ pub enum Error { NotExpectedLength, #[error("Can not be empty")] Empty, - #[error("Commitment verification failed")] - CommitmentVerificationFail, + #[error("Pedersen parameters length is not suficient")] + PedersenParamsLen, + #[error("Pedersen verification failed")] + PedersenVerificationFail, } /// FoldingScheme defines trait that is implemented by the diverse folding schemes. It is defined diff --git a/src/pedersen.rs b/src/pedersen.rs index d0b984b..823ec74 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -37,9 +37,17 @@ impl Pedersen { params } - pub fn commit(params: &Params, v: &Vec, r: &C::ScalarField) -> C { + pub fn commit( + params: &Params, + v: &Vec, + r: &C::ScalarField, + ) -> Result { + if params.generators.len() < v.len() { + return Err(Error::PedersenParamsLen); + } // h⋅r + - params.h.mul(r) + C::msm(¶ms.generators[..v.len()], v).unwrap() + // use msm_unchecked because we already ensured at the if that lengths match + Ok(params.h.mul(r) + C::msm_unchecked(¶ms.generators[..v.len()], v)) } pub fn prove( @@ -49,12 +57,17 @@ impl Pedersen { v: &Vec, r: &C::ScalarField, ) -> Result, Error> { + if params.generators.len() < v.len() { + return Err(Error::PedersenParamsLen); + } + transcript.absorb_point(cm); let r1 = transcript.get_challenge(); let d = transcript.get_challenges(v.len()); // R = h⋅r_1 + - let R: C = params.h.mul(r1) + C::msm(¶ms.generators[..d.len()], &d).unwrap(); + // use msm_unchecked because we already ensured at the if that lengths match + let R: C = params.h.mul(r1) + C::msm_unchecked(¶ms.generators[..d.len()], &d); transcript.absorb_point(&R); let e = transcript.get_challenge(); @@ -72,7 +85,11 @@ impl Pedersen { transcript: &mut impl Transcript, cm: C, proof: Proof, - ) -> bool { + ) -> Result<(), Error> { + if params.generators.len() < proof.u.len() { + return Err(Error::PedersenParamsLen); + } + transcript.absorb_point(&cm); transcript.get_challenge(); // r_1 transcript.get_challenges(proof.u.len()); // d @@ -81,12 +98,13 @@ impl Pedersen { // check that: R + cm == h⋅r_u + let lhs = proof.R + cm.mul(e); + // use msm_unchecked because we already ensured at the if that lengths match let rhs = params.h.mul(proof.r_u) - + C::msm(¶ms.generators[..proof.u.len()], &proof.u).unwrap(); + + C::msm_unchecked(¶ms.generators[..proof.u.len()], &proof.u); if lhs != rhs { - return false; + return Err(Error::PedersenVerificationFail); } - true + Ok(()) } } @@ -113,9 +131,8 @@ mod tests { let v: Vec = vec![Fr::rand(&mut rng); n]; let r: Fr = Fr::rand(&mut rng); - let cm = Pedersen::::commit(¶ms, &v, &r); + let cm = Pedersen::::commit(¶ms, &v, &r).unwrap(); let proof = Pedersen::::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap(); - let v = Pedersen::::verify(¶ms, &mut transcript_v, cm, proof); - assert!(v); + Pedersen::::verify(¶ms, &mut transcript_v, cm, proof).unwrap(); } }