Skip to content

Commit 0fff078

Browse files
committed
adjust recursive calculation using standard gates
1 parent c66506c commit 0fff078

File tree

1 file changed

+116
-41
lines changed

1 file changed

+116
-41
lines changed

src/backends/plonky2/recursion/circuit.rs

Lines changed: 116 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use itertools::Itertools;
1212
use plonky2::{
1313
self,
1414
field::{extension::quintic::QuinticExtension, types::Field},
15-
gates::noop::NoopGate,
15+
gates::{gate::GateRef, noop::NoopGate},
1616
hash::hash_types::HashOutTarget,
1717
iop::{
1818
target::Target,
@@ -311,48 +311,42 @@ fn coset_interpolation_gate(
311311
unsafe { std::mem::transmute(gate) }
312312
}
313313

314-
pub fn common_data_for_recursion<I: InnerCircuit>(
315-
arity: usize,
316-
num_public_inputs: usize,
317-
inner_params: &I::Params,
318-
) -> Result<CommonCircuitData<F, D>> {
319-
let config = CircuitConfig::standard_recursion_config();
320-
321-
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
322-
use plonky2::gates::gate::GateRef;
323-
// Add our standard set of gates
324-
for gate in [
314+
/// Returns the minimum set of gates that define our recursively verifiable circuits.
315+
/// NOTE: The overhead between verifying any proof with just the `NoopGate` and verifying a proof
316+
/// with all these standard gates is about 400 num_gates (rows), no matter the circuit size.
317+
fn standard_gates(config: &CircuitConfig) -> Vec<GateRef<F, D>> {
318+
let nnf_mul_simple =
319+
GateAdapter::<NNFMulSimple<5, QuinticExtension<F>>>::new_from_config(config);
320+
let ec_add_homog_offset = GateAdapter::<ECAddHomogOffset>::new_from_config(config);
321+
vec![
325322
GateRef::new(plonky2::gates::noop::NoopGate {}),
326323
GateRef::new(plonky2::gates::constant::ConstantGate::new(
327324
config.num_constants,
328325
)),
329326
GateRef::new(plonky2::gates::poseidon_mds::PoseidonMdsGate::new()),
330327
GateRef::new(plonky2::gates::poseidon::PoseidonGate::new()),
331328
GateRef::new(plonky2::gates::public_input::PublicInputGate {}),
332-
GateRef::new(plonky2::gates::base_sum::BaseSumGate::<2>::new_from_config::<F>(&config)),
329+
GateRef::new(plonky2::gates::base_sum::BaseSumGate::<2>::new_from_config::<F>(config)),
333330
GateRef::new(plonky2::gates::reducing_extension::ReducingExtensionGate::new(32)),
334331
GateRef::new(plonky2::gates::reducing::ReducingGate::new(43)),
335332
GateRef::new(
336-
plonky2::gates::arithmetic_extension::ArithmeticExtensionGate::new_from_config(&config),
337-
),
338-
GateRef::new(plonky2::gates::arithmetic_base::ArithmeticGate::new_from_config(&config)),
339-
GateRef::new(
340-
plonky2::gates::multiplication_extension::MulExtensionGate::new_from_config(&config),
333+
plonky2::gates::arithmetic_extension::ArithmeticExtensionGate::new_from_config(config),
341334
),
342-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 1)),
343-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 2)),
344-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 3)),
345-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 4)),
346-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 5)),
347-
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 6)),
348-
GateRef::new(GateAdapter::<NNFMulSimple<5, QuinticExtension<F>>>::new_from_config(&config)),
335+
GateRef::new(plonky2::gates::arithmetic_base::ArithmeticGate::new_from_config(config)),
349336
GateRef::new(
350-
GateAdapter::<NNFMulSimple<5, QuinticExtension<F>>>::new_from_config(&config)
351-
.recursive_gate(),
337+
plonky2::gates::multiplication_extension::MulExtensionGate::new_from_config(config),
352338
),
353-
GateRef::new(GateAdapter::<ECAddHomogOffset>::new_from_config(&config)),
354-
GateRef::new(GateAdapter::<ECAddHomogOffset>::new_from_config(&config).recursive_gate()),
355-
GateRef::new(plonky2::gates::exponentiation::ExponentiationGate::new_from_config(&config)),
339+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 1)),
340+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 2)),
341+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 3)),
342+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 4)),
343+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 5)),
344+
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(config, 6)),
345+
GateRef::new(nnf_mul_simple.recursive_gate()),
346+
GateRef::new(nnf_mul_simple),
347+
GateRef::new(ec_add_homog_offset.recursive_gate()),
348+
GateRef::new(ec_add_homog_offset),
349+
GateRef::new(plonky2::gates::exponentiation::ExponentiationGate::new_from_config(config)),
356350
// It would be better do `CosetInterpolationGate::with_max_degree(4, 6)` but unfortunately
357351
// that plonk2 method is `pub(crate)`, so we need to get around that somehow.
358352
GateRef::new(coset_interpolation_gate(
@@ -377,7 +371,42 @@ pub fn common_data_for_recursion<I: InnerCircuit>(
377371
18446462594437939201,
378372
],
379373
)),
380-
] {
374+
]
375+
}
376+
377+
/// Estimate the number of gates to verify a proof of `degree_bits` that uses the
378+
/// `standard_gates(&standard_recursion_config)`
379+
fn estimate_verif_num_gates(degree_bits: usize) -> usize {
380+
// Formula obtained via linear regression using `test_measure_recursion` results with
381+
// `standard_recursion_config`.
382+
let num_gates: usize = 236 * degree_bits + 1171;
383+
// Add 2% for error because the results are not a clean line
384+
num_gates * 102 / 100
385+
}
386+
387+
/// Estimate the number of gates after blinding (to add zk) and padding of a circuit with
388+
/// `2^degree_bits` gates using `standard_recursion_zk_config`.
389+
#[allow(dead_code)]
390+
fn estimate_gates_after_zk(degree_bits: usize) -> usize {
391+
// Table data obtained using `test_measure_zk` results with `standard_recursion_zk_config`.
392+
match degree_bits {
393+
0..=12 => 1 << 14,
394+
13 => 1 << 15,
395+
n => 1 << (n + 1),
396+
}
397+
}
398+
399+
pub fn common_data_for_recursion<I: InnerCircuit>(
400+
arity: usize,
401+
num_public_inputs: usize,
402+
inner_params: &I::Params,
403+
) -> Result<CommonCircuitData<F, D>> {
404+
let config = CircuitConfig::standard_recursion_config();
405+
406+
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
407+
// Add our standard set of gates
408+
let standard_gates = standard_gates(&config);
409+
for gate in standard_gates.into_iter() {
381410
builder.add_gate_to_gate_set(gate);
382411
}
383412

@@ -394,14 +423,6 @@ pub fn common_data_for_recursion<I: InnerCircuit>(
394423
builder.build::<C>()
395424
);
396425

397-
let estimate_verif_num_gates = |degree_bits: usize| {
398-
// Formula obtained via linear regression using `test_measure_recursion` results with
399-
// `standard_recursion_config`.
400-
let num_gates: usize = 236 * degree_bits + 698;
401-
// Add 8% for error because the results are not a clean line
402-
num_gates * 108 / 100
403-
};
404-
405426
// Loop until we find a circuit size that can verify `arity` proofs of itself
406427
let mut degree_bits = log2_ceil(inner_num_gates);
407428
loop {
@@ -804,6 +825,34 @@ mod tests {
804825
#[test]
805826
fn test_measure_recursion() {
806827
let config = CircuitConfig::standard_recursion_config();
828+
for i in 7..20 {
829+
let mut builder = CircuitBuilder::new(config.clone());
830+
let standard_gates = standard_gates(&config);
831+
for gate in standard_gates.into_iter() {
832+
builder.add_gate_to_gate_set(gate);
833+
}
834+
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
835+
builder.add_gate(NoopGate, vec![]);
836+
}
837+
println!("build degree 2^{} ...", i);
838+
let circuit_data = builder.build::<C>();
839+
assert_eq!(i, circuit_data.common.degree_bits());
840+
841+
let mut builder = CircuitBuilder::new(config.clone());
842+
let measure = measure_gates_begin!(&builder, format!("verifier for 2^{}", i));
843+
let verifier_data_i =
844+
builder.add_virtual_verifier_data(builder.config.fri_config.cap_height);
845+
let proof = builder.add_virtual_proof_with_pis(&circuit_data.common);
846+
builder.verify_proof::<C>(&proof, &verifier_data_i, &circuit_data.common);
847+
measure_gates_end!(&builder, measure);
848+
}
849+
measure_gates_print!();
850+
}
851+
852+
#[ignore]
853+
#[test]
854+
fn test_measure_zk() {
855+
let config = CircuitConfig::standard_recursion_zk_config();
807856
for i in 7..18 {
808857
let mut builder = CircuitBuilder::new(config.clone());
809858
builder.add_gate_to_gate_set(plonky2::gates::gate::GateRef::new(
@@ -812,12 +861,38 @@ mod tests {
812861
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
813862
builder.add_gate(NoopGate, vec![]);
814863
}
864+
let circuit_data = builder.build::<C>();
865+
println!(
866+
"2^{} gates require 2^{} rows",
867+
i,
868+
circuit_data.common.degree_bits()
869+
);
870+
}
871+
}
872+
873+
#[ignore]
874+
#[test]
875+
fn test_measure_zk_recursion() {
876+
let config = CircuitConfig::standard_recursion_zk_config();
877+
for i in 12..18 {
878+
let mut builder = CircuitBuilder::new(config.clone());
879+
let standard_gates = standard_gates(&config);
880+
for gate in standard_gates.into_iter() {
881+
builder.add_gate_to_gate_set(gate);
882+
}
883+
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
884+
builder.add_gate(NoopGate, vec![]);
885+
}
886+
let expected_degree_bits = log2_ceil(estimate_gates_after_zk(i));
815887
println!("build degree 2^{} ...", i);
816888
let circuit_data = builder.build::<C>();
817-
assert_eq!(circuit_data.common.degree_bits(), i);
889+
assert_eq!(expected_degree_bits, circuit_data.common.degree_bits());
818890

819891
let mut builder = CircuitBuilder::new(config.clone());
820-
let measure = measure_gates_begin!(&builder, format!("verifier for 2^{}", i));
892+
let measure = measure_gates_begin!(
893+
&builder,
894+
format!("verifier for zk 2^{}", expected_degree_bits)
895+
);
821896
let verifier_data_i =
822897
builder.add_virtual_verifier_data(builder.config.fri_config.cap_height);
823898
let proof = builder.add_virtual_proof_with_pis(&circuit_data.common);

0 commit comments

Comments
 (0)