|  |  | @ -0,0 +1,558 @@ | 
			
		
	
		
			
				
					|  |  |  | /*
 | 
			
		
	
		
			
				
					|  |  |  |  Tree recursion with conditionals.
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             p_7
 | 
			
		
	
		
			
				
					|  |  |  |             ▲
 | 
			
		
	
		
			
				
					|  |  |  |             │
 | 
			
		
	
		
			
				
					|  |  |  |           ┌─┴─┐
 | 
			
		
	
		
			
				
					|  |  |  |           │ F │
 | 
			
		
	
		
			
				
					|  |  |  |           └───┘
 | 
			
		
	
		
			
				
					|  |  |  |            ▲ ▲
 | 
			
		
	
		
			
				
					|  |  |  |          ┌─┘ └─┐
 | 
			
		
	
		
			
				
					|  |  |  |      ┌───┘     └───┐
 | 
			
		
	
		
			
				
					|  |  |  |      │p_5          │p_6
 | 
			
		
	
		
			
				
					|  |  |  |    ┌─┴─┐         ┌─┴─┐
 | 
			
		
	
		
			
				
					|  |  |  |    │ F │         │ F │
 | 
			
		
	
		
			
				
					|  |  |  |    └───┘         └───┘
 | 
			
		
	
		
			
				
					|  |  |  |     ▲ ▲           ▲ ▲
 | 
			
		
	
		
			
				
					|  |  |  |   ┌─┘ └─┐       ┌─┘ └─┐
 | 
			
		
	
		
			
				
					|  |  |  |   │     │       │     │
 | 
			
		
	
		
			
				
					|  |  |  |  p_1   p_2     p_3   p_4
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  where each p_i is either
 | 
			
		
	
		
			
				
					|  |  |  |     - signature verification
 | 
			
		
	
		
			
				
					|  |  |  |     - recursive plonky2 proof (proof that verifies previous proof)
 | 
			
		
	
		
			
				
					|  |  |  |             (generated by `RecursiveCircuit::prove_step` method)
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  and F verifies the two incoming p_i's, that is
 | 
			
		
	
		
			
				
					|  |  |  |     - (signature proof OR recursive proof) AND (signature proof OR recursive proof)
 | 
			
		
	
		
			
				
					|  |  |  |  and produces a new proof.
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |  To run the tests that checks this logic: | 
			
		
	
		
			
				
					|  |  |  |  cargo test --release test_tree_recursion -- --nocapture
 | 
			
		
	
		
			
				
					|  |  |  | */
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | use anyhow::Result;
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::field::types::Field;
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::gates::noop::NoopGate;
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::iop::target::{BoolTarget, Target};
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::iop::witness::{PartialWitness, WitnessWrite};
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::plonk::circuit_builder::CircuitBuilder;
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::plonk::circuit_data::{
 | 
			
		
	
		
			
				
					|  |  |  |     CircuitConfig, CircuitData, VerifierCircuitData, VerifierCircuitTarget,
 | 
			
		
	
		
			
				
					|  |  |  | };
 | 
			
		
	
		
			
				
					|  |  |  | use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget};
 | 
			
		
	
		
			
				
					|  |  |  | use std::time::Instant;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | use sch::schnorr::*;
 | 
			
		
	
		
			
				
					|  |  |  | use sch::schnorr_prover::*;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | use super::{PlonkyProof, C, F};
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /// if s==0: returns x
 | 
			
		
	
		
			
				
					|  |  |  | /// if s==1: returns y
 | 
			
		
	
		
			
				
					|  |  |  | /// Warning: this method assumes all input values are ensured to be \in {0,1}
 | 
			
		
	
		
			
				
					|  |  |  | fn selector_gate(builder: &mut CircuitBuilder<F, 2>, x: Target, y: Target, s: Target) -> Target {
 | 
			
		
	
		
			
				
					|  |  |  |     // z = x + s(y-x)
 | 
			
		
	
		
			
				
					|  |  |  |     let y_x = builder.sub(y, x);
 | 
			
		
	
		
			
				
					|  |  |  |     // z = x+s(y-x) <==> mul_add(s, yx, x)=s*(y-x)+x
 | 
			
		
	
		
			
				
					|  |  |  |     builder.mul_add(s, y_x, x)
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /// ensures b \in {0,1}
 | 
			
		
	
		
			
				
					|  |  |  | fn binary_check(builder: &mut CircuitBuilder<F, 2>, b: Target) {
 | 
			
		
	
		
			
				
					|  |  |  |     let zero = builder.zero();
 | 
			
		
	
		
			
				
					|  |  |  |     let one = builder.one();
 | 
			
		
	
		
			
				
					|  |  |  |     // b * (b-1) == 0
 | 
			
		
	
		
			
				
					|  |  |  |     let b_1 = builder.sub(b, one);
 | 
			
		
	
		
			
				
					|  |  |  |     let r = builder.mul(b, b_1);
 | 
			
		
	
		
			
				
					|  |  |  |     builder.connect(r, zero);
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /// Contains the methods to `build` (ie. create the targets, the logic of the circuit), and
 | 
			
		
	
		
			
				
					|  |  |  | /// `fill_targets` (ie. set the specific values to be used for the previously created targets).
 | 
			
		
	
		
			
				
					|  |  |  | ///
 | 
			
		
	
		
			
				
					|  |  |  | /// The logic of this gadget verifies the given signature if `selector==0`.
 | 
			
		
	
		
			
				
					|  |  |  | /// We reuse this gadget for both the signature verifications of the left & right signatures in the
 | 
			
		
	
		
			
				
					|  |  |  | /// node of the recursion tree.
 | 
			
		
	
		
			
				
					|  |  |  | pub struct SignatureGadgetTargets {
 | 
			
		
	
		
			
				
					|  |  |  |     selector_targ: Target,
 | 
			
		
	
		
			
				
					|  |  |  |     selector_booltarg: BoolTarget,
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pk_targ: SchnorrPublicKeyTarget,
 | 
			
		
	
		
			
				
					|  |  |  |     sig_targ: SchnorrSignatureTarget,
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | impl SignatureGadgetTargets {
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn build(
 | 
			
		
	
		
			
				
					|  |  |  |         mut builder: &mut CircuitBuilder<F, 2>,
 | 
			
		
	
		
			
				
					|  |  |  |         msg_targ: &MessageTarget,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Result<SignatureGadgetTargets> {
 | 
			
		
	
		
			
				
					|  |  |  |         let selector_targ = builder.add_virtual_target();
 | 
			
		
	
		
			
				
					|  |  |  |         // ensure that selector_booltarg is \in {0,1}
 | 
			
		
	
		
			
				
					|  |  |  |         binary_check(builder, selector_targ);
 | 
			
		
	
		
			
				
					|  |  |  |         let selector_booltarg = BoolTarget::new_unsafe(selector_targ);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // signature verification:
 | 
			
		
	
		
			
				
					|  |  |  |         let sb: SchnorrBuilder = SchnorrBuilder {};
 | 
			
		
	
		
			
				
					|  |  |  |         let pk_targ = SchnorrPublicKeyTarget::new_virtual(&mut builder);
 | 
			
		
	
		
			
				
					|  |  |  |         let sig_targ = SchnorrSignatureTarget::new_virtual(&mut builder);
 | 
			
		
	
		
			
				
					|  |  |  |         let sig_verif_targ = sb.verify_sig::<C>(&mut builder, &sig_targ, &msg_targ, &pk_targ);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         /*
 | 
			
		
	
		
			
				
					|  |  |  |         - if selector=0
 | 
			
		
	
		
			
				
					|  |  |  |             verify_sig==1 && proof_enabled=0
 | 
			
		
	
		
			
				
					|  |  |  |         - if selector=1
 | 
			
		
	
		
			
				
					|  |  |  |             verify_sig==NaN && proof_enabled=1   (don't check the sig)
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             to disable the verify_sig check, when selector=1: | 
			
		
	
		
			
				
					|  |  |  |                 x=verify_sig, y=always_1, s=selector   (all values \in {0,1})
 | 
			
		
	
		
			
				
					|  |  |  |                 z = x + s(y-x)
 | 
			
		
	
		
			
				
					|  |  |  |         */
 | 
			
		
	
		
			
				
					|  |  |  |         // if selector=0: check that sig_verif==1
 | 
			
		
	
		
			
				
					|  |  |  |         // if selector=1: check that one==1
 | 
			
		
	
		
			
				
					|  |  |  |         let one = builder.one();
 | 
			
		
	
		
			
				
					|  |  |  |         let expected = selector_gate(
 | 
			
		
	
		
			
				
					|  |  |  |             builder,
 | 
			
		
	
		
			
				
					|  |  |  |             sig_verif_targ.target,
 | 
			
		
	
		
			
				
					|  |  |  |             one,
 | 
			
		
	
		
			
				
					|  |  |  |             selector_booltarg.target,
 | 
			
		
	
		
			
				
					|  |  |  |         );
 | 
			
		
	
		
			
				
					|  |  |  |         let one_2 = builder.one();
 | 
			
		
	
		
			
				
					|  |  |  |         builder.connect(expected, one_2);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(Self {
 | 
			
		
	
		
			
				
					|  |  |  |             selector_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             selector_booltarg,
 | 
			
		
	
		
			
				
					|  |  |  |             pk_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             sig_targ,
 | 
			
		
	
		
			
				
					|  |  |  |         })
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn fill_targets(
 | 
			
		
	
		
			
				
					|  |  |  |         &mut self,
 | 
			
		
	
		
			
				
					|  |  |  |         pw: &mut PartialWitness<F>,
 | 
			
		
	
		
			
				
					|  |  |  |         // left side
 | 
			
		
	
		
			
				
					|  |  |  |         selector: F, // 1=proof, 0=sig
 | 
			
		
	
		
			
				
					|  |  |  |         pk: &SchnorrPublicKey,
 | 
			
		
	
		
			
				
					|  |  |  |         sig: &SchnorrSignature,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Result<()> {
 | 
			
		
	
		
			
				
					|  |  |  |         pw.set_target(self.selector_targ, selector)?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // set signature related values:
 | 
			
		
	
		
			
				
					|  |  |  |         self.pk_targ.set_witness(pw, &pk).unwrap();
 | 
			
		
	
		
			
				
					|  |  |  |         self.sig_targ.set_witness(pw, &sig).unwrap();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(())
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | /// Contains the methods to `build` (ie. create the targets, the logic of the circuit), and
 | 
			
		
	
		
			
				
					|  |  |  | /// `fill_targets` (ie. set the specific values to be used for the previously created targets).
 | 
			
		
	
		
			
				
					|  |  |  | pub struct RecursiveCircuit {
 | 
			
		
	
		
			
				
					|  |  |  |     msg_targ: MessageTarget,
 | 
			
		
	
		
			
				
					|  |  |  |     L_sig_targets: SignatureGadgetTargets,
 | 
			
		
	
		
			
				
					|  |  |  |     R_sig_targets: SignatureGadgetTargets,
 | 
			
		
	
		
			
				
					|  |  |  |     // L_sig_verif_targ: BoolTarget,
 | 
			
		
	
		
			
				
					|  |  |  |     L_proof_targ: ProofWithPublicInputsTarget<2>,
 | 
			
		
	
		
			
				
					|  |  |  |     R_proof_targ: ProofWithPublicInputsTarget<2>,
 | 
			
		
	
		
			
				
					|  |  |  |     // the next two are common for both L&R proofs. It is the data for this circuit itself (cyclic circuit).
 | 
			
		
	
		
			
				
					|  |  |  |     verifier_data_targ: VerifierCircuitTarget,
 | 
			
		
	
		
			
				
					|  |  |  |     verifier_data: VerifierCircuitData<F, C, 2>,
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | impl RecursiveCircuit {
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn prepare_public_inputs(
 | 
			
		
	
		
			
				
					|  |  |  |         verifier_data: VerifierCircuitData<F, C, 2>,
 | 
			
		
	
		
			
				
					|  |  |  |         msg: Vec<F>,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Vec<F> {
 | 
			
		
	
		
			
				
					|  |  |  |         [
 | 
			
		
	
		
			
				
					|  |  |  |             msg.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |             // add verifier_data as public inputs:
 | 
			
		
	
		
			
				
					|  |  |  |             verifier_data.verifier_only.circuit_digest.elements.to_vec(),
 | 
			
		
	
		
			
				
					|  |  |  |             verifier_data
 | 
			
		
	
		
			
				
					|  |  |  |                 .verifier_only
 | 
			
		
	
		
			
				
					|  |  |  |                 .constants_sigmas_cap
 | 
			
		
	
		
			
				
					|  |  |  |                 .0
 | 
			
		
	
		
			
				
					|  |  |  |                 .iter()
 | 
			
		
	
		
			
				
					|  |  |  |                 .flat_map(|e| e.elements)
 | 
			
		
	
		
			
				
					|  |  |  |                 .collect(),
 | 
			
		
	
		
			
				
					|  |  |  |         ]
 | 
			
		
	
		
			
				
					|  |  |  |         .concat()
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  |     // notice that this method does not fill the targets, which is done in the method
 | 
			
		
	
		
			
				
					|  |  |  |     // `fill_recursive_circuit_targets`
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn build(
 | 
			
		
	
		
			
				
					|  |  |  |         builder: &mut CircuitBuilder<F, 2>,
 | 
			
		
	
		
			
				
					|  |  |  |         verifier_data: VerifierCircuitData<F, C, 2>,
 | 
			
		
	
		
			
				
					|  |  |  |         msg_len: usize,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Result<Self> {
 | 
			
		
	
		
			
				
					|  |  |  |         let msg_targ = MessageTarget::new_with_size(builder, msg_len);
 | 
			
		
	
		
			
				
					|  |  |  |         // set msg as public input
 | 
			
		
	
		
			
				
					|  |  |  |         builder.register_public_inputs(&msg_targ.msg);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // build the signature verification logic
 | 
			
		
	
		
			
				
					|  |  |  |         let L_sig_targets = SignatureGadgetTargets::build(builder, &msg_targ)?;
 | 
			
		
	
		
			
				
					|  |  |  |         let R_sig_targets = SignatureGadgetTargets::build(builder, &msg_targ)?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // proof verification:
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let common_data = verifier_data.common.clone();
 | 
			
		
	
		
			
				
					|  |  |  |         let verifier_data_targ = builder.add_verifier_data_public_inputs();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let L_proof_targ = builder.add_virtual_proof_with_pis(&common_data);
 | 
			
		
	
		
			
				
					|  |  |  |         builder.conditionally_verify_cyclic_proof_or_dummy::<C>(
 | 
			
		
	
		
			
				
					|  |  |  |             L_sig_targets.selector_booltarg,
 | 
			
		
	
		
			
				
					|  |  |  |             &L_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             &common_data,
 | 
			
		
	
		
			
				
					|  |  |  |         )?;
 | 
			
		
	
		
			
				
					|  |  |  |         let R_proof_targ = builder.add_virtual_proof_with_pis(&common_data);
 | 
			
		
	
		
			
				
					|  |  |  |         builder.conditionally_verify_cyclic_proof_or_dummy::<C>(
 | 
			
		
	
		
			
				
					|  |  |  |             R_sig_targets.selector_booltarg,
 | 
			
		
	
		
			
				
					|  |  |  |             &R_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             &common_data,
 | 
			
		
	
		
			
				
					|  |  |  |         )?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(Self {
 | 
			
		
	
		
			
				
					|  |  |  |             msg_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             L_sig_targets,
 | 
			
		
	
		
			
				
					|  |  |  |             R_sig_targets,
 | 
			
		
	
		
			
				
					|  |  |  |             L_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             R_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             verifier_data_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             verifier_data,
 | 
			
		
	
		
			
				
					|  |  |  |         })
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn fill_targets(
 | 
			
		
	
		
			
				
					|  |  |  |         &mut self,
 | 
			
		
	
		
			
				
					|  |  |  |         pw: &mut PartialWitness<F>,
 | 
			
		
	
		
			
				
					|  |  |  |         msg: &Vec<F>,
 | 
			
		
	
		
			
				
					|  |  |  |         // left side
 | 
			
		
	
		
			
				
					|  |  |  |         L_selector: F, // 1=proof, 0=sig
 | 
			
		
	
		
			
				
					|  |  |  |         L_pk: &SchnorrPublicKey,
 | 
			
		
	
		
			
				
					|  |  |  |         L_sig: &SchnorrSignature,
 | 
			
		
	
		
			
				
					|  |  |  |         L_recursive_proof: &PlonkyProof,
 | 
			
		
	
		
			
				
					|  |  |  |         // right side
 | 
			
		
	
		
			
				
					|  |  |  |         R_selector: F, // 1=proof, 0=sig
 | 
			
		
	
		
			
				
					|  |  |  |         R_pk: &SchnorrPublicKey,
 | 
			
		
	
		
			
				
					|  |  |  |         R_sig: &SchnorrSignature,
 | 
			
		
	
		
			
				
					|  |  |  |         R_recursive_proof: &PlonkyProof,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Result<()> {
 | 
			
		
	
		
			
				
					|  |  |  |         // set the msg value (used by both sig gadgets, left and right)
 | 
			
		
	
		
			
				
					|  |  |  |         self.msg_targ.set_witness(pw, &msg).unwrap();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // set the signature related values
 | 
			
		
	
		
			
				
					|  |  |  |         self.L_sig_targets
 | 
			
		
	
		
			
				
					|  |  |  |             .fill_targets(pw, L_selector, L_pk, L_sig)?;
 | 
			
		
	
		
			
				
					|  |  |  |         self.R_sig_targets
 | 
			
		
	
		
			
				
					|  |  |  |             .fill_targets(pw, R_selector, R_pk, R_sig)?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // set proof related values:
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // recursive proofs verification
 | 
			
		
	
		
			
				
					|  |  |  |         pw.set_verifier_data_target(&self.verifier_data_targ, &self.verifier_data.verifier_only)?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let public_inputs =
 | 
			
		
	
		
			
				
					|  |  |  |             RecursiveCircuit::prepare_public_inputs(self.verifier_data.clone(), msg.clone());
 | 
			
		
	
		
			
				
					|  |  |  |         // left proof verification values
 | 
			
		
	
		
			
				
					|  |  |  |         pw.set_proof_with_pis_target(
 | 
			
		
	
		
			
				
					|  |  |  |             &self.L_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             &ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |                 proof: L_recursive_proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |                 public_inputs: public_inputs.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |             },
 | 
			
		
	
		
			
				
					|  |  |  |         )?;
 | 
			
		
	
		
			
				
					|  |  |  |         // right proof verification values
 | 
			
		
	
		
			
				
					|  |  |  |         pw.set_proof_with_pis_target(
 | 
			
		
	
		
			
				
					|  |  |  |             &self.R_proof_targ,
 | 
			
		
	
		
			
				
					|  |  |  |             &ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |                 proof: R_recursive_proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |                 public_inputs,
 | 
			
		
	
		
			
				
					|  |  |  |             },
 | 
			
		
	
		
			
				
					|  |  |  |         )?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(())
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | #[derive(Debug, Clone)]
 | 
			
		
	
		
			
				
					|  |  |  | pub struct Recursion {}
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | pub fn common_data_for_recursion(msg_len: usize) -> CircuitData<F, C, 2> {
 | 
			
		
	
		
			
				
					|  |  |  |     // 1st
 | 
			
		
	
		
			
				
					|  |  |  |     let config = CircuitConfig::standard_recursion_config();
 | 
			
		
	
		
			
				
					|  |  |  |     let builder = CircuitBuilder::<F, 2>::new(config);
 | 
			
		
	
		
			
				
					|  |  |  |     let data = builder.build::<C>();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // 2nd
 | 
			
		
	
		
			
				
					|  |  |  |     let config = CircuitConfig::standard_recursion_config();
 | 
			
		
	
		
			
				
					|  |  |  |     let mut builder = CircuitBuilder::<F, 2>::new(config.clone());
 | 
			
		
	
		
			
				
					|  |  |  |     let verifier_data = builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height);
 | 
			
		
	
		
			
				
					|  |  |  |     // left proof
 | 
			
		
	
		
			
				
					|  |  |  |     let proof = builder.add_virtual_proof_with_pis(&data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     builder.verify_proof::<C>(&proof, &verifier_data, &data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     // right proof
 | 
			
		
	
		
			
				
					|  |  |  |     let proof = builder.add_virtual_proof_with_pis(&data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     builder.verify_proof::<C>(&proof, &verifier_data, &data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     let data = builder.build::<C>();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // 3rd
 | 
			
		
	
		
			
				
					|  |  |  |     let config = CircuitConfig::standard_recursion_config();
 | 
			
		
	
		
			
				
					|  |  |  |     let mut builder = CircuitBuilder::<F, 2>::new(config.clone());
 | 
			
		
	
		
			
				
					|  |  |  |     let msg_targ = MessageTarget::new_with_size(&mut builder, msg_len);
 | 
			
		
	
		
			
				
					|  |  |  |     // sigs verify
 | 
			
		
	
		
			
				
					|  |  |  |     builder.register_public_inputs(&msg_targ.msg);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     builder.add_gate(
 | 
			
		
	
		
			
				
					|  |  |  |         // add a ConstantGate, because without this, when later generating the `dummy_circuit`
 | 
			
		
	
		
			
				
					|  |  |  |         // (inside the `conditionally_verify_cyclic_proof_or_dummy`), it fails due the
 | 
			
		
	
		
			
				
					|  |  |  |         // `CommonCircuitData` of the generated circuit not matching the given `CommonCircuitData`
 | 
			
		
	
		
			
				
					|  |  |  |         // to create it. Without this it fails because it misses a ConstantGate.
 | 
			
		
	
		
			
				
					|  |  |  |         plonky2::gates::constant::ConstantGate::new(config.num_constants),
 | 
			
		
	
		
			
				
					|  |  |  |         vec![],
 | 
			
		
	
		
			
				
					|  |  |  |     );
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     let _ = SignatureGadgetTargets::build(&mut builder, &msg_targ).unwrap();
 | 
			
		
	
		
			
				
					|  |  |  |     let _ = SignatureGadgetTargets::build(&mut builder, &msg_targ).unwrap();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // proofs verify
 | 
			
		
	
		
			
				
					|  |  |  |     let verifier_data = builder.add_verifier_data_public_inputs();
 | 
			
		
	
		
			
				
					|  |  |  |     // left proof
 | 
			
		
	
		
			
				
					|  |  |  |     let proof_L = builder.add_virtual_proof_with_pis(&data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     builder.verify_proof::<C>(&proof_L, &verifier_data, &data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     // right proof
 | 
			
		
	
		
			
				
					|  |  |  |     let proof_R = builder.add_virtual_proof_with_pis(&data.common);
 | 
			
		
	
		
			
				
					|  |  |  |     builder.verify_proof::<C>(&proof_R, &verifier_data, &data.common);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // pad min gates
 | 
			
		
	
		
			
				
					|  |  |  |     while builder.num_gates() < 1 << 13 {
 | 
			
		
	
		
			
				
					|  |  |  |         builder.add_gate(NoopGate, vec![]);
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  |     builder.build::<C>()
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | impl Recursion {
 | 
			
		
	
		
			
				
					|  |  |  |     /// returns the full-recursive CircuitData
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn circuit_data(msg_len: usize) -> Result<CircuitData<F, C, 2>> {
 | 
			
		
	
		
			
				
					|  |  |  |         let mut data = common_data_for_recursion(msg_len);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // build the actual RecursiveCircuit circuit data
 | 
			
		
	
		
			
				
					|  |  |  |         let config = CircuitConfig::standard_recursion_config();
 | 
			
		
	
		
			
				
					|  |  |  |         let mut builder = CircuitBuilder::new(config);
 | 
			
		
	
		
			
				
					|  |  |  |         let _ = RecursiveCircuit::build(&mut builder, data.verifier_data(), msg_len)?;
 | 
			
		
	
		
			
				
					|  |  |  |         data = builder.build::<C>();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(data)
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     pub fn prove_step(
 | 
			
		
	
		
			
				
					|  |  |  |         verifier_data: VerifierCircuitData<F, C, 2>,
 | 
			
		
	
		
			
				
					|  |  |  |         msg: &Vec<F>,
 | 
			
		
	
		
			
				
					|  |  |  |         // left side
 | 
			
		
	
		
			
				
					|  |  |  |         L_selector: F, // 1=proof, 0=sig
 | 
			
		
	
		
			
				
					|  |  |  |         pk_L: &SchnorrPublicKey,
 | 
			
		
	
		
			
				
					|  |  |  |         sig_L: &SchnorrSignature,
 | 
			
		
	
		
			
				
					|  |  |  |         recursive_proof_L: &PlonkyProof,
 | 
			
		
	
		
			
				
					|  |  |  |         // right side
 | 
			
		
	
		
			
				
					|  |  |  |         R_selector: F, // 1=proof, 0=sig
 | 
			
		
	
		
			
				
					|  |  |  |         pk_R: &SchnorrPublicKey,
 | 
			
		
	
		
			
				
					|  |  |  |         sig_R: &SchnorrSignature,
 | 
			
		
	
		
			
				
					|  |  |  |         recursive_proof_R: &PlonkyProof,
 | 
			
		
	
		
			
				
					|  |  |  |     ) -> Result<PlonkyProof> {
 | 
			
		
	
		
			
				
					|  |  |  |         println!("prove_step:");
 | 
			
		
	
		
			
				
					|  |  |  |         if L_selector.is_nonzero() {
 | 
			
		
	
		
			
				
					|  |  |  |             println!("  (L_selector==1), verify left proof");
 | 
			
		
	
		
			
				
					|  |  |  |         } else {
 | 
			
		
	
		
			
				
					|  |  |  |             println!("  (L_selector==0), verify left signature");
 | 
			
		
	
		
			
				
					|  |  |  |         }
 | 
			
		
	
		
			
				
					|  |  |  |         if R_selector.is_nonzero() {
 | 
			
		
	
		
			
				
					|  |  |  |             println!("  (R_selector==1), verify right proof");
 | 
			
		
	
		
			
				
					|  |  |  |         } else {
 | 
			
		
	
		
			
				
					|  |  |  |             println!("  (R_selector==0), verify right signature");
 | 
			
		
	
		
			
				
					|  |  |  |         }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let config = CircuitConfig::standard_recursion_config();
 | 
			
		
	
		
			
				
					|  |  |  |         let mut builder = CircuitBuilder::new(config);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // assign the targets
 | 
			
		
	
		
			
				
					|  |  |  |         let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |         let mut circuit = RecursiveCircuit::build(&mut builder, verifier_data.clone(), msg.len())?;
 | 
			
		
	
		
			
				
					|  |  |  |         println!("RecursiveCircuit::build(): {:?}", start.elapsed());
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // fill the targets
 | 
			
		
	
		
			
				
					|  |  |  |         let mut pw = PartialWitness::new();
 | 
			
		
	
		
			
				
					|  |  |  |         let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |         circuit.fill_targets(
 | 
			
		
	
		
			
				
					|  |  |  |             &mut pw,
 | 
			
		
	
		
			
				
					|  |  |  |             msg,
 | 
			
		
	
		
			
				
					|  |  |  |             L_selector,
 | 
			
		
	
		
			
				
					|  |  |  |             pk_L,
 | 
			
		
	
		
			
				
					|  |  |  |             sig_L,
 | 
			
		
	
		
			
				
					|  |  |  |             recursive_proof_L,
 | 
			
		
	
		
			
				
					|  |  |  |             R_selector,
 | 
			
		
	
		
			
				
					|  |  |  |             pk_R,
 | 
			
		
	
		
			
				
					|  |  |  |             sig_R,
 | 
			
		
	
		
			
				
					|  |  |  |             recursive_proof_R,
 | 
			
		
	
		
			
				
					|  |  |  |         )?;
 | 
			
		
	
		
			
				
					|  |  |  |         println!("circuit.fill_targets(): {:?}", start.elapsed());
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |         let data = builder.build::<C>();
 | 
			
		
	
		
			
				
					|  |  |  |         println!("builder.build(): {:?}", start.elapsed());
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |         let new_proof = data.prove(pw)?;
 | 
			
		
	
		
			
				
					|  |  |  |         println!("generate new_proof: {:?}", start.elapsed());
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |         data.verify(new_proof.clone())?;
 | 
			
		
	
		
			
				
					|  |  |  |         println!("verify new_proof: {:?}", start.elapsed());
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         #[cfg(test)]
 | 
			
		
	
		
			
				
					|  |  |  |         data.verifier_data().verify(ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |             proof: new_proof.proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |             public_inputs: new_proof.public_inputs.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |         })?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         #[cfg(test)]
 | 
			
		
	
		
			
				
					|  |  |  |         verifier_data.verify(ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |             proof: new_proof.proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |             public_inputs: new_proof.public_inputs.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |         })?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(new_proof.proof)
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  | #[cfg(test)]
 | 
			
		
	
		
			
				
					|  |  |  | mod tests {
 | 
			
		
	
		
			
				
					|  |  |  |     use anyhow::Result;
 | 
			
		
	
		
			
				
					|  |  |  |     use hashbrown::HashMap;
 | 
			
		
	
		
			
				
					|  |  |  |     use plonky2::field::types::Field;
 | 
			
		
	
		
			
				
					|  |  |  |     use plonky2::plonk::proof::ProofWithPublicInputs;
 | 
			
		
	
		
			
				
					|  |  |  |     use plonky2::recursion::dummy_circuit::cyclic_base_proof;
 | 
			
		
	
		
			
				
					|  |  |  |     use rand;
 | 
			
		
	
		
			
				
					|  |  |  |     use std::time::Instant;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     use super::*;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     // this sets the plonky2 internal logs level
 | 
			
		
	
		
			
				
					|  |  |  |     fn set_log() {
 | 
			
		
	
		
			
				
					|  |  |  |         let _ = env_logger::builder()
 | 
			
		
	
		
			
				
					|  |  |  |             .filter_level(log::LevelFilter::Warn)
 | 
			
		
	
		
			
				
					|  |  |  |             .is_test(true)
 | 
			
		
	
		
			
				
					|  |  |  |             .try_init();
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |     /// to run:
 | 
			
		
	
		
			
				
					|  |  |  |     /// cargo test --release test_tree_recursion -- --nocapture
 | 
			
		
	
		
			
				
					|  |  |  |     #[test]
 | 
			
		
	
		
			
				
					|  |  |  |     fn test_tree_recursion() -> Result<()> {
 | 
			
		
	
		
			
				
					|  |  |  |         set_log();
 | 
			
		
	
		
			
				
					|  |  |  |         let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
 | 
			
		
	
		
			
				
					|  |  |  |         let schnorr = SchnorrSigner::new();
 | 
			
		
	
		
			
				
					|  |  |  |         const MSG_LEN: usize = 5;
 | 
			
		
	
		
			
				
					|  |  |  |         let msg: Vec<F> = schnorr.u64_into_goldilocks_vec(vec![1500, 1600, 2, 2, 2]);
 | 
			
		
	
		
			
				
					|  |  |  |         assert_eq!(msg.len(), MSG_LEN);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let l: u32 = 2; // levels of the recursion (binary) tree
 | 
			
		
	
		
			
				
					|  |  |  |         let k = 2_u32.pow(l); // number of leafs in the recursion tree
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // generate k key pairs
 | 
			
		
	
		
			
				
					|  |  |  |         let sk_vec: Vec<SchnorrSecretKey> =
 | 
			
		
	
		
			
				
					|  |  |  |             (0..k).map(|i| SchnorrSecretKey { sk: i as u64 }).collect();
 | 
			
		
	
		
			
				
					|  |  |  |         let pk_vec: Vec<SchnorrPublicKey> = sk_vec.iter().map(|&sk| schnorr.keygen(&sk)).collect();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         let sig_vec: Vec<SchnorrSignature> = sk_vec
 | 
			
		
	
		
			
				
					|  |  |  |             .iter()
 | 
			
		
	
		
			
				
					|  |  |  |             .map(|&sk| schnorr.sign(&msg, &sk, &mut rng))
 | 
			
		
	
		
			
				
					|  |  |  |             .collect();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // build the circuit_data & verifier_data for the recursive circuit
 | 
			
		
	
		
			
				
					|  |  |  |         let circuit_data = Recursion::circuit_data(MSG_LEN)?;
 | 
			
		
	
		
			
				
					|  |  |  |         let verifier_data = circuit_data.verifier_data();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // let dummy_circuit = dummy_circuit::<F, C, 2>(&circuit_data.common); // WIP
 | 
			
		
	
		
			
				
					|  |  |  |         // let dummy_proof_pis = dummy_proof(&dummy_circuit, HashMap::new())?; // WIP
 | 
			
		
	
		
			
				
					|  |  |  |         let dummy_proof_pis = cyclic_base_proof(
 | 
			
		
	
		
			
				
					|  |  |  |             &circuit_data.common,
 | 
			
		
	
		
			
				
					|  |  |  |             &verifier_data.verifier_only,
 | 
			
		
	
		
			
				
					|  |  |  |             HashMap::new(),
 | 
			
		
	
		
			
				
					|  |  |  |         );
 | 
			
		
	
		
			
				
					|  |  |  |         let dummy_proof = dummy_proof_pis.proof;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // we start with k dummy proofs, since at the leafs level we don't have proofs yet and we
 | 
			
		
	
		
			
				
					|  |  |  |         // just verify the signatures
 | 
			
		
	
		
			
				
					|  |  |  |         let mut proofs_at_level_i: Vec<PlonkyProof> =
 | 
			
		
	
		
			
				
					|  |  |  |             (0..k).into_iter().map(|_| dummy_proof.clone()).collect();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // loop over the recursion levels
 | 
			
		
	
		
			
				
					|  |  |  |         for i in 0..l {
 | 
			
		
	
		
			
				
					|  |  |  |             println!("\n=== recursion level i={}", i);
 | 
			
		
	
		
			
				
					|  |  |  |             let mut next_level_proofs: Vec<PlonkyProof> = vec![];
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |             // loop over the nodes of each recursion tree level
 | 
			
		
	
		
			
				
					|  |  |  |             for j in (0..proofs_at_level_i.len()).into_iter().step_by(2) {
 | 
			
		
	
		
			
				
					|  |  |  |                 println!("\n------ recursion node i={}, j={}", i, j);
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // - if we're at the first level of the recursion tree:
 | 
			
		
	
		
			
				
					|  |  |  |                 //      proof_enabled=false=0, so that the circuit verifies the signature and not the proof.
 | 
			
		
	
		
			
				
					|  |  |  |                 // - else:
 | 
			
		
	
		
			
				
					|  |  |  |                 //      proof_enabled=true=1, so that the circuit verifies the proof and not the signature.
 | 
			
		
	
		
			
				
					|  |  |  |                 //
 | 
			
		
	
		
			
				
					|  |  |  |                 //  In future tests we will try other cases (eg. left sig, right proof), but for
 | 
			
		
	
		
			
				
					|  |  |  |                 //  the moment we just do base_case: sig verify, other cases: proof verify.
 | 
			
		
	
		
			
				
					|  |  |  |                 let proof_enabled = if i == 0 { F::ZERO } else { F::ONE };
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // do the recursive step
 | 
			
		
	
		
			
				
					|  |  |  |                 let start = Instant::now();
 | 
			
		
	
		
			
				
					|  |  |  |                 let new_proof = Recursion::prove_step(
 | 
			
		
	
		
			
				
					|  |  |  |                     verifier_data.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |                     &msg,
 | 
			
		
	
		
			
				
					|  |  |  |                     // left side:
 | 
			
		
	
		
			
				
					|  |  |  |                     proof_enabled,
 | 
			
		
	
		
			
				
					|  |  |  |                     &pk_vec[j],
 | 
			
		
	
		
			
				
					|  |  |  |                     &sig_vec[j],
 | 
			
		
	
		
			
				
					|  |  |  |                     &proofs_at_level_i[j],
 | 
			
		
	
		
			
				
					|  |  |  |                     // right side
 | 
			
		
	
		
			
				
					|  |  |  |                     proof_enabled,
 | 
			
		
	
		
			
				
					|  |  |  |                     &pk_vec[j + 1],
 | 
			
		
	
		
			
				
					|  |  |  |                     &sig_vec[j + 1],
 | 
			
		
	
		
			
				
					|  |  |  |                     &proofs_at_level_i[j + 1],
 | 
			
		
	
		
			
				
					|  |  |  |                 )?;
 | 
			
		
	
		
			
				
					|  |  |  |                 println!(
 | 
			
		
	
		
			
				
					|  |  |  |                     "Recursion::prove_step (level: i={}, node: j={}) took: {:?}",
 | 
			
		
	
		
			
				
					|  |  |  |                     i,
 | 
			
		
	
		
			
				
					|  |  |  |                     j,
 | 
			
		
	
		
			
				
					|  |  |  |                     start.elapsed()
 | 
			
		
	
		
			
				
					|  |  |  |                 );
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // verify the recursive proof
 | 
			
		
	
		
			
				
					|  |  |  |                 let public_inputs =
 | 
			
		
	
		
			
				
					|  |  |  |                     RecursiveCircuit::prepare_public_inputs(verifier_data.clone(), msg.clone());
 | 
			
		
	
		
			
				
					|  |  |  |                 verifier_data.clone().verify(ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |                     proof: new_proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |                     public_inputs: public_inputs.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |                 })?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |                 // set new_proof for next iteration
 | 
			
		
	
		
			
				
					|  |  |  |                 next_level_proofs.push(new_proof);
 | 
			
		
	
		
			
				
					|  |  |  |             }
 | 
			
		
	
		
			
				
					|  |  |  |             proofs_at_level_i = next_level_proofs.clone();
 | 
			
		
	
		
			
				
					|  |  |  |         }
 | 
			
		
	
		
			
				
					|  |  |  |         assert_eq!(proofs_at_level_i.len(), 1);
 | 
			
		
	
		
			
				
					|  |  |  |         let last_proof = proofs_at_level_i[0].clone();
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         // verify the last proof
 | 
			
		
	
		
			
				
					|  |  |  |         let public_inputs =
 | 
			
		
	
		
			
				
					|  |  |  |             RecursiveCircuit::prepare_public_inputs(verifier_data.clone(), msg.clone());
 | 
			
		
	
		
			
				
					|  |  |  |         verifier_data.clone().verify(ProofWithPublicInputs {
 | 
			
		
	
		
			
				
					|  |  |  |             proof: last_proof.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |             public_inputs: public_inputs.clone(),
 | 
			
		
	
		
			
				
					|  |  |  |         })?;
 | 
			
		
	
		
			
				
					|  |  |  | 
 | 
			
		
	
		
			
				
					|  |  |  |         Ok(())
 | 
			
		
	
		
			
				
					|  |  |  |     }
 | 
			
		
	
		
			
				
					|  |  |  |     // WIP will add more tests with other sig/proof combinations
 | 
			
		
	
		
			
				
					|  |  |  | }
 |