Skip to content

Commit c232e1b

Browse files
committed
adjust recursive calculation using standard gates
1 parent 237019c commit c232e1b

File tree

1 file changed

+104
-28
lines changed

1 file changed

+104
-28
lines changed

src/backends/plonky2/recursion/circuit.rs

Lines changed: 104 additions & 28 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,
@@ -46,7 +46,7 @@ pub struct VerifiedProofTarget {
4646
}
4747

4848
/// Expected maximum number of constant gates
49-
const MAX_CONSTANT_GATES: usize = 64;
49+
const MAX_CONSTANT_GATES: usize = 32;
5050

5151
impl VerifiedProofTarget {
5252
fn add_virtual(builder: &mut CircuitBuilder<F, D>, num_public_inputs: usize) -> Self {
@@ -309,33 +309,27 @@ fn coset_interpolation_gate(
309309
unsafe { std::mem::transmute(gate) }
310310
}
311311

312-
pub fn common_data_for_recursion<I: InnerCircuit>(
313-
arity: usize,
314-
num_public_inputs: usize,
315-
inner_params: &I::Params,
316-
) -> Result<CommonCircuitData<F, D>> {
317-
let config = CircuitConfig::standard_recursion_config();
318-
319-
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
320-
use plonky2::gates::gate::GateRef;
321-
// Add our standard set of gates
322-
for gate in [
312+
/// Returns the minimum set of gates that define our recursively verifiable circuits.
313+
/// NOTE: The overhead between verifying any proof with just the `NoopGate` and verifying a proof
314+
/// with all these standard gates is about 400 num_gates (rows), no matter the circuit size.
315+
fn standard_gates(config: &CircuitConfig) -> Vec<GateRef<F, D>> {
316+
vec![
323317
GateRef::new(plonky2::gates::noop::NoopGate {}),
324318
GateRef::new(plonky2::gates::constant::ConstantGate::new(
325319
config.num_constants,
326320
)),
327321
GateRef::new(plonky2::gates::poseidon_mds::PoseidonMdsGate::new()),
328322
GateRef::new(plonky2::gates::poseidon::PoseidonGate::new()),
329323
GateRef::new(plonky2::gates::public_input::PublicInputGate {}),
330-
GateRef::new(plonky2::gates::base_sum::BaseSumGate::<2>::new_from_config::<F>(&config)),
324+
GateRef::new(plonky2::gates::base_sum::BaseSumGate::<2>::new_from_config::<F>(config)),
331325
GateRef::new(plonky2::gates::reducing_extension::ReducingExtensionGate::new(32)),
332326
GateRef::new(plonky2::gates::reducing::ReducingGate::new(43)),
333327
GateRef::new(
334-
plonky2::gates::arithmetic_extension::ArithmeticExtensionGate::new_from_config(&config),
328+
plonky2::gates::arithmetic_extension::ArithmeticExtensionGate::new_from_config(config),
335329
),
336-
GateRef::new(plonky2::gates::arithmetic_base::ArithmeticGate::new_from_config(&config)),
330+
GateRef::new(plonky2::gates::arithmetic_base::ArithmeticGate::new_from_config(config)),
337331
GateRef::new(
338-
plonky2::gates::multiplication_extension::MulExtensionGate::new_from_config(&config),
332+
plonky2::gates::multiplication_extension::MulExtensionGate::new_from_config(config),
339333
),
340334
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 1)),
341335
GateRef::new(plonky2::gates::random_access::RandomAccessGate::new_from_config(&config, 2)),
@@ -348,6 +342,7 @@ pub fn common_data_for_recursion<I: InnerCircuit>(
348342
.recursive_gate(),
349343
),
350344
GateRef::new(GateAdapter::<ECAddHomog>::new_from_config(&config).recursive_gate()),
345+
GateRef::new(plonky2::gates::exponentiation::ExponentiationGate::new_from_config(&config)),
351346
// It would be better do `CosetInterpolationGate::with_max_degree(4, 6)` but unfortunately
352347
// that plonk2 method is `pub(crate)`, so we need to get around that somehow.
353348
GateRef::new(coset_interpolation_gate(
@@ -372,7 +367,42 @@ pub fn common_data_for_recursion<I: InnerCircuit>(
372367
18446462594437939201,
373368
],
374369
)),
375-
] {
370+
]
371+
}
372+
373+
/// Estimate the number of gates to verify a proof of `degree_bits` that uses the
374+
/// `standard_gates(&standard_recursion_config)`
375+
fn estimate_verif_num_gates(degree_bits: usize) -> usize {
376+
// Formula obtained via linear regression using `test_measure_recursion` results with
377+
// `standard_recursion_config`.
378+
let num_gates: usize = 236 * degree_bits + 1171;
379+
// Add 2% for error because the results are not a clean line
380+
num_gates * 102 / 100
381+
}
382+
383+
/// Estimate the number of gates after blinding (to add zk) and padding of a circuit with
384+
/// `2^degree_bits` gates using `standard_recursion_zk_config`.
385+
#[allow(dead_code)]
386+
fn estimate_gates_after_zk(degree_bits: usize) -> usize {
387+
// Table data obtained using `test_measure_zk` results with `standard_recursion_zk_config`.
388+
match degree_bits {
389+
0..=12 => 1 << 14,
390+
13 => 1 << 15,
391+
n => 1 << n + 1,
392+
}
393+
}
394+
395+
pub fn common_data_for_recursion<I: InnerCircuit>(
396+
arity: usize,
397+
num_public_inputs: usize,
398+
inner_params: &I::Params,
399+
) -> Result<CommonCircuitData<F, D>> {
400+
let config = CircuitConfig::standard_recursion_config();
401+
402+
let mut builder = CircuitBuilder::<F, D>::new(config.clone());
403+
// Add our standard set of gates
404+
let standard_gates = standard_gates(&config);
405+
for gate in standard_gates.into_iter() {
376406
builder.add_gate_to_gate_set(gate);
377407
}
378408

@@ -389,14 +419,6 @@ pub fn common_data_for_recursion<I: InnerCircuit>(
389419
builder.build::<C>()
390420
);
391421

392-
let estimate_verif_num_gates = |degree_bits: usize| {
393-
// Formula obtained via linear regression using `test_measure_recursion` results with
394-
// `standard_recursion_config`.
395-
let num_gates: usize = 236 * degree_bits + 698;
396-
// Add 8% for error because the results are not a clean line
397-
num_gates * 108 / 100
398-
};
399-
400422
// Loop until we find a circuit size that can verify `arity` proofs of itself
401423
let mut degree_bits = log2_ceil(inner_num_gates);
402424
loop {
@@ -799,6 +821,34 @@ mod tests {
799821
#[test]
800822
fn test_measure_recursion() {
801823
let config = CircuitConfig::standard_recursion_config();
824+
for i in 7..20 {
825+
let mut builder = CircuitBuilder::new(config.clone());
826+
let standard_gates = standard_gates(&config);
827+
for gate in standard_gates.into_iter() {
828+
builder.add_gate_to_gate_set(gate);
829+
}
830+
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
831+
builder.add_gate(NoopGate, vec![]);
832+
}
833+
println!("build degree 2^{} ...", i);
834+
let circuit_data = builder.build::<C>();
835+
assert_eq!(i, circuit_data.common.degree_bits());
836+
837+
let mut builder = CircuitBuilder::new(config.clone());
838+
let measure = measure_gates_begin!(&builder, format!("verifier for 2^{}", i));
839+
let verifier_data_i =
840+
builder.add_virtual_verifier_data(builder.config.fri_config.cap_height);
841+
let proof = builder.add_virtual_proof_with_pis(&circuit_data.common);
842+
builder.verify_proof::<C>(&proof, &verifier_data_i, &circuit_data.common);
843+
measure_gates_end!(&builder, measure);
844+
}
845+
measure_gates_print!();
846+
}
847+
848+
#[ignore]
849+
#[test]
850+
fn test_measure_zk() {
851+
let config = CircuitConfig::standard_recursion_zk_config();
802852
for i in 7..18 {
803853
let mut builder = CircuitBuilder::new(config.clone());
804854
builder.add_gate_to_gate_set(plonky2::gates::gate::GateRef::new(
@@ -807,12 +857,38 @@ mod tests {
807857
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
808858
builder.add_gate(NoopGate, vec![]);
809859
}
860+
let circuit_data = builder.build::<C>();
861+
println!(
862+
"2^{} gates require 2^{} rows",
863+
i,
864+
circuit_data.common.degree_bits()
865+
);
866+
}
867+
}
868+
869+
#[ignore]
870+
#[test]
871+
fn test_measure_zk_recursion() {
872+
let config = CircuitConfig::standard_recursion_zk_config();
873+
for i in 12..18 {
874+
let mut builder = CircuitBuilder::new(config.clone());
875+
let standard_gates = standard_gates(&config);
876+
for gate in standard_gates.into_iter() {
877+
builder.add_gate_to_gate_set(gate);
878+
}
879+
while builder.num_gates() < (1 << i) - MAX_CONSTANT_GATES {
880+
builder.add_gate(NoopGate, vec![]);
881+
}
882+
let expected_degree_bits = log2_ceil(estimate_gates_after_zk(i));
810883
println!("build degree 2^{} ...", i);
811884
let circuit_data = builder.build::<C>();
812-
assert_eq!(circuit_data.common.degree_bits(), i);
885+
assert_eq!(expected_degree_bits, circuit_data.common.degree_bits());
813886

814887
let mut builder = CircuitBuilder::new(config.clone());
815-
let measure = measure_gates_begin!(&builder, format!("verifier for 2^{}", i));
888+
let measure = measure_gates_begin!(
889+
&builder,
890+
format!("verifier for zk 2^{}", expected_degree_bits)
891+
);
816892
let verifier_data_i =
817893
builder.add_virtual_verifier_data(builder.config.fri_config.cap_height);
818894
let proof = builder.add_virtual_proof_with_pis(&circuit_data.common);

0 commit comments

Comments
 (0)