From 13e471aeaf408355e3764091a35335152055574c Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 4 Oct 2023 15:43:24 +0200 Subject: [PATCH] add error handling to several pending methods (#30) --- rust-toolchain | 2 +- src/ccs/mod.rs | 4 +- src/ccs/r1cs.rs | 10 +++- src/decider/circuit.rs | 29 +++++++--- src/folding/hypernova/cccs.rs | 4 +- src/folding/hypernova/lcccs.rs | 8 ++- src/folding/hypernova/nimfs.rs | 85 +++++++++++++++++---------- src/folding/nova/circuits.rs | 2 +- src/folding/nova/nifs.rs | 103 +++++++++++++++++---------------- src/lib.rs | 15 ++++- src/pedersen.rs | 9 +-- src/utils/vec.rs | 52 +++++++++++------ 12 files changed, 203 insertions(+), 120 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index f474f5a..68bc7ff 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -1.71.0 \ No newline at end of file +1.71.1 diff --git a/src/ccs/mod.rs b/src/ccs/mod.rs index 23ba24b..b96ca61 100644 --- a/src/ccs/mod.rs +++ b/src/ccs/mod.rs @@ -51,14 +51,14 @@ impl CCS { // complete the hadamard chain let mut hadamard_result = vec![C::ScalarField::one(); self.m]; for M_j in vec_M_j.into_iter() { - hadamard_result = hadamard(&hadamard_result, &mat_vec_mul_sparse(M_j, z)); + hadamard_result = hadamard(&hadamard_result, &mat_vec_mul_sparse(M_j, z))?; } // multiply by the coefficient of this step let c_M_j_z = vec_scalar_mul(&hadamard_result, &self.c[i]); // add it to the final vector - result = vec_add(&result, &c_M_j_z); + result = vec_add(&result, &c_M_j_z)?; } // make sure the final vector is all zeroes diff --git a/src/ccs/r1cs.rs b/src/ccs/r1cs.rs index 26084ad..b4397f4 100644 --- a/src/ccs/r1cs.rs +++ b/src/ccs/r1cs.rs @@ -22,8 +22,10 @@ impl R1CS { let Az = mat_vec_mul_sparse(&self.A, z); let Bz = mat_vec_mul_sparse(&self.B, z); let Cz = mat_vec_mul_sparse(&self.C, z); - let AzBz = hadamard(&Az, &Bz); - assert_eq!(AzBz, Cz); + let AzBz = hadamard(&Az, &Bz)?; + if AzBz != Cz { + return Err(Error::NotSatisfied); + } Ok(()) } @@ -60,7 +62,9 @@ impl RelaxedR1CS { let uCz = vec_scalar_mul(&Cz, &self.u); let uCzE = vec_add(&uCz, &self.E); let AzBz = hadamard(&Az, &Bz); - assert_eq!(AzBz, uCzE); + if AzBz != uCzE { + return Err(Error::NotSatisfied); + } Ok(()) } diff --git a/src/decider/circuit.rs b/src/decider/circuit.rs index 14fcce6..61b979c 100644 --- a/src/decider/circuit.rs +++ b/src/decider/circuit.rs @@ -10,6 +10,7 @@ use core::{borrow::Borrow, marker::PhantomData}; use crate::ccs::r1cs::RelaxedR1CS; use crate::utils::vec::SparseMatrix; +use crate::Error; pub type ConstraintF = <::BaseField as Field>::BasePrimeField; @@ -19,13 +20,13 @@ pub struct RelaxedR1CSGadget { } impl RelaxedR1CSGadget { /// performs the RelaxedR1CS check (Az∘Bz==uCz+E) - pub fn check(rel_r1cs: RelaxedR1CSVar, z: Vec>) -> Result<(), SynthesisError> { + pub fn check(rel_r1cs: RelaxedR1CSVar, z: Vec>) -> Result<(), Error> { let Az = mat_vec_mul_sparse(rel_r1cs.A, z.clone()); let Bz = mat_vec_mul_sparse(rel_r1cs.B, z.clone()); let Cz = mat_vec_mul_sparse(rel_r1cs.C, z.clone()); let uCz = vec_scalar_mul(&Cz, &rel_r1cs.u); - let uCzE = vec_add(&uCz, &rel_r1cs.E); - let AzBz = hadamard(&Az, &Bz); + let uCzE = vec_add(&uCz, &rel_r1cs.E)?; + let AzBz = hadamard(&Az, &Bz)?; for i in 0..AzBz.len() { AzBz[i].enforce_equal(&uCzE[i].clone())?; } @@ -42,13 +43,18 @@ fn mat_vec_mul_sparse(m: SparseMatrixVar, v: Vec>) -> } res } -pub fn vec_add(a: &Vec>, b: &Vec>) -> Vec> { - assert_eq!(a.len(), b.len()); +pub fn vec_add( + a: &Vec>, + b: &Vec>, +) -> Result>, Error> { + if a.len() != b.len() { + return Err(Error::NotSameLength); + } let mut r: Vec> = vec![FpVar::::zero(); a.len()]; for i in 0..a.len() { r[i] = a[i].clone() + b[i].clone(); } - r + Ok(r) } pub fn vec_scalar_mul(vec: &Vec>, c: &FpVar) -> Vec> { let mut result = vec![FpVar::::zero(); vec.len()]; @@ -57,13 +63,18 @@ pub fn vec_scalar_mul(vec: &Vec>, c: &FpVar) -> Vec(a: &Vec>, b: &Vec>) -> Vec> { - assert_eq!(a.len(), b.len()); +pub fn hadamard( + a: &Vec>, + b: &Vec>, +) -> Result>, Error> { + if a.len() != b.len() { + return Err(Error::NotSameLength); + } let mut r: Vec> = vec![FpVar::::zero(); a.len()]; for i in 0..a.len() { r[i] = a[i].clone() * b[i].clone(); } - r + Ok(r) } #[derive(Debug, Clone)] diff --git a/src/folding/hypernova/cccs.rs b/src/folding/hypernova/cccs.rs index 9922dbf..3a00d32 100644 --- a/src/folding/hypernova/cccs.rs +++ b/src/folding/hypernova/cccs.rs @@ -109,7 +109,9 @@ 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. - assert_eq!(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); + } // check CCCS relation let z: Vec = diff --git a/src/folding/hypernova/lcccs.rs b/src/folding/hypernova/lcccs.rs index be4a34c..e136475 100644 --- a/src/folding/hypernova/lcccs.rs +++ b/src/folding/hypernova/lcccs.rs @@ -94,12 +94,16 @@ 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. - assert_eq!(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); + } // check CCS relation let z: Vec = [vec![self.u], self.x.clone(), w.w.to_vec()].concat(); let computed_v = compute_all_sum_Mz_evals(&ccs.M, &z, &self.r_x, ccs.s_prime); - assert_eq!(computed_v, self.v); + if computed_v != self.v { + return Err(Error::NotSatisfied); + } Ok(()) } } diff --git a/src/folding/hypernova/nimfs.rs b/src/folding/hypernova/nimfs.rs index b824c39..da44514 100644 --- a/src/folding/hypernova/nimfs.rs +++ b/src/folding/hypernova/nimfs.rs @@ -13,6 +13,7 @@ use crate::utils::hypercube::BooleanHypercube; use crate::utils::sum_check::structs::IOPProof as SumCheckProof; use crate::utils::sum_check::{verifier::interpolate_uni_poly, SumCheck}; use crate::utils::virtual_polynomial::VPAuxInfo; +use crate::Error; use std::marker::PhantomData; @@ -139,8 +140,9 @@ impl NIMFS { /// Performs the multifolding prover. Given μ LCCCS instances and ν CCS instances, fold them /// into a single LCCCS instance. Since this is the prover, also fold their witness. - /// Returns the final folded LCCCS, the folded witness, the sumcheck proof, and the helper - /// sumcheck claim sigmas and thetas. + /// Returns the final folded LCCCS, the folded witness, and the multifolding proof, which + /// contains the sumcheck proof and the helper sumcheck claim sigmas and thetas. + #[allow(clippy::type_complexity)] pub fn prove( transcript: &mut IOPTranscript, ccs: &CCS, @@ -148,11 +150,15 @@ impl NIMFS { new_instances: &[CCCS], w_lcccs: &[Witness], w_cccs: &[Witness], - ) -> (Proof, LCCCS, Witness) { + ) -> Result<(Proof, LCCCS, Witness), Error> { // TODO appends to transcript - assert!(!running_instances.is_empty()); - assert!(!new_instances.is_empty()); + if running_instances.is_empty() { + return Err(Error::Empty); + } + if new_instances.is_empty() { + return Err(Error::Empty); + } // construct the LCCCS z vector from the relaxation factor, public IO and witness // XXX this deserves its own function in LCCCS @@ -205,7 +211,9 @@ impl NIMFS { // note: this is the sum of g(x) over the whole boolean hypercube let extracted_sum = as SumCheck>::extract_sum(&sumcheck_proof); - assert_eq!(extracted_sum, g_over_bhc); + if extracted_sum != g_over_bhc { + return Err(Error::NotEqual); + } // Sanity check 2: expect \sum v_j * gamma^j to be equal to the sum of g(x) over the // boolean hypercube (and also equal to the extracted_sum from the SumCheck). let mut sum_v_j_gamma = C::ScalarField::zero(); @@ -215,8 +223,12 @@ impl NIMFS { sum_v_j_gamma += running_instance.v[j] * gamma_j; } } - assert_eq!(g_over_bhc, sum_v_j_gamma); - assert_eq!(extracted_sum, sum_v_j_gamma); + if g_over_bhc != sum_v_j_gamma { + return Err(Error::NotEqual); + } + if extracted_sum != sum_v_j_gamma { + return Err(Error::NotEqual); + } ////////////////////////////////////////////////////////////////////// // Step 2: dig into the sumcheck and extract r_x_prime @@ -240,14 +252,14 @@ impl NIMFS { // Step 8: Fold the witnesses let folded_witness = Self::fold_witness(w_lcccs, w_cccs, rho); - ( + Ok(( Proof:: { sc_proof: sumcheck_proof, sigmas_thetas, }, folded_lcccs, folded_witness, - ) + )) } /// Performs the multifolding verifier. Given μ LCCCS instances and ν CCS instances, fold them @@ -259,11 +271,15 @@ impl NIMFS { running_instances: &[LCCCS], new_instances: &[CCCS], proof: Proof, - ) -> LCCCS { + ) -> Result, Error> { // TODO appends to transcript - assert!(!running_instances.is_empty()); - assert!(!new_instances.is_empty()); + if running_instances.is_empty() { + return Err(Error::Empty); + } + if new_instances.is_empty() { + return Err(Error::Empty); + } // Step 1: Get some challenges let gamma: C::ScalarField = transcript.get_and_append_challenge(b"gamma").unwrap(); @@ -312,7 +328,9 @@ impl NIMFS { &r_x_prime, ); // check that the g(r_x') from the sumcheck proof is equal to the computed c from sigmas&thetas - assert_eq!(c, sumcheck_subclaim.expected_evaluation); + if c != sumcheck_subclaim.expected_evaluation { + return Err(Error::NotEqual); + } // Sanity check: we can also compute g(r_x') from the proof last evaluation value, and // should be equal to the previously obtained values. @@ -321,23 +339,24 @@ impl NIMFS { *r_x_prime.last().unwrap(), ) .unwrap(); - assert_eq!(g_on_rxprime_from_sumcheck_last_eval, c); - assert_eq!( - g_on_rxprime_from_sumcheck_last_eval, - sumcheck_subclaim.expected_evaluation - ); + if g_on_rxprime_from_sumcheck_last_eval != c { + return Err(Error::NotEqual); + } + if g_on_rxprime_from_sumcheck_last_eval != sumcheck_subclaim.expected_evaluation { + return Err(Error::NotEqual); + } // Step 6: Get the folding challenge let rho: C::ScalarField = transcript.get_and_append_challenge(b"rho").unwrap(); // Step 7: Compute the folded instance - Self::fold( + Ok(Self::fold( running_instances, new_instances, &proof.sigmas_thetas, r_x_prime, rho, - ) + )) } } @@ -417,7 +436,8 @@ pub mod tests { &[new_instance.clone()], &[w1], &[w2], - ); + ) + .unwrap(); // Verifier's transcript let mut transcript_v = IOPTranscript::::new(b"multifolding"); @@ -430,7 +450,8 @@ pub mod tests { &[running_instance.clone()], &[new_instance.clone()], proof, - ); + ) + .unwrap(); assert_eq!(folded_lcccs, folded_lcccs_v); // Check that the folded LCCCS instance is a valid instance with respect to the folded witness @@ -475,7 +496,8 @@ pub mod tests { &[new_instance.clone()], &[w1], &[w2], - ); + ) + .unwrap(); // run the verifier side of the multifolding let folded_lcccs_v = NIMFS::::verify( @@ -484,7 +506,8 @@ pub mod tests { &[running_instance.clone()], &[new_instance.clone()], proof, - ); + ) + .unwrap(); assert_eq!(folded_lcccs, folded_lcccs_v); @@ -552,7 +575,8 @@ pub mod tests { &cccs_instances, &w_lcccs, &w_cccs, - ); + ) + .unwrap(); // Verifier's transcript let mut transcript_v = IOPTranscript::::new(b"multifolding"); @@ -565,7 +589,8 @@ pub mod tests { &lcccs_instances, &cccs_instances, proof, - ); + ) + .unwrap(); assert_eq!(folded_lcccs, folded_lcccs_v); // Check that the folded LCCCS instance is a valid instance with respect to the folded witness @@ -636,7 +661,8 @@ pub mod tests { &cccs_instances, &w_lcccs, &w_cccs, - ); + ) + .unwrap(); // Run the verifier side of the multifolding let folded_lcccs_v = NIMFS::::verify( @@ -645,7 +671,8 @@ pub mod tests { &lcccs_instances, &cccs_instances, proof, - ); + ) + .unwrap(); assert_eq!(folded_lcccs, folded_lcccs_v); // Check that the folded LCCCS instance is a valid instance with respect to the folded witness diff --git a/src/folding/nova/circuits.rs b/src/folding/nova/circuits.rs index 9d97ade..69ea0a6 100644 --- a/src/folding/nova/circuits.rs +++ b/src/folding/nova/circuits.rs @@ -222,7 +222,7 @@ mod tests { let r_Fr = Fr::from_bigint(BigInteger::from_bits_le(&r_bits)).unwrap(); let (_w3, ci3, _T, cmT) = - NIFS::::prove(&pedersen_params, r_Fr, &r1cs, &w1, &ci1, &w2, &ci2); + NIFS::::prove(&pedersen_params, r_Fr, &r1cs, &w1, &ci1, &w2, &ci2).unwrap(); let cs = ConstraintSystem::::new_ref(); diff --git a/src/folding/nova/nifs.rs b/src/folding/nova/nifs.rs index d211933..65167e8 100644 --- a/src/folding/nova/nifs.rs +++ b/src/folding/nova/nifs.rs @@ -8,6 +8,7 @@ use crate::folding::nova::{CommittedInstance, Witness}; use crate::pedersen::{Params as PedersenParams, Pedersen, Proof as PedersenProof}; use crate::transcript::Transcript; use crate::utils::vec::*; +use crate::Error; /// Implements the Non-Interactive Folding Scheme described in section 4 of /// https://eprint.iacr.org/2021/370.pdf @@ -26,7 +27,7 @@ where u2: C::ScalarField, z1: &[C::ScalarField], z2: &[C::ScalarField], - ) -> Vec { + ) -> Result, Error> { let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone()); // this is parallelizable (for the future) @@ -37,12 +38,12 @@ where let Bz2 = mat_vec_mul_sparse(&B, z2); let Cz2 = mat_vec_mul_sparse(&C, z2); - let Az1_Bz2 = hadamard(&Az1, &Bz2); - let Az2_Bz1 = hadamard(&Az2, &Bz1); + let Az1_Bz2 = hadamard(&Az1, &Bz2)?; + let Az2_Bz1 = hadamard(&Az2, &Bz1)?; let u1Cz2 = vec_scalar_mul(&Cz2, &u1); let u2Cz1 = vec_scalar_mul(&Cz1, &u2); - vec_sub(&vec_sub(&vec_add(&Az1_Bz2, &Az2_Bz1), &u1Cz2), &u2Cz1) + vec_sub(&vec_sub(&vec_add(&Az1_Bz2, &Az2_Bz1)?, &u1Cz2)?, &u2Cz1) } pub fn fold_witness( @@ -51,17 +52,17 @@ where w2: &Witness, T: &[C::ScalarField], rT: C::ScalarField, - ) -> Witness { + ) -> Result, Error> { let r2 = r * r; let E: Vec = vec_add( - &vec_add(&w1.E, &vec_scalar_mul(T, &r)), + &vec_add(&w1.E, &vec_scalar_mul(T, &r))?, &vec_scalar_mul(&w2.E, &r2), - ); + )?; let rE = w1.rE + r * rT + r2 * w2.rE; let W: Vec = w1.W.iter().zip(&w2.W).map(|(a, b)| *a + (r * b)).collect(); let rW = w1.rW + r * w2.rW; - Witness:: { E, rE, W, rW } + Ok(Witness:: { E, rE, W, rW }) } pub fn fold_committed_instance( @@ -95,22 +96,22 @@ where ci1: &CommittedInstance, w2: &Witness, ci2: &CommittedInstance, - ) -> (Witness, CommittedInstance, Vec, C) { + ) -> Result<(Witness, CommittedInstance, Vec, C), Error> { let z1: Vec = [vec![ci1.u], ci1.x.to_vec(), w1.W.to_vec()].concat(); let z2: Vec = [vec![ci2.u], ci2.x.to_vec(), w2.W.to_vec()].concat(); // compute cross terms - let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2); + 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); // fold witness - let w3 = NIFS::::fold_witness(r, w1, w2, &T, rT); + let w3 = NIFS::::fold_witness(r, w1, w2, &T, rT)?; // fold committed instancs let ci3 = NIFS::::fold_committed_instance(r, ci1, ci2, &cmT); - (w3, ci3, T, cmT) + Ok((w3, ci3, T, cmT)) } // NIFS.V @@ -124,28 +125,30 @@ where NIFS::::fold_committed_instance(r, ci1, ci2, cmT) } - // verify commited folded instance (ci) relations + /// Verify commited folded instance (ci) relations. Notice that this method does not open the + /// commitments, but just checks that the given committed instances (ci1, ci2) when folded + /// result in the folded committed instance (ci3) values. pub fn verify_folded_instance( r: C::ScalarField, ci1: &CommittedInstance, ci2: &CommittedInstance, ci3: &CommittedInstance, cmT: &C, - ) -> bool { + ) -> Result<(), Error> { let r2 = r * r; if ci3.cmE != (ci1.cmE + cmT.mul(r) + ci2.cmE.mul(r2)) { - return false; + return Err(Error::NotSatisfied); } if ci3.u != ci1.u + r * ci2.u { - return false; + return Err(Error::NotSatisfied); } if ci3.cmW != (ci1.cmW + ci2.cmW.mul(r)) { - return false; + return Err(Error::NotSatisfied); } - if ci3.x != vec_add(&ci1.x, &vec_scalar_mul(&ci2.x, &r)) { - return false; + if ci3.x != vec_add(&ci1.x, &vec_scalar_mul(&ci2.x, &r))? { + return Err(Error::NotSatisfied); } - true + Ok(()) } pub fn open_commitments( @@ -155,31 +158,33 @@ where ci: &CommittedInstance, T: Vec, cmT: &C, - ) -> (PedersenProof, PedersenProof, PedersenProof) { - let cmE_proof = Pedersen::prove(pedersen_params, tr, &ci.cmE, &w.E, &w.rE); - let cmW_proof = Pedersen::prove(pedersen_params, tr, &ci.cmW, &w.W, &w.rW); - let cmT_proof = Pedersen::prove(pedersen_params, tr, cmT, &T, &C::ScalarField::one()); // cm(T) is committed with rT=1 - (cmE_proof, cmW_proof, cmT_proof) + ) -> Result<[PedersenProof; 3], Error> { + let cmE_proof = Pedersen::prove(pedersen_params, tr, &ci.cmE, &w.E, &w.rE)?; + let cmW_proof = Pedersen::prove(pedersen_params, tr, &ci.cmW, &w.W, &w.rW)?; + let cmT_proof = Pedersen::prove(pedersen_params, tr, cmT, &T, &C::ScalarField::one())?; // cm(T) is committed with rT=1 + Ok([cmE_proof, cmW_proof, cmT_proof]) } pub fn verify_commitments( tr: &mut impl Transcript, pedersen_params: &PedersenParams, ci: CommittedInstance, cmT: C, - cmE_proof: PedersenProof, - cmW_proof: PedersenProof, - cmT_proof: PedersenProof, - ) -> bool { - if !Pedersen::verify(pedersen_params, tr, ci.cmE, cmE_proof) { - return false; + cm_proofs: [PedersenProof; 3], + ) -> Result<(), Error> { + if cm_proofs.len() != 3 { + // 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()) { + return Err(Error::CommitmentVerificationFail); } - if !Pedersen::verify(pedersen_params, tr, ci.cmW, cmW_proof) { - return false; + if !Pedersen::verify(pedersen_params, tr, ci.cmW, cm_proofs[1].clone()) { + return Err(Error::CommitmentVerificationFail); } - if !Pedersen::verify(pedersen_params, tr, cmT, cmT_proof) { - return false; + if !Pedersen::verify(pedersen_params, tr, cmT, cm_proofs[2].clone()) { + return Err(Error::CommitmentVerificationFail); } - true + Ok(()) } } @@ -222,7 +227,7 @@ mod tests { // NIFS.P let (w3, _, T, cmT) = - NIFS::::prove(&pedersen_params, r, &r1cs, &w1, &ci1, &w2, &ci2); + NIFS::::prove(&pedersen_params, r, &r1cs, &w1, &ci1, &w2, &ci2).unwrap(); // NIFS.V let ci3 = NIFS::::verify(r, &ci1, &ci2, &cmT); @@ -230,7 +235,7 @@ mod tests { // naive check that the folded witness satisfies the relaxed r1cs let z3: Vec = [vec![ci3.u], ci3.x.to_vec(), w3.W.to_vec()].concat(); // check that z3 is as expected - let z3_aux = vec_add(&z1, &vec_scalar_mul(&z2, &r)); + let z3_aux = vec_add(&z1, &vec_scalar_mul(&z2, &r)).unwrap(); assert_eq!(z3, z3_aux); // check that relations hold for the 2 inputted instances and the folded one check_relaxed_r1cs(&r1cs, z1, ci1.u, &w1.E); @@ -244,9 +249,7 @@ mod tests { assert_eq!(ci3_expected.cmW, ci3.cmW); // NIFS.Verify_Folded_Instance: - assert!(NIFS::::verify_folded_instance( - r, &ci1, &ci2, &ci3, &cmT - )); + NIFS::::verify_folded_instance(r, &ci1, &ci2, &ci3, &cmT).unwrap(); let poseidon_config = poseidon_test_config::(); // init Prover's transcript @@ -255,24 +258,23 @@ mod tests { let mut transcript_v = PoseidonTranscript::::new(&poseidon_config); // check openings of ci3.cmE, ci3.cmW and cmT - let (cmE_proof, cmW_proof, cmT_proof) = NIFS::::open_commitments( + let cm_proofs = NIFS::::open_commitments( &mut transcript_p, &pedersen_params, &w3, &ci3, T, &cmT, - ); - let v = NIFS::::verify_commitments( + ) + .unwrap(); + NIFS::::verify_commitments( &mut transcript_v, &pedersen_params, ci3, cmT, - cmE_proof, - cmW_proof, - cmT_proof, - ); - assert!(v); + cm_proofs, + ) + .unwrap(); } #[test] @@ -319,7 +321,8 @@ mod tests { &running_committed_instance, &incomming_instance_w, &incomming_committed_instance, - ); + ) + .unwrap(); // NIFS.V let folded_committed_instance = NIFS::::verify( diff --git a/src/lib.rs b/src/lib.rs index 29e7935..c9daa1f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,10 +16,23 @@ pub mod frontend; pub mod pedersen; pub mod utils; -#[derive(Debug, Error)] +#[derive(Debug, Error, PartialEq)] pub enum Error { + #[error("ark_relations::r1cs::SynthesisError")] + SynthesisError(#[from] ark_relations::r1cs::SynthesisError), + #[error("Relation not satisfied")] NotSatisfied, + #[error("Not equal")] + NotEqual, + #[error("Vectors should have the same length")] + NotSameLength, + #[error("Vector's length is not the expected")] + NotExpectedLength, + #[error("Can not be empty")] + Empty, + #[error("Commitment verification failed")] + CommitmentVerificationFail, } /// 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 16af2e5..d0b984b 100644 --- a/src/pedersen.rs +++ b/src/pedersen.rs @@ -5,6 +5,7 @@ use std::marker::PhantomData; use crate::utils::vec::{vec_add, vec_scalar_mul}; use crate::transcript::Transcript; +use crate::Error; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Proof { @@ -47,7 +48,7 @@ impl Pedersen { cm: &C, v: &Vec, r: &C::ScalarField, - ) -> Proof { + ) -> Result, Error> { transcript.absorb_point(cm); let r1 = transcript.get_challenge(); let d = transcript.get_challenges(v.len()); @@ -59,11 +60,11 @@ impl Pedersen { let e = transcript.get_challenge(); // u = d + v⋅e - let u = vec_add(&vec_scalar_mul(v, &e), &d); + let u = vec_add(&vec_scalar_mul(v, &e), &d)?; // r_u = e⋅r + r_1 let r_u = e * r + r1; - Proof:: { R, u, r_u } + Ok(Proof:: { R, u, r_u }) } pub fn verify( @@ -113,7 +114,7 @@ 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 proof = Pedersen::::prove(¶ms, &mut transcript_p, &cm, &v, &r); + let proof = Pedersen::::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap(); let v = Pedersen::::verify(¶ms, &mut transcript_v, cm, proof); assert!(v); } diff --git a/src/utils/vec.rs b/src/utils/vec.rs index 8e71b32..34382c3 100644 --- a/src/utils/vec.rs +++ b/src/utils/vec.rs @@ -3,6 +3,8 @@ pub use ark_relations::r1cs::Matrix as R1CSMatrix; use ark_std::cfg_iter; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; +use crate::Error; + #[derive(Clone, Debug, Eq, PartialEq)] pub struct SparseMatrix { pub n_rows: usize, @@ -42,22 +44,26 @@ pub fn dense_matrix_to_sparse(m: Vec>) -> SparseMatrix r } -pub fn vec_add(a: &[F], b: &[F]) -> Vec { - assert_eq!(a.len(), b.len()); +pub fn vec_add(a: &[F], b: &[F]) -> Result, Error> { + if a.len() != b.len() { + return Err(Error::NotSameLength); + } let mut r: Vec = vec![F::zero(); a.len()]; for i in 0..a.len() { r[i] = a[i] + b[i]; } - r + Ok(r) } -pub fn vec_sub(a: &[F], b: &[F]) -> Vec { - assert_eq!(a.len(), b.len()); +pub fn vec_sub(a: &[F], b: &[F]) -> Result, Error> { + if a.len() != b.len() { + return Err(Error::NotSameLength); + } let mut r: Vec = vec![F::zero(); a.len()]; for i in 0..a.len() { r[i] = a[i] - b[i]; } - r + Ok(r) } pub fn vec_scalar_mul(vec: &[F], c: &F) -> Vec { @@ -77,9 +83,13 @@ pub fn is_zero_vec(vec: &[F]) -> bool { true } -pub fn mat_vec_mul(M: &Vec>, z: &[F]) -> Vec { - assert!(!M.is_empty()); - assert_eq!(M[0].len(), z.len()); +pub fn mat_vec_mul(M: &Vec>, z: &[F]) -> Result, Error> { + if M.is_empty() { + return Err(Error::Empty); + } + if M[0].len() != z.len() { + return Err(Error::NotSameLength); + } let mut r: Vec = vec![F::zero(); M.len()]; for (i, M_i) in M.iter().enumerate() { @@ -87,7 +97,7 @@ pub fn mat_vec_mul(M: &Vec>, z: &[F]) -> Vec { r[i] += *M_ij * z[j]; } } - r + Ok(r) } pub fn mat_vec_mul_sparse(matrix: &SparseMatrix, vector: &[F]) -> Vec { @@ -101,9 +111,11 @@ pub fn mat_vec_mul_sparse(matrix: &SparseMatrix, vector: &[F]) res } -pub fn hadamard(a: &[F], b: &[F]) -> Vec { - assert_eq!(a.len(), b.len()); - cfg_iter!(a).zip(b).map(|(a, b)| *a * b).collect() +pub fn hadamard(a: &[F], b: &[F]) -> Result, Error> { + if a.len() != b.len() { + return Err(Error::NotSameLength); + } + Ok(cfg_iter!(a).zip(b).map(|(a, b)| *a * b).collect()) } #[cfg(test)] @@ -155,7 +167,7 @@ pub mod tests { ]) .to_dense(); let z = to_F_vec(vec![1, 3, 35, 9, 27, 30]); - assert_eq!(mat_vec_mul(&A, &z), to_F_vec(vec![3, 9, 30, 35])); + assert_eq!(mat_vec_mul(&A, &z).unwrap(), to_F_vec(vec![3, 9, 30, 35])); assert_eq!( mat_vec_mul_sparse(&dense_matrix_to_sparse(A), &z), to_F_vec(vec![3, 9, 30, 35]) @@ -165,7 +177,7 @@ pub mod tests { let v = to_F_vec(vec![19, 55, 50, 3]); assert_eq!( - mat_vec_mul(&A.to_dense(), &v), + mat_vec_mul(&A.to_dense(), &v).unwrap(), to_F_vec(vec![418, 1158, 979]) ); assert_eq!(mat_vec_mul_sparse(&A, &v), to_F_vec(vec![418, 1158, 979])); @@ -175,12 +187,18 @@ pub mod tests { fn test_hadamard_product() { let a = to_F_vec::(vec![1, 2, 3, 4, 5, 6]); let b = to_F_vec(vec![7, 8, 9, 10, 11, 12]); - assert_eq!(hadamard(&a, &b), to_F_vec(vec![7, 16, 27, 40, 55, 72])); + assert_eq!( + hadamard(&a, &b).unwrap(), + to_F_vec(vec![7, 16, 27, 40, 55, 72]) + ); } #[test] fn test_vec_add() { let a: Vec = to_F_vec::(vec![1, 2, 3, 4, 5, 6]); let b: Vec = to_F_vec(vec![7, 8, 9, 10, 11, 12]); - assert_eq!(vec_add(&a, &b), to_F_vec(vec![8, 10, 12, 14, 16, 18])); + assert_eq!( + vec_add(&a, &b).unwrap(), + to_F_vec(vec![8, 10, 12, 14, 16, 18]) + ); } }