mirror of
https://github.com/arnaucube/Nova.git
synced 2026-02-01 08:46:39 +01:00
Separate prover and verifier keys in CompressedSNARK (#145)
* checkpoint * simplify further * checkpoint * gens --> ck * update benches * address clippy * cleanup * update version
This commit is contained in:
204
src/lib.rs
204
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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user