Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Zero Knowledge Fold for Nova IVC from HyperNova #330

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 64 additions & 6 deletions benches/compressed-snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ cfg_if::cfg_if! {
criterion_group! {
name = compressed_snark;
config = Criterion::default().warm_up_time(Duration::from_millis(3000)).with_profiler(pprof::criterion::PProfProfiler::new(100, pprof::criterion::Output::Flamegraph(None)));
targets = bench_compressed_snark, bench_compressed_snark_with_computational_commitments
targets = bench_compressed_snark, bench_randomizing_compressed_snark, bench_compressed_snark_with_computational_commitments, bench_randomizing_compressed_snark_with_computational_commitments
}
} else {
criterion_group! {
name = compressed_snark;
config = Criterion::default().warm_up_time(Duration::from_millis(3000));
targets = bench_compressed_snark, bench_compressed_snark_with_computational_commitments
targets = bench_compressed_snark, bench_randomizing_compressed_snark, bench_compressed_snark_with_computational_commitments,
bench_randomizing_compressed_snark_with_computational_commitments
}
}
}
Expand All @@ -59,9 +60,11 @@ const NUM_SAMPLES: usize = 10;
/// Parameters
/// - `group``: the criterion benchmark group
/// - `num_cons`: the number of constraints in the step circuit
/// - `randomizing`: if there is a zk layer added before compression
fn bench_compressed_snark_internal<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1CSSNARKTrait<E2>>(
group: &mut BenchmarkGroup<'_, WallTime>,
num_cons: usize,
randomizing: bool,
) {
let c_primary = NonTrivialCircuit::new(num_cons);
let c_secondary = TrivialCircuit::default();
Expand Down Expand Up @@ -109,12 +112,13 @@ fn bench_compressed_snark_internal<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1C
assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
black_box(&pp),
black_box(&pk),
black_box(&recursive_snark)
black_box(&recursive_snark),
black_box(randomizing)
)
.is_ok());
})
});
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark, randomizing);
assert!(res.is_ok());
let compressed_snark = res.unwrap();

Expand Down Expand Up @@ -153,7 +157,7 @@ fn bench_compressed_snark(c: &mut Criterion) {
let mut group = c.benchmark_group(format!("CompressedSNARK-StepCircuitSize-{num_cons}"));
group.sample_size(NUM_SAMPLES);

bench_compressed_snark_internal::<S1, S2>(&mut group, num_cons);
bench_compressed_snark_internal::<S1, S2>(&mut group, num_cons, false);

group.finish();
}
Expand Down Expand Up @@ -181,7 +185,61 @@ fn bench_compressed_snark_with_computational_commitments(c: &mut Criterion) {
.sampling_mode(SamplingMode::Flat)
.sample_size(NUM_SAMPLES);

bench_compressed_snark_internal::<SS1, SS2>(&mut group, num_cons);
bench_compressed_snark_internal::<SS1, SS2>(&mut group, num_cons, false);

group.finish();
}
}

fn bench_randomizing_compressed_snark(c: &mut Criterion) {
// we vary the number of constraints in the step circuit
for &num_cons_in_augmented_circuit in [
NUM_CONS_VERIFIER_CIRCUIT_PRIMARY,
16384,
32768,
65536,
131072,
262144,
524288,
1048576,
]
.iter()
{
// number of constraints in the step circuit
let num_cons = num_cons_in_augmented_circuit - NUM_CONS_VERIFIER_CIRCUIT_PRIMARY;

let mut group = c.benchmark_group(format!("CompressedSNARK-StepCircuitSize-{num_cons}"));
group.sample_size(NUM_SAMPLES);

bench_compressed_snark_internal::<S1, S2>(&mut group, num_cons, true);

group.finish();
}
}

fn bench_randomizing_compressed_snark_with_computational_commitments(c: &mut Criterion) {
// we vary the number of constraints in the step circuit
for &num_cons_in_augmented_circuit in [
NUM_CONS_VERIFIER_CIRCUIT_PRIMARY,
16384,
32768,
65536,
131072,
262144,
]
.iter()
{
// number of constraints in the step circuit
let num_cons = num_cons_in_augmented_circuit - NUM_CONS_VERIFIER_CIRCUIT_PRIMARY;

let mut group = c.benchmark_group(format!(
"CompressedSNARK-Commitments-StepCircuitSize-{num_cons}"
));
group
.sampling_mode(SamplingMode::Flat)
.sample_size(NUM_SAMPLES);

bench_compressed_snark_internal::<SS1, SS2>(&mut group, num_cons, true);

group.finish();
}
Expand Down
2 changes: 1 addition & 1 deletion examples/and.rs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ fn main() {

let start = Instant::now();

let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark, false);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
Expand Down
2 changes: 1 addition & 1 deletion examples/hashchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ fn main() {

let start = Instant::now();

let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark, false);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
Expand Down
2 changes: 1 addition & 1 deletion examples/minroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ fn main() {

let start = Instant::now();

let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark);
let res = CompressedSNARK::<_, _, _, _, S1, S2>::prove(&pp, &pk, &recursive_snark, false);
println!(
"CompressedSNARK::prove: {:?}, took {:?}",
res.is_ok(),
Expand Down
30 changes: 28 additions & 2 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ pub struct NovaAugmentedCircuitInputs<E: Engine> {
z0: Vec<E::Base>,
zi: Option<Vec<E::Base>>,
U: Option<RelaxedR1CSInstance<E>>,
ri: Option<E::Base>,
r_next: E::Base,
srinathsetty marked this conversation as resolved.
Show resolved Hide resolved
u: Option<R1CSInstance<E>>,
T: Option<Commitment<E>>,
}
Expand All @@ -65,6 +67,8 @@ impl<E: Engine> NovaAugmentedCircuitInputs<E> {
z0: Vec<E::Base>,
zi: Option<Vec<E::Base>>,
U: Option<RelaxedR1CSInstance<E>>,
ri: Option<E::Base>,
r_next: E::Base,
u: Option<R1CSInstance<E>>,
T: Option<Commitment<E>>,
) -> Self {
Expand All @@ -74,6 +78,8 @@ impl<E: Engine> NovaAugmentedCircuitInputs<E> {
z0,
zi,
U,
ri,
r_next,
u,
T,
}
Expand Down Expand Up @@ -117,6 +123,8 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
Vec<AllocatedNum<E::Base>>,
Vec<AllocatedNum<E::Base>>,
AllocatedRelaxedR1CSInstance<E>,
AllocatedNum<E::Base>,
AllocatedNum<E::Base>,
AllocatedR1CSInstance<E>,
AllocatedPoint<E>,
),
Expand Down Expand Up @@ -158,6 +166,14 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
self.params.n_limbs,
)?;

// Allocate ri
let r_i = AllocatedNum::alloc(cs.namespace(|| "ri"), || {
Ok(self.inputs.get()?.ri.unwrap_or(E::Base::ZERO))
})?;

// Allocate r_i+1
let r_next = AllocatedNum::alloc(cs.namespace(|| "r_i+1"), || Ok(self.inputs.get()?.r_next))?;

// Allocate the instance to be folded in
let u = AllocatedR1CSInstance::alloc(
cs.namespace(|| "allocate instance u to fold"),
Expand All @@ -174,7 +190,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
)?;
T.check_on_curve(cs.namespace(|| "check T on curve"))?;

Ok((params, i, z_0, z_i, U, u, T))
Ok((params, i, z_0, z_i, U, r_i, r_next, u, T))
}

/// Synthesizes base case and returns the new relaxed `R1CSInstance`
Expand Down Expand Up @@ -212,6 +228,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
z_0: &[AllocatedNum<E::Base>],
z_i: &[AllocatedNum<E::Base>],
U: &AllocatedRelaxedR1CSInstance<E>,
r_i: &AllocatedNum<E::Base>,
u: &AllocatedR1CSInstance<E>,
T: &AllocatedPoint<E>,
arity: usize,
Expand All @@ -230,6 +247,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
ro.absorb(e);
}
U.absorb_in_ro(cs.namespace(|| "absorb U"), &mut ro)?;
ro.absorb(r_i);

let hash_bits = ro.squeeze(cs.namespace(|| "Input hash"), NUM_HASH_BITS)?;
let hash = le_bits_to_num(cs.namespace(|| "bits to hash"), &hash_bits)?;
Expand Down Expand Up @@ -263,7 +281,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
let arity = self.step_circuit.arity();

// Allocate all witnesses
let (params, i, z_0, z_i, U, u, T) =
let (params, i, z_0, z_i, U, r_i, r_next, u, T) =
self.alloc_witness(cs.namespace(|| "allocate the circuit witness"), arity)?;

// Compute variable indicating if this is the base case
Expand All @@ -282,6 +300,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
&z_0,
&z_i,
&U,
&r_i,
&u,
&T,
arity,
Expand Down Expand Up @@ -347,6 +366,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
ro.absorb(e);
}
Unew.absorb_in_ro(cs.namespace(|| "absorb U_new"), &mut ro)?;
ro.absorb(&r_next);
let hash_bits = ro.squeeze(cs.namespace(|| "output hash bits"), NUM_HASH_BITS)?;
let hash = le_bits_to_num(cs.namespace(|| "convert hash to num"), &hash_bits)?;

Expand Down Expand Up @@ -410,6 +430,7 @@ mod tests {

// Execute the base case for the primary
let zero1 = <<E2 as Engine>::Base as Field>::ZERO;
let ri_1 = <<E2 as Engine>::Base as Field>::ZERO;
let mut cs1 = SatisfyingAssignment::<E1>::new();
let inputs1: NovaAugmentedCircuitInputs<E2> = NovaAugmentedCircuitInputs::new(
scalar_as_base::<E1>(zero1), // pass zero for testing
Expand All @@ -418,6 +439,8 @@ mod tests {
None,
None,
None,
ri_1,
None,
None,
);
let circuit1: NovaAugmentedCircuit<'_, E2, TrivialCircuit<<E2 as Engine>::Base>> =
Expand All @@ -429,13 +452,16 @@ mod tests {

// Execute the base case for the secondary
let zero2 = <<E1 as Engine>::Base as Field>::ZERO;
let ri_2 = <<E1 as Engine>::Base as Field>::ZERO;
let mut cs2 = SatisfyingAssignment::<E2>::new();
let inputs2: NovaAugmentedCircuitInputs<E1> = NovaAugmentedCircuitInputs::new(
scalar_as_base::<E2>(zero2), // pass zero for testing
zero2,
vec![zero2],
None,
None,
None,
ri_2,
Some(inst1),
None,
);
Expand Down
3 changes: 2 additions & 1 deletion src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ pub(crate) const NUM_CHALLENGE_BITS: usize = 128;
pub(crate) const NUM_HASH_BITS: usize = 250;
pub(crate) const BN_LIMB_WIDTH: usize = 64;
pub(crate) const BN_N_LIMBS: usize = 4;
pub(crate) const NUM_FE_WITHOUT_IO_FOR_CRHF: usize = 17;
pub(crate) const NUM_FE_WITHOUT_IO_FOR_CRHF: usize = 18;
pub(crate) const NUM_FE_FOR_RO: usize = 9;
pub(crate) const NUM_FE_FOR_RO_RELAXED: usize = 19;
Loading
Loading