Created
February 20, 2024 22:17
-
-
Save featherin/10d5dea8f32eaffd7d52557eaa9dadda to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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