mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-10 07:51:32 +01:00
add error handling to several pending methods (#30)
This commit is contained in:
@@ -1 +1 @@
|
||||
1.71.0
|
||||
1.71.1
|
||||
|
||||
@@ -51,14 +51,14 @@ impl<C: CurveGroup> CCS<C> {
|
||||
// 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
|
||||
|
||||
@@ -22,8 +22,10 @@ impl<F: PrimeField> R1CS<F> {
|
||||
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<F: PrimeField> RelaxedR1CS<F> {
|
||||
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(())
|
||||
}
|
||||
|
||||
@@ -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<F: PrimeField> {
|
||||
}
|
||||
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<F: PrimeField>(m: SparseMatrixVar<F>, v: Vec<FpVar<F>>) ->
|
||||
}
|
||||
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<F: PrimeField>(vec: &Vec<FpVar<F>>, c: &FpVar<F>) -> Vec<F
|
||||
}
|
||||
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)]
|
||||
|
||||
@@ -109,7 +109,9 @@ impl<C: CurveGroup> CCCS<C> {
|
||||
) -> 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> =
|
||||
|
||||
@@ -94,12 +94,16 @@ impl<C: CurveGroup> LCCCS<C> {
|
||||
) -> 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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<C: CurveGroup> NIMFS<C> {
|
||||
|
||||
/// 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<C: CurveGroup> NIMFS<C> {
|
||||
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<C: CurveGroup> NIMFS<C> {
|
||||
// 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<C: CurveGroup> NIMFS<C> {
|
||||
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<C: CurveGroup> NIMFS<C> {
|
||||
// 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<C: CurveGroup> NIMFS<C> {
|
||||
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<C: CurveGroup> NIMFS<C> {
|
||||
&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<C: CurveGroup> NIMFS<C> {
|
||||
*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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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.cmW, cmW_proof) {
|
||||
return false;
|
||||
if !Pedersen::verify(pedersen_params, tr, ci.cmE, cm_proofs[0].clone()) {
|
||||
return Err(Error::CommitmentVerificationFail);
|
||||
}
|
||||
if !Pedersen::verify(pedersen_params, tr, cmT, cmT_proof) {
|
||||
return false;
|
||||
if !Pedersen::verify(pedersen_params, tr, ci.cmW, cm_proofs[1].clone()) {
|
||||
return Err(Error::CommitmentVerificationFail);
|
||||
}
|
||||
true
|
||||
if !Pedersen::verify(pedersen_params, tr, cmT, cm_proofs[2].clone()) {
|
||||
return Err(Error::CommitmentVerificationFail);
|
||||
}
|
||||
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(
|
||||
|
||||
15
src/lib.rs
15
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,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<C: CurveGroup> Pedersen<C> {
|
||||
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<C: CurveGroup> Pedersen<C> {
|
||||
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(¶ms, &v, &r);
|
||||
let proof = Pedersen::<Projective>::prove(¶ms, &mut transcript_p, &cm, &v, &r);
|
||||
let proof = Pedersen::<Projective>::prove(¶ms, &mut transcript_p, &cm, &v, &r).unwrap();
|
||||
let v = Pedersen::<Projective>::verify(¶ms, &mut transcript_v, cm, proof);
|
||||
assert!(v);
|
||||
}
|
||||
|
||||
@@ -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<F: PrimeField>(m: Vec<Vec<F>>) -> SparseMatrix<F>
|
||||
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<F: PrimeField>(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<F: PrimeField>(M: &Vec<Vec<F>>, z: &[F]) -> Vec<F> {
|
||||
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<F: PrimeField>(matrix: &SparseMatrix<F>, 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])
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user