use std::marker::PhantomData; use plonky2::hash::hash_types::RichField; use plonky2::iop::witness::{PartialWitness, WitnessWrite}; use plonky2::plonk::circuit_builder::CircuitBuilder; use plonky2::plonk::circuit_data::{CircuitConfig, CircuitData, VerifierCircuitData, VerifierCircuitTarget}; use plonky2::plonk::config::{AlgebraicHasher, GenericConfig}; use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; use plonky2_field::extension::Extendable; use plonky2_poseidon2::poseidon2_hash::poseidon2::Poseidon2; use crate::recursion::circuits::inner_circuit::InnerCircuit; use crate::{error::CircuitError,Result}; /// recursion leaf circuit for the recursion tree circuit #[derive(Clone, Debug)] pub struct LeafCircuit< F: RichField + Extendable + Poseidon2, const D: usize, I: InnerCircuit > { pub inner_circ: I, phantom_data: PhantomData } impl< F: RichField + Extendable + Poseidon2, const D: usize, I: InnerCircuit > LeafCircuit { pub fn new(inner_circ: I) -> Self { Self{ inner_circ, phantom_data:PhantomData::default(), } } } #[derive(Clone, Debug)] pub struct LeafTargets < const D: usize, >{ pub inner_proof: ProofWithPublicInputsTarget, pub verifier_data: VerifierCircuitTarget, } #[derive(Clone, Debug)] pub struct LeafInput< F: RichField + Extendable + Poseidon2, const D: usize, C: GenericConfig, >{ pub inner_proof: ProofWithPublicInputs, pub verifier_data: VerifierCircuitData } impl< F: RichField + Extendable + Poseidon2, const D: usize, I: InnerCircuit, > LeafCircuit{ /// build the leaf circuit pub fn build< C: GenericConfig, H: AlgebraicHasher, >(&self, builder: &mut CircuitBuilder) -> Result> where >::Hasher: AlgebraicHasher { let common = self.inner_circ.get_common_data()?; // the proof virtual targets - only one for now // TODO: make it M proofs let vir_proof = builder.add_virtual_proof_with_pis(&common); // hash the public input & make it public let inner_pub_input = vir_proof.public_inputs.clone(); let hash_inner_pub_input = builder.hash_n_to_hash_no_pad::(inner_pub_input); builder.register_public_inputs(&hash_inner_pub_input.elements); // virtual target for the verifier data let inner_verifier_data = builder.add_virtual_verifier_data(common.config.fri_config.cap_height); // verify the proofs in-circuit (only one now) builder.verify_proof::(&vir_proof.clone(),&inner_verifier_data,&common); // return targets let t = LeafTargets { inner_proof: vir_proof, verifier_data: inner_verifier_data, }; Ok(t) } /// assign the leaf targets with given input pub fn assign_targets< C: GenericConfig, H: AlgebraicHasher, >(&self, pw: &mut PartialWitness, targets: &LeafTargets, input: &LeafInput) -> Result<()> where >::Hasher: AlgebraicHasher { // assign the proof pw.set_proof_with_pis_target(&targets.inner_proof,&input.inner_proof) .map_err(|e| { CircuitError::ProofTargetAssignmentError("inner-proof".to_string(), e.to_string()) })?; // assign the verifier data pw.set_verifier_data_target(&targets.verifier_data, &input.verifier_data.verifier_only) .map_err(|e| { CircuitError::VerifierDataTargetAssignmentError(e.to_string()) })?; Ok(()) } /// returns the leaf circuit data /// TODO: make generic recursion config pub fn get_circuit_data< C: GenericConfig, H: AlgebraicHasher, >(&self) -> Result> where >::Hasher: AlgebraicHasher { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::::new(config); self.build::(&mut builder)?; let circ_data = builder.build::(); Ok(circ_data) } }