@@ -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 ,
@@ -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