@ -1,43 +1,78 @@
/*
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 ;
/// N-arity tree of recursion with conditionals.
///
/// p_root
/// ▲
/// │
/// ┌────────┐
/// │ F │
/// └────────┘
/// ▲ ▲ ▲ ▲
/// ┌─┘ │ │ └─┐
/// ┌────┘ ┌─┘ └┐ └───┐
/// │ │ ... │ │
/// ┌────────┐┌┴┐┌─┐┌┴┐ ┌────────┐
/// │ F ││.││.││.│ │ F │
/// └────────┘└─┘└─┘└─┘ └────────┘
/// ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
/// ┌─┘ │ └┐ └─┐ ┌─┘┌┘ └┐ └┐
/// │ │ │ │ │ │ │ │
/// p_1 p_2 ... p_n p'_1 p'_2... p'_n
///
///
/// where each p_i is either
/// - signature verification
/// - recursive plonky2 proof (proof that verifies previous proof)
/// (generated by `RecursiveCircuit::prove_step` method)
/// in other words, each p_i is checking:
/// `(signature proof OR recursive proof)`
///
/// Each node of the recursion tree, ie. each F, verifies the N incoming p_i's, that is
/// `(signature proof OR recursive proof) AND ... AND (signature proof OR recursive proof)`
/// and produces a new proof.
///
///
/// For example, if N is set to N=2, then we work with a binary recursion tree:
/// p_root
/// ▲
/// │
/// ┌─┴─┐
/// │ F │
/// └───┘
/// ▲ ▲
/// ┌─┘ └─┐
/// ┌───┘ └───┐
/// │p_5 │p_6
/// ┌─┴─┐ ┌─┴─┐
/// │ F │ │ F │
/// └───┘ └───┘
/// ▲ ▲ ▲ ▲
/// ┌─┘ └─┐ ┌─┘ └─┐
/// │ │ │ │
/// p_1 p_2 p_3 p_4
///
/// So that each node (F box) is verifying 2 p_i's, ie:
/// `(signature proof OR recursive proof) AND (signature proof OR recursive proof)`
///
///
/// With N=3, each node will be verifying 3 p_i's.
/// `(signature proof OR recursive proof) AND (signature proof OR recursive proof) AND (signature proof OR recursive proof)`
///
///
///
/// Also, notice that if we set N=1, it is directly a linear chain of recursive proofs ('tree' of
/// arity 1):
/// ┌─┐ ┌─┐ ┌─┐ ┌─┐
/// ─────►│F├────►│F├────►│F├────►│F├────►
/// p_1 └─┘ p_2 └─┘ p_3 └─┘ p_4 └─┘ p_5
///
/// where each p_i is proving: `(signature proof OR recursive proof)`.
///
///
/// To run the tests that checks this logic:
/// cargo test --release test_tree_recursion -- --nocapture
use anyhow ::{ anyhow , Result } ;
use plonky2 ::field ::types ::Field ;
use plonky2 ::field ::types ::Field ;
use plonky2 ::gates ::noop ::NoopGate ;
use plonky2 ::gates ::noop ::NoopGate ;
use plonky2 ::iop ::target ::{ BoolTarget , Target } ;
use plonky2 ::iop ::witness ::{ PartialWitness , WitnessWrite } ;
use plonky2 ::iop ::witness ::{ PartialWitness , WitnessWrite } ;
use plonky2 ::plonk ::circuit_builder ::CircuitBuilder ;
use plonky2 ::plonk ::circuit_builder ::CircuitBuilder ;
use plonky2 ::plonk ::circuit_data ::{
use plonky2 ::plonk ::circuit_data ::{
@ -49,121 +84,23 @@ use std::time::Instant;
use sch ::schnorr ::* ;
use sch ::schnorr ::* ;
use sch ::schnorr_prover ::* ;
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 ) ;
}
use super ::{ sig_gadget ::SignatureGadgetTargets , PlonkyProof , C , D , F } ;
/// Contains the methods to `build` (ie. create the targets, the logic of the circuit), and
/// 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).
/// `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 {
pub struct RecursiveCircuit < const N : usize > {
msg_targ : MessageTarget ,
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).
sigs_targ : Vec < SignatureGadgetTargets > ,
proofs_targ : Vec < ProofWithPublicInputsTarget < D > > ,
// the next two are common for all the given proofs. It is the data for this circuit itself
// (cyclic circuit).
verifier_data_targ : VerifierCircuitTarget ,
verifier_data_targ : VerifierCircuitTarget ,
verifier_data : VerifierCircuitData < F , C , 2 > ,
verifier_data : VerifierCircuitData < F , C , D > ,
}
}
impl RecursiveCircuit {
impl < const N : usize > RecursiveCircuit < N > {
pub fn prepare_public_inputs (
pub fn prepare_public_inputs (
verifier_data : VerifierCircuitData < F , C , 2 > ,
verifier_data : VerifierCircuitData < F , C , D > ,
msg : Vec < F > ,
msg : Vec < F > ,
) -> Vec < F > {
) -> Vec < F > {
[
[
@ -180,11 +117,12 @@ impl RecursiveCircuit {
]
]
. concat ( )
. concat ( )
}
}
// notice that this method does not fill the targets, which is done in the method
// notice that this method does not fill the targets, which is done in the method
// `fill_recursive_circuit_targets`
// `fill_recursive_circuit_targets`
pub fn build (
pub fn build (
builder : & mut CircuitBuilder < F , 2 > ,
verifier_data : VerifierCircuitData < F , C , 2 > ,
builder : & mut CircuitBuilder < F , D > ,
verifier_data : VerifierCircuitData < F , C , D > ,
msg_len : usize ,
msg_len : usize ,
) -> Result < Self > {
) -> Result < Self > {
let msg_targ = MessageTarget ::new_with_size ( builder , msg_len ) ;
let msg_targ = MessageTarget ::new_with_size ( builder , msg_len ) ;
@ -192,33 +130,32 @@ impl RecursiveCircuit {
builder . register_public_inputs ( & msg_targ . msg ) ;
builder . register_public_inputs ( & msg_targ . msg ) ;
// build the signature verification logic
// build the signature verification logic
let L_sig_targets = SignatureGadgetTargets ::build ( builder , & msg_targ ) ? ;
let R_sig_targets = SignatureGadgetTargets ::build ( builder , & msg_targ ) ? ;
let mut sigs_targ : Vec < SignatureGadgetTargets > = vec ! [ ] ;
for _ in 0 . . N {
let sig_targets = SignatureGadgetTargets ::build ( builder , & msg_targ ) ? ;
sigs_targ . push ( sig_targets ) ;
}
// proof verification:
// proof verification:
let common_data = verifier_data . common . clone ( ) ;
let common_data = verifier_data . common . clone ( ) ;
let verifier_data_targ = builder . add_verifier_data_public_inputs ( ) ;
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 ,
) ? ;
let mut proofs_targ : Vec < ProofWithPublicInputsTarget < D > > = vec ! [ ] ;
for i in 0 . . N {
let proof_targ = builder . add_virtual_proof_with_pis ( & common_data ) ;
builder . conditionally_verify_cyclic_proof_or_dummy ::< C > (
sigs_targ [ i ] . selector_booltarg ,
& proof_targ ,
& common_data ,
) ? ;
proofs_targ . push ( proof_targ ) ;
}
Ok ( Self {
Ok ( Self {
msg_targ ,
msg_targ ,
L_sig_targets ,
R_sig_targets ,
L_proof_targ ,
R_proof_targ ,
sigs_targ ,
proofs_targ ,
verifier_data_targ ,
verifier_data_targ ,
verifier_data ,
verifier_data ,
} )
} )
@ -228,25 +165,18 @@ impl RecursiveCircuit {
& mut self ,
& mut self ,
pw : & mut PartialWitness < F > ,
pw : & mut PartialWitness < F > ,
msg : & Vec < 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 ,
selectors : Vec < F > , // 1=proof, 0=sig
pks : & Vec < SchnorrPublicKey > ,
sigs : & Vec < SchnorrSignature > ,
recursive_proofs : & Vec < PlonkyProof > ,
) -> Result < ( ) > {
) -> Result < ( ) > {
// set the msg value (used by both sig gadgets, left and right )
// set the msg value (used by all N sig gadgets)
self . msg_targ . set_witness ( pw , & msg ) . unwrap ( ) ;
self . msg_targ . set_witness ( pw , & msg ) . unwrap ( ) ;
// set the signature related values
// 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 ) ? ;
for i in 0 . . N {
self . sigs_targ [ i ] . fill_targets ( pw , selectors [ i ] , & pks [ i ] , & sigs [ i ] ) ? ;
}
// set proof related values:
// set proof related values:
@ -254,52 +184,45 @@ impl RecursiveCircuit {
pw . set_verifier_data_target ( & self . verifier_data_targ , & self . verifier_data . verifier_only ) ? ;
pw . set_verifier_data_target ( & self . verifier_data_targ , & self . verifier_data . verifier_only ) ? ;
let public_inputs =
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 ,
} ,
) ? ;
RecursiveCircuit ::< N > ::prepare_public_inputs ( self . verifier_data . clone ( ) , msg . clone ( ) ) ;
for i in 0 . . N {
pw . set_proof_with_pis_target (
& self . proofs_targ [ i ] ,
& ProofWithPublicInputs {
proof : recursive_proofs [ i ] . clone ( ) ,
public_inputs : public_inputs . clone ( ) ,
} ,
) ? ;
}
Ok ( ( ) )
Ok ( ( ) )
}
}
}
}
#[ derive(Debug, Clone) ]
#[ derive(Debug, Clone) ]
pub struct Recursion { }
pub struct Recursion < const N : usize > { }
pub fn common_data_for_recursion ( msg_len : usize ) -> CircuitData < F , C , 2 > {
pub fn common_data_for_recursion < const N : usize > ( msg_len : usize ) -> Result < CircuitData < F , C , D > > {
// 1st
// 1st
let config = CircuitConfig ::standard_recursion_config ( ) ;
let config = CircuitConfig ::standard_recursion_config ( ) ;
let builder = CircuitBuilder ::< F , 2 > ::new ( config ) ;
let builder = CircuitBuilder ::< F , D > ::new ( config ) ;
let data = builder . build ::< C > ( ) ;
let data = builder . build ::< C > ( ) ;
// 2nd
// 2nd
let config = CircuitConfig ::standard_recursion_config ( ) ;
let config = CircuitConfig ::standard_recursion_config ( ) ;
let mut builder = CircuitBuilder ::< F , 2 > ::new ( config . clone ( ) ) ;
let mut builder = CircuitBuilder ::< F , D > ::new ( config . clone ( ) ) ;
let verifier_data = builder . add_virtual_verifier_data ( data . common . config . fri_config . cap_height ) ;
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 ) ;
// proofs
for _ in 0 . . N {
let proof = builder . add_virtual_proof_with_pis ( & data . common ) ;
builder . verify_proof ::< C > ( & proof , & verifier_data , & data . common ) ;
}
// let n_gates = builder.num_gates();
let data = builder . build ::< C > ( ) ;
let data = builder . build ::< C > ( ) ;
// 3rd
// 3rd
let config = CircuitConfig ::standard_recursion_config ( ) ;
let config = CircuitConfig ::standard_recursion_config ( ) ;
let mut builder = CircuitBuilder ::< F , 2 > ::new ( config . clone ( ) ) ;
let mut builder = CircuitBuilder ::< F , D > ::new ( config . clone ( ) ) ;
let msg_targ = MessageTarget ::new_with_size ( & mut builder , msg_len ) ;
let msg_targ = MessageTarget ::new_with_size ( & mut builder , msg_len ) ;
// sigs verify
// sigs verify
builder . register_public_inputs ( & msg_targ . msg ) ;
builder . register_public_inputs ( & msg_targ . msg ) ;
@ -318,58 +241,70 @@ pub fn common_data_for_recursion(msg_len: usize) -> CircuitData {
// proofs verify
// proofs verify
let verifier_data = builder . add_verifier_data_public_inputs ( ) ;
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 ) ;
// proofs
for _ in 0 . . N {
let proof = builder . add_virtual_proof_with_pis ( & data . common ) ;
builder . verify_proof ::< C > ( & proof , & verifier_data , & data . common ) ;
}
// pad min gates
// pad min gates
while builder . num_gates ( ) < 1 < < 13 {
let n_gates = compute_num_gates ::< N > ( ) ? ;
while builder . num_gates ( ) < n_gates {
builder . add_gate ( NoopGate , vec ! [ ] ) ;
builder . add_gate ( NoopGate , vec ! [ ] ) ;
}
}
builder . build ::< C > ( )
dbg ! ( builder . num_gates ( ) ) ;
Ok ( builder . build ::< C > ( ) )
}
fn compute_num_gates < const N : usize > ( ) -> Result < usize > {
// Note: the following numbers are WIP, obtained by trial-error by running different
// configurations in the tests.
let n_gates = match N {
1 = > 1 < < 12 ,
2 = > 1 < < 13 ,
3 . . = 5 = > 1 < < 14 ,
6 = > 1 < < 15 ,
_ = > 0 ,
} ;
if n_gates = = 0 {
return Err ( anyhow ! (
"arity of N={} not supported yet. Currently supported N from 1 to 6 (both included)" ,
N
) ) ;
}
Ok ( n_gates )
}
}
impl Recursion {
impl < const N : usize > Recursion < N > {
/// returns the full-recursive CircuitData
/// 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 ) ;
pub fn circuit_data ( msg_len : usize ) -> Result < CircuitData < F , C , D > > {
let mut data = common_data_for_recursion ::< N > ( msg_len ) ? ;
// build the actual RecursiveCircuit circuit data
// build the actual RecursiveCircuit circuit data
let config = CircuitConfig ::standard_recursion_config ( ) ;
let config = CircuitConfig ::standard_recursion_config ( ) ;
let mut builder = CircuitBuilder ::new ( config ) ;
let mut builder = CircuitBuilder ::new ( config ) ;
let _ = RecursiveCircuit ::build ( & mut builder , data . verifier_data ( ) , msg_len ) ? ;
let _ = RecursiveCircuit ::< N > ::build ( & mut builder , data . verifier_data ( ) , msg_len ) ? ;
dbg ! ( builder . num_gates ( ) ) ;
data = builder . build ::< C > ( ) ;
data = builder . build ::< C > ( ) ;
Ok ( data )
Ok ( data )
}
}
pub fn prove_step (
pub fn prove_step (
verifier_data : VerifierCircuitData < F , C , 2 > ,
verifier_data : VerifierCircuitData < F , C , D > ,
msg : & Vec < F > ,
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 ,
selectors : Vec < F > , // 1=proof, 0=sig
pks : & Vec < SchnorrPublicKey > ,
sigs : & Vec < SchnorrSignature > ,
recursive_proofs : & Vec < PlonkyProof > ,
) -> Result < PlonkyProof > {
) -> Result < PlonkyProof > {
println ! ( "prove_step:" ) ;
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" ) ;
for i in 0 . . N {
if selectors [ i ] . is_nonzero ( ) {
println ! ( " (selectors[{}]==1), verify {}-th proof" , i , i ) ;
} else {
println ! ( " (selectors[{}]==0), verify {}-th signature" , i , i ) ;
}
}
}
let config = CircuitConfig ::standard_recursion_config ( ) ;
let config = CircuitConfig ::standard_recursion_config ( ) ;
@ -377,24 +312,14 @@ impl Recursion {
// assign the targets
// assign the targets
let start = Instant ::now ( ) ;
let start = Instant ::now ( ) ;
let mut circuit = RecursiveCircuit ::build ( & mut builder , verifier_data . clone ( ) , msg . len ( ) ) ? ;
let mut circuit =
RecursiveCircuit ::< N > ::build ( & mut builder , verifier_data . clone ( ) , msg . len ( ) ) ? ;
println ! ( "RecursiveCircuit::build(): {:?}" , start . elapsed ( ) ) ;
println ! ( "RecursiveCircuit::build(): {:?}" , start . elapsed ( ) ) ;
// fill the targets
// fill the targets
let mut pw = PartialWitness ::new ( ) ;
let mut pw = PartialWitness ::new ( ) ;
let start = Instant ::now ( ) ;
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 ,
) ? ;
circuit . fill_targets ( & mut pw , msg , selectors , pks , sigs , recursive_proofs ) ? ;
println ! ( "circuit.fill_targets(): {:?}" , start . elapsed ( ) ) ;
println ! ( "circuit.fill_targets(): {:?}" , start . elapsed ( ) ) ;
let start = Instant ::now ( ) ;
let start = Instant ::now ( ) ;
@ -449,16 +374,36 @@ mod tests {
/// cargo test --release test_tree_recursion -- --nocapture
/// cargo test --release test_tree_recursion -- --nocapture
#[ test ]
#[ test ]
fn test_tree_recursion ( ) -> Result < ( ) > {
fn test_tree_recursion ( ) -> Result < ( ) > {
// For testing: change the following `N` value to try different arities of the recursion tree:
test_tree_recursion_opt ::< 2 > ( ) ? ; // N=2
test_tree_recursion_opt ::< 3 > ( ) ? ; // N=3
Ok ( ( ) )
}
fn test_tree_recursion_opt < const N : usize > ( ) -> Result < ( ) > {
set_log ( ) ;
set_log ( ) ;
println ! ( "\n--------------------------------------------------" ) ;
println ! ( "\n--------------------------------------------------" ) ;
println ! (
"\nrunning test:\n test_tree_recursion_opt with N={} (arity)" ,
N
) ;
let l : u32 = 2 ; // levels of the recursion (binary) tree
let k = ( N as u32 ) . pow ( l ) as usize ; // number of leafs in the recursion tree, N^l
println ! (
"Testing a {}-arity recursion tree, of {} levels, with {} leaves" ,
N , l , k
) ;
let mut rng : rand ::rngs ::ThreadRng = rand ::thread_rng ( ) ;
let mut rng : rand ::rngs ::ThreadRng = rand ::thread_rng ( ) ;
let schnorr = SchnorrSigner ::new ( ) ;
let schnorr = SchnorrSigner ::new ( ) ;
const MSG_LEN : usize = 5 ;
const MSG_LEN : usize = 5 ;
let msg : Vec < F > = schnorr . u64_into_goldilocks_vec ( vec ! [ 1500 , 1600 , 2 , 2 , 2 ] ) ;
let msg : Vec < F > = schnorr . u64_into_goldilocks_vec ( vec ! [ 1500 , 1600 , 2 , 2 , 2 ] ) ;
assert_eq ! ( msg . len ( ) , MSG_LEN ) ;
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
// generate k key pairs
let sk_vec : Vec < SchnorrSecretKey > =
let sk_vec : Vec < SchnorrSecretKey > =
( 0 . . k ) . map ( | i | SchnorrSecretKey { sk : i as u64 } ) . collect ( ) ;
( 0 . . k ) . map ( | i | SchnorrSecretKey { sk : i as u64 } ) . collect ( ) ;
@ -470,11 +415,9 @@ mod tests {
. collect ( ) ;
. collect ( ) ;
// build the circuit_data & verifier_data for the recursive circuit
// build the circuit_data & verifier_data for the recursive circuit
let circuit_data = Recursion ::circuit_data ( MSG_LEN ) ? ;
let circuit_data = Recursion ::< N > ::circuit_data ( MSG_LEN ) ? ;
let verifier_data = circuit_data . verifier_data ( ) ;
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 (
let dummy_proof_pis = cyclic_base_proof (
& circuit_data . common ,
& circuit_data . common ,
& verifier_data . verifier_only ,
& verifier_data . verifier_only ,
@ -493,33 +436,49 @@ mod tests {
let mut next_level_proofs : Vec < PlonkyProof > = vec ! [ ] ;
let mut next_level_proofs : Vec < PlonkyProof > = vec ! [ ] ;
// loop over the nodes of each recursion tree level
// 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 ) ;
for j in ( 0 . . proofs_at_level_i . len ( ) ) . into_iter ( ) . step_by ( N ) {
println ! (
"\n------ recursion node: (level) i={}, (node in level) j={}" ,
i , j
) ;
// - if we're at the first level of the recursion tree:
// - 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.
// proof_enabled=false=0, so that the circuit verifies the signature and not the proof.
// - else:
// - else:
// proof_enabled=true=1, so that the circuit verifies the proof and not the signature.
// 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.
// In future tests we will try other cases (eg. some sigs and some proofs in a
// node), 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 } ;
let proof_enabled = if i = = 0 { F ::ZERO } else { F ::ONE } ;
// prepare the inputs for the `Recursion::prove_step` call
let proofs_selectors = ( 0 . . N ) . into_iter ( ) . map ( | _ | proof_enabled . clone ( ) ) . collect ( ) ;
let pks = ( 0 . . N )
. into_iter ( )
. enumerate ( )
. map ( | ( k , _ ) | pk_vec [ j + k ] . clone ( ) )
. collect ( ) ;
let sigs = ( 0 . . N )
. into_iter ( )
. enumerate ( )
. map ( | ( k , _ ) | sig_vec [ j + k ] . clone ( ) )
. collect ( ) ;
let proofs = ( 0 . . N )
. into_iter ( )
. enumerate ( )
. map ( | ( k , _ ) | proofs_at_level_i [ j + k ] . clone ( ) )
. collect ( ) ;
// do the recursive step
// do the recursive step
let start = Instant ::now ( ) ;
let start = Instant ::now ( ) ;
let new_proof = Recursion ::prove_step (
let new_proof = Recursion ::< N > ::prove_step (
verifier_data . clone ( ) ,
verifier_data . clone ( ) ,
& msg ,
& 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 ] ,
proofs_selectors ,
& pks ,
& sigs ,
& proofs ,
) ? ;
) ? ;
println ! (
println ! (
"Recursion::prove_step (level: i={}, node: j={}) took: {:?}" ,
"Recursion::prove_step (level: i={}, node: j={}) took: {:?}" ,
@ -529,8 +488,10 @@ mod tests {
) ;
) ;
// verify the recursive proof
// verify the recursive proof
let public_inputs =
RecursiveCircuit ::prepare_public_inputs ( verifier_data . clone ( ) , msg . clone ( ) ) ;
let public_inputs = RecursiveCircuit ::< N > ::prepare_public_inputs (
verifier_data . clone ( ) ,
msg . clone ( ) ,
) ;
verifier_data . clone ( ) . verify ( ProofWithPublicInputs {
verifier_data . clone ( ) . verify ( ProofWithPublicInputs {
proof : new_proof . clone ( ) ,
proof : new_proof . clone ( ) ,
public_inputs : public_inputs . clone ( ) ,
public_inputs : public_inputs . clone ( ) ,
@ -546,7 +507,7 @@ mod tests {
// verify the last proof
// verify the last proof
let public_inputs =
let public_inputs =
RecursiveCircuit ::prepare_public_inputs ( verifier_data . clone ( ) , msg . clone ( ) ) ;
RecursiveCircuit ::< N > ::prepare_public_inputs ( verifier_data . clone ( ) , msg . clone ( ) ) ;
verifier_data . clone ( ) . verify ( ProofWithPublicInputs {
verifier_data . clone ( ) . verify ( ProofWithPublicInputs {
proof : last_proof . clone ( ) ,
proof : last_proof . clone ( ) ,
public_inputs : public_inputs . clone ( ) ,
public_inputs : public_inputs . clone ( ) ,
@ -554,5 +515,4 @@ mod tests {
Ok ( ( ) )
Ok ( ( ) )
}
}
// WIP will add more tests with other sig/proof combinations
}
}