Skip to content

Commit ac8b057

Browse files
authored
Zero Knowledge Fold for Nova IVC from HyperNova (#330)
* randomly sample instance * draft of randomized proving * lib compiles * nifs tests pass * recursive verify sketch * correct verifying recursivesnark * clean up * test passes for RecursiveSNARK random fold * draft for prove/verify compressed snark, some refactoring * clean up * tests pass for compressedSNARK * comments, clarity * public method * add blinds draft * blinding and deblinding r1cs instances * rand in hashing * hashing tests, clippy * requested simplifying changes * clarity refactoring * no blinding label, better derandom funcs, benchmark space * inline randomizing inside CompressedSNARK, clippy, tests * kzg blinds, derand key, refactoring * refactoring
1 parent 2772826 commit ac8b057

File tree

12 files changed

+973
-145
lines changed

12 files changed

+973
-145
lines changed

benches/compressed-snark.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ cfg_if::cfg_if! {
4343
criterion_group! {
4444
name = compressed_snark;
4545
config = Criterion::default().warm_up_time(Duration::from_millis(3000));
46-
targets = bench_compressed_snark, bench_compressed_snark_with_computational_commitments
46+
targets = bench_compressed_snark, bench_compressed_snark_with_computational_commitments,
4747
}
4848
}
4949
}
@@ -109,7 +109,7 @@ fn bench_compressed_snark_internal<S1: RelaxedR1CSSNARKTrait<E1>, S2: RelaxedR1C
109109
assert!(CompressedSNARK::<_, _, _, _, S1, S2>::prove(
110110
black_box(&pp),
111111
black_box(&pk),
112-
black_box(&recursive_snark)
112+
black_box(&recursive_snark),
113113
)
114114
.is_ok());
115115
})

src/circuit.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ pub struct NovaAugmentedCircuitInputs<E: Engine> {
5353
z0: Vec<E::Base>,
5454
zi: Option<Vec<E::Base>>,
5555
U: Option<RelaxedR1CSInstance<E>>,
56+
ri: Option<E::Base>,
57+
r_next: E::Base,
5658
u: Option<R1CSInstance<E>>,
5759
T: Option<Commitment<E>>,
5860
}
@@ -65,6 +67,8 @@ impl<E: Engine> NovaAugmentedCircuitInputs<E> {
6567
z0: Vec<E::Base>,
6668
zi: Option<Vec<E::Base>>,
6769
U: Option<RelaxedR1CSInstance<E>>,
70+
ri: Option<E::Base>,
71+
r_next: E::Base,
6872
u: Option<R1CSInstance<E>>,
6973
T: Option<Commitment<E>>,
7074
) -> Self {
@@ -74,6 +78,8 @@ impl<E: Engine> NovaAugmentedCircuitInputs<E> {
7478
z0,
7579
zi,
7680
U,
81+
ri,
82+
r_next,
7783
u,
7884
T,
7985
}
@@ -117,6 +123,8 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
117123
Vec<AllocatedNum<E::Base>>,
118124
Vec<AllocatedNum<E::Base>>,
119125
AllocatedRelaxedR1CSInstance<E>,
126+
AllocatedNum<E::Base>,
127+
AllocatedNum<E::Base>,
120128
AllocatedR1CSInstance<E>,
121129
AllocatedPoint<E>,
122130
),
@@ -158,6 +166,14 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
158166
self.params.n_limbs,
159167
)?;
160168

169+
// Allocate ri
170+
let r_i = AllocatedNum::alloc(cs.namespace(|| "ri"), || {
171+
Ok(self.inputs.get()?.ri.unwrap_or(E::Base::ZERO))
172+
})?;
173+
174+
// Allocate r_i+1
175+
let r_next = AllocatedNum::alloc(cs.namespace(|| "r_i+1"), || Ok(self.inputs.get()?.r_next))?;
176+
161177
// Allocate the instance to be folded in
162178
let u = AllocatedR1CSInstance::alloc(
163179
cs.namespace(|| "allocate instance u to fold"),
@@ -174,7 +190,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
174190
)?;
175191
T.check_on_curve(cs.namespace(|| "check T on curve"))?;
176192

177-
Ok((params, i, z_0, z_i, U, u, T))
193+
Ok((params, i, z_0, z_i, U, r_i, r_next, u, T))
178194
}
179195

180196
/// Synthesizes base case and returns the new relaxed `R1CSInstance`
@@ -212,6 +228,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
212228
z_0: &[AllocatedNum<E::Base>],
213229
z_i: &[AllocatedNum<E::Base>],
214230
U: &AllocatedRelaxedR1CSInstance<E>,
231+
r_i: &AllocatedNum<E::Base>,
215232
u: &AllocatedR1CSInstance<E>,
216233
T: &AllocatedPoint<E>,
217234
arity: usize,
@@ -230,6 +247,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
230247
ro.absorb(e);
231248
}
232249
U.absorb_in_ro(cs.namespace(|| "absorb U"), &mut ro)?;
250+
ro.absorb(r_i);
233251

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

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

269287
// Compute variable indicating if this is the base case
@@ -282,6 +300,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
282300
&z_0,
283301
&z_i,
284302
&U,
303+
&r_i,
285304
&u,
286305
&T,
287306
arity,
@@ -347,6 +366,7 @@ impl<'a, E: Engine, SC: StepCircuit<E::Base>> NovaAugmentedCircuit<'a, E, SC> {
347366
ro.absorb(e);
348367
}
349368
Unew.absorb_in_ro(cs.namespace(|| "absorb U_new"), &mut ro)?;
369+
ro.absorb(&r_next);
350370
let hash_bits = ro.squeeze(cs.namespace(|| "output hash bits"), NUM_HASH_BITS)?;
351371
let hash = le_bits_to_num(cs.namespace(|| "convert hash to num"), &hash_bits)?;
352372

@@ -410,6 +430,7 @@ mod tests {
410430

411431
// Execute the base case for the primary
412432
let zero1 = <<E2 as Engine>::Base as Field>::ZERO;
433+
let ri_1 = <<E2 as Engine>::Base as Field>::ZERO;
413434
let mut cs1 = SatisfyingAssignment::<E1>::new();
414435
let inputs1: NovaAugmentedCircuitInputs<E2> = NovaAugmentedCircuitInputs::new(
415436
scalar_as_base::<E1>(zero1), // pass zero for testing
@@ -418,6 +439,8 @@ mod tests {
418439
None,
419440
None,
420441
None,
442+
ri_1,
443+
None,
421444
None,
422445
);
423446
let circuit1: NovaAugmentedCircuit<'_, E2, TrivialCircuit<<E2 as Engine>::Base>> =
@@ -429,13 +452,16 @@ mod tests {
429452

430453
// Execute the base case for the secondary
431454
let zero2 = <<E1 as Engine>::Base as Field>::ZERO;
455+
let ri_2 = <<E1 as Engine>::Base as Field>::ZERO;
432456
let mut cs2 = SatisfyingAssignment::<E2>::new();
433457
let inputs2: NovaAugmentedCircuitInputs<E1> = NovaAugmentedCircuitInputs::new(
434458
scalar_as_base::<E2>(zero2), // pass zero for testing
435459
zero2,
436460
vec![zero2],
437461
None,
438462
None,
463+
None,
464+
ri_2,
439465
Some(inst1),
440466
None,
441467
);

src/constants.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@ pub(crate) const NUM_CHALLENGE_BITS: usize = 128;
22
pub(crate) const NUM_HASH_BITS: usize = 250;
33
pub(crate) const BN_LIMB_WIDTH: usize = 64;
44
pub(crate) const BN_N_LIMBS: usize = 4;
5-
pub(crate) const NUM_FE_WITHOUT_IO_FOR_CRHF: usize = 17;
5+
pub(crate) const NUM_FE_WITHOUT_IO_FOR_CRHF: usize = 18;
66
pub(crate) const NUM_FE_FOR_RO: usize = 9;
7+
pub(crate) const NUM_FE_FOR_RO_RELAXED: usize = 34;

0 commit comments

Comments
 (0)