@@ -5,6 +5,7 @@ import { Tuple } from '../util/types.js';
55import { Proof } from './proof.js' ;
66import { mapObject , mapToObject , zip } from '../util/arrays.js' ;
77import { Undefined , Void } from './zkprogram.js' ;
8+ import { Bool } from '../provable/bool.js' ;
89
910export { Recursive } ;
1011
@@ -38,7 +39,13 @@ function Recursive<
3839 InferProvable < PublicInputType > ,
3940 InferProvable < PublicOutputType > ,
4041 PrivateInputs [ Key ]
41- > ;
42+ > & {
43+ if : ConditionalRecursiveProver <
44+ InferProvable < PublicInputType > ,
45+ InferProvable < PublicOutputType > ,
46+ PrivateInputs [ Key ]
47+ > ;
48+ } ;
4249} {
4350 type PublicInput = InferProvable < PublicInputType > ;
4451 type PublicOutput = InferProvable < PublicOutputType > ;
@@ -62,11 +69,17 @@ function Recursive<
6269
6370 let methodKeys : MethodKey [ ] = Object . keys ( methods ) ;
6471
65- let regularRecursiveProvers = mapObject ( zkprogram , ( prover , key ) => {
72+ let regularRecursiveProvers = mapToObject ( methodKeys , ( key ) => {
6673 return async function proveRecursively_ (
74+ conditionAndConfig : Bool | { condition : Bool ; domainLog2 ?: number } ,
6775 publicInput : PublicInput ,
6876 ...args : TupleToInstances < PrivateInputs [ MethodKey ] >
69- ) {
77+ ) : Promise < PublicOutput > {
78+ let condition =
79+ conditionAndConfig instanceof Bool
80+ ? conditionAndConfig
81+ : conditionAndConfig . condition ;
82+
7083 // create the base proof in a witness block
7184 let proof = await Provable . witnessAsync ( SelfProof , async ( ) => {
7285 // move method args to constants
@@ -77,6 +90,24 @@ function Recursive<
7790 let constArgs = zip ( args , privateInputs [ key ] ) . map ( ( [ arg , type ] ) =>
7891 Provable . toConstant ( type , arg )
7992 ) ;
93+
94+ if ( ! condition . toBoolean ( ) ) {
95+ let publicOutput : PublicOutput =
96+ ProvableType . synthesize ( publicOutputType ) ;
97+ let maxProofsVerified : 0 | 1 | 2 =
98+ ( await zkprogram . maxProofsVerified ( ) ) as any ; // TODO
99+ return SelfProof . dummy (
100+ publicInput ,
101+ publicOutput ,
102+ maxProofsVerified ,
103+ conditionAndConfig instanceof Bool
104+ ? undefined
105+ : conditionAndConfig . domainLog2
106+ ) ;
107+ }
108+
109+ let prover = zkprogram [ key ] ;
110+
80111 if ( hasPublicInput ) {
81112 let { proof } = await prover ( constInput , ...constArgs ) ;
82113 return proof ;
@@ -93,32 +124,48 @@ function Recursive<
93124
94125 // declare and verify the proof, and return its public output
95126 proof . declare ( ) ;
96- proof . verify ( ) ;
127+ proof . verifyIf ( condition ) ;
97128 return proof . publicOutput ;
98129 } ;
99130 } ) ;
100131
101- type RecursiveProver_ < K extends MethodKey > = RecursiveProver <
102- PublicInput ,
103- PublicOutput ,
104- PrivateInputs [ K ]
105- > ;
106- type RecursiveProvers = {
107- [ K in MethodKey ] : RecursiveProver_ < K > ;
108- } ;
109- let proveRecursively : RecursiveProvers = mapToObject (
110- methodKeys ,
111- ( key : MethodKey ) => {
132+ return mapObject (
133+ regularRecursiveProvers ,
134+ (
135+ prover
136+ ) : RecursiveProver < PublicInput , PublicOutput , PrivateInputs [ MethodKey ] > & {
137+ if : ConditionalRecursiveProver <
138+ PublicInput ,
139+ PublicOutput ,
140+ PrivateInputs [ MethodKey ]
141+ > ;
142+ } => {
112143 if ( ! hasPublicInput ) {
113- return ( ( ...args : any ) =>
114- regularRecursiveProvers [ key ] ( undefined as any , ...args ) ) as any ;
144+ return Object . assign (
145+ ( ( ...args : any ) =>
146+ prover ( new Bool ( true ) , undefined as any , ...args ) ) as any ,
147+ {
148+ if : (
149+ condition : Bool | { condition : Bool ; domainLog2 ?: number } ,
150+ ...args : any
151+ ) => prover ( condition , undefined as any , ...args ) ,
152+ }
153+ ) ;
115154 } else {
116- return regularRecursiveProvers [ key ] as any ;
155+ return Object . assign (
156+ ( ( pi : PublicInput , ...args : any ) =>
157+ prover ( new Bool ( true ) , pi , ...args ) ) as any ,
158+ {
159+ if : (
160+ condition : Bool | { condition : Bool ; domainLog2 ?: number } ,
161+ pi : PublicInput ,
162+ ...args : any
163+ ) => prover ( condition , pi , ...args ) ,
164+ }
165+ ) ;
117166 }
118167 }
119168 ) ;
120-
121- return proveRecursively ;
122169}
123170
124171type RecursiveProver <
@@ -132,6 +179,21 @@ type RecursiveProver<
132179 ...args : TupleToInstances < Args >
133180 ) => Promise < PublicOutput > ;
134181
182+ type ConditionalRecursiveProver <
183+ PublicInput ,
184+ PublicOutput ,
185+ Args extends Tuple < ProvableType >
186+ > = PublicInput extends undefined
187+ ? (
188+ condition : Bool | { condition : Bool ; domainLog2 ?: number } ,
189+ ...args : TupleToInstances < Args >
190+ ) => Promise < PublicOutput >
191+ : (
192+ condition : Bool | { condition : Bool ; domainLog2 ?: number } ,
193+ publicInput : PublicInput ,
194+ ...args : TupleToInstances < Args >
195+ ) => Promise < PublicOutput > ;
196+
135197type TupleToInstances < T > = {
136198 [ I in keyof T ] : InferProvable < T [ I ] > ;
137199} ;
0 commit comments