Browse Source

add error handling to several pending methods (#30)

main
arnaucube 1 year ago
committed by GitHub
parent
commit
13e471aeaf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 203 additions and 120 deletions
  1. +1
    -1
      rust-toolchain
  2. +2
    -2
      src/ccs/mod.rs
  3. +7
    -3
      src/ccs/r1cs.rs
  4. +20
    -9
      src/decider/circuit.rs
  5. +3
    -1
      src/folding/hypernova/cccs.rs
  6. +6
    -2
      src/folding/hypernova/lcccs.rs
  7. +56
    -29
      src/folding/hypernova/nimfs.rs
  8. +1
    -1
      src/folding/nova/circuits.rs
  9. +53
    -50
      src/folding/nova/nifs.rs
  10. +14
    -1
      src/lib.rs
  11. +5
    -4
      src/pedersen.rs
  12. +35
    -17
      src/utils/vec.rs

+ 1
- 1
rust-toolchain

@ -1 +1 @@
1.71.0
1.71.1

+ 2
- 2
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

+ 7
- 3
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(())
}

+ 20
- 9
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<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
@ -19,13 +20,13 @@ pub struct RelaxedR1CSGadget {
}
impl<F: PrimeField> RelaxedR1CSGadget<F> {
/// performs the RelaxedR1CS check (Az∘Bz==uCz+E)
pub fn check(rel_r1cs: RelaxedR1CSVar<F>, z: Vec<FpVar<F>>) -> Result<(), SynthesisError> {
pub fn check(rel_r1cs: RelaxedR1CSVar<F>, z: Vec<FpVar<F>>) -> 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<F: PrimeField>(a: &Vec<FpVar<F>>, b: &Vec<FpVar<F>>) -> Vec<FpVar<F>> {
assert_eq!(a.len(), b.len());
pub fn vec_add<F: PrimeField>(
a: &Vec<FpVar<F>>,
b: &Vec<FpVar<F>>,
) -> Result<Vec<FpVar<F>>, Error> {
if a.len() != b.len() {
return Err(Error::NotSameLength);
}
let mut r: Vec<FpVar<F>> = vec![FpVar::<F>::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<F: PrimeField>(vec: &Vec<FpVar<F>>, c: &FpVar<F>) -> Vec<FpVar<F>> {
let mut result = vec![FpVar::<F>::zero(); vec.len()];
@ -57,13 +63,18 @@ pub fn vec_scalar_mul(vec: &Vec>, c: &FpVar) -> Vec
}
result
}
pub fn hadamard<F: PrimeField>(a: &Vec<FpVar<F>>, b: &Vec<FpVar<F>>) -> Vec<FpVar<F>> {
assert_eq!(a.len(), b.len());
pub fn hadamard<F: PrimeField>(
a: &Vec<FpVar<F>>,
b: &Vec<FpVar<F>>,
) -> Result<Vec<FpVar<F>>, Error> {
if a.len() != b.len() {
return Err(Error::NotSameLength);
}
let mut r: Vec<FpVar<F>> = vec![FpVar::<F>::zero(); a.len()];
for i in 0..a.len() {
r[i] = a[i].clone() * b[i].clone();
}
r
Ok(r)
}
#[derive(Debug, Clone)]

+ 3
- 1
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<C::ScalarField> =

+ 6
- 2
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<C::ScalarField> = [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(())
}
}

+ 56
- 29
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<C::ScalarField>,
ccs: &CCS<C>,
@ -148,11 +150,15 @@ impl NIMFS {
new_instances: &[CCCS<C>],
w_lcccs: &[Witness<C::ScalarField>],
w_cccs: &[Witness<C::ScalarField>],
) -> (Proof<C>, LCCCS<C>, Witness<C::ScalarField>) {
) -> Result<(Proof<C>, LCCCS<C>, Witness<C::ScalarField>), 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 =
<PolyIOP<C::ScalarField> as SumCheck<C::ScalarField>>::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::<C> {
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<C>],
new_instances: &[CCCS<C>],
proof: Proof<C>,
) -> LCCCS<C> {
) -> Result<LCCCS<C>, 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::<Fr>::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::<Projective>::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::<Fr>::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::<Projective>::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

+ 1
- 1
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::<Projective>::prove(&pedersen_params, r_Fr, &r1cs, &w1, &ci1, &w2, &ci2);
NIFS::<Projective>::prove(&pedersen_params, r_Fr, &r1cs, &w1, &ci1, &w2, &ci2).unwrap();
let cs = ConstraintSystem::<Fr>::new_ref();

+ 53
- 50
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<C::ScalarField> {
) -> Result<Vec<C::ScalarField>, 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<C>,
T: &[C::ScalarField],
rT: C::ScalarField,
) -> Witness<C> {
) -> Result<Witness<C>, Error> {
let r2 = r * r;
let E: Vec<C::ScalarField> = 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<C::ScalarField> = w1.W.iter().zip(&w2.W).map(|(a, b)| *a + (r * b)).collect();
let rW = w1.rW + r * w2.rW;
Witness::<C> { E, rE, W, rW }
Ok(Witness::<C> { E, rE, W, rW })
}
pub fn fold_committed_instance(
@ -95,22 +96,22 @@ where
ci1: &CommittedInstance<C>,
w2: &Witness<C>,
ci2: &CommittedInstance<C>,
) -> (Witness<C>, CommittedInstance<C>, Vec<C::ScalarField>, C) {
) -> Result<(Witness<C>, CommittedInstance<C>, Vec<C::ScalarField>, C), Error> {
let z1: Vec<C::ScalarField> = [vec![ci1.u], ci1.x.to_vec(), w1.W.to_vec()].concat();
let z2: Vec<C::ScalarField> = [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::<C>::fold_witness(r, w1, w2, &T, rT);
let w3 = NIFS::<C>::fold_witness(r, w1, w2, &T, rT)?;
// fold committed instancs
let ci3 = NIFS::<C>::fold_committed_instance(r, ci1, ci2, &cmT);
(w3, ci3, T, cmT)
Ok((w3, ci3, T, cmT))
}
// NIFS.V
@ -124,28 +125,30 @@ where
NIFS::<C>::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<C>,
ci2: &CommittedInstance<C>,
ci3: &CommittedInstance<C>,
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<C>,
T: Vec<C::ScalarField>,
cmT: &C,
) -> (PedersenProof<C>, PedersenProof<C>, PedersenProof<C>) {
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<C>; 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<C>,
pedersen_params: &PedersenParams<C>,
ci: CommittedInstance<C>,
cmT: C,
cmE_proof: PedersenProof<C>,
cmW_proof: PedersenProof<C>,
cmT_proof: PedersenProof<C>,
) -> bool {
if !Pedersen::verify(pedersen_params, tr, ci.cmE, cmE_proof) {
return false;
cm_proofs: [PedersenProof<C>; 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::<Projective>::prove(&pedersen_params, r, &r1cs, &w1, &ci1, &w2, &ci2);
NIFS::<Projective>::prove(&pedersen_params, r, &r1cs, &w1, &ci1, &w2, &ci2).unwrap();
// NIFS.V
let ci3 = NIFS::<Projective>::verify(r, &ci1, &ci2, &cmT);
@ -230,7 +235,7 @@ mod tests {
// naive check that the folded witness satisfies the relaxed r1cs
let z3: Vec<Fr> = [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::<Projective>::verify_folded_instance(
r, &ci1, &ci2, &ci3, &cmT
));
NIFS::<Projective>::verify_folded_instance(r, &ci1, &ci2, &ci3, &cmT).unwrap();
let poseidon_config = poseidon_test_config::<Fr>();
// init Prover's transcript
@ -255,24 +258,23 @@ mod tests {
let mut transcript_v = PoseidonTranscript::<Projective>::new(&poseidon_config);
// check openings of ci3.cmE, ci3.cmW and cmT
let (cmE_proof, cmW_proof, cmT_proof) = NIFS::<Projective>::open_commitments(
let cm_proofs = NIFS::<Projective>::open_commitments(
&mut transcript_p,
&pedersen_params,
&w3,
&ci3,
T,
&cmT,
);
let v = NIFS::<Projective>::verify_commitments(
)
.unwrap();
NIFS::<Projective>::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::<Projective>::verify(

+ 14
- 1
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

+ 5
- 4
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<C: CurveGroup> {
@ -47,7 +48,7 @@ impl Pedersen {
cm: &C,
v: &Vec<C::ScalarField>,
r: &C::ScalarField,
) -> Proof<C> {
) -> Result<Proof<C>, 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::<C> { R, u, r_u }
Ok(Proof::<C> { R, u, r_u })
}
pub fn verify(
@ -113,7 +114,7 @@ mod tests {
let v: Vec<Fr> = vec![Fr::rand(&mut rng); n];
let r: Fr = Fr::rand(&mut rng);
let cm = Pedersen::<Projective>::commit(&params, &v, &r);
let proof = Pedersen::<Projective>::prove(&params, &mut transcript_p, &cm, &v, &r);
let proof = Pedersen::<Projective>::prove(&params, &mut transcript_p, &cm, &v, &r).unwrap();
let v = Pedersen::<Projective>::verify(&params, &mut transcript_v, cm, proof);
assert!(v);
}

+ 35
- 17
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<F: PrimeField> {
pub n_rows: usize,
@ -42,22 +44,26 @@ pub fn dense_matrix_to_sparse(m: Vec>) -> SparseMatrix
r
}
pub fn vec_add<F: PrimeField>(a: &[F], b: &[F]) -> Vec<F> {
assert_eq!(a.len(), b.len());
pub fn vec_add<F: PrimeField>(a: &[F], b: &[F]) -> Result<Vec<F>, Error> {
if a.len() != b.len() {
return Err(Error::NotSameLength);
}
let mut r: Vec<F> = vec![F::zero(); a.len()];
for i in 0..a.len() {
r[i] = a[i] + b[i];
}
r
Ok(r)
}
pub fn vec_sub<F: PrimeField>(a: &[F], b: &[F]) -> Vec<F> {
assert_eq!(a.len(), b.len());
pub fn vec_sub<F: PrimeField>(a: &[F], b: &[F]) -> Result<Vec<F>, Error> {
if a.len() != b.len() {
return Err(Error::NotSameLength);
}
let mut r: Vec<F> = 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<F: PrimeField>(vec: &[F], c: &F) -> Vec<F> {
@ -77,9 +83,13 @@ pub fn is_zero_vec(vec: &[F]) -> bool {
true
}
pub fn mat_vec_mul<F: PrimeField>(M: &Vec<Vec<F>>, z: &[F]) -> Vec<F> {
assert!(!M.is_empty());
assert_eq!(M[0].len(), z.len());
pub fn mat_vec_mul<F: PrimeField>(M: &Vec<Vec<F>>, z: &[F]) -> Result<Vec<F>, Error> {
if M.is_empty() {
return Err(Error::Empty);
}
if M[0].len() != z.len() {
return Err(Error::NotSameLength);
}
let mut r: Vec<F> = 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<F: PrimeField>(matrix: &SparseMatrix<F>, vector: &[F]) -> Vec<F> {
@ -101,9 +111,11 @@ pub fn mat_vec_mul_sparse(matrix: &SparseMatrix, vector: &[F])
res
}
pub fn hadamard<F: PrimeField>(a: &[F], b: &[F]) -> Vec<F> {
assert_eq!(a.len(), b.len());
cfg_iter!(a).zip(b).map(|(a, b)| *a * b).collect()
pub fn hadamard<F: PrimeField>(a: &[F], b: &[F]) -> Result<Vec<F>, 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::<Fr>(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<Fr> = to_F_vec::<Fr>(vec![1, 2, 3, 4, 5, 6]);
let b: Vec<Fr> = 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])
);
}
}

Loading…
Cancel
Save