@@ -12,7 +12,7 @@ use itertools::Itertools;
1212use 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
5151impl 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