From fb3f5e7db8bfc4a619fde1f62c511998cac8a731 Mon Sep 17 00:00:00 2001 From: Daniel Lubarov Date: Tue, 2 Nov 2021 14:43:07 -0700 Subject: [PATCH] Shrink further with another couple layers of recursion (#335) * More wires for ConstantGate * fix * fix * Optimize recursive Poseidon constraint evaluation - Avoid `ArithmeticGate`s with unique constants; use `ConstantGate` wires instead - Avoid an unnecessary squaring in exponentiations Brings Poseidon evaluation down to a reasonable 273 gates when `num_routed_wires = 48`. * Shrink further with another couple layers of recursion To keep it reasonably fast, we shrink to degree 2^12 before we start using a really high rate. Each layer is reasonably quick this way; overall time is ~20s for me. Final proof is now 52-54kb. It can go down to ~51kb if we add one more layer with `num_routed_wires: 28` (vs 32), but I feel like I may be overcomplicating this already... --- src/plonk/recursive_verifier.rs | 96 ++++++++++++++++++++++++++++----- 1 file changed, 84 insertions(+), 12 deletions(-) diff --git a/src/plonk/recursive_verifier.rs b/src/plonk/recursive_verifier.rs index d4200860..ad049275 100644 --- a/src/plonk/recursive_verifier.rs +++ b/src/plonk/recursive_verifier.rs @@ -402,29 +402,96 @@ mod tests { type F = GoldilocksField; const D: usize = 2; - let normal_config = CircuitConfig::standard_recursion_config(); - let final_config = CircuitConfig { + let standard_config = CircuitConfig::standard_recursion_config(); + + // A dummy proof with degree 2^13. + let (proof, vd, cd) = dummy_proof::(&standard_config, 8_000)?; + assert_eq!(cd.degree_bits, 13); + + // A standard recursive proof with degree 2^13. + let (proof, vd, cd) = recursive_proof( + proof, + vd, + cd, + &standard_config, + &standard_config, + false, + false, + )?; + assert_eq!(cd.degree_bits, 13); + + // A high-rate recursive proof with degree 2^13, designed to be verifiable with 2^12 + // gates and 48 routed wires. + let high_rate_config = CircuitConfig { + rate_bits: 5, + fri_config: FriConfig { + proof_of_work_bits: 20, + num_query_rounds: 16, + ..standard_config.fri_config.clone() + }, + ..standard_config + }; + let (proof, vd, cd) = recursive_proof( + proof, + vd, + cd, + &standard_config, + &high_rate_config, + true, + true, + )?; + assert_eq!(cd.degree_bits, 13); + + // A higher-rate recursive proof with degree 2^12, designed to be verifiable with 2^12 + // gates and 28 routed wires. + let higher_rate_more_routing_config = CircuitConfig { rate_bits: 7, - cap_height: 0, + num_routed_wires: 48, fri_config: FriConfig { proof_of_work_bits: 23, - reduction_strategy: FriReductionStrategy::MinSize(None), num_query_rounds: 11, + ..standard_config.fri_config.clone() }, - ..normal_config + ..high_rate_config.clone() }; + let (proof, vd, cd) = recursive_proof( + proof, + vd, + cd, + &high_rate_config, + &higher_rate_more_routing_config, + true, + true, + )?; + assert_eq!(cd.degree_bits, 12); - let (proof, vd, cd) = dummy_proof::(&normal_config, 8_000)?; - let (proof, vd, cd) = - recursive_proof(proof, vd, cd, &normal_config, &normal_config, false, false)?; - let (proof, _vd, cd) = - recursive_proof(proof, vd, cd, &normal_config, &final_config, true, true)?; + // A final proof of degree 2^12, optimized for size. + let final_config = CircuitConfig { + cap_height: 0, + num_routed_wires: 32, + fri_config: FriConfig { + reduction_strategy: FriReductionStrategy::MinSize(None), + ..higher_rate_more_routing_config.fri_config.clone() + }, + ..higher_rate_more_routing_config + }; + let (proof, _vd, cd) = recursive_proof( + proof, + vd, + cd, + &higher_rate_more_routing_config, + &final_config, + true, + true, + )?; + assert_eq!(cd.degree_bits, 12); test_serialization(&proof, &cd)?; Ok(()) } + /// Creates a dummy proof which should have roughly `num_dummy_gates` gates. fn dummy_proof, const D: usize>( config: &CircuitConfig, num_dummy_gates: u64, @@ -434,12 +501,17 @@ mod tests { CommonCircuitData, )> { let mut builder = CircuitBuilder::::new(config.clone()); + let input = builder.add_virtual_target(); for i in 0..num_dummy_gates { - builder.constant(F::from_canonical_u64(i)); + // Use unique constants to force a new `ArithmeticGate`. + let i_f = F::from_canonical_u64(i); + builder.arithmetic(i_f, i_f, input, input, input); } let data = builder.build(); - let proof = data.prove(PartialWitness::new())?; + let mut inputs = PartialWitness::new(); + inputs.set_target(input, F::ZERO); + let proof = data.prove(inputs)?; data.verify(proof.clone())?; Ok((proof, data.verifier_only, data.common))