Skip to content

Instantly share code, notes, and snippets.

@featherin
Created February 20, 2024 22:17
Show Gist options
  • Save featherin/10d5dea8f32eaffd7d52557eaa9dadda to your computer and use it in GitHub Desktop.
Save featherin/10d5dea8f32eaffd7d52557eaa9dadda to your computer and use it in GitHub Desktop.
use bellpepper_core::{num::AllocatedNum, ConstraintSystem, SynthesisError};
use flate2::{write::ZlibEncoder, Compression};
use nova_snark::{
provider::{Bn256EngineKZG, GrumpkinEngine},
traits::{
circuit::{StepCircuit, TrivialCircuit},
snark::RelaxedR1CSSNARKTrait,
Engine, Group,
},
CompressedSNARK, PublicParams, RecursiveSNARK,
};
use std::time::Instant;
type E1 = Bn256EngineKZG;
type E2 = GrumpkinEngine;
type EE1 = nova_snark::provider::hyperkzg::EvaluationEngine<E1>;
type EE2 = nova_snark::provider::ipa_pc::EvaluationEngine<E2>;
type S1 = nova_snark::spartan::snark::RelaxedR1CSSNARK<E1, EE1>; // non-preprocessing SNARK
type S2 = nova_snark::spartan::snark::RelaxedR1CSSNARK<E2, EE2>; // non-preprocessing SNARK
#[derive(Clone, Debug)]
struct FakeHashCircuit<G: Group> {
x: G::Scalar,
}
impl<G: Group> StepCircuit<G::Scalar> for FakeHashCircuit<G> {
fn arity(&self) -> usize {
1
}
fn synthesize<CS: ConstraintSystem<G::Scalar>>(
&self,
cs: &mut CS,
z: &[AllocatedNum<G::Scalar>],
) -> Result<Vec<AllocatedNum<G::Scalar>>, SynthesisError> {
let z = z[0].clone();
let x = AllocatedNum::alloc_input(cs.namespace(|| format!("x")), || Ok(self.x))?;
z.mul(cs.namespace(|| format!("Compute H(z, x) = z * x")), &x)
.map(|v| vec![v])
}
}
fn main() {
let num_steps = 10;
let circuit_primary = FakeHashCircuit {
x: Default::default(),
};
let circuit_secondary = TrivialCircuit::default();
// produce public parameters
let start = Instant::now();
println!("Producing public parameters...");
let pp = PublicParams::<
E1,
E2,
FakeHashCircuit<<E1 as Engine>::GE>,
TrivialCircuit<<E2 as Engine>::Scalar>,
>::setup(
&circuit_primary,
&circuit_secondary,
&*S1::ck_floor(),
&*S2::ck_floor(),
)
.unwrap();
println!("PublicParams::setup, took {:?} ", start.elapsed());
println!(
"Number of constraints per step (primary circuit): {}",
pp.num_constraints().0
);
println!(
"Number of constraints per step (secondary circuit): {}",
pp.num_constraints().1
);
println!(
"Number of variables per step (primary circuit): {}",
pp.num_variables().0
);
println!(
"Number of variables per step (secondary circuit): {}",
pp.num_variables().1
);
let circuits = (0..num_steps)
.map(|i| FakeHashCircuit {
x: <E1 as Engine>::Scalar::from(i as u64),
})
.collect::<Vec<_>>();
let z0_primary = vec![<E1 as Engine>::Scalar::one()];
let z0_secondary = vec![<E2 as Engine>::Scalar::zero()];
type C1 = FakeHashCircuit<<E1 as Engine>::GE>;
type C2 = TrivialCircuit<<E2 as Engine>::Scalar>;
// produce a recursive SNARK
println!("Generating a RecursiveSNARK...");
let mut recursive_snark: RecursiveSNARK<E1, E2, C1, C2> = RecursiveSNARK::<E1, E2, C1, C2>::new(
&pp,
&circuits[0],
&circuit_secondary,
&z0_primary,
&z0_secondary,
)
.unwrap();
for (i, circuit_primary) in circuits.iter().enumerate() {
let start = Instant::now();
let res = recursive_snark.prove_step(&pp, circuit_primary, &circuit_secondary);
assert!(res.is_ok());
println!(
"RecursiveSNARK::prove_step {}: {:?}, took {:?} ",
i,
res.is_ok(),
start.elapsed()
);
}
// verify the recursive SNARK
println!("Verifying a RecursiveSNARK...");
let start = Instant::now();
let res = recursive_snark.verify(&pp, num_steps, &z0_primary, &z0_secondary);
println!(
"RecursiveSNARK::verify: {:?}, took {:?}",
res.is_ok(),
start.elapsed()
);
assert!(res.is_ok());
// produce a compressed SNARK
println!("Generating a CompressedSNARK using Spartan with HyperKZG...");
let (pk, vk) = CompressedSNARK::<_, _, _, _, S1, S2>::setup(&pp).unwrap();
let start = Instant::now();
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
start.elapsed()
);
assert!(res.is_ok());
let compressed_snark = res.unwrap();
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
bincode::serialize_into(&mut encoder, &compressed_snark).unwrap();
let compressed_snark_encoded = encoder.finish().unwrap();
println!(
"CompressedSNARK::len {:?} bytes",
compressed_snark_encoded.len()
);
// verify the compressed SNARK
println!("Verifying a CompressedSNARK...");
let start = Instant::now();
let res = compressed_snark.verify(&vk, num_steps, &z0_primary, &z0_secondary);
println!(
"CompressedSNARK::verify: {:?}, took {:?}",
res.is_ok(),
start.elapsed()
);
assert!(res.is_ok());
println!("=========================================================");
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment