From de44dc78dbd522b3e8b3bcc1b478c4f19c4b3135 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 11 Nov 2024 12:17:55 +0100 Subject: [PATCH 1/5] Add L * POD1_Introducer recursive (1-level recursion) verifiers in the RecursiveCircuit --- pod2/src/recursion/recursion_framework.rs | 234 ++++++++++++++++------ 1 file changed, 171 insertions(+), 63 deletions(-) diff --git a/pod2/src/recursion/recursion_framework.rs b/pod2/src/recursion/recursion_framework.rs index 78acfd1..1d530a6 100644 --- a/pod2/src/recursion/recursion_framework.rs +++ b/pod2/src/recursion/recursion_framework.rs @@ -49,6 +49,7 @@ use super::{InnerCircuitTrait, OpsExecutorTrait}; use crate::{PlonkyProof, C, D, F}; /// RecursionTree defines the tree, where each recursive node executes +/// - L POD1-Introducer proof verifiers /// - M InnerCircuitTrait /// - N plonky2 recursive proof verifiers /// - the given OpsExecutorTrait @@ -56,48 +57,61 @@ use crate::{PlonkyProof, C, D, F}; pub struct RecursionTree< I: InnerCircuitTrait, O: OpsExecutorTrait, + const L: usize, const M: usize, const N: usize, const NS: usize, const VL: usize, > where - [(); M + N]:, + [(); L + M + N]:, { _i: PhantomData, _o: PhantomData, } -impl - RecursionTree +impl + RecursionTree where I: InnerCircuitTrait, O: OpsExecutorTrait, - [(); M + N]:, + [(); L + M + N]:, { /// returns the full-recursive CircuitData pub fn circuit_data() -> Result> { - RecursionCircuit::::circuit_data() + RecursionCircuit::::circuit_data() } pub fn prepare_public_inputs( verifier_data: VerifierCircuitData, public_inputs: Vec, ) -> Vec { - RecursionCircuit::::prepare_public_inputs(verifier_data, public_inputs) + RecursionCircuit::::prepare_public_inputs( + verifier_data, + public_inputs, + ) } pub fn prove_node( prover: &ProverCircuitData, - circuit: &mut RecursionCircuit, - selectors: [F; M + N], - inner_circuits_input: [I::Input; M], + circuit: &mut RecursionCircuit, + selectors: [F; L + M + N], ops_executor_input: O::Input, ops_executor_output: O::Output, + // pod1's public inputs needed to verify pod1's proof, not public inputs in the current + // RecursiveCircuit + pod1_public_inputs: [Vec; L], + pod1_proofs: &[PlonkyProof; L], + inner_circuits_input: [I::Input; M], recursive_proofs: &[PlonkyProof; N], ) -> Result { println!("prove_node:"); - for i in 0..M + N { - let what = if i < M { "inner circuit" } else { "proof" }; + for i in 0..L + M + N { + let what = match i { + 0..L => "pod1 proof", + L..M => "inner circuit", + M..N => "recursive proof", + _ => "unknown", + }; if selectors[i].is_nonzero() { println!(" (selectors[{}] enabled), verify {}", i, what); } else { @@ -111,9 +125,10 @@ where circuit.set_targets( &mut pw, selectors, - inner_circuits_input, ops_executor_input, ops_executor_output, + pod1_public_inputs, + pod1_proofs, recursive_proofs, )?; println!("circuit.set_targets(): {:?}", start.elapsed()); @@ -133,40 +148,47 @@ where /// It contains the methods to `add_targets` (ie. create the targets, the logic of the circuit), /// and `set_targets` (ie. set the specific values to be used for the previously created targets). /// -/// I: InnerCircuitTrait /// O: OpsExecutorTrait +/// L: number of pod1-proofs per recursive step /// M: number of InnerCircuits per recursive step /// N: number of plonky2 proofs per recursive step pub struct RecursionCircuit< I: InnerCircuitTrait, O: OpsExecutorTrait, + const L: usize, const M: usize, const N: usize, const NS: usize, const VL: usize, > where - [(); M + N]:, + [(); L + M + N]:, { - selectors_targ: [Target; M + N], - inner_circuit_targ: [I::Targets; M], + selectors_targ: [Target; L + M + N], ops_executor_targ: O::Targets, + pod1_proofs_targ: [ProofWithPublicInputsTarget; L], + inner_circuit_targ: [I::Targets; M], proofs_targ: [ProofWithPublicInputsTarget; N], - // the next two are common for all the given proofs. It is the data for this circuit itself - // (cyclic circuit). + // the next parameters are common for all the given proofs. + // 1-level-recursion params (pod1 translator verifier): + pod1_verifier_data_targ: VerifierCircuitTarget, // TODO naming: introducer proof + pod1_verifier_data: VerifierCircuitData, + // cyclic-recursion params: + // It is the data for this circuit + // itself (cyclic circuit). verifier_data_targ: VerifierCircuitTarget, verifier_data: VerifierCircuitData, } -impl - RecursionCircuit +impl + RecursionCircuit where I: InnerCircuitTrait, O: OpsExecutorTrait, - [(); M + N]:, + [(); L + M + N]:, { /// returns the full-recursive CircuitData pub fn circuit_data() -> Result> { - let mut data = common_data_for_recursion::()?; + let mut data = common_data_for_recursion::()?; // build the actual RecursionCircuit circuit data let config = CircuitConfig::standard_recursion_config(); @@ -199,13 +221,16 @@ where dummy_proof_pis.proof } + // notice that this method is used to prepare the public inputs for both the + // 1-level-recursion-verification (used for the POD1-Introducer verification) and the + // cyclic-recursion-verification pub fn prepare_public_inputs( - verifier_data: VerifierCircuitData, public_inputs: Vec, + verifier_data: VerifierCircuitData, ) -> Vec { [ public_inputs, - // add verifier_data as public inputs: + // add verifier_data verifier_data.verifier_only.circuit_digest.elements.to_vec(), verifier_data .verifier_only @@ -222,34 +247,58 @@ where // `fill_recursive_circuit_targets` pub fn add_targets( builder: &mut CircuitBuilder, + // pod1 circuit verifier_data + pod1_verifier_data: VerifierCircuitData, + // self's verifier_data verifier_data: VerifierCircuitData, ) -> Result { // build the InnerCircuit logic. Also set the selectors, used both by the InnerCircuit and // by the recursive proofs verifications. - let selectors_targ: [Target; M + N] = array::from_fn(|_| { + let selectors_targ: [Target; L + M + N] = array::from_fn(|_| { let selector_F_targ = builder.add_virtual_target(); // ensure that selector_booltarg is \in {0,1} binary_check(builder, selector_F_targ); selector_F_targ }); - let selectors_bool_targ: [BoolTarget; M + N] = + let selectors_bool_targ: [BoolTarget; L + M + N] = array::from_fn(|i| BoolTarget::new_unsafe(selectors_targ[i])); - let inner_circuit_targ: [I::Targets; M] = - array::try_from_fn(|i| I::add_targets(builder, &selectors_bool_targ[i]))?; - let ops_executor_targ: O::Targets = O::add_targets(builder)?; + // Notice: pod1 recursive verification is only 1-level-depth recursion, whereas the other + // proof verification is infinity-levels-depth recursion (cyclic recursion). + + // pod1 proof verification + let pod1_common_data = verifier_data.common.clone(); + + let pod1_verifier_data_targ = builder.add_verifier_data_public_inputs(); + + let pod1_proofs_targ: Result<[ProofWithPublicInputsTarget; M]> = + array::try_from_fn(|i| { + let pod1_proof_targ = builder.add_virtual_proof_with_pis(&pod1_common_data); + builder.conditionally_verify_proof_or_dummy::( + selectors_bool_targ[i], + &pod1_proof_targ, + &pod1_verifier_data_targ, + &pod1_common_data, + )?; + Ok(pod1_proof_targ) + }); + let pod1_proofs_targ = pod1_proofs_targ?; + + // InnerCircuits logic + let inner_circuit_targ: [I::Targets; M] = + array::try_from_fn(|i| I::add_targets(builder, &selectors_bool_targ[L + i]))?; + // proof verification: let common_data = verifier_data.common.clone(); - let verifier_data_targ = builder.add_verifier_data_public_inputs(); let proofs_targ: Result<[ProofWithPublicInputsTarget; N]> = array::try_from_fn(|i| { let proof_targ = builder.add_virtual_proof_with_pis(&common_data); builder.conditionally_verify_cyclic_proof_or_dummy::( - selectors_bool_targ[M + i], + selectors_bool_targ[L + M + i], &proof_targ, &common_data, )?; @@ -259,9 +308,12 @@ where Ok(Self { selectors_targ, - inner_circuit_targ, ops_executor_targ, + pod1_proofs_targ, + inner_circuit_targ, proofs_targ, + pod1_verifier_data_targ, + pod1_verifier_data, verifier_data_targ, verifier_data, }) @@ -274,15 +326,42 @@ where // correspond to the N PlonkyProofs verifications. If the selector is set to 1, it enables // the verification (either of the InnerCircuit or the Plonky2Proof verification). selectors: [F; M + N], - inner_circuit_input: [I::Input; M], ops_executor_input: O::Input, ops_executor_output: O::Output, // public inputs + pod1_public_inputs: [Vec; L], + pod1_recursive_proofs: &[PlonkyProof; L], + inner_circuit_input: [I::Input; M], recursive_proofs: &[PlonkyProof; N], ) -> Result<()> { for i in 0..(M + N) { pw.set_target(self.selectors_targ[i], selectors[i])?; } + // set the OpExecutor related values, and get it's public inputs + let oe_pubinp: Vec = O::set_targets( + pw, + &self.ops_executor_targ, + &ops_executor_input, + &ops_executor_output, + )?; + + // set proof related values: + + // pod1 proof verification + pw.set_verifier_data_target(&self.verifier_data_targ, &self.verifier_data.verifier_only)?; + for i in 0..L { + // put together the public inputs with the verifier_data + let pub_inp = + Self::prepare_public_inputs(pod1_public_inputs, self.pod1_verifier_data.clone()); + pw.set_proof_with_pis_target( + &self.pod1_proofs_targ[i], + &ProofWithPublicInputs { + proof: pod1_recursive_proofs[i].clone(), + public_inputs: pub_inp.clone(), + }, + )?; + } + // set the InnerCircuit related values let mut ic_pubinp: Vec> = vec![]; for i in 0..M { @@ -293,22 +372,13 @@ where )?); } - let oe_pubinp = O::set_targets( - pw, - &self.ops_executor_targ, - &ops_executor_input, - &ops_executor_output, - )?; - - // set proof related values: - // recursive proofs verification pw.set_verifier_data_target(&self.verifier_data_targ, &self.verifier_data.verifier_only)?; // join the public inputs from the InnerCircuits and the OpsExecutor let pubinp: Vec = [ic_pubinp.into_iter().flatten().collect(), oe_pubinp].concat(); // put together the public inputs with the verifier_data - let public_inputs = Self::prepare_public_inputs(self.verifier_data.clone(), pubinp); + let public_inputs = Self::prepare_public_inputs(pubinp, self.verifier_data.clone()); for i in 0..N { pw.set_proof_with_pis_target( &self.proofs_targ[i], @@ -326,13 +396,14 @@ where pub fn common_data_for_recursion< I: InnerCircuitTrait, O: OpsExecutorTrait, + const L: usize, const M: usize, const N: usize, const NS: usize, const VL: usize, >() -> Result> where - [(); M + N]:, + [(); L + M + N]:, { // 1st let config = CircuitConfig::standard_recursion_config(); @@ -376,16 +447,21 @@ where // add the OpsExecutor targets let _: O::Targets = O::add_targets(&mut builder)?; - // proofs verify - let verifier_data = builder.add_verifier_data_public_inputs(); + // pod1 proofs // TODO group with N in a single loop + let pod1_verifier_data = builder.add_verifier_data_public_inputs(); + for _ in 0..L { + let proof = builder.add_virtual_proof_with_pis(&data.common); + builder.verify_proof::(&proof, &pod1_verifier_data, &data.common); + } // proofs + let verifier_data = builder.add_verifier_data_public_inputs(); for _ in 0..N { let proof = builder.add_virtual_proof_with_pis(&data.common); builder.verify_proof::(&proof, &verifier_data, &data.common); } // pad min gates - let n_gates = compute_num_gates::()?; + let n_gates = compute_num_gates::()?; while builder.num_gates() < n_gates { builder.add_gate(NoopGate, vec![]); } @@ -393,10 +469,14 @@ where } // TODO: Take `VL` into account. -fn compute_num_gates() -> Result { +fn compute_num_gates( +) -> Result +where + [(); L + N]:, +{ // Note: the following numbers are WIP, obtained by trial-error by running different // configurations in the tests. - let n_gates = match N { + let n_gates = match L + N { 0..=1 => 1 << 12, 2 => { if NS < 9 { @@ -411,8 +491,8 @@ fn compute_num_gates() -> Resu }; if n_gates == 0 { return Err(anyhow!( - "arity of N={} not supported yet. Currently supported N from 1 to 6 (both included)", - N + "arity of L+N={} not supported yet. Currently supported L+N from 1 to 6 (both included)", + L+N )); } Ok(n_gates) @@ -423,12 +503,14 @@ mod tests { use anyhow::Result; use plonky2::field::types::{Field, Sample}; use plonky2::plonk::proof::ProofWithPublicInputs; + use plonky2::recursion::dummy_circuit::dummy_proof; use rand; use std::array; use std::time::Instant; use super::*; + use crate::pod::gadget::SchnorrPODGadget; use crate::recursion::traits_examples::{ ExampleGadget, ExampleGadgetInput, ExampleOpsExecutor, }; @@ -446,15 +528,20 @@ mod tests { /// cargo test --release test_recursion -- --nocapture #[test] fn test_recursion() -> Result<()> { - test_recursion_opt::<3, 2, 2, 0>()?; // + test_recursion_opt::<0, 3, 2, 2, 0>()?; // Ok(()) } - fn test_recursion_opt( - ) -> Result<()> + fn test_recursion_opt< + const L: usize, + const M: usize, + const N: usize, + const NS: usize, + const VL: usize, + >() -> Result<()> where - [(); M + N]:, + [(); L + M + N]:, { set_log(); println!("\n--------------------------------------------------"); @@ -494,17 +581,34 @@ mod tests { .collect(); assert_eq!(sig_vec.len(), M); - type RC = - RecursionCircuit, M, N, NS, VL>; - type RT = - RecursionTree, M, N, NS, VL>; + // TODO + // // POD1 introducer logic: + // let config = CircuitConfig::standard_recursion_config(); + // let mut builder = CircuitBuilder::::new(config); + // let selector_targ = builder.add_virtual_target(); + // let selector_booltarg = BoolTarget::new_unsafe(selector_targ); + // let _ = SchnorrPODGadget::::add_targets(&mut builder, &selector_booltarg)?; + // let data = builder.build::(); + // let pod1_circuit_data: CircuitData = data.circuit_data; + // + // let pod1_public_inputs: [Vec; M] = array::from_fn(|k| vec![]); + // let pod1_proofs: [PlonkyProof; M] = array::from_fn(|k| dummy_proof(&pod1_circuit_data)); + + let pod1_public_inputs: [Vec; M] = array::from_fn(|k| vec![]); + let pod1_dummy_proof: PlonkyProof = IntroducerCircuit::dummy_proof(pod1_circuit_data)?; + let pod1_proofs: [PlonkyProof; M] = array::from_fn(|k| pod1_dummy_proof.clone())); + + type RC = + RecursionCircuit, L, M, N, NS, VL>; + type RT = + RecursionTree, L, M, N, NS, VL>; // build the circuit_data & verifier_data for the recursive circuit - let circuit_data = RC::::circuit_data()?; + let circuit_data = RC::::circuit_data()?; let verifier_data = circuit_data.verifier_data(); - let prover = RC::::build_prover(verifier_data.clone())?; + let prover = RC::::build_prover(verifier_data.clone())?; - let dummy_proof = RC::::dummy_proof(circuit_data); + let dummy_proof = RC::::dummy_proof(circuit_data); // we start with k dummy proofs, since at the leafs level we don't have proofs yet and we // just verify the signatures. At each level we divide the amount of proofs by N. At the @@ -546,6 +650,8 @@ mod tests { // let ops_executor_input = array::from_fn(|_| ()); let ops_executor_input = (); let ops_executor_output = (); + + // let pod1_proofs: [PlonkyProof; M] = array::from_fn(|k| pod1_proofs[j + k].clone()); let proofs: [PlonkyProof; N] = array::from_fn(|k| proofs_at_level_i[j + k].clone()); // do the recursive step @@ -554,9 +660,11 @@ mod tests { &prover, &mut circuit, selectors, - innercircuits_input, ops_executor_input, ops_executor_output, + pod1_public_inputs, + &pod1_proofs, + innercircuits_input, &proofs, )?; println!( From 274596e13715286a20017c255b1f71a985fc3dee Mon Sep 17 00:00:00 2001 From: arnaucube Date: Mon, 11 Nov 2024 16:50:19 +0100 Subject: [PATCH 2/5] complete first version of the new RecursiveCircuit which includes L POD1-introducer verifiers --- pod2/src/pod/gadget/introducer.rs | 29 ++++++++ pod2/src/recursion/recursion_framework.rs | 85 ++++++++++++----------- 2 files changed, 73 insertions(+), 41 deletions(-) create mode 100644 pod2/src/pod/gadget/introducer.rs diff --git a/pod2/src/pod/gadget/introducer.rs b/pod2/src/pod/gadget/introducer.rs new file mode 100644 index 0000000..3ae8041 --- /dev/null +++ b/pod2/src/pod/gadget/introducer.rs @@ -0,0 +1,29 @@ +use anyhow::{anyhow, Result}; +use hashbrown::HashMap; +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, ProverCircuitData, VerifierCircuitData, VerifierCircuitTarget, +}; +use plonky2::plonk::proof::{ProofWithPublicInputs, ProofWithPublicInputsTarget}; +use plonky2::recursion::dummy_circuit::cyclic_base_proof; +use std::array; +use std::marker::PhantomData; +use std::time::Instant; + +use crate::{PlonkyProof, C, D, F}; + +pub struct IntroducerCircuit {} + +impl IntroducerCircuit { + pub fn circuit_data() -> Result> { + todo!(); + } + + pub fn dummy_proof(circuit_data: CircuitData) -> Result { + todo!(); + } +} diff --git a/pod2/src/recursion/recursion_framework.rs b/pod2/src/recursion/recursion_framework.rs index 1d530a6..962e246 100644 --- a/pod2/src/recursion/recursion_framework.rs +++ b/pod2/src/recursion/recursion_framework.rs @@ -75,19 +75,20 @@ where I: InnerCircuitTrait, O: OpsExecutorTrait, [(); L + M + N]:, + [(); L + N]:, { /// returns the full-recursive CircuitData - pub fn circuit_data() -> Result> { - RecursionCircuit::::circuit_data() + pub fn circuit_data(pod1_verifier_data: VerifierCircuitData) -> Result> { + RecursionCircuit::::circuit_data(pod1_verifier_data) } pub fn prepare_public_inputs( - verifier_data: VerifierCircuitData, public_inputs: Vec, + verifier_data: VerifierCircuitData, ) -> Vec { RecursionCircuit::::prepare_public_inputs( - verifier_data, public_inputs, + verifier_data, ) } @@ -99,7 +100,7 @@ where ops_executor_output: O::Output, // pod1's public inputs needed to verify pod1's proof, not public inputs in the current // RecursiveCircuit - pod1_public_inputs: [Vec; L], + pod1_public_inputs: &[Vec; L], pod1_proofs: &[PlonkyProof; L], inner_circuits_input: [I::Input; M], recursive_proofs: &[PlonkyProof; N], @@ -108,8 +109,8 @@ where for i in 0..L + M + N { let what = match i { 0..L => "pod1 proof", - L..M => "inner circuit", - M..N => "recursive proof", + L..(L+M) => "inner circuit", + (L+M)..N => "recursive proof", _ => "unknown", }; if selectors[i].is_nonzero() { @@ -129,6 +130,7 @@ where ops_executor_output, pod1_public_inputs, pod1_proofs, + inner_circuits_input, recursive_proofs, )?; println!("circuit.set_targets(): {:?}", start.elapsed()); @@ -185,15 +187,17 @@ where I: InnerCircuitTrait, O: OpsExecutorTrait, [(); L + M + N]:, + [(); L + N]:, { /// returns the full-recursive CircuitData - pub fn circuit_data() -> Result> { + pub fn circuit_data(pod1_verifier_data: VerifierCircuitData) -> Result> { let mut data = common_data_for_recursion::()?; // build the actual RecursionCircuit circuit data let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::new(config); - let _ = Self::add_targets(&mut builder, data.verifier_data())?; + + let _ = Self::add_targets(&mut builder, pod1_verifier_data, data.verifier_data())?; data = builder.build::(); Ok(data) @@ -201,12 +205,13 @@ where /// returns ProverCircuitData pub fn build_prover( + pod1_verifier_data: VerifierCircuitData, verifier_data: VerifierCircuitData, ) -> Result> { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::new(config); - let _ = Self::add_targets(&mut builder, verifier_data.clone())?; + let _ = Self::add_targets(&mut builder, pod1_verifier_data, verifier_data.clone())?; Ok(builder.build_prover::()) } @@ -273,7 +278,7 @@ where let pod1_verifier_data_targ = builder.add_verifier_data_public_inputs(); - let pod1_proofs_targ: Result<[ProofWithPublicInputsTarget; M]> = + let pod1_proofs_targ: Result<[ProofWithPublicInputsTarget; L]> = array::try_from_fn(|i| { let pod1_proof_targ = builder.add_virtual_proof_with_pis(&pod1_common_data); builder.conditionally_verify_proof_or_dummy::( @@ -325,15 +330,15 @@ where // the first M selectors correspond to the M InnerCircuits, and the following N selectors // correspond to the N PlonkyProofs verifications. If the selector is set to 1, it enables // the verification (either of the InnerCircuit or the Plonky2Proof verification). - selectors: [F; M + N], + selectors: [F; L + M + N], ops_executor_input: O::Input, ops_executor_output: O::Output, // public inputs - pod1_public_inputs: [Vec; L], + pod1_public_inputs: &[Vec; L], pod1_recursive_proofs: &[PlonkyProof; L], inner_circuit_input: [I::Input; M], recursive_proofs: &[PlonkyProof; N], ) -> Result<()> { - for i in 0..(M + N) { + for i in 0..(L + M + N) { pw.set_target(self.selectors_targ[i], selectors[i])?; } @@ -351,8 +356,8 @@ where pw.set_verifier_data_target(&self.verifier_data_targ, &self.verifier_data.verifier_only)?; for i in 0..L { // put together the public inputs with the verifier_data - let pub_inp = - Self::prepare_public_inputs(pod1_public_inputs, self.pod1_verifier_data.clone()); + let pub_inp = Self::prepare_public_inputs(vec![], self.pod1_verifier_data.clone()); + // Self::prepare_public_inputs(pod1_public_inputs[i], self.pod1_verifier_data.clone()); pw.set_proof_with_pis_target( &self.pod1_proofs_targ[i], &ProofWithPublicInputs { @@ -404,6 +409,7 @@ pub fn common_data_for_recursion< >() -> Result> where [(); L + M + N]:, + [(); L + N]:, { // 1st let config = CircuitConfig::standard_recursion_config(); @@ -510,7 +516,7 @@ mod tests { use super::*; - use crate::pod::gadget::SchnorrPODGadget; + use crate::pod::gadget::{IntroducerCircuit, SchnorrPODGadget}; use crate::recursion::traits_examples::{ ExampleGadget, ExampleGadgetInput, ExampleOpsExecutor, }; @@ -542,6 +548,7 @@ mod tests { >() -> Result<()> where [(); L + M + N]:, + [(); L + N]:, { set_log(); println!("\n--------------------------------------------------"); @@ -581,22 +588,12 @@ mod tests { .collect(); assert_eq!(sig_vec.len(), M); - // TODO - // // POD1 introducer logic: - // let config = CircuitConfig::standard_recursion_config(); - // let mut builder = CircuitBuilder::::new(config); - // let selector_targ = builder.add_virtual_target(); - // let selector_booltarg = BoolTarget::new_unsafe(selector_targ); - // let _ = SchnorrPODGadget::::add_targets(&mut builder, &selector_booltarg)?; - // let data = builder.build::(); - // let pod1_circuit_data: CircuitData = data.circuit_data; - // - // let pod1_public_inputs: [Vec; M] = array::from_fn(|k| vec![]); - // let pod1_proofs: [PlonkyProof; M] = array::from_fn(|k| dummy_proof(&pod1_circuit_data)); - - let pod1_public_inputs: [Vec; M] = array::from_fn(|k| vec![]); + // POD1 introducer logic: + let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_verifier_data = pod1_circuit_data.verifier_data(); let pod1_dummy_proof: PlonkyProof = IntroducerCircuit::dummy_proof(pod1_circuit_data)?; - let pod1_proofs: [PlonkyProof; M] = array::from_fn(|k| pod1_dummy_proof.clone())); + let pod1_proofs: [PlonkyProof; L] = array::from_fn(|k| pod1_dummy_proof.clone()); + let pod1_public_inputs: [Vec; L] = array::from_fn(|k| vec![]); type RC = RecursionCircuit, L, M, N, NS, VL>; @@ -604,9 +601,10 @@ mod tests { RecursionTree, L, M, N, NS, VL>; // build the circuit_data & verifier_data for the recursive circuit - let circuit_data = RC::::circuit_data()?; + let circuit_data = RC::::circuit_data(pod1_verifier_data.clone())?; let verifier_data = circuit_data.verifier_data(); - let prover = RC::::build_prover(verifier_data.clone())?; + let prover = + RC::::build_prover(pod1_verifier_data.clone(), verifier_data.clone())?; let dummy_proof = RC::::dummy_proof(circuit_data); @@ -619,7 +617,11 @@ mod tests { let config = CircuitConfig::standard_recursion_config(); let mut builder = CircuitBuilder::new(config); let start = Instant::now(); - let mut circuit = RC::::add_targets(&mut builder, verifier_data.clone())?; + let mut circuit = RC::::add_targets( + &mut builder, + pod1_verifier_data.clone(), + verifier_data.clone(), + )?; println!("RecursionCircuit::add_targets(): {:?}", start.elapsed()); // loop over the recursion levels @@ -635,11 +637,12 @@ mod tests { ); // prepare the inputs for the `RecursionTree::prove_node` call - let mut selectors: [F; M + N] = [F::ONE; M + N]; + let mut selectors: [F; L + M + N] = [F::ONE; L + M + N]; if i == 0 { // if we're at the base level, set to 0 (=disable) the N selectors of the // proofs verifications - selectors[M..M + N].fill(F::ZERO); + selectors[0..L].fill(F::ZERO); // pod1 proof verifications + selectors[M..L + M + N].fill(F::ZERO); // recursive proof verifications } let innercircuits_input: [ExampleGadgetInput; M] = array::from_fn(|k| ExampleGadgetInput { @@ -656,13 +659,13 @@ mod tests { // do the recursive step let start = Instant::now(); - let new_proof = RT::::prove_node( + let new_proof = RT::::prove_node( &prover, &mut circuit, selectors, ops_executor_input, ops_executor_output, - pod1_public_inputs, + &pod1_public_inputs, &pod1_proofs, innercircuits_input, &proofs, @@ -676,7 +679,7 @@ mod tests { // verify the recursive proof let public_inputs = - RT::::prepare_public_inputs(verifier_data.clone(), vec![]); + RT::::prepare_public_inputs(vec![], verifier_data.clone()); verifier_data.clone().verify(ProofWithPublicInputs { proof: new_proof.clone(), public_inputs: public_inputs.clone(), @@ -692,7 +695,7 @@ mod tests { // verify the last proof let public_inputs = - RT::::prepare_public_inputs(verifier_data.clone(), vec![]); + RT::::prepare_public_inputs(vec![], verifier_data.clone()); verifier_data.clone().verify(ProofWithPublicInputs { proof: last_proof.clone(), public_inputs: public_inputs.clone(), From 2f106898832acfbf3b96f7f56477c22326008b3e Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 12 Nov 2024 02:44:50 +0100 Subject: [PATCH 3/5] start to integrate the new RecursionCircuit containing POD1-Introducer proof verification with the PlonkyButNotPlonkyPOD --- pod2/src/pod/gadget/introducer.rs | 4 + pod2/src/pod/gadget/mod.rs | 2 + pod2/src/pod/gadget/plonky_pod.rs | 144 ++++++++++++++++------ pod2/src/pod/mod.rs | 78 ++++++++---- pod2/src/recursion/recursion_framework.rs | 27 ++-- 5 files changed, 181 insertions(+), 74 deletions(-) diff --git a/pod2/src/pod/gadget/introducer.rs b/pod2/src/pod/gadget/introducer.rs index 3ae8041..a09e055 100644 --- a/pod2/src/pod/gadget/introducer.rs +++ b/pod2/src/pod/gadget/introducer.rs @@ -18,6 +18,10 @@ use crate::{PlonkyProof, C, D, F}; pub struct IntroducerCircuit {} +/// IntroducerCircuit defines the circuit whose plonky2 proof is verified in the RecursiveCircuit +/// (1-level recursion). +// TODO probably traitify this, and in the RecursionCircuit use the trait and not this specific +// struct directly. impl IntroducerCircuit { pub fn circuit_data() -> Result> { todo!(); diff --git a/pod2/src/pod/gadget/mod.rs b/pod2/src/pod/gadget/mod.rs index c706369..3589877 100644 --- a/pod2/src/pod/gadget/mod.rs +++ b/pod2/src/pod/gadget/mod.rs @@ -1,10 +1,12 @@ use core::fmt; use serde::{Deserialize, Serialize}; +pub mod introducer; pub mod opexecutor; pub mod plonky_pod; pub mod schnorr_pod; +pub use introducer::IntroducerCircuit; pub use opexecutor::OpExecutorGadget; pub use plonky_pod::PlonkyButNotPlonkyGadget; pub use schnorr_pod::SchnorrPODGadget; diff --git a/pod2/src/pod/gadget/plonky_pod.rs b/pod2/src/pod/gadget/plonky_pod.rs index b352f12..c36aeb5 100644 --- a/pod2/src/pod/gadget/plonky_pod.rs +++ b/pod2/src/pod/gadget/plonky_pod.rs @@ -11,7 +11,7 @@ use std::time::Instant; use crate::pod::entry::Entry; use crate::pod::gadget::GadgetID; -use crate::pod::gadget::{opexecutor::OpExecutorGadget, schnorr_pod::SchnorrPODGadget}; +use crate::pod::gadget::{IntroducerCircuit, OpExecutorGadget, SchnorrPODGadget}; use crate::pod::operation::OpList; use crate::pod::payload::{PODPayload, StatementList}; use crate::pod::statement::Statement; @@ -21,13 +21,27 @@ use crate::signature::schnorr::SchnorrSecretKey; use crate::{PlonkyProof, C, D, F}; -pub struct ProverParams -where - [(); M + N]:, +pub struct ProverParams< + const L: usize, + const M: usize, + const N: usize, + const NS: usize, + const VL: usize, +> where + [(); L + M + N]:, + [(); L + N]:, { - circuit: - RecursionCircuit, OpExecutorGadget<{ M + N }, NS, VL>, M, N, NS, VL>, + circuit: RecursionCircuit< + SchnorrPODGadget, + OpExecutorGadget<{ L + M + N }, NS, VL>, + L, + M, + N, + NS, + VL, + >, prover: ProverCircuitData, + pod1_dummy_proof: PlonkyProof, dummy_proof: PlonkyProof, } @@ -57,36 +71,44 @@ where /// ``` // TODO: `PlonkyButNotPlonkyGadget` is a placeholder name, set better struct name. pub struct PlonkyButNotPlonkyGadget< + const L: usize, const M: usize, const N: usize, const NS: usize, const VL: usize, > where - [(); M + N]:; + [(); L + M + N]:, + [(); L + N]:; -impl - PlonkyButNotPlonkyGadget +impl + PlonkyButNotPlonkyGadget where - [(); M + N]:, + [(); L + M + N]:, + [(); L + N]:, { /// Returns the RecursiveCircuit's CircuitData, which is reused for all calls of the `execute` /// method - pub fn circuit_data() -> Result> { + pub fn circuit_data( + pod1_verifier_data: VerifierCircuitData, + ) -> Result> { // generate circuit data RecursionCircuit::< SchnorrPODGadget, - OpExecutorGadget<{ M + N }, NS, VL>, // NP=M+N + OpExecutorGadget<{ L + M + N }, NS, VL>, // NP=L+M+N + L, M, N, NS, VL, - >::circuit_data() + >::circuit_data(pod1_verifier_data) } /// returns ProverCircuitData pub fn build_prover_params( + pod1_circuit_data: CircuitData, circuit_data: CircuitData, - ) -> Result> { + ) -> Result> { + let pod1_verifier_data = pod1_circuit_data.verifier_data(); let verifier_data = circuit_data.verifier_data(); let config = CircuitConfig::standard_recursion_config(); @@ -94,41 +116,50 @@ where let circuit = RecursionCircuit::< SchnorrPODGadget, - OpExecutorGadget<{ M + N }, NS, VL>, + OpExecutorGadget<{ L + M + N }, NS, VL>, + L, M, N, NS, VL, - >::add_targets(&mut builder, verifier_data.clone())?; + >::add_targets( + &mut builder, + pod1_verifier_data.clone(), + verifier_data.clone(), + )?; let prover = RecursionCircuit::< SchnorrPODGadget, - OpExecutorGadget<{ M + N }, NS, VL>, // NP=M+N + OpExecutorGadget<{ L + M + N }, NS, VL>, // NP=L+M+N + L, M, N, NS, VL, - >::build_prover(verifier_data)?; + >::build_prover(pod1_verifier_data, verifier_data)?; let dummy_proof = RecursionCircuit::< SchnorrPODGadget, - OpExecutorGadget<{ M + N }, NS, VL>, + OpExecutorGadget<{ L + M + N }, NS, VL>, + L, M, N, NS, VL, >::dummy_proof(circuit_data); + let pod1_dummy_proof = IntroducerCircuit::dummy_proof(pod1_circuit_data)?; Ok(ProverParams { circuit, prover, + pod1_dummy_proof, dummy_proof, }) } /// Generates a new POD from the given input PODs and the OpList (operations list) pub fn execute( - prover_params: &mut ProverParams, + prover_params: &mut ProverParams, input_pods: &[(String, POD)], op_list: OpList, origin_renaming_map: HashMap<(String, String), String>, @@ -137,6 +168,8 @@ where // Check that the input data is valid, i.e. that we have at most M // SchnorrPODs and N PlonkyPODs in our list, *and each POD // contains exactly `NS` statements*. + // + // TODO do the same with L pod1 pods let mut schnorr_pods: Vec<(String, POD)> = input_pods .to_vec() .into_iter() @@ -203,6 +236,8 @@ where &SchnorrSecretKey { sk: 0 }, )?; + // TODO do the same with L POD1-Introducer PODs + // // Arrange input PODs as a list of M SchnorrPODs followed by N // PlonkyPODs. Pad with appropriate dummy data. let schnorr_pods_padded: [(String, POD); M] = array::from_fn(|i| { @@ -219,7 +254,8 @@ where (format!("_DUMMYPLONKY{}", i), dummy_plonky_pod.clone()) } }); - let padded_pod_list: [(String, POD); M + N] = array::from_fn(|i| { + // TODO add L pod1introducer_pods_padded here: + let padded_pod_list: [(String, POD); L + M + N] = array::from_fn(|i| { if i < M { schnorr_pods_padded[i].clone() } else { @@ -229,7 +265,10 @@ where // Prepare selectors. Set them enabled for the given schnorr & plonky pods, and disabled for // the padding ones - let selectors: [F; M + N] = array::from_fn(|i| { + // + // TODO add L selectors here for the pod1_introducer_pods + let selectors: [F; L + M + N] = array::from_fn(|i| { + // TODO match i? maybe can not bcs L,M,N are consts if i < M { GoldilocksField(if i < schnorr_count - 1 { 1 } else { 0 }) } else { @@ -265,7 +304,14 @@ where // proof verification circuit. // prepare inputs for the circuit + + // TODO add prepare also the L POD1introducer PODs + let pod1_proofs: [PlonkyProof; L] = + array::from_fn(|k| prover_params.pod1_dummy_proof.clone()); + let pod1_public_inputs: [Vec; L] = array::from_fn(|k| vec![]); + let inner_circuit_input: [POD; M] = array::from_fn(|i| schnorr_pods_padded[i].1.clone()); + let recursive_proofs: [PlonkyProof; N] = array::from_fn(|i| { // convert the PODProof.proof into an actual PlonkyProof: match plonky_pods_padded[i].1.proof.clone() { @@ -283,7 +329,8 @@ where // let start_add_targets = Instant::now(); // let mut circuit = RecursionCircuit::< // SchnorrPODGadget, - // OpExecutorGadget<{ M + N }, NS, VL>, + // OpExecutorGadget<{ L+M + N }, NS, VL>, + // L, // M, // N, // NS, @@ -295,9 +342,11 @@ where prover_params.circuit.set_targets( &mut pw, selectors, - inner_circuit_input, // =[InnerCircuit::Input; M] (gpg_input, op_list), // =OpsExecutor::Input output_statements.clone(), // =OpsExecutor::Output + &pod1_public_inputs, + &pod1_proofs, // =[PlonkyProof; L] (non-cyclic proofs)) + inner_circuit_input, // =[InnerCircuit::Input; M] &recursive_proofs, )?; @@ -315,8 +364,8 @@ where let time_execute = start_execute.elapsed(); // println!( - // "| {} | {} | {} | {} | {:#.2?} | {:#.2?} |", - // M, N, NS, VL, time_prove, time_execute, + // "| {} | {} | {} | {} | {} | {:#.2?} | {:#.2?} |", + // L, M, N, NS, VL, time_prove, time_execute, // ); Ok(POD { @@ -389,6 +438,7 @@ mod tests { use crate::{ pod::{ entry::Entry, + gadget::{IntroducerCircuit, OpExecutorGadget, SchnorrPODGadget}, operation::{OpList, Operation as Op, OperationCmd as OpCmd}, statement::StatementRef, POD, @@ -425,6 +475,7 @@ mod tests { // TODO: `PlonkyButNotPlonkyGadget` is tmp, put better name. #[test] fn test_PlonkyButNotPlonkyGadget() -> Result<()> { + const L: usize = 0; // max num POD1-Introducer PODs // TODO use L!=0 const M: usize = 3; // max num SchnorrPOD const N: usize = 2; // max num Plonky2 recursive proof const NS: usize = 3; // num statements @@ -473,13 +524,18 @@ mod tests { // build the circuit_data, this struct is reused for all the calls of // PlonkyButNotPlonkyGadget::execute - let circuit_data = PlonkyButNotPlonkyGadget::::circuit_data()?; + let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_verifier_data = pod1_circuit_data.verifier_data(); + let circuit_data = + PlonkyButNotPlonkyGadget::::circuit_data(pod1_verifier_data)?; let verifier_data = circuit_data.verifier_data(); - let mut prover_params = - PlonkyButNotPlonkyGadget::::build_prover_params(circuit_data)?; + let mut prover_params = PlonkyButNotPlonkyGadget::::build_prover_params( + pod1_circuit_data, + circuit_data, + )?; let start = Instant::now(); - let new_pod = PlonkyButNotPlonkyGadget::::execute( + let new_pod = PlonkyButNotPlonkyGadget::::execute( &mut prover_params, &pods_list, op_list, @@ -488,7 +544,7 @@ mod tests { println!("PlonkyButNotPlonkyGadget::execute(): {:?}", start.elapsed()); // verify the new_pod's plonky2 proof - PlonkyButNotPlonkyGadget::::verify_plonky_pod(verifier_data, new_pod)?; + PlonkyButNotPlonkyGadget::::verify_plonky_pod(verifier_data, new_pod)?; // TODO do a 2nd iteration where the generated plonky2-pod is (recursively) verified Ok(()) @@ -496,11 +552,12 @@ mod tests { #[test] fn get_numbers_PlonkyButNotPlonkyGadget() -> Result<()> { - println!("| M | N | NS | VL | prove | total |"); - println!("|--- | --- | --- | --- | ------ | ------ |"); + println!("| L | M | N | NS | VL | prove | total |"); + println!("| --- | --- | --- | --- | --- | ------ | ------ |"); - test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<3, 1, 1, 0>()?; - test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<3, 1, 3, 0>()?; + // TODO use L!=0, maybe L=1 (to verify 1 POD1introducer POD at each recursion + test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<0, 3, 1, 1, 0>()?; + test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<0, 3, 1, 3, 0>()?; // the next tests are commented out by default because they take longer time to compute // test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<3, 1, 5, 0>()?; // test_empty_inputs_PlonkyButNotPlonkyGadget_opt::<3, 1, 10, 0>()?; @@ -519,13 +576,15 @@ mod tests { } fn test_empty_inputs_PlonkyButNotPlonkyGadget_opt< + const L: usize, // max num POD1-Introducer PODs // TODO use L!=0 const M: usize, // max num SchnorrPOD const N: usize, // max num Plonky2 recursive proof const NS: usize, // num statements const VL: usize, // vec length in contains op >() -> Result<()> where - [(); M + N]:, + [(); L + M + N]:, + [(); L + N]:, { let pods_list = vec![]; let out_statement_names = (0..NS) @@ -538,11 +597,16 @@ mod tests { .collect(), ); - let circuit_data = PlonkyButNotPlonkyGadget::::circuit_data()?; - let mut prover_params = - PlonkyButNotPlonkyGadget::::build_prover_params(circuit_data)?; + let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_verifier_data = pod1_circuit_data.verifier_data(); + let circuit_data = + PlonkyButNotPlonkyGadget::::circuit_data(pod1_verifier_data)?; + let mut prover_params = PlonkyButNotPlonkyGadget::::build_prover_params( + pod1_circuit_data, + circuit_data, + )?; - let _new_pod = PlonkyButNotPlonkyGadget::::execute( + let _new_pod = PlonkyButNotPlonkyGadget::::execute( &mut prover_params, &pods_list, op_list, diff --git a/pod2/src/pod/mod.rs b/pod2/src/pod/mod.rs index 3125520..04890ec 100644 --- a/pod2/src/pod/mod.rs +++ b/pod2/src/pod/mod.rs @@ -11,7 +11,7 @@ use serde::Serialize; use plonky2::field::types::PrimeField64; use std::collections::HashMap; -use crate::pod::gadget::plonky_pod::PlonkyButNotPlonkyGadget; +use crate::pod::gadget::{IntroducerCircuit, PlonkyButNotPlonkyGadget}; use crate::pod::{ entry::Entry, gadget::GadgetID, @@ -58,15 +58,23 @@ pub struct POD { } impl POD { + /// L: number of POD1-Introducer PODs /// M: number of PODs /// N: number of Plonky PODs /// NS: number of Statements /// VL: vector length - pub fn verify( + pub fn verify< + const L: usize, + const M: usize, + const N: usize, + const NS: usize, + const VL: usize, + >( &self, ) -> Result where - [(); M + N]:, + [(); L + M + N]:, + [(); L + N]:, { match &self.proof { PODProof::Schnorr(p) => { @@ -113,9 +121,12 @@ impl POD { // get the verifier_data on the fly) takes a considerable amount of time to // compute. Need to think how we modify the interface to pass the verifier_data to // this method. - let circuit_data = PlonkyButNotPlonkyGadget::::circuit_data()?; + let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_verifier_data = pod1_circuit_data.verifier_data(); + let circuit_data = + PlonkyButNotPlonkyGadget::::circuit_data(pod1_verifier_data)?; let verifier_data = circuit_data.verifier_data(); - PlonkyButNotPlonkyGadget::::verify_plonky_pod( + PlonkyButNotPlonkyGadget::::verify_plonky_pod( verifier_data, self.clone(), )?; @@ -231,15 +242,22 @@ impl POD { // the prover_params is passed as parameter, because compunting it depends on first computing // the circuit_data, which takes a considerable amount of time to compute. So we compute it // once at the beginning and just reuse it through all the calls to execute_plonky_gadget. - pub fn execute_plonky_gadget( - prover_params: &mut crate::pod::gadget::plonky_pod::ProverParams, + pub fn execute_plonky_gadget< + const L: usize, + const M: usize, + const N: usize, + const NS: usize, + const VL: usize, + >( + prover_params: &mut crate::pod::gadget::plonky_pod::ProverParams, input: &GPGInput, cmds: &[OpCmd], ) -> Result where - [(); M + N]:, + [(); L + M + N]:, + [(); L + N]:, { - PlonkyButNotPlonkyGadget::::execute( + PlonkyButNotPlonkyGadget::::execute( prover_params, &input.pods_list, crate::pod::operation::OpList(cmds.to_vec()), @@ -608,8 +626,8 @@ mod tests { &SchnorrSecretKey { sk: 42 }, )?; - assert!(schnorr_pod1.verify::<3, 2, 2, 0>()?); - assert!(schnorr_pod2.verify::<3, 2, 2, 0>()?); + assert!(schnorr_pod1.verify::<0, 3, 2, 2, 0>()?); // TODO use L!=0 + assert!(schnorr_pod2.verify::<0, 3, 2, 2, 0>()?); // TODO use L!=0 let mut schnorr_pod3 = POD::execute_schnorr_gadget::(&[entry1.clone()], &SchnorrSecretKey { sk: 25 })?; @@ -622,7 +640,7 @@ mod tests { schnorr_pod3.payload.statements_list[1].1 = other_statement; // now signature shouldn't verify - assert!(!(schnorr_pod3.verify::<3, 2, 2, 0>()?)); + assert!(!(schnorr_pod3.verify::<0, 3, 2, 2, 0>()?)); // TODO use L!=0 Ok(()) } @@ -736,7 +754,7 @@ mod tests { ]; let oracle_pod = POD::execute_oracle_gadget(&gpg_input, &ops).unwrap(); - assert!(oracle_pod.verify::<3, 2, 2, 0>()?); + assert!(oracle_pod.verify::<0, 3, 2, 2, 0>()?); // TODO use L!=0 // make another oracle POD which takes that oracle POD and a schnorr POD @@ -819,12 +837,13 @@ mod tests { for statement in oracle_pod2.payload.statements_list.iter() { println!("{:?}", statement); } - assert!(oracle_pod2.verify::<3, 2, 2, 0>()?); + assert!(oracle_pod2.verify::<0, 3, 2, 2, 0>()?); // TODO use L!=0 Ok(()) } #[test] fn plonky_pod_from_schnorr() -> Result<()> { + const L: usize = 0; // TODO L=0, use L!=0 const M: usize = 2; const N: usize = 1; const NS: usize = 3; @@ -884,12 +903,17 @@ mod tests { ), ]; - let circuit_data = PlonkyButNotPlonkyGadget::::circuit_data()?; - let mut prover_params = - PlonkyButNotPlonkyGadget::::build_prover_params(circuit_data)?; + let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_verifier_data = pod1_circuit_data.verifier_data(); + let circuit_data = + PlonkyButNotPlonkyGadget::::circuit_data(pod1_verifier_data)?; + let mut prover_params = PlonkyButNotPlonkyGadget::::build_prover_params( + pod1_circuit_data, + circuit_data, + )?; let plonky_pod = - POD::execute_plonky_gadget::(&mut prover_params, &gpg_input, &ops)?; - assert!(plonky_pod.verify::()? == true); + POD::execute_plonky_gadget::(&mut prover_params, &gpg_input, &ops)?; + assert!(plonky_pod.verify::()? == true); // make another oracle POD which takes that oracle POD and a schnorr POD @@ -928,11 +952,11 @@ mod tests { ]; let plonky_pod2 = - POD::execute_plonky_gadget::(&mut prover_params, &gpg_input, &ops)?; + POD::execute_plonky_gadget::(&mut prover_params, &gpg_input, &ops)?; for statement in plonky_pod2.payload.statements_list.iter() { println!("{:?}", statement); } - assert!(plonky_pod2.verify::()? == true); + assert!(plonky_pod2.verify::()? == true); Ok(()) } @@ -1049,7 +1073,7 @@ mod tests { ]; let bob_tf = POD::execute_oracle_gadget(&bob_tf_input, &bob_tf_ops).unwrap(); - assert!(bob_tf.verify::<3, 2, 2, 0>()?); + assert!(bob_tf.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 // make the "bob trusted friend" POD let mut charlie_tf_input_pods = HashMap::new(); @@ -1114,7 +1138,7 @@ mod tests { ]; let charlie_tf = POD::execute_oracle_gadget(&charlie_tf_input, &charlie_tf_ops).unwrap(); - assert!(charlie_tf.verify::<3, 2, 2, 0>()?); + assert!(charlie_tf.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 // make the "great boy" POD let age_bound_entry = Entry::new_from_scalar("known_attestors", GoldilocksField(17)); @@ -1284,7 +1308,7 @@ mod tests { ]; let alice_grb = POD::execute_oracle_gadget(&grb_input, &grb_ops).unwrap(); - assert!(alice_grb.verify::<3, 2, 2, 0>()?); + assert!(alice_grb.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 for statement in alice_grb.payload.statements_list { println!("{:?}", statement); @@ -1424,7 +1448,7 @@ mod tests { ]; let sum_pod = POD::execute_oracle_gadget(&sum_pod_input, &sum_pod_ops).unwrap(); - assert!(sum_pod.verify::<3, 2, 2, 0>()?); + assert!(sum_pod.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 // [defpod sum-pod // result 25 @@ -1459,7 +1483,7 @@ mod tests { ]; let product_pod = POD::execute_oracle_gadget(&product_pod_input, &product_pod_ops)?; - assert!(product_pod.verify::<3, 2, 2, 0>()?); + assert!(product_pod.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 // [defpod product-pod // result 1200 @@ -1573,7 +1597,7 @@ mod tests { ]; let final_pod = POD::execute_oracle_gadget(&final_pod_input, &final_pod_ops).unwrap(); - assert!(final_pod.verify::<3, 2, 2, 0>()?); + assert!(final_pod.verify::<0, 3, 2, 2, 0>()?); // TODO L=0, use L!=0 // If you are curious what the statements in this POD are // for statement in final_pod.payload.statements_list { diff --git a/pod2/src/recursion/recursion_framework.rs b/pod2/src/recursion/recursion_framework.rs index 962e246..e7b3565 100644 --- a/pod2/src/recursion/recursion_framework.rs +++ b/pod2/src/recursion/recursion_framework.rs @@ -78,7 +78,9 @@ where [(); L + N]:, { /// returns the full-recursive CircuitData - pub fn circuit_data(pod1_verifier_data: VerifierCircuitData) -> Result> { + pub fn circuit_data( + pod1_verifier_data: VerifierCircuitData, + ) -> Result> { RecursionCircuit::::circuit_data(pod1_verifier_data) } @@ -107,12 +109,21 @@ where ) -> Result { println!("prove_node:"); for i in 0..L + M + N { - let what = match i { - 0..L => "pod1 proof", - L..(L+M) => "inner circuit", - (L+M)..N => "recursive proof", - _ => "unknown", + let what = if i < L { + "pod1 proof" + } else if i > L && i < L + M { + "inner circuit" + } else if i > L + M && i < L + M + N { + "recursive proof" + } else { + "unknown" }; + // let what = match i { + // 0..L => "pod1 proof", + // L..(L+M) => "inner circuit", + // (L+M)..(L+M+N) => "recursive proof", + // _ => "unknown", + // }; if selectors[i].is_nonzero() { println!(" (selectors[{}] enabled), verify {}", i, what); } else { @@ -190,7 +201,9 @@ where [(); L + N]:, { /// returns the full-recursive CircuitData - pub fn circuit_data(pod1_verifier_data: VerifierCircuitData) -> Result> { + pub fn circuit_data( + pod1_verifier_data: VerifierCircuitData, + ) -> Result> { let mut data = common_data_for_recursion::()?; // build the actual RecursionCircuit circuit data From c4435cceabcbf9dd84415a4c7d32b75640da3d06 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 12 Nov 2024 16:43:41 +0100 Subject: [PATCH 4/5] add dummy logic to the IntroducerCircuit so that tests can be run --- pod2/src/pod/gadget/introducer.rs | 22 +++++++++++++++++++--- pod2/src/recursion/recursion_framework.rs | 16 ++++++++++------ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/pod2/src/pod/gadget/introducer.rs b/pod2/src/pod/gadget/introducer.rs index a09e055..26fecbb 100644 --- a/pod2/src/pod/gadget/introducer.rs +++ b/pod2/src/pod/gadget/introducer.rs @@ -19,15 +19,31 @@ use crate::{PlonkyProof, C, D, F}; pub struct IntroducerCircuit {} /// IntroducerCircuit defines the circuit whose plonky2 proof is verified in the RecursiveCircuit -/// (1-level recursion). +/// (1-level recursion). This is, the POD1-Introducer circuit. // TODO probably traitify this, and in the RecursionCircuit use the trait and not this specific // struct directly. +// But for the moment we can implement here the circuit that verifies a POD1 (POD1-Introducer). impl IntroducerCircuit { pub fn circuit_data() -> Result> { - todo!(); + let config = CircuitConfig::standard_recursion_zk_config(); + + let mut builder = CircuitBuilder::::new(config.clone()); + Self::circuit_logic(&mut builder); + + let data = builder.build::(); + Ok(data) } pub fn dummy_proof(circuit_data: CircuitData) -> Result { - todo!(); + let inputs = PartialWitness::new(); + let proof = circuit_data.prove(inputs)?; + Ok(proof.proof) + } + + pub fn circuit_logic(builder: &mut CircuitBuilder) { + let num_dummy_gates = 5_000; + for _ in 0..num_dummy_gates { + builder.add_gate(NoopGate, vec![]); + } } } diff --git a/pod2/src/recursion/recursion_framework.rs b/pod2/src/recursion/recursion_framework.rs index e7b3565..f0ca24a 100644 --- a/pod2/src/recursion/recursion_framework.rs +++ b/pod2/src/recursion/recursion_framework.rs @@ -289,7 +289,10 @@ where // pod1 proof verification let pod1_common_data = verifier_data.common.clone(); - let pod1_verifier_data_targ = builder.add_verifier_data_public_inputs(); + // notice that pod1_verifier_data is not registered as public input, while the cyclic + // recursive verifier_data is registered as public input. + let pod1_verifier_data_targ = builder + .add_virtual_verifier_data(pod1_verifier_data.common.config.fri_config.cap_height); let pod1_proofs_targ: Result<[ProofWithPublicInputsTarget; L]> = array::try_from_fn(|i| { @@ -467,7 +470,8 @@ where let _: O::Targets = O::add_targets(&mut builder)?; // pod1 proofs // TODO group with N in a single loop - let pod1_verifier_data = builder.add_verifier_data_public_inputs(); + let pod1_verifier_data = + builder.add_virtual_verifier_data(data.common.config.fri_config.cap_height); for _ in 0..L { let proof = builder.add_virtual_proof_with_pis(&data.common); builder.verify_proof::(&proof, &pod1_verifier_data, &data.common); @@ -567,14 +571,14 @@ mod tests { println!("\n--------------------------------------------------"); println!("\n--------------------------------------------------"); println!( - "\nrunning test:\n===test_tree_recursion_opt with M={} (num InnerCircuits) N={} (arity of the recursion tree)", - M, N + "\nrunning test:\n===test_tree_recursion_opt with L={} (num POD1-Introducer proofs) M={} (num InnerCircuits) N={} (arity of the recursion tree)", + L, M, N ); let l: u32 = 2; // levels of the recursion (binary) tree println!( - "Testing {} recursive iterations, where each iteration checks M={} InnerCircuits and N={} plonky2 proofs", - l, M, N + "Testing {} recursive iterations, where each iteration checks L={} POD1-Introducer plonky2 proofs, M={} InnerCircuits and N={} cyclic plonky2 proofs", + l, L, M, N ); let mut rng: rand::rngs::ThreadRng = rand::thread_rng(); From b22a7dcb70f45769d5abbc63d5455cbd4d5933bd Mon Sep 17 00:00:00 2001 From: arnaucube Date: Wed, 13 Nov 2024 13:15:17 +0100 Subject: [PATCH 5/5] Add IntroducerCircuitTrait and integrate it with the recursion framework. Add an example of IntroducerCircuitTrait (ExampleIntroducer) which verifies a Schnorr signature, that is, the RecursionCircuit will verify the plonky2 proof of that circuit (together with M Schnorr sigs, and N cyclic-recursion proofs from previous RecursionCircuits --- pod2/src/pod/gadget/introducer.rs | 40 +++++++------- pod2/src/pod/gadget/plonky_pod.rs | 3 +- pod2/src/pod/mod.rs | 2 + pod2/src/recursion/mod.rs | 2 +- pod2/src/recursion/recursion_framework.rs | 11 ++-- pod2/src/recursion/traits.rs | 65 ++++++++++++++++++++++- pod2/src/recursion/traits_examples.rs | 57 +++++++++++++++++++- 7 files changed, 151 insertions(+), 29 deletions(-) diff --git a/pod2/src/pod/gadget/introducer.rs b/pod2/src/pod/gadget/introducer.rs index 26fecbb..f8a84b2 100644 --- a/pod2/src/pod/gadget/introducer.rs +++ b/pod2/src/pod/gadget/introducer.rs @@ -14,36 +14,36 @@ use std::array; use std::marker::PhantomData; use std::time::Instant; +use crate::pod::gadget::SchnorrPODGadget; +use crate::recursion::IntroducerCircuitTrait; use crate::{PlonkyProof, C, D, F}; pub struct IntroducerCircuit {} /// IntroducerCircuit defines the circuit whose plonky2 proof is verified in the RecursiveCircuit /// (1-level recursion). This is, the POD1-Introducer circuit. -// TODO probably traitify this, and in the RecursionCircuit use the trait and not this specific -// struct directly. -// But for the moment we can implement here the circuit that verifies a POD1 (POD1-Introducer). -impl IntroducerCircuit { - pub fn circuit_data() -> Result> { - let config = CircuitConfig::standard_recursion_zk_config(); +impl IntroducerCircuitTrait for IntroducerCircuit { + type Input = (); // TODO + type Targets = (); - let mut builder = CircuitBuilder::::new(config.clone()); - Self::circuit_logic(&mut builder); - - let data = builder.build::(); - Ok(data) + /// return dummy inputs that will satisfy the circuit. This is used to generate the + /// dummy_proof. + fn dummy_inputs() -> Result { + todo!(); } - pub fn dummy_proof(circuit_data: CircuitData) -> Result { - let inputs = PartialWitness::new(); - let proof = circuit_data.prove(inputs)?; - Ok(proof.proof) + /// set up the circuit logic + fn add_targets(builder: &mut CircuitBuilder) -> Result { + todo!(); } - pub fn circuit_logic(builder: &mut CircuitBuilder) { - let num_dummy_gates = 5_000; - for _ in 0..num_dummy_gates { - builder.add_gate(NoopGate, vec![]); - } + /// set the actual witness values for the current instance of the circuit. Returns a Vec + /// containing the values that will be set as public inputs + fn set_targets( + pw: &mut PartialWitness, + targets: &Self::Targets, + input: &Self::Input, + ) -> Result<()> { + todo!(); } } diff --git a/pod2/src/pod/gadget/plonky_pod.rs b/pod2/src/pod/gadget/plonky_pod.rs index c36aeb5..be4e986 100644 --- a/pod2/src/pod/gadget/plonky_pod.rs +++ b/pod2/src/pod/gadget/plonky_pod.rs @@ -16,7 +16,7 @@ use crate::pod::operation::OpList; use crate::pod::payload::{PODPayload, StatementList}; use crate::pod::statement::Statement; use crate::pod::{GPGInput, PODProof, POD}; -use crate::recursion::RecursionCircuit; +use crate::recursion::{IntroducerCircuitTrait, RecursionCircuit}; use crate::signature::schnorr::SchnorrSecretKey; use crate::{PlonkyProof, C, D, F}; @@ -443,6 +443,7 @@ mod tests { statement::StatementRef, POD, }, + recursion::IntroducerCircuitTrait, signature::schnorr::SchnorrSecretKey, }; diff --git a/pod2/src/pod/mod.rs b/pod2/src/pod/mod.rs index 04890ec..4463060 100644 --- a/pod2/src/pod/mod.rs +++ b/pod2/src/pod/mod.rs @@ -18,6 +18,7 @@ use crate::pod::{ payload::{HashablePayload, PODPayload}, value::ScalarOrVec, }; +use crate::recursion::IntroducerCircuitTrait; use crate::signature::schnorr::{ SchnorrPublicKey, SchnorrSecretKey, SchnorrSignature, SchnorrSigner, }; @@ -463,6 +464,7 @@ impl GPGInput { #[cfg(test)] mod tests { + use crate::recursion::IntroducerCircuitTrait; use operation::Operation as Op; use parcnet_pod::{pod::pod_impl::create_pod, pod_entries}; use statement::StatementRef; diff --git a/pod2/src/recursion/mod.rs b/pod2/src/recursion/mod.rs index de8f8fb..6b4fdc4 100644 --- a/pod2/src/recursion/mod.rs +++ b/pod2/src/recursion/mod.rs @@ -5,4 +5,4 @@ pub mod utils; // expose at the recursion module level the objects needed to use it pub use recursion_framework::{RecursionCircuit, RecursionTree}; -pub use traits::{InnerCircuitTrait, OpsExecutorTrait}; +pub use traits::{InnerCircuitTrait, IntroducerCircuitTrait, OpsExecutorTrait}; diff --git a/pod2/src/recursion/recursion_framework.rs b/pod2/src/recursion/recursion_framework.rs index f0ca24a..86c4548 100644 --- a/pod2/src/recursion/recursion_framework.rs +++ b/pod2/src/recursion/recursion_framework.rs @@ -107,7 +107,7 @@ where inner_circuits_input: [I::Input; M], recursive_proofs: &[PlonkyProof; N], ) -> Result { - println!("prove_node:"); + println!("prove_node with L={}, M={}, N={}:", L, M, N); for i in 0..L + M + N { let what = if i < L { "pod1 proof" @@ -533,9 +533,10 @@ mod tests { use super::*; - use crate::pod::gadget::{IntroducerCircuit, SchnorrPODGadget}; + use crate::pod::gadget::SchnorrPODGadget; + use crate::recursion::traits::IntroducerCircuitTrait; use crate::recursion::traits_examples::{ - ExampleGadget, ExampleGadgetInput, ExampleOpsExecutor, + ExampleGadget, ExampleGadgetInput, ExampleIntroducer, ExampleOpsExecutor, }; use crate::signature::schnorr::*; @@ -606,9 +607,9 @@ mod tests { assert_eq!(sig_vec.len(), M); // POD1 introducer logic: - let pod1_circuit_data = IntroducerCircuit::circuit_data()?; + let pod1_circuit_data = ExampleIntroducer::circuit_data()?; let pod1_verifier_data = pod1_circuit_data.verifier_data(); - let pod1_dummy_proof: PlonkyProof = IntroducerCircuit::dummy_proof(pod1_circuit_data)?; + let pod1_dummy_proof: PlonkyProof = ExampleIntroducer::dummy_proof(pod1_circuit_data)?; let pod1_proofs: [PlonkyProof; L] = array::from_fn(|k| pod1_dummy_proof.clone()); let pod1_public_inputs: [Vec; L] = array::from_fn(|k| vec![]); diff --git a/pod2/src/recursion/traits.rs b/pod2/src/recursion/traits.rs index 7ea2d88..2f7ac42 100644 --- a/pod2/src/recursion/traits.rs +++ b/pod2/src/recursion/traits.rs @@ -3,7 +3,70 @@ use plonky2::iop::target::BoolTarget; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; -use crate::{D, F}; +use plonky2::plonk::circuit_data::CircuitConfig; +use plonky2::plonk::circuit_data::CircuitData; +use plonky2::plonk::circuit_data::ProverCircuitData; + +use crate::{PlonkyProof, C, D, F}; + +/// IntroducerCircuitTrait defines the circuit whose plonky2 proof is verified in the +/// RecursiveCircuit (1-level recursion). This is, the POD1-Introducer circuit. +/// +/// Notice that the methods `circuit_data`, `dummy_proof`, `build_prover` are already implemented +/// at the trait level, in a generic way agnostic to the specific logic of the circuit. So the only +/// methods that need to be implemented are `add_targets` and `set_targets`. +pub trait IntroducerCircuitTrait { + type Targets; + type Input; + + fn circuit_data() -> Result> { + let config = CircuitConfig::standard_recursion_zk_config(); + + let mut builder = CircuitBuilder::::new(config.clone()); + Self::add_targets(&mut builder); + + let data = builder.build::(); + Ok(data) + } + fn dummy_proof(circuit_data: CircuitData) -> Result { + // fn dummy_proof(prover: ProverCircuitData) -> Result { + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::new(config); + + // prepare some dummy signature + let input = Self::dummy_inputs()?; + + let targets = Self::add_targets(&mut builder)?; + + let mut pw = PartialWitness::new(); + Self::set_targets(&mut pw, &targets, &input)?; + + let proof = circuit_data.prove(pw)?; + Ok(proof.proof) + } + fn build_prover() -> Result> { + let config = CircuitConfig::standard_recursion_config(); + let mut builder = CircuitBuilder::new(config); + + let _ = Self::add_targets(&mut builder)?; + + Ok(builder.build_prover::()) + } + + /// return dummy inputs that will satisfy the circuit. This is used to generate the + /// dummy_proof. + fn dummy_inputs() -> Result; + + /// set up the circuit logic + fn add_targets(builder: &mut CircuitBuilder) -> Result; + + /// set the actual witness values for the current instance of the circuit + fn set_targets( + pw: &mut PartialWitness, + targets: &Self::Targets, + input: &Self::Input, + ) -> Result<()>; +} /// InnerCircuit is the trait that is used to define the logic of the circuit that is used at each /// node of the recursive tree. diff --git a/pod2/src/recursion/traits_examples.rs b/pod2/src/recursion/traits_examples.rs index 98ed604..6be9da3 100644 --- a/pod2/src/recursion/traits_examples.rs +++ b/pod2/src/recursion/traits_examples.rs @@ -1,6 +1,7 @@ /// This file contains a simple example implementing the InnerCircuit trait, by a circuit that /// checks a signature over the given msg. use anyhow::Result; +use plonky2::field::types::Field; use plonky2::iop::target::BoolTarget; use plonky2::iop::witness::PartialWitness; use plonky2::plonk::circuit_builder::CircuitBuilder; @@ -10,9 +11,63 @@ use crate::pod::circuit::operation::OperationTarget; use crate::signature::schnorr::*; use crate::signature::schnorr_prover::*; -use super::{utils::assert_one_if_enabled, InnerCircuitTrait, OpsExecutorTrait}; +use super::{ + utils::assert_one_if_enabled, InnerCircuitTrait, IntroducerCircuitTrait, OpsExecutorTrait, +}; use crate::{C, D, F}; +pub struct ExampleIntroducer {} + +impl IntroducerCircuitTrait for ExampleIntroducer { + type Targets = ExampleGadgetTargets; + type Input = ExampleGadgetInput; + + /// Notice that the methods `circuit_data`, `dummy_proof`, `build_prover` are already + /// implemented at the trait level, in a generic way agnostic to the specific logic of the + /// circuit. + + fn dummy_inputs() -> Result { + let mut rng: rand::rngs::ThreadRng = rand::thread_rng(); + let schnorr = SchnorrSigner::new(); + let msg: Vec = vec![F::ZERO, F::ZERO, F::ZERO, F::ZERO]; + let sk: SchnorrSecretKey = SchnorrSecretKey { sk: 0u64 }; + let pk: SchnorrPublicKey = schnorr.keygen(&sk); + let sig: SchnorrSignature = schnorr.sign(&msg.to_vec(), &sk, &mut rng); + Ok(Self::Input { pk, sig, msg }) + } + + fn add_targets(builder: &mut CircuitBuilder) -> Result { + // signature verification: + let sb: SchnorrBuilder = SchnorrBuilder {}; + let pk_targ = SchnorrPublicKeyTarget::new_virtual(builder); + let sig_targ = SchnorrSignatureTarget::new_virtual(builder); + let msg_targ = MessageTarget::new_with_size(builder, 4); + let sig_verif_targ = sb.verify_sig::(builder, &sig_targ, &msg_targ, &pk_targ); + + let true_target = builder._true(); + builder.connect(sig_verif_targ.target, true_target.target); + + Ok(Self::Targets { + pk_targ, + sig_targ, + msg_targ, + }) + } + + fn set_targets( + pw: &mut PartialWitness, + targets: &Self::Targets, + pod: &Self::Input, + ) -> Result<()> { + // set signature related values: + targets.pk_targ.set_witness(pw, &pod.pk).unwrap(); + targets.sig_targ.set_witness(pw, &pod.sig).unwrap(); + targets.msg_targ.set_witness(pw, &pod.msg).unwrap(); + + Ok(()) + } +} + pub struct ExampleGadgetInput { pub pk: SchnorrPublicKey, pub sig: SchnorrSignature,