Browse Source

Separate prover and verifier keys in CompressedSNARK (#145)

* checkpoint

* simplify further

* checkpoint

* gens --> ck

* update benches

* address clippy

* cleanup

* update version
main
Srinath Setty 2 years ago
committed by GitHub
parent
commit
1e4995274b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 391 additions and 344 deletions
  1. +1
    -1
      Cargo.toml
  2. +6
    -2
      benches/compressed-snark.rs
  3. +4
    -2
      examples/minroot.rs
  4. +3
    -3
      src/bellperson/mod.rs
  5. +12
    -13
      src/bellperson/r1cs.rs
  6. +9
    -9
      src/circuit.rs
  7. +9
    -9
      src/gadgets/ecc.rs
  8. +129
    -75
      src/lib.rs
  9. +33
    -29
      src/nifs.rs
  10. +65
    -53
      src/provider/ipa_pc.rs
  11. +19
    -19
      src/provider/pasta.rs
  12. +40
    -40
      src/provider/pedersen.rs
  13. +22
    -29
      src/r1cs.rs
  14. +18
    -28
      src/spartan/mod.rs
  15. +3
    -3
      src/traits/commitment.rs
  16. +11
    -5
      src/traits/evaluation.rs
  17. +7
    -24
      src/traits/snark.rs

+ 1
- 1
Cargo.toml

@ -1,6 +1,6 @@
[package]
name = "nova-snark"
version = "0.16.0"
version = "0.17.0"
authors = ["Srinath Setty <srinath@microsoft.com>"]
edition = "2021"
description = "Recursive zkSNARKs without trusted setup"

+ 6
- 2
benches/compressed-snark.rs

@ -49,6 +49,9 @@ fn bench_compressed_snark(c: &mut Criterion) {
TrivialTestCircuit::default(),
);
// Produce prover and verifier keys for CompressedSNARK
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp);
// produce a recursive SNARK
let num_steps = 3;
let mut recursive_snark: Option<RecursiveSNARK<G1, G2, C1, C2>> = None;
@ -84,12 +87,13 @@ fn bench_compressed_snark(c: &mut Criterion) {
b.iter(|| {
assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
black_box(&pp),
black_box(&pk),
black_box(&recursive_snark)
)
.is_ok());
})
});
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
@ -98,7 +102,7 @@ fn bench_compressed_snark(c: &mut Criterion) {
b.iter(|| {
assert!(black_box(&compressed_snark)
.verify(
black_box(&pp),
black_box(&vk),
black_box(num_steps),
black_box(vec![<G1 as Group>::Scalar::from(2u64)]),
black_box(vec![<G2 as Group>::Scalar::from(2u64)]),

+ 4
- 2
examples/minroot.rs

@ -256,13 +256,15 @@ fn main() {
// produce a compressed SNARK
println!("Generating a CompressedSNARK using Spartan with IPA-PC...");
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp);
let start = Instant::now();
type EE1 = nova_snark::provider::ipa_pc::EvaluationEngine<G1>;
type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<G2>;
type S1 = nova_snark::spartan::RelaxedR1CSSNARK<G1, EE1>;
type S2 = nova_snark::spartan::RelaxedR1CSSNARK<G2, EE2>;
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
@ -282,7 +284,7 @@ fn main() {
// verify the compressed SNARK
println!("Verifying a CompressedSNARK...");
let start = Instant::now();
let res = compressed_snark.verify(&pp, num_steps, z0_primary, z0_secondary);
let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary);
println!(
"CompressedSNARK::verify: {:?}, took {:?}",
res.is_ok(),

+ 3
- 3
src/bellperson/mod.rs

@ -47,14 +47,14 @@ mod tests {
let mut cs: ShapeCS<G> = ShapeCS::new();
let _ = synthesize_alloc_bit(&mut cs);
let shape = cs.r1cs_shape();
let gens = cs.r1cs_gens();
let ck = cs.commitment_key();
// Now get the assignment
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
let _ = synthesize_alloc_bit(&mut cs);
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
// Make sure that this is satisfiable
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
}
}

+ 12
- 13
src/bellperson/r1cs.rs

@ -3,23 +3,22 @@
#![allow(non_snake_case)]
use super::{shape_cs::ShapeCS, solver::SatisfyingAssignment};
use bellperson::{Index, LinearCombination};
use ff::PrimeField;
use crate::{
errors::NovaError,
r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness},
r1cs::{R1CSInstance, R1CSShape, R1CSWitness, R1CS},
traits::Group,
CommitmentKey,
};
use bellperson::{Index, LinearCombination};
use ff::PrimeField;
/// `NovaWitness` provide a method for acquiring an `R1CSInstance` and `R1CSWitness` from implementers.
pub trait NovaWitness<G: Group> {
/// Return an instance and witness, given a shape and gens.
/// Return an instance and witness, given a shape and ck.
fn r1cs_instance_and_witness(
&self,
shape: &R1CSShape<G>,
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError>;
}
@ -27,8 +26,8 @@ pub trait NovaWitness {
pub trait NovaShape<G: Group> {
/// Return an appropriate `R1CSShape` struct.
fn r1cs_shape(&self) -> R1CSShape<G>;
/// Return an appropriate `R1CSGens` struct.
fn r1cs_gens(&self) -> R1CSGens<G>;
/// Return an appropriate `CommitmentKey` struct.
fn commitment_key(&self) -> CommitmentKey<G>;
}
impl<G: Group> NovaWitness<G> for SatisfyingAssignment<G>
@ -38,12 +37,12 @@ where
fn r1cs_instance_and_witness(
&self,
shape: &R1CSShape<G>,
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
) -> Result<(R1CSInstance<G>, R1CSWitness<G>), NovaError> {
let W = R1CSWitness::<G>::new(shape, &self.aux_assignment)?;
let X = &self.input_assignment[1..];
let comm_W = W.commit(gens);
let comm_W = W.commit(ck);
let instance = R1CSInstance::<G>::new(shape, &comm_W, X)?;
@ -88,8 +87,8 @@ where
S
}
fn r1cs_gens(&self) -> R1CSGens<G> {
R1CSGens::<G>::new(self.num_constraints(), self.num_aux())
fn commitment_key(&self) -> CommitmentKey<G> {
R1CS::<G>::commitment_key(self.num_constraints(), self.num_aux())
}
}

+ 9
- 9
src/circuit.rs

@ -3,7 +3,7 @@
//! only the primary executes the next step of the computation.
//! We have two running instances. Each circuit takes as input 2 hashes: one for each
//! of the running instances. Each of these hashes is
//! H(params = H(shape, gens), i, z0, zi, U). Each circuit folds the last invocation of
//! H(params = H(shape, ck), i, z0, zi, U). Each circuit folds the last invocation of
//! the other into the running instance
use crate::{
@ -390,7 +390,7 @@ mod tests {
let ro_consts1: ROConstantsCircuit<G2> = PoseidonConstantsCircuit::new();
let ro_consts2: ROConstantsCircuit<G1> = PoseidonConstantsCircuit::new();
// Initialize the shape and gens for the primary
// Initialize the shape and ck for the primary
let circuit1: NovaAugmentedCircuit<G2, TrivialTestCircuit<<G2 as Group>::Base>> =
NovaAugmentedCircuit::new(
params1.clone(),
@ -400,10 +400,10 @@ mod tests {
);
let mut cs: ShapeCS<G1> = ShapeCS::new();
let _ = circuit1.synthesize(&mut cs);
let (shape1, gens1) = (cs.r1cs_shape(), cs.r1cs_gens());
let (shape1, ck1) = (cs.r1cs_shape(), cs.commitment_key());
assert_eq!(cs.num_constraints(), 9815);
// Initialize the shape and gens for the secondary
// Initialize the shape and ck for the secondary
let circuit2: NovaAugmentedCircuit<G1, TrivialTestCircuit<<G1 as Group>::Base>> =
NovaAugmentedCircuit::new(
params2.clone(),
@ -413,7 +413,7 @@ mod tests {
);
let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = circuit2.synthesize(&mut cs);
let (shape2, gens2) = (cs.r1cs_shape(), cs.r1cs_gens());
let (shape2, ck2) = (cs.r1cs_shape(), cs.commitment_key());
assert_eq!(cs.num_constraints(), 10347);
// Execute the base case for the primary
@ -436,9 +436,9 @@ mod tests {
ro_consts1,
);
let _ = circuit1.synthesize(&mut cs1);
let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &gens1).unwrap();
let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &ck1).unwrap();
// Make sure that this is satisfiable
assert!(shape1.is_sat(&gens1, &inst1, &witness1).is_ok());
assert!(shape1.is_sat(&ck1, &inst1, &witness1).is_ok());
// Execute the base case for the secondary
let zero2 = <<G1 as Group>::Base as Field>::zero();
@ -460,8 +460,8 @@ mod tests {
ro_consts2,
);
let _ = circuit.synthesize(&mut cs2);
let (inst2, witness2) = cs2.r1cs_instance_and_witness(&shape2, &gens2).unwrap();
let (inst2, witness2) = cs2.r1cs_instance_and_witness(&shape2, &ck2).unwrap();
// Make sure that it is satisfiable
assert!(shape2.is_sat(&gens2, &inst2, &witness2).is_ok());
assert!(shape2.is_sat(&ck2, &inst2, &witness2).is_ok());
}
}

+ 9
- 9
src/gadgets/ecc.rs

@ -976,12 +976,12 @@ mod tests {
let _ = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
println!("Number of constraints: {}", cs.num_constraints());
let shape = cs.r1cs_shape();
let gens = cs.r1cs_gens();
let ck = cs.commitment_key();
// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
let (a, e, s) = synthesize_smul::<G1, _>(cs.namespace(|| "synthesize"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let a_p: Point<G1> = Point::new(
a.x.get_value().unwrap(),
@ -996,7 +996,7 @@ mod tests {
let e_new = a_p.scalar_mul(&s);
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
// Make sure that this is satisfiable
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
}
fn synthesize_add_equal<G, CS>(mut cs: CS) -> (AllocatedPoint<G>, AllocatedPoint<G>)
@ -1018,12 +1018,12 @@ mod tests {
let _ = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
println!("Number of constraints: {}", cs.num_constraints());
let shape = cs.r1cs_shape();
let gens = cs.r1cs_gens();
let ck = cs.commitment_key();
// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
let (a, e) = synthesize_add_equal::<G1, _>(cs.namespace(|| "synthesize add equal"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let a_p: Point<G1> = Point::new(
a.x.get_value().unwrap(),
a.y.get_value().unwrap(),
@ -1037,7 +1037,7 @@ mod tests {
let e_new = a_p.add(&a_p);
assert!(e_p.x == e_new.x && e_p.y == e_new.y);
// Make sure that it is satisfiable
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
}
fn synthesize_add_negation<G, CS>(mut cs: CS) -> AllocatedPoint<G>
@ -1064,12 +1064,12 @@ mod tests {
let _ = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add equal"));
println!("Number of constraints: {}", cs.num_constraints());
let shape = cs.r1cs_shape();
let gens = cs.r1cs_gens();
let ck = cs.commitment_key();
// Then the satisfying assignment
let mut cs: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
let e = synthesize_add_negation::<G1, _>(cs.namespace(|| "synthesize add negation"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let e_p: Point<G1> = Point::new(
e.x.get_value().unwrap(),
e.y.get_value().unwrap(),
@ -1077,6 +1077,6 @@ mod tests {
);
assert!(e_p.is_infinity);
// Make sure that it is satisfiable
assert!(shape.is_sat(&gens, &inst, &witness).is_ok());
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
}
}

+ 129
- 75
src/lib.rs

@ -38,9 +38,7 @@ use errors::NovaError;
use ff::Field;
use gadgets::utils::scalar_as_base;
use nifs::NIFS;
use r1cs::{
R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
};
use r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness};
use serde::{Deserialize, Serialize};
use traits::{
circuit::StepCircuit,
@ -63,14 +61,12 @@ where
F_arity_secondary: usize,
ro_consts_primary: ROConstants<G1>,
ro_consts_circuit_primary: ROConstantsCircuit<G2>,
r1cs_gens_primary: R1CSGens<G1>,
ck_primary: CommitmentKey<G1>,
r1cs_shape_primary: R1CSShape<G1>,
r1cs_shape_padded_primary: R1CSShape<G1>,
ro_consts_secondary: ROConstants<G2>,
ro_consts_circuit_secondary: ROConstantsCircuit<G1>,
r1cs_gens_secondary: R1CSGens<G2>,
ck_secondary: CommitmentKey<G2>,
r1cs_shape_secondary: R1CSShape<G2>,
r1cs_shape_padded_secondary: R1CSShape<G2>,
augmented_circuit_params_primary: NovaAugmentedCircuitParams,
augmented_circuit_params_secondary: NovaAugmentedCircuitParams,
_p_c1: PhantomData<C1>,
@ -101,7 +97,7 @@ where
let ro_consts_circuit_primary: ROConstantsCircuit<G2> = ROConstantsCircuit::<G2>::new();
let ro_consts_circuit_secondary: ROConstantsCircuit<G1> = ROConstantsCircuit::<G1>::new();
// Initialize gens for the primary
// Initialize ck for the primary
let circuit_primary: NovaAugmentedCircuit<G2, C1> = NovaAugmentedCircuit::new(
augmented_circuit_params_primary.clone(),
None,
@ -110,10 +106,9 @@ where
);
let mut cs: ShapeCS<G1> = ShapeCS::new();
let _ = circuit_primary.synthesize(&mut cs);
let (r1cs_shape_primary, r1cs_gens_primary) = (cs.r1cs_shape(), cs.r1cs_gens());
let r1cs_shape_padded_primary = r1cs_shape_primary.pad();
let (r1cs_shape_primary, ck_primary) = (cs.r1cs_shape(), cs.commitment_key());
// Initialize gens for the secondary
// Initialize ck for the secondary
let circuit_secondary: NovaAugmentedCircuit<G1, C2> = NovaAugmentedCircuit::new(
augmented_circuit_params_secondary.clone(),
None,
@ -122,22 +117,19 @@ where
);
let mut cs: ShapeCS<G2> = ShapeCS::new();
let _ = circuit_secondary.synthesize(&mut cs);
let (r1cs_shape_secondary, r1cs_gens_secondary) = (cs.r1cs_shape(), cs.r1cs_gens());
let r1cs_shape_padded_secondary = r1cs_shape_secondary.pad();
let (r1cs_shape_secondary, ck_secondary) = (cs.r1cs_shape(), cs.commitment_key());
Self {
F_arity_primary,
F_arity_secondary,
ro_consts_primary,
ro_consts_circuit_primary,
r1cs_gens_primary,
ck_primary,
r1cs_shape_primary,
r1cs_shape_padded_primary,
ro_consts_secondary,
ro_consts_circuit_secondary,
r1cs_gens_secondary,
ck_secondary,
r1cs_shape_secondary,
r1cs_shape_padded_secondary,
augmented_circuit_params_primary,
augmented_circuit_params_secondary,
_p_c1: Default::default(),
@ -230,7 +222,7 @@ where
);
let _ = circuit_primary.synthesize(&mut cs_primary);
let (u_primary, w_primary) = cs_primary
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.r1cs_gens_primary)
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)
.map_err(|_e| NovaError::UnSat)?;
// base case for the secondary
@ -252,7 +244,7 @@ where
);
let _ = circuit_secondary.synthesize(&mut cs_secondary);
let (u_secondary, w_secondary) = cs_secondary
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.r1cs_gens_secondary)
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary)
.map_err(|_e| NovaError::UnSat)?;
// IVC proof for the primary circuit
@ -261,7 +253,7 @@ where
let r_W_primary =
RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &l_w_primary);
let r_U_primary = RelaxedR1CSInstance::from_r1cs_instance(
&pp.r1cs_gens_primary,
&pp.ck_primary,
&pp.r1cs_shape_primary,
&l_u_primary,
);
@ -271,7 +263,7 @@ where
let l_u_secondary = u_secondary;
let r_W_secondary = RelaxedR1CSWitness::<G2>::default(&pp.r1cs_shape_secondary);
let r_U_secondary =
RelaxedR1CSInstance::<G2>::default(&pp.r1cs_gens_secondary, &pp.r1cs_shape_secondary);
RelaxedR1CSInstance::<G2>::default(&pp.ck_secondary, &pp.r1cs_shape_secondary);
// Outputs of the two circuits thus far
let zi_primary = c_primary.output(&z0_primary);
@ -300,7 +292,7 @@ where
Some(r_snark) => {
// fold the secondary circuit's instance
let (nifs_secondary, (r_U_secondary, r_W_secondary)) = NIFS::prove(
&pp.r1cs_gens_secondary,
&pp.ck_secondary,
&pp.ro_consts_secondary,
&pp.r1cs_shape_secondary,
&r_snark.r_U_secondary,
@ -329,12 +321,12 @@ where
let _ = circuit_primary.synthesize(&mut cs_primary);
let (l_u_primary, l_w_primary) = cs_primary
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.r1cs_gens_primary)
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)
.map_err(|_e| NovaError::UnSat)?;
// fold the primary circuit's instance
let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove(
&pp.r1cs_gens_primary,
&pp.ck_primary,
&pp.ro_consts_primary,
&pp.r1cs_shape_primary,
&r_snark.r_U_primary,
@ -363,7 +355,7 @@ where
let _ = circuit_secondary.synthesize(&mut cs_secondary);
let (l_u_secondary, l_w_secondary) = cs_secondary
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.r1cs_gens_secondary)
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary)
.map_err(|_e| NovaError::UnSat)?;
// update the running instances and witnesses
@ -464,17 +456,14 @@ where
rayon::join(
|| {
pp.r1cs_shape_primary.is_sat_relaxed(
&pp.r1cs_gens_primary,
&pp.ck_primary,
&self.r_U_primary,
&self.r_W_primary,
)
},
|| {
pp.r1cs_shape_primary.is_sat(
&pp.r1cs_gens_primary,
&self.l_u_primary,
&self.l_w_primary,
)
pp.r1cs_shape_primary
.is_sat(&pp.ck_primary, &self.l_u_primary, &self.l_w_primary)
},
)
},
@ -482,14 +471,14 @@ where
rayon::join(
|| {
pp.r1cs_shape_secondary.is_sat_relaxed(
&pp.r1cs_gens_secondary,
&pp.ck_secondary,
&self.r_U_secondary,
&self.r_W_secondary,
)
},
|| {
pp.r1cs_shape_secondary.is_sat(
&pp.r1cs_gens_secondary,
&pp.ck_secondary,
&self.l_u_secondary,
&self.l_w_secondary,
)
@ -508,9 +497,51 @@ where
}
}
/// A SNARK that proves the knowledge of a valid `RecursiveSNARK`
/// A type that holds the prover key for `CompressedSNARK`
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct ProverKey<G1, G2, C1, C2, S1, S2>
where
G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
S1: RelaxedR1CSSNARKTrait<G1>,
S2: RelaxedR1CSSNARKTrait<G2>,
{
pk_primary: S1::ProverKey,
pk_secondary: S2::ProverKey,
_p_c1: PhantomData<C1>,
_p_c2: PhantomData<C2>,
}
/// A type that holds the verifier key for `CompressedSNARK`
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct VerifierKey<G1, G2, C1, C2, S1, S2>
where
G1: Group<Base = <G2 as Group>::Scalar>,
G2: Group<Base = <G1 as Group>::Scalar>,
C1: StepCircuit<G1::Scalar>,
C2: StepCircuit<G2::Scalar>,
S1: RelaxedR1CSSNARKTrait<G1>,
S2: RelaxedR1CSSNARKTrait<G2>,
{
F_arity_primary: usize,
F_arity_secondary: usize,
ro_consts_primary: ROConstants<G1>,
ro_consts_secondary: ROConstants<G2>,
r1cs_shape_primary_digest: G1::Scalar,
r1cs_shape_secondary_digest: G2::Scalar,
vk_primary: S1::VerifierKey,
vk_secondary: S2::VerifierKey,
_p_c1: PhantomData<C1>,
_p_c2: PhantomData<C2>,
}
/// A SNARK that proves the knowledge of a valid `RecursiveSNARK`
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct CompressedSNARK<G1, G2, C1, C2, S1, S2>
where
G1: Group<Base = <G2 as Group>::Scalar>,
@ -546,16 +577,50 @@ where
S1: RelaxedR1CSSNARKTrait<G1>,
S2: RelaxedR1CSSNARKTrait<G2>,
{
/// Creates prover and verifier keys for `CompressedSNARK`
pub fn setup(
pp: &PublicParams<G1, G2, C1, C2>,
) -> (
ProverKey<G1, G2, C1, C2, S1, S2>,
VerifierKey<G1, G2, C1, C2, S1, S2>,
) {
let (pk_primary, vk_primary) = S1::setup(&pp.ck_primary, &pp.r1cs_shape_primary);
let (pk_secondary, vk_secondary) = S2::setup(&pp.ck_secondary, &pp.r1cs_shape_secondary);
let pk = ProverKey {
pk_primary,
pk_secondary,
_p_c1: Default::default(),
_p_c2: Default::default(),
};
let vk = VerifierKey {
F_arity_primary: pp.F_arity_primary,
F_arity_secondary: pp.F_arity_secondary,
ro_consts_primary: pp.ro_consts_primary.clone(),
ro_consts_secondary: pp.ro_consts_secondary.clone(),
r1cs_shape_primary_digest: pp.r1cs_shape_primary.get_digest(),
r1cs_shape_secondary_digest: pp.r1cs_shape_secondary.get_digest(),
vk_primary,
vk_secondary,
_p_c1: Default::default(),
_p_c2: Default::default(),
};
(pk, vk)
}
/// Create a new `CompressedSNARK`
pub fn prove(
pp: &PublicParams<G1, G2, C1, C2>,
pk: &ProverKey<G1, G2, C1, C2, S1, S2>,
recursive_snark: &RecursiveSNARK<G1, G2, C1, C2>,
) -> Result<Self, NovaError> {
let (res_primary, res_secondary) = rayon::join(
// fold the primary circuit's instance
|| {
NIFS::prove(
&pp.r1cs_gens_primary,
&pp.ck_primary,
&pp.ro_consts_primary,
&pp.r1cs_shape_primary,
&recursive_snark.r_U_primary,
@ -567,7 +632,7 @@ where
|| {
// fold the secondary circuit's instance
NIFS::prove(
&pp.r1cs_gens_secondary,
&pp.ck_secondary,
&pp.ro_consts_secondary,
&pp.r1cs_shape_secondary,
&recursive_snark.r_U_secondary,
@ -581,26 +646,15 @@ where
let (nifs_primary, (f_U_primary, f_W_primary)) = res_primary?;
let (nifs_secondary, (f_U_secondary, f_W_secondary)) = res_secondary?;
// produce a prover key for the SNARK
let (pk_primary, pk_secondary) = rayon::join(
|| S1::prover_key(&pp.r1cs_gens_primary, &pp.r1cs_shape_padded_primary),
|| S2::prover_key(&pp.r1cs_gens_secondary, &pp.r1cs_shape_padded_secondary),
);
// create SNARKs proving the knowledge of f_W_primary and f_W_secondary
let (f_W_snark_primary, f_W_snark_secondary) = rayon::join(
|| {
S1::prove(
&pk_primary,
&f_U_primary,
&f_W_primary.pad(&pp.r1cs_shape_padded_primary), // pad the witness since shape was padded
)
},
|| S1::prove(&pp.ck_primary, &pk.pk_primary, &f_U_primary, &f_W_primary),
|| {
S2::prove(
&pk_secondary,
&pp.ck_secondary,
&pk.pk_secondary,
&f_U_secondary,
&f_W_secondary.pad(&pp.r1cs_shape_padded_secondary), // pad the witness since the shape was padded
&f_W_secondary,
)
},
);
@ -627,7 +681,7 @@ where
/// Verify the correctness of the `CompressedSNARK`
pub fn verify(
&self,
pp: &PublicParams<G1, G2, C1, C2>,
vk: &VerifierKey<G1, G2, C1, C2, S1, S2>,
num_steps: usize,
z0_primary: Vec<G1::Scalar>,
z0_secondary: Vec<G2::Scalar>,
@ -649,10 +703,10 @@ where
// check if the output hashes in R1CS instances point to the right running instances
let (hash_primary, hash_secondary) = {
let mut hasher = <G2 as Group>::RO::new(
pp.ro_consts_secondary.clone(),
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_primary,
vk.ro_consts_secondary.clone(),
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_primary,
);
hasher.absorb(scalar_as_base::<G2>(pp.r1cs_shape_secondary.get_digest()));
hasher.absorb(scalar_as_base::<G2>(vk.r1cs_shape_secondary_digest));
hasher.absorb(G1::Scalar::from(num_steps as u64));
for e in z0_primary {
hasher.absorb(e);
@ -663,10 +717,10 @@ where
self.r_U_secondary.absorb_in_ro(&mut hasher);
let mut hasher2 = <G1 as Group>::RO::new(
pp.ro_consts_primary.clone(),
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_secondary,
vk.ro_consts_primary.clone(),
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_secondary,
);
hasher2.absorb(scalar_as_base::<G1>(pp.r1cs_shape_primary.get_digest()));
hasher2.absorb(scalar_as_base::<G1>(vk.r1cs_shape_primary_digest));
hasher2.absorb(G2::Scalar::from(num_steps as u64));
for e in z0_secondary {
hasher2.absorb(e);
@ -690,31 +744,25 @@ where
// fold the running instance and last instance to get a folded instance
let f_U_primary = self.nifs_primary.verify(
&pp.ro_consts_primary,
&pp.r1cs_shape_primary,
&vk.ro_consts_primary,
&vk.r1cs_shape_primary_digest,
&self.r_U_primary,
&self.l_u_primary,
)?;
let f_U_secondary = self.nifs_secondary.verify(
&pp.ro_consts_secondary,
&pp.r1cs_shape_secondary,
&vk.ro_consts_secondary,
&vk.r1cs_shape_secondary_digest,
&self.r_U_secondary,
&self.l_u_secondary,
)?;
// produce a verifier key for the SNARK
let (vk_primary, vk_secondary) = rayon::join(
|| S1::verifier_key(&pp.r1cs_gens_primary, &pp.r1cs_shape_padded_primary),
|| S2::verifier_key(&pp.r1cs_gens_secondary, &pp.r1cs_shape_padded_secondary),
);
// check the satisfiability of the folded instances using SNARKs proving the knowledge of their satisfying witnesses
let (res_primary, res_secondary) = rayon::join(
|| self.f_W_snark_primary.verify(&vk_primary, &f_U_primary),
|| self.f_W_snark_primary.verify(&vk.vk_primary, &f_U_primary),
|| {
self
.f_W_snark_secondary
.verify(&vk_secondary, &f_U_secondary)
.verify(&vk.vk_secondary, &f_U_secondary)
},
);
@ -725,7 +773,7 @@ where
}
}
type CommitmentGens<G> = <<G as traits::Group>::CE as CommitmentEngineTrait<G>>::CommitmentGens;
type CommitmentKey<G> = <<G as traits::Group>::CE as CommitmentEngineTrait<G>>::CommitmentKey;
type Commitment<G> = <<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment;
type CompressedCommitment<G> = <<<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment;
type CE<G> = <G as Group>::CE;
@ -962,14 +1010,17 @@ mod tests {
assert_eq!(zn_secondary, zn_secondary_direct);
assert_eq!(zn_secondary, vec![<G2 as Group>::Scalar::from(2460515u64)]);
// produce the prover and verifier keys for compressed snark
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp);
// produce a compressed SNARK
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
// verify the compressed SNARK
let res = compressed_snark.verify(
&pp,
&vk,
num_steps,
vec![<G1 as Group>::Scalar::one()],
vec![<G2 as Group>::Scalar::zero()],
@ -1110,13 +1161,16 @@ mod tests {
let res = recursive_snark.verify(&pp, num_steps, z0_primary.clone(), z0_secondary.clone());
assert!(res.is_ok());
// produce the prover and verifier keys for compressed snark
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp);
// produce a compressed SNARK
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
// verify the compressed SNARK
let res = compressed_snark.verify(&pp, num_steps, z0_primary, z0_secondary);
let res = compressed_snark.verify(&vk, num_steps, z0_primary, z0_secondary);
assert!(res.is_ok());
}

+ 33
- 29
src/nifs.rs

@ -5,9 +5,10 @@
use crate::{
constants::{NUM_CHALLENGE_BITS, NUM_FE_FOR_RO},
errors::NovaError,
r1cs::{R1CSGens, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness},
r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness},
scalar_as_base,
traits::{commitment::CommitmentTrait, AbsorbInROTrait, Group, ROTrait},
Commitment, CompressedCommitment,
Commitment, CommitmentKey, CompressedCommitment,
};
use core::marker::PhantomData;
use serde::{Deserialize, Serialize};
@ -27,12 +28,12 @@ type ROConstants =
impl<G: Group> NIFS<G> {
/// Takes as input a Relaxed R1CS instance-witness tuple `(U1, W1)` and
/// an R1CS instance-witness tuple `(U2, W2)` with the same structure `shape`
/// and defined with respect to the same `gens`, and outputs
/// and defined with respect to the same `ck`, and outputs
/// a folded Relaxed R1CS instance-witness tuple `(U, W)` of the same shape `shape`,
/// with the guarantee that the folded witness `W` satisfies the folded instance `U`
/// if and only if `W1` satisfies `U1` and `W2` satisfies `U2`.
pub fn prove(
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
ro_consts: &ROConstants<G>,
S: &R1CSShape<G>,
U1: &RelaxedR1CSInstance<G>,
@ -51,7 +52,7 @@ impl NIFS {
U2.absorb_in_ro(&mut ro);
// compute a commitment to the cross-term
let (T, comm_T) = S.commit_T(gens, U1, W1, U2, W2)?;
let (T, comm_T) = S.commit_T(ck, U1, W1, U2, W2)?;
// append `comm_T` to the transcript and obtain a challenge
comm_T.absorb_in_ro(&mut ro);
@ -83,15 +84,15 @@ impl NIFS {
pub fn verify(
&self,
ro_consts: &ROConstants<G>,
S: &R1CSShape<G>,
S_digest: &G::Scalar,
U1: &RelaxedR1CSInstance<G>,
U2: &R1CSInstance<G>,
) -> Result<RelaxedR1CSInstance<G>, NovaError> {
// initialize a new RO
let mut ro = G::RO::new(ro_consts.clone(), NUM_FE_FOR_RO);
// append S to the transcript
S.absorb_in_ro(&mut ro);
// append the digest of S to the transcript
ro.absorb(scalar_as_base::<G>(*S_digest));
// append U1 and U2 to transcript
U1.absorb_in_ro(&mut ro);
@ -115,7 +116,10 @@ impl NIFS {
#[cfg(test)]
mod tests {
use super::*;
use crate::traits::{Group, ROConstantsTrait};
use crate::{
r1cs::R1CS,
traits::{Group, ROConstantsTrait},
};
use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
use ff::{Field, PrimeField};
use rand::rngs::OsRng;
@ -168,32 +172,32 @@ mod tests {
let mut cs: ShapeCS<G> = ShapeCS::new();
let _ = synthesize_tiny_r1cs_bellperson(&mut cs, None);
let shape = cs.r1cs_shape();
let gens = cs.r1cs_gens();
let ck = cs.commitment_key();
let ro_consts =
<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new();
// Now get the instance and assignment for one instance
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
let _ = synthesize_tiny_r1cs_bellperson(&mut cs, Some(S::from(5)));
let (U1, W1) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (U1, W1) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
// Make sure that the first instance is satisfiable
assert!(shape.is_sat(&gens, &U1, &W1).is_ok());
assert!(shape.is_sat(&ck, &U1, &W1).is_ok());
// Now get the instance and assignment for second instance
let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
let _ = synthesize_tiny_r1cs_bellperson(&mut cs, Some(S::from(135)));
let (U2, W2) = cs.r1cs_instance_and_witness(&shape, &gens).unwrap();
let (U2, W2) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
// Make sure that the second instance is satisfiable
assert!(shape.is_sat(&gens, &U2, &W2).is_ok());
assert!(shape.is_sat(&ck, &U2, &W2).is_ok());
// execute a sequence of folds
execute_sequence(&gens, &ro_consts, &shape, &U1, &W1, &U2, &W2);
execute_sequence(&ck, &ro_consts, &shape, &U1, &W1, &U2, &W2);
}
fn execute_sequence(
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
ro_consts: &<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants,
shape: &R1CSShape<G>,
U1: &R1CSInstance<G>,
@ -203,15 +207,15 @@ mod tests {
) {
// produce a default running instance
let mut r_W = RelaxedR1CSWitness::default(shape);
let mut r_U = RelaxedR1CSInstance::default(gens, shape);
let mut r_U = RelaxedR1CSInstance::default(ck, shape);
// produce a step SNARK with (W1, U1) as the first incoming witness-instance pair
let res = NIFS::prove(gens, ro_consts, shape, &r_U, &r_W, U1, W1);
let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U1, W1);
assert!(res.is_ok());
let (nifs, (_U, W)) = res.unwrap();
// verify the step SNARK with U1 as the first incoming instance
let res = nifs.verify(ro_consts, shape, &r_U, U1);
let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U1);
assert!(res.is_ok());
let U = res.unwrap();
@ -222,12 +226,12 @@ mod tests {
r_U = U;
// produce a step SNARK with (W2, U2) as the second incoming witness-instance pair
let res = NIFS::prove(gens, ro_consts, shape, &r_U, &r_W, U2, W2);
let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U2, W2);
assert!(res.is_ok());
let (nifs, (_U, W)) = res.unwrap();
// verify the step SNARK with U1 as the first incoming instance
let res = nifs.verify(ro_consts, shape, &r_U, U2);
let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U2);
assert!(res.is_ok());
let U = res.unwrap();
@ -238,7 +242,7 @@ mod tests {
r_U = U;
// check if the running instance is satisfiable
assert!(shape.is_sat_relaxed(gens, &r_U, &r_W).is_ok());
assert!(shape.is_sat_relaxed(ck, &r_U, &r_W).is_ok());
}
#[test]
@ -301,12 +305,12 @@ mod tests {
};
// generate generators and ro constants
let gens = R1CSGens::new(num_cons, num_vars);
let ck = R1CS::<G>::commitment_key(num_cons, num_vars);
let ro_consts =
<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants::new();
let rand_inst_witness_generator =
|gens: &R1CSGens<G>, I: &S| -> (S, R1CSInstance<G>, R1CSWitness<G>) {
|ck: &CommitmentKey<G>, I: &S| -> (S, R1CSInstance<G>, R1CSWitness<G>) {
let i0 = *I;
// compute a satisfying (vars, X) tuple
@ -328,24 +332,24 @@ mod tests {
res.unwrap()
};
let U = {
let comm_W = W.commit(gens);
let comm_W = W.commit(ck);
let res = R1CSInstance::new(&S, &comm_W, &X);
assert!(res.is_ok());
res.unwrap()
};
// check that generated instance is satisfiable
assert!(S.is_sat(gens, &U, &W).is_ok());
assert!(S.is_sat(ck, &U, &W).is_ok());
(O, U, W)
};
let mut csprng: OsRng = OsRng;
let I = S::random(&mut csprng); // the first input is picked randomly for the first instance
let (O, U1, W1) = rand_inst_witness_generator(&gens, &I);
let (_O, U2, W2) = rand_inst_witness_generator(&gens, &O);
let (O, U1, W1) = rand_inst_witness_generator(&ck, &I);
let (_O, U2, W2) = rand_inst_witness_generator(&ck, &O);
// execute a sequence of folds
execute_sequence(&gens, &ro_consts, &S, &U1, &W1, &U2, &W2);
execute_sequence(&ck, &ro_consts, &S, &U1, &W1, &U2, &W2);
}
}

+ 65
- 53
src/provider/ipa_pc.rs

@ -2,14 +2,14 @@
#![allow(clippy::too_many_arguments)]
use crate::{
errors::NovaError,
provider::pedersen::CommitmentGensExtTrait,
provider::pedersen::CommitmentKeyExtTrait,
spartan::polynomial::EqPolynomial,
traits::{
commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait},
commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait},
evaluation::EvaluationEngineTrait,
AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait,
},
Commitment, CommitmentGens, CompressedCommitment, CE,
Commitment, CommitmentKey, CompressedCommitment, CE,
};
use core::iter;
use ff::Field;
@ -17,12 +17,19 @@ use rayon::prelude::*;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
/// Provides an implementation of generators for proving evaluations
/// Provides an implementation of the prover key
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct EvaluationGens<G: Group> {
gens_v: CommitmentGens<G>,
gens_s: CommitmentGens<G>,
pub struct ProverKey<G: Group> {
ck_s: CommitmentKey<G>,
}
/// Provides an implementation of the verifier key
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct VerifierKey<G: Group> {
ck_v: CommitmentKey<G>,
ck_s: CommitmentKey<G>,
}
/// Provides an implementation of a polynomial evaluation argument
@ -41,21 +48,31 @@ pub struct EvaluationEngine {
impl<G> EvaluationEngineTrait<G> for EvaluationEngine<G>
where
G: Group,
CommitmentGens<G>: CommitmentGensExtTrait<G, CE = G::CE>,
CommitmentKey<G>: CommitmentKeyExtTrait<G, CE = G::CE>,
{
type CE = G::CE;
type EvaluationGens = EvaluationGens<G>;
type ProverKey = ProverKey<G>;
type VerifierKey = VerifierKey<G>;
type EvaluationArgument = EvaluationArgument<G>;
fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens {
EvaluationGens {
gens_v: gens.clone(),
gens_s: CommitmentGens::<G>::new(b"ipa", 1),
}
fn setup(
ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey,
) -> (Self::ProverKey, Self::VerifierKey) {
let pk = ProverKey {
ck_s: CommitmentKey::<G>::new(b"ipa", 1),
};
let vk = VerifierKey {
ck_v: ck.clone(),
ck_s: CommitmentKey::<G>::new(b"ipa", 1),
};
(pk, vk)
}
fn prove(
gens: &Self::EvaluationGens,
ck: &CommitmentKey<G>,
pk: &Self::ProverKey,
transcript: &mut G::TE,
comm: &Commitment<G>,
poly: &[G::Scalar],
@ -66,13 +83,13 @@ where
let w = InnerProductWitness::new(poly);
Ok(EvaluationArgument {
ipa: InnerProductArgument::prove(&gens.gens_v, &gens.gens_s, &u, &w, transcript)?,
ipa: InnerProductArgument::prove(ck, &pk.ck_s, &u, &w, transcript)?,
})
}
/// A method to verify purported evaluations of a batch of polynomials
fn verify(
gens: &Self::EvaluationGens,
vk: &Self::VerifierKey,
transcript: &mut G::TE,
comm: &Commitment<G>,
point: &[G::Scalar],
@ -82,8 +99,8 @@ where
let u = InnerProductInstance::new(comm, &EqPolynomial::new(point.to_vec()).evals(), eval);
arg.ipa.verify(
&gens.gens_v,
&gens.gens_s,
&vk.ck_v,
&vk.ck_s,
(2_usize).pow(point.len() as u32),
&u,
transcript,
@ -147,15 +164,15 @@ struct InnerProductArgument {
impl<G> InnerProductArgument<G>
where
G: Group,
CommitmentGens<G>: CommitmentGensExtTrait<G, CE = G::CE>,
CommitmentKey<G>: CommitmentKeyExtTrait<G, CE = G::CE>,
{
fn protocol_name() -> &'static [u8] {
b"inner product argument"
}
fn prove(
gens: &CommitmentGens<G>,
gens_c: &CommitmentGens<G>,
ck: &CommitmentKey<G>,
ck_c: &CommitmentKey<G>,
U: &InnerProductInstance<G>,
W: &InnerProductWitness<G>,
transcript: &mut G::TE,
@ -171,12 +188,12 @@ where
// sample a random base for commiting to the inner product
let r = G::Scalar::challenge(b"r", transcript)?;
let gens_c = gens_c.scale(&r);
let ck_c = ck_c.scale(&r);
// a closure that executes a step of the recursive inner product argument
let prove_inner = |a_vec: &[G::Scalar],
b_vec: &[G::Scalar],
gens: &CommitmentGens<G>,
ck: &CommitmentKey<G>,
transcript: &mut G::TE|
-> Result<
(
@ -184,18 +201,18 @@ where
CompressedCommitment<G>,
Vec<G::Scalar>,
Vec<G::Scalar>,
CommitmentGens<G>,
CommitmentKey<G>,
),
NovaError,
> {
let n = a_vec.len();
let (gens_L, gens_R) = gens.split_at(n / 2);
let (ck_L, ck_R) = ck.split_at(n / 2);
let c_L = inner_product(&a_vec[0..n / 2], &b_vec[n / 2..n]);
let c_R = inner_product(&a_vec[n / 2..n], &b_vec[0..n / 2]);
let L = CE::<G>::commit(
&gens_R.combine(&gens_c),
&ck_R.combine(&ck_c),
&a_vec[0..n / 2]
.iter()
.chain(iter::once(&c_L))
@ -204,7 +221,7 @@ where
)
.compress();
let R = CE::<G>::commit(
&gens_L.combine(&gens_c),
&ck_L.combine(&ck_c),
&a_vec[n / 2..n]
.iter()
.chain(iter::once(&c_R))
@ -232,9 +249,9 @@ where
.map(|(b_L, b_R)| *b_L * r_inverse + r * *b_R)
.collect::<Vec<G::Scalar>>();
let gens_folded = gens.fold(&r_inverse, &r);
let ck_folded = ck.fold(&r_inverse, &r);
Ok((L, R, a_vec_folded, b_vec_folded, gens_folded))
Ok((L, R, a_vec_folded, b_vec_folded, ck_folded))
};
// two vectors to hold the logarithmic number of group elements
@ -244,16 +261,16 @@ where
// we create mutable copies of vectors and generators
let mut a_vec = W.a_vec.to_vec();
let mut b_vec = U.b_vec.to_vec();
let mut gens = gens.clone();
let mut ck = ck.clone();
for _i in 0..(U.b_vec.len() as f64).log2() as usize {
let (L, R, a_vec_folded, b_vec_folded, gens_folded) =
prove_inner(&a_vec, &b_vec, &gens, transcript)?;
let (L, R, a_vec_folded, b_vec_folded, ck_folded) =
prove_inner(&a_vec, &b_vec, &ck, transcript)?;
L_vec.push(L);
R_vec.push(R);
a_vec = a_vec_folded;
b_vec = b_vec_folded;
gens = gens_folded;
ck = ck_folded;
}
Ok(InnerProductArgument {
@ -266,8 +283,8 @@ where
fn verify(
&self,
gens: &CommitmentGens<G>,
gens_c: &CommitmentGens<G>,
ck: &CommitmentKey<G>,
ck_c: &CommitmentKey<G>,
n: usize,
U: &InnerProductInstance<G>,
transcript: &mut G::TE,
@ -286,9 +303,9 @@ where
// sample a random base for commiting to the inner product
let r = G::Scalar::challenge(b"r", transcript)?;
let gens_c = gens_c.scale(&r);
let ck_c = ck_c.scale(&r);
let P = U.comm_a_vec + CE::<G>::commit(&gens_c, &[U.c]);
let P = U.comm_a_vec + CE::<G>::commit(&ck_c, &[U.c]);
let batch_invert = |v: &[G::Scalar]| -> Result<Vec<G::Scalar>, NovaError> {
let mut products = vec![G::Scalar::zero(); v.len()];
@ -354,23 +371,23 @@ where
s
};
let gens_hat = {
let c = CE::<G>::commit(gens, &s).compress();
CommitmentGens::<G>::reinterpret_commitments_as_gens(&[c])?
let ck_hat = {
let c = CE::<G>::commit(ck, &s).compress();
CommitmentKey::<G>::reinterpret_commitments_as_ck(&[c])?
};
let b_hat = inner_product(&U.b_vec, &s);
let P_hat = {
let gens_folded = {
let gens_L = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.L_vec)?;
let gens_R = CommitmentGens::<G>::reinterpret_commitments_as_gens(&self.R_vec)?;
let gens_P = CommitmentGens::<G>::reinterpret_commitments_as_gens(&[P.compress()])?;
gens_L.combine(&gens_R).combine(&gens_P)
let ck_folded = {
let ck_L = CommitmentKey::<G>::reinterpret_commitments_as_ck(&self.L_vec)?;
let ck_R = CommitmentKey::<G>::reinterpret_commitments_as_ck(&self.R_vec)?;
let ck_P = CommitmentKey::<G>::reinterpret_commitments_as_ck(&[P.compress()])?;
ck_L.combine(&ck_R).combine(&ck_P)
};
CE::<G>::commit(
&gens_folded,
&ck_folded,
&r_square
.iter()
.chain(r_inverse_square.iter())
@ -380,12 +397,7 @@ where
)
};
if P_hat
== CE::<G>::commit(
&gens_hat.combine(&gens_c),
&[self.a_hat, self.a_hat * b_hat],
)
{
if P_hat == CE::<G>::commit(&ck_hat.combine(&ck_c), &[self.a_hat, self.a_hat * b_hat]) {
Ok(())
} else {
Err(NovaError::InvalidIPA)

+ 19
- 19
src/provider/pasta.rs

@ -105,7 +105,7 @@ macro_rules! impl_traits {
reader.read_exact(&mut uniform_bytes).unwrap();
uniform_bytes_vec.push(uniform_bytes);
}
let gens_proj: Vec<$name_curve> = (0..n)
let ck_proj: Vec<$name_curve> = (0..n)
.collect::<Vec<usize>>()
.into_par_iter()
.map(|i| {
@ -115,22 +115,22 @@ macro_rules! impl_traits {
.collect();
let num_threads = rayon::current_num_threads();
if gens_proj.len() > num_threads {
let chunk = (gens_proj.len() as f64 / num_threads as f64).ceil() as usize;
if ck_proj.len() > num_threads {
let chunk = (ck_proj.len() as f64 / num_threads as f64).ceil() as usize;
(0..num_threads)
.collect::<Vec<usize>>()
.into_par_iter()
.map(|i| {
let start = i * chunk;
let end = if i == num_threads - 1 {
gens_proj.len()
ck_proj.len()
} else {
core::cmp::min((i + 1) * chunk, gens_proj.len())
core::cmp::min((i + 1) * chunk, ck_proj.len())
};
if end > start {
let mut gens = vec![$name_curve_affine::identity(); end - start];
<Self as Curve>::batch_normalize(&gens_proj[start..end], &mut gens);
gens
let mut ck = vec![$name_curve_affine::identity(); end - start];
<Self as Curve>::batch_normalize(&ck_proj[start..end], &mut ck);
ck
} else {
vec![]
}
@ -140,9 +140,9 @@ macro_rules! impl_traits {
.flatten()
.collect()
} else {
let mut gens = vec![$name_curve_affine::identity(); n];
<Self as Curve>::batch_normalize(&gens_proj, &mut gens);
gens
let mut ck = vec![$name_curve_affine::identity(); n];
<Self as Curve>::batch_normalize(&ck_proj, &mut ck);
ck
}
}
@ -353,14 +353,14 @@ mod tests {
let mut shake = Shake256::default();
shake.input(label);
let mut reader = shake.xof_result();
let mut gens = Vec::new();
let mut ck = Vec::new();
for _ in 0..n {
let mut uniform_bytes = [0u8; 32];
reader.read_exact(&mut uniform_bytes).unwrap();
let hash = Ep::hash_to_curve("from_uniform_bytes");
gens.push(hash(&uniform_bytes).to_affine());
ck.push(hash(&uniform_bytes).to_affine());
}
gens
ck
}
#[test]
@ -369,11 +369,11 @@ mod tests {
for n in [
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 1021,
] {
let gens_par = <G as Group>::from_label(label, n);
let gens_ser = from_label_serial(label, n);
assert_eq!(gens_par.len(), n);
assert_eq!(gens_ser.len(), n);
assert_eq!(gens_par, gens_ser);
let ck_par = <G as Group>::from_label(label, n);
let ck_ser = from_label_serial(label, n);
assert_eq!(ck_par.len(), n);
assert_eq!(ck_ser.len(), n);
assert_eq!(ck_par, ck_ser);
}
}
}

+ 40
- 40
src/provider/pedersen.rs

@ -2,7 +2,7 @@
use crate::{
errors::NovaError,
traits::{
commitment::{CommitmentEngineTrait, CommitmentGensTrait, CommitmentTrait},
commitment::{CommitmentEngineTrait, CommitmentKeyTrait, CommitmentTrait},
AbsorbInROTrait, AppendToTranscriptTrait, CompressedGroup, Group, ROTrait,
TranscriptEngineTrait,
},
@ -18,8 +18,8 @@ use serde::{Deserialize, Serialize};
/// A type that holds commitment generators
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct CommitmentGens<G: Group> {
gens: Vec<G::PreprocessedGroupElement>,
pub struct CommitmentKey<G: Group> {
ck: Vec<G::PreprocessedGroupElement>,
_p: PhantomData<G>,
}
@ -37,24 +37,24 @@ pub struct CompressedCommitment {
comm: G::CompressedGroupElement,
}
impl<G: Group> CommitmentGensTrait<G> for CommitmentGens<G> {
impl<G: Group> CommitmentKeyTrait<G> for CommitmentKey<G> {
type Commitment = Commitment<G>;
fn new(label: &'static [u8], n: usize) -> Self {
CommitmentGens {
gens: G::from_label(label, n.next_power_of_two()),
CommitmentKey {
ck: G::from_label(label, n.next_power_of_two()),
_p: Default::default(),
}
}
fn len(&self) -> usize {
self.gens.len()
self.ck.len()
}
fn commit(&self, v: &[G::Scalar]) -> Self::Commitment {
assert!(self.gens.len() >= v.len());
assert!(self.ck.len() >= v.len());
Commitment {
comm: G::vartime_multiscalar_mul(v, &self.gens[..v.len()]),
comm: G::vartime_multiscalar_mul(v, &self.ck[..v.len()]),
}
}
}
@ -209,15 +209,15 @@ pub struct CommitmentEngine {
}
impl<G: Group> CommitmentEngineTrait<G> for CommitmentEngine<G> {
type CommitmentGens = CommitmentGens<G>;
type CommitmentKey = CommitmentKey<G>;
type Commitment = Commitment<G>;
fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment {
gens.commit(v)
fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment {
ck.commit(v)
}
}
pub(crate) trait CommitmentGensExtTrait<G: Group>: CommitmentGensTrait<G> {
pub(crate) trait CommitmentKeyExtTrait<G: Group>: CommitmentKeyTrait<G> {
type CE: CommitmentEngineTrait<G>;
/// Splits the commitment key into two pieces at a specified point
@ -235,87 +235,87 @@ pub(crate) trait CommitmentGensExtTrait: CommitmentGensTrait {
fn scale(&self, r: &G::Scalar) -> Self;
/// Reinterprets commitments as commitment keys
fn reinterpret_commitments_as_gens(
c: &[<<<Self as CommitmentGensExtTrait<G>>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment],
fn reinterpret_commitments_as_ck(
c: &[<<<Self as CommitmentKeyExtTrait<G>>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment],
) -> Result<Self, NovaError>
where
Self: Sized;
}
impl<G: Group> CommitmentGensExtTrait<G> for CommitmentGens<G> {
impl<G: Group> CommitmentKeyExtTrait<G> for CommitmentKey<G> {
type CE = CommitmentEngine<G>;
fn split_at(&self, n: usize) -> (CommitmentGens<G>, CommitmentGens<G>) {
fn split_at(&self, n: usize) -> (CommitmentKey<G>, CommitmentKey<G>) {
(
CommitmentGens {
gens: self.gens[0..n].to_vec(),
CommitmentKey {
ck: self.ck[0..n].to_vec(),
_p: Default::default(),
},
CommitmentGens {
gens: self.gens[n..].to_vec(),
CommitmentKey {
ck: self.ck[n..].to_vec(),
_p: Default::default(),
},
)
}
fn combine(&self, other: &CommitmentGens<G>) -> CommitmentGens<G> {
let gens = {
let mut c = self.gens.clone();
c.extend(other.gens.clone());
fn combine(&self, other: &CommitmentKey<G>) -> CommitmentKey<G> {
let ck = {
let mut c = self.ck.clone();
c.extend(other.ck.clone());
c
};
CommitmentGens {
gens,
CommitmentKey {
ck,
_p: Default::default(),
}
}
// combines the left and right halves of `self` using `w1` and `w2` as the weights
fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentGens<G> {
fn fold(&self, w1: &G::Scalar, w2: &G::Scalar) -> CommitmentKey<G> {
let w = vec![*w1, *w2];
let (L, R) = self.split_at(self.len() / 2);
let gens = (0..self.len() / 2)
let ck = (0..self.len() / 2)
.into_par_iter()
.map(|i| {
let bases = [L.gens[i].clone(), R.gens[i].clone()].to_vec();
let bases = [L.ck[i].clone(), R.ck[i].clone()].to_vec();
G::vartime_multiscalar_mul(&w, &bases).preprocessed()
})
.collect();
CommitmentGens {
gens,
CommitmentKey {
ck,
_p: Default::default(),
}
}
/// Scales each element in `self` by `r`
fn scale(&self, r: &G::Scalar) -> Self {
let gens_scaled = self
.gens
let ck_scaled = self
.ck
.clone()
.into_par_iter()
.map(|g| G::vartime_multiscalar_mul(&[*r], &[g]).preprocessed())
.collect();
CommitmentGens {
gens: gens_scaled,
CommitmentKey {
ck: ck_scaled,
_p: Default::default(),
}
}
/// reinterprets a vector of commitments as a set of generators
fn reinterpret_commitments_as_gens(c: &[CompressedCommitment<G>]) -> Result<Self, NovaError> {
fn reinterpret_commitments_as_ck(c: &[CompressedCommitment<G>]) -> Result<Self, NovaError> {
let d = (0..c.len())
.into_par_iter()
.map(|i| Commitment::<G>::decompress(&c[i]))
.collect::<Result<Vec<Commitment<G>>, NovaError>>()?;
let gens = (0..d.len())
let ck = (0..d.len())
.into_par_iter()
.map(|i| d[i].comm.preprocessed())
.collect();
Ok(CommitmentGens {
gens,
Ok(CommitmentKey {
ck,
_p: Default::default(),
})
}

+ 22
- 29
src/r1cs.rs

@ -8,12 +8,12 @@ use crate::{
utils::scalar_as_base,
},
traits::{
commitment::{CommitmentEngineTrait, CommitmentGensTrait},
commitment::{CommitmentEngineTrait, CommitmentKeyTrait},
AbsorbInROTrait, AppendToTranscriptTrait, Group, ROTrait,
},
Commitment, CommitmentGens, CE,
Commitment, CommitmentKey, CE,
};
use core::cmp::max;
use core::{cmp::max, marker::PhantomData};
use ff::Field;
use flate2::{write::ZlibEncoder, Compression};
use itertools::concat;
@ -24,8 +24,8 @@ use sha3::{Digest, Sha3_256};
/// Public parameters for a given R1CS
#[derive(Clone, Serialize, Deserialize)]
#[serde(bound = "")]
pub struct R1CSGens<G: Group> {
pub(crate) gens: CommitmentGens<G>,
pub struct R1CS<G: Group> {
_p: PhantomData<G>,
}
/// A type that holds the shape of the R1CS matrices
@ -71,12 +71,10 @@ pub struct RelaxedR1CSInstance {
pub(crate) u: G::Scalar,
}
impl<G: Group> R1CSGens<G> {
impl<G: Group> R1CS<G> {
/// Samples public parameters for the specified number of constraints and variables in an R1CS
pub fn new(num_cons: usize, num_vars: usize) -> R1CSGens<G> {
R1CSGens {
gens: CommitmentGens::<G>::new(b"gens", max(num_vars, num_cons)),
}
pub fn commitment_key(num_cons: usize, num_vars: usize) -> CommitmentKey<G> {
CommitmentKey::<G>::new(b"ck", max(num_vars, num_cons))
}
}
@ -181,7 +179,7 @@ impl R1CSShape {
/// Checks if the Relaxed R1CS instance is satisfiable given a witness and its shape
pub fn is_sat_relaxed(
&self,
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
U: &RelaxedR1CSInstance<G>,
W: &RelaxedR1CSWitness<G>,
) -> Result<(), NovaError> {
@ -206,10 +204,8 @@ impl R1CSShape {
// verify if comm_E and comm_W are commitments to E and W
let res_comm: bool = {
let (comm_W, comm_E) = rayon::join(
|| CE::<G>::commit(&gens.gens, &W.W),
|| CE::<G>::commit(&gens.gens, &W.E),
);
let (comm_W, comm_E) =
rayon::join(|| CE::<G>::commit(ck, &W.W), || CE::<G>::commit(ck, &W.E));
U.comm_W == comm_W && U.comm_E == comm_E
};
@ -223,7 +219,7 @@ impl R1CSShape {
/// Checks if the R1CS instance is satisfiable given a witness and its shape
pub fn is_sat(
&self,
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
U: &R1CSInstance<G>,
W: &R1CSWitness<G>,
) -> Result<(), NovaError> {
@ -246,7 +242,7 @@ impl R1CSShape {
};
// verify if comm_W is a commitment to W
let res_comm: bool = U.comm_W == CE::<G>::commit(&gens.gens, &W.W);
let res_comm: bool = U.comm_W == CE::<G>::commit(ck, &W.W);
if res_eq && res_comm {
Ok(())
@ -259,7 +255,7 @@ impl R1CSShape {
/// Relaxed R1CS instance-witness pair and an R1CS instance-witness pair
pub fn commit_T(
&self,
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
U1: &RelaxedR1CSInstance<G>,
W1: &RelaxedR1CSWitness<G>,
U2: &R1CSInstance<G>,
@ -300,7 +296,7 @@ impl R1CSShape {
.map(|(((a, b), c), d)| *a + *b - *c - *d)
.collect::<Vec<G::Scalar>>();
let comm_T = CE::<G>::commit(&gens.gens, &T);
let comm_T = CE::<G>::commit(ck, &T);
Ok((T, comm_T))
}
@ -466,8 +462,8 @@ impl R1CSWitness {
}
/// Commits to the witness using the supplied generators
pub fn commit(&self, gens: &R1CSGens<G>) -> Commitment<G> {
CE::<G>::commit(&gens.gens, &self.W)
pub fn commit(&self, ck: &CommitmentKey<G>) -> Commitment<G> {
CE::<G>::commit(ck, &self.W)
}
}
@ -523,11 +519,8 @@ impl RelaxedR1CSWitness {
}
/// Commits to the witness using the supplied generators
pub fn commit(&self, gens: &R1CSGens<G>) -> (Commitment<G>, Commitment<G>) {
(
CE::<G>::commit(&gens.gens, &self.W),
CE::<G>::commit(&gens.gens, &self.E),
)
pub fn commit(&self, ck: &CommitmentKey<G>) -> (Commitment<G>, Commitment<G>) {
(CE::<G>::commit(ck, &self.W), CE::<G>::commit(ck, &self.E))
}
/// Folds an incoming R1CSWitness into the current one
@ -577,7 +570,7 @@ impl RelaxedR1CSWitness {
impl<G: Group> RelaxedR1CSInstance<G> {
/// Produces a default RelaxedR1CSInstance given R1CSGens and R1CSShape
pub fn default(_gens: &R1CSGens<G>, S: &R1CSShape<G>) -> RelaxedR1CSInstance<G> {
pub fn default(_ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> RelaxedR1CSInstance<G> {
let (comm_W, comm_E) = (Commitment::<G>::default(), Commitment::<G>::default());
RelaxedR1CSInstance {
comm_W,
@ -589,11 +582,11 @@ impl RelaxedR1CSInstance {
/// Initializes a new RelaxedR1CSInstance from an R1CSInstance
pub fn from_r1cs_instance(
gens: &R1CSGens<G>,
ck: &CommitmentKey<G>,
S: &R1CSShape<G>,
instance: &R1CSInstance<G>,
) -> RelaxedR1CSInstance<G> {
let mut r_instance = RelaxedR1CSInstance::default(gens, S);
let mut r_instance = RelaxedR1CSInstance::default(ck, S);
r_instance.comm_W = instance.comm_W;
r_instance.u = G::Scalar::one();
r_instance.X = instance.X.clone();

+ 18
- 28
src/spartan/mod.rs

@ -5,12 +5,12 @@ mod sumcheck;
use crate::{
errors::NovaError,
r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
traits::{
evaluation::EvaluationEngineTrait,
snark::{ProverKeyTrait, RelaxedR1CSSNARKTrait, VerifierKeyTrait},
AppendToTranscriptTrait, ChallengeTrait, Group, TranscriptEngineTrait,
evaluation::EvaluationEngineTrait, snark::RelaxedR1CSSNARKTrait, AppendToTranscriptTrait,
ChallengeTrait, Group, TranscriptEngineTrait,
},
CommitmentKey,
};
use ff::Field;
use itertools::concat;
@ -23,38 +23,18 @@ use sumcheck::SumcheckProof;
#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
gens: EE::EvaluationGens,
pk_ee: EE::ProverKey,
S: R1CSShape<G>,
}
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> ProverKeyTrait<G> for ProverKey<G, EE> {
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self {
ProverKey {
gens: EE::setup(&gens.gens),
S: S.clone(),
}
}
}
/// A type that represents the verifier's key
#[derive(Serialize, Deserialize)]
#[serde(bound = "")]
pub struct VerifierKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
gens: EE::EvaluationGens,
vk_ee: EE::VerifierKey,
S: R1CSShape<G>,
}
impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> VerifierKeyTrait<G>
for VerifierKey<G, EE>
{
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self {
VerifierKey {
gens: EE::setup(&gens.gens),
S: S.clone(),
}
}
}
/// A succinct proof of knowledge of a witness to a relaxed R1CS instance
/// The proof is produced using Spartan's combination of the sum-check and
/// the commitment to a vector viewed as a polynomial commitment
@ -78,12 +58,22 @@ impl> RelaxedR1CSSNARKTrait
type ProverKey = ProverKey<G, EE>;
type VerifierKey = VerifierKey<G, EE>;
fn setup(ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> (Self::ProverKey, Self::VerifierKey) {
let (pk_ee, vk_ee) = EE::setup(ck);
let pk = ProverKey { pk_ee, S: S.pad() };
let vk = VerifierKey { vk_ee, S: S.pad() };
(pk, vk)
}
/// produces a succinct proof of satisfiability of a RelaxedR1CS instance
fn prove(
ck: &CommitmentKey<G>,
pk: &Self::ProverKey,
U: &RelaxedR1CSInstance<G>,
W: &RelaxedR1CSWitness<G>,
) -> Result<Self, NovaError> {
let W = W.pad(&pk.S); // pad the witness
let mut transcript = G::TE::new(b"RelaxedR1CSSNARK");
// sanity check that R1CSShape has certain size characteristics
@ -275,7 +265,7 @@ impl> RelaxedR1CSSNARKTrait
.collect::<Vec<G::Scalar>>();
let eval = eval_E_prime + gamma * eval_W_prime;
let eval_arg = EE::prove(&pk.gens, &mut transcript, &comm, &poly, &r_z, &eval)?;
let eval_arg = EE::prove(ck, &pk.pk_ee, &mut transcript, &comm, &poly, &r_z, &eval)?;
Ok(RelaxedR1CSSNARK {
sc_proof_outer,
@ -428,7 +418,7 @@ impl> RelaxedR1CSSNARKTrait
// verify eval_W and eval_E
EE::verify(
&vk.gens,
&vk.vk_ee,
&mut transcript,
&comm,
&r_z,

+ 3
- 3
src/traits/commitment.rs

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
/// This trait defines the behavior of commitment key
#[allow(clippy::len_without_is_empty)]
pub trait CommitmentGensTrait<G: Group>:
pub trait CommitmentKeyTrait<G: Group>:
Clone + Debug + Send + Sync + Serialize + for<'de> Deserialize<'de>
{
/// Holds the type of the commitment that can be produced
@ -99,11 +99,11 @@ pub trait CommitmentEngineTrait:
Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>
{
/// Holds the type of the commitment key
type CommitmentGens: CommitmentGensTrait<G, Commitment = Self::Commitment>;
type CommitmentKey: CommitmentKeyTrait<G, Commitment = Self::Commitment>;
/// Holds the type of the commitment
type Commitment: CommitmentTrait<G>;
/// Commits to the provided vector using the provided generators
fn commit(gens: &Self::CommitmentGens, v: &[G::Scalar]) -> Self::Commitment;
fn commit(ck: &Self::CommitmentKey, v: &[G::Scalar]) -> Self::Commitment;
}

+ 11
- 5
src/traits/evaluation.rs

@ -14,18 +14,24 @@ pub trait EvaluationEngineTrait:
/// A type that holds the associated commitment engine
type CE: CommitmentEngineTrait<G>;
/// A type that holds generators
type EvaluationGens: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// A type that holds the prover key
type ProverKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// A type that holds the verifier key
type VerifierKey: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// A type that holds the evaluation argument
type EvaluationArgument: Clone + Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// A method to perform any additional setup needed to produce proofs of evaluations
fn setup(gens: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentGens) -> Self::EvaluationGens;
fn setup(
ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey,
) -> (Self::ProverKey, Self::VerifierKey);
/// A method to prove the evaluation of a multilinear polynomial
fn prove(
gens: &Self::EvaluationGens,
ck: &<Self::CE as CommitmentEngineTrait<G>>::CommitmentKey,
pk: &Self::ProverKey,
transcript: &mut G::TE,
comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment,
poly: &[G::Scalar],
@ -35,7 +41,7 @@ pub trait EvaluationEngineTrait:
/// A method to verify the purported evaluation of a multilinear polynomials
fn verify(
gens: &Self::EvaluationGens,
vk: &Self::VerifierKey,
transcript: &mut G::TE,
comm: &<Self::CE as CommitmentEngineTrait<G>>::Commitment,
point: &[G::Scalar],

+ 7
- 24
src/traits/snark.rs

@ -1,46 +1,29 @@
//! This module defines a collection of traits that define the behavior of a zkSNARK for RelaxedR1CS
use crate::{
errors::NovaError,
r1cs::{R1CSGens, R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
traits::Group,
CommitmentKey,
};
use serde::{Deserialize, Serialize};
/// A trait that defines the behavior of a zkSNARK's prover key
pub trait ProverKeyTrait<G: Group>: Send + Sync {
/// Produces a new prover's key
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self;
}
/// A trait that defines the behavior of a zkSNARK's verifier key
pub trait VerifierKeyTrait<G: Group>: Send + Sync {
/// Produces a new verifier's key
fn new(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self;
}
/// A trait that defines the behavior of a zkSNARK
pub trait RelaxedR1CSSNARKTrait<G: Group>:
Sized + Send + Sync + Serialize + for<'de> Deserialize<'de>
{
/// A type that represents the prover's key
type ProverKey: ProverKeyTrait<G> + Serialize + for<'de> Deserialize<'de>;
type ProverKey: Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// A type that represents the verifier's key
type VerifierKey: VerifierKeyTrait<G> + Serialize + for<'de> Deserialize<'de>;
/// Produces a prover key
fn prover_key(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self::ProverKey {
Self::ProverKey::new(gens, S)
}
type VerifierKey: Send + Sync + Serialize + for<'de> Deserialize<'de>;
/// Produces a verifier key
fn verifier_key(gens: &R1CSGens<G>, S: &R1CSShape<G>) -> Self::VerifierKey {
Self::VerifierKey::new(gens, S)
}
/// Produces the keys for the prover and the verifier
fn setup(ck: &CommitmentKey<G>, S: &R1CSShape<G>) -> (Self::ProverKey, Self::VerifierKey);
/// Produces a new SNARK for a relaxed R1CS
fn prove(
ck: &CommitmentKey<G>,
pk: &Self::ProverKey,
U: &RelaxedR1CSInstance<G>,
W: &RelaxedR1CSWitness<G>,

Loading…
Cancel
Save