mina_tree/zkapps/
intefaces.rs

1use std::marker::PhantomData;
2
3use mina_curves::pasta::Fp;
4use mina_signer::CompressedPubKey;
5
6use crate::proofs::{
7    field::{Boolean, FieldWitness},
8    to_field_elements::ToFieldElements,
9    transaction::Check,
10};
11
12use crate::{
13    scan_state::currency::{self, SlotSpan, TxnVersion},
14    zkapps::zkapp_logic,
15};
16
17use crate::{
18    scan_state::transaction_logic::{
19        zkapp_command::{self, CheckAuthorizationResult, SetOrKeep},
20        TimingValidation, TransactionFailure,
21    },
22    sparse_ledger::LedgerIntf,
23    AccountId, AuthRequired, MyCow, ReceiptChainHash, TokenId, ZkAppAccount,
24};
25
26pub trait WitnessGenerator<F: FieldWitness>
27where
28    Self: Sized,
29{
30    type Bool: BoolInterface;
31
32    fn exists<T>(&mut self, data: T) -> T
33    where
34        T: ToFieldElements<F> + Check<F>;
35
36    fn exists_no_check<T>(&mut self, data: T) -> T
37    where
38        T: ToFieldElements<F>;
39
40    /// Here `b` might be a `CircuitVar::Constant`, in that case we don't call
41    /// `Witness::exists_no_check` for the value.
42    /// <https://github.com/openmina/snarky/blob/ff2631f47bb644f7a31fd30be16ee0e5ff5279fa/src/base/utils.ml#L155>
43    ///
44    /// TODO: Ideally we should replace `exists_no_check` above with this `exists_no_check_on_bool`,
45    /// but it's more parameters to type, and most of the time `b` is not a constant
46    fn exists_no_check_on_bool<T>(&mut self, b: Self::Bool, data: T) -> T
47    where
48        T: ToFieldElements<F>;
49
50    fn on_if<T, Fun, Fun2>(&mut self, b: Self::Bool, param: BranchParam<T, Self, Fun, Fun2>) -> T
51    where
52        T: ToFieldElements<F>,
53        Fun: FnOnce(&mut Self) -> T,
54        Fun2: FnOnce(&mut Self) -> T,
55    {
56        let BranchParam { on_true, on_false } = param;
57        let value = match b.as_boolean() {
58            Boolean::True => on_true.eval(self),
59            Boolean::False => on_false.eval(self),
60        };
61        self.exists_no_check_on_bool(b, value)
62    }
63}
64
65pub trait ZkappHandler {
66    type Z: ZkappApplication;
67    type AccountUpdate: AccountUpdateInterface;
68    type Account: AccountInterface;
69    type Bool: BoolInterface;
70    type W: WitnessGenerator<Fp>;
71    type GlobalState: GlobalStateInterface;
72
73    fn check_account_precondition(
74        account_update: &Self::AccountUpdate,
75        account: &Self::Account,
76        new_account: Self::Bool,
77        local_state: &mut zkapp_logic::LocalState<Self::Z>,
78        w: &mut Self::W,
79    );
80    fn check_protocol_state_precondition(
81        protocol_state_predicate: &zkapp_command::ZkAppPreconditions,
82        global_state: &mut Self::GlobalState,
83        w: &mut Self::W,
84    ) -> Self::Bool;
85    fn check_valid_while_precondition(
86        valid_while: &zkapp_command::Numeric<crate::scan_state::currency::Slot>,
87        global_state: &mut Self::GlobalState,
88        w: &mut Self::W,
89    ) -> Self::Bool;
90    fn init_account(account_update: &Self::AccountUpdate, account: Self::Account) -> Self::Account;
91}
92
93pub struct Opt<T> {
94    pub is_some: Boolean,
95    pub data: T,
96}
97
98impl<T: Default> Opt<T> {
99    pub fn from_option(opt: Option<T>) -> Self {
100        match opt {
101            Some(data) => Self {
102                is_some: Boolean::True,
103                data,
104            },
105            None => Self {
106                is_some: Boolean::False,
107                data: T::default(),
108            },
109        }
110    }
111}
112
113impl<A, B> Opt<(A, B)> {
114    pub fn unzip(self) -> (Opt<A>, Opt<B>) {
115        let Self {
116            is_some,
117            data: (a, b),
118        } = self;
119        let a = Opt { is_some, data: a };
120        let b = Opt { is_some, data: b };
121        (a, b)
122    }
123}
124
125pub trait AmountInterface
126where
127    Self: Sized,
128{
129    type W: WitnessGenerator<Fp>;
130    type Bool: BoolInterface;
131
132    fn zero() -> Self;
133    fn of_constant_fee(fee: currency::Fee) -> Self;
134}
135
136pub trait SignedAmountInterface
137where
138    Self: Sized,
139{
140    type W: WitnessGenerator<Fp>;
141    type Bool: BoolInterface;
142    type Amount: AmountInterface;
143
144    fn zero() -> Self;
145    fn is_neg(&self) -> Self::Bool;
146    fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool;
147    fn is_non_neg(&self) -> Self::Bool;
148    fn negate(&self) -> Self;
149    fn add_flagged(&self, other: &Self, w: &mut Self::W) -> (Self, Self::Bool);
150    fn of_unsigned(unsigned: Self::Amount) -> Self;
151    fn on_if(b: Self::Bool, param: SignedAmountBranchParam<&Self>, w: &mut Self::W) -> Self;
152}
153
154pub trait BalanceInterface
155where
156    Self: Sized,
157{
158    type W: WitnessGenerator<Fp>;
159    type Bool: BoolInterface;
160    type Amount: AmountInterface;
161    type SignedAmount: SignedAmountInterface;
162
163    fn add_signed_amount_flagged(
164        &self,
165        signed_amount: Self::SignedAmount,
166        w: &mut Self::W,
167    ) -> (Self, Self::Bool);
168}
169
170pub trait IndexInterface
171where
172    Self: Sized,
173{
174    fn zero() -> Self;
175    fn succ(&self) -> Self;
176}
177
178pub trait ReceiptChainHashElementInterface
179where
180    Self: Sized,
181{
182    fn of_commitment(commitment: impl ReceiptChainHashInterface) -> Self;
183}
184
185pub trait ReceiptChainHashInterface {
186    type W: WitnessGenerator<Fp>;
187    type Index;
188    fn cons_zkapp_command_commitment(
189        index: Self::Index,
190        element: Fp,
191        other: ReceiptChainHash,
192        w: &mut Self::W,
193    ) -> ReceiptChainHash;
194}
195
196pub trait GlobalSlotSinceGenesisInterface {
197    type W: WitnessGenerator<Fp>;
198    type Bool: BoolInterface;
199
200    fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool;
201    fn exists_no_check(self, w: &mut Self::W) -> Self;
202}
203
204pub trait GlobalSlotSpanInterface {
205    type W: WitnessGenerator<Fp>;
206    type Bool: BoolInterface;
207    type SlotSpan;
208
209    fn greater_than(this: &Self::SlotSpan, other: &Self::SlotSpan, w: &mut Self::W) -> Self::Bool;
210}
211
212pub trait CallForestInterface
213where
214    Self: Sized,
215{
216    type W: WitnessGenerator<Fp>;
217    type AccountUpdate: AccountUpdateInterface;
218    type Bool: BoolInterface;
219
220    fn empty() -> Self;
221    fn is_empty(&self, w: &mut Self::W) -> Self::Bool;
222    fn pop_exn(&self, w: &mut Self::W) -> ((Self::AccountUpdate, Self), Self);
223}
224
225pub struct StackFrameMakeParams<'a, Calls> {
226    pub caller: TokenId,
227    pub caller_caller: TokenId,
228    pub calls: &'a Calls,
229}
230
231#[derive(Debug)]
232pub struct SignedAmountBranchParam<T> {
233    pub on_true: T,
234    pub on_false: T,
235}
236
237pub struct BranchParam<T, W, F: FnOnce(&mut W) -> T, F2: FnOnce(&mut W) -> T> {
238    pub on_true: BranchEvaluation<T, W, F>,
239    pub on_false: BranchEvaluation<T, W, F2>,
240}
241
242pub trait StackFrameInterface
243where
244    Self: Sized,
245{
246    type Calls: CallForestInterface<W = Self::W>;
247    type W: WitnessGenerator<Fp>;
248    type Bool: BoolInterface;
249
250    fn caller(&self) -> TokenId;
251    fn caller_caller(&self) -> TokenId;
252    fn calls(&self) -> &Self::Calls;
253    fn make(params: StackFrameMakeParams<'_, Self::Calls>) -> Self;
254    fn make_default(params: StackFrameMakeParams<'_, Self::Calls>) -> Self;
255    fn on_if<F, F2>(
256        b: Self::Bool,
257        param: BranchParam<Self, Self::W, F, F2>,
258        w: &mut Self::W,
259    ) -> Self
260    where
261        F: FnOnce(&mut Self::W) -> Self,
262        F2: FnOnce(&mut Self::W) -> Self;
263}
264
265pub trait StackInterface
266where
267    Self: Sized,
268{
269    type Elt;
270    type W: WitnessGenerator<Fp>;
271    type Bool: BoolInterface;
272
273    fn empty() -> Self;
274    fn is_empty(&self, w: &mut Self::W) -> Self::Bool;
275    fn pop(&self, w: &mut Self::W) -> Opt<(Self::Elt, Self)>;
276    fn push(elt: Self::Elt, onto: Self, w: &mut Self::W) -> Self;
277}
278
279pub trait CallStackInterface
280where
281    Self: Sized + StackInterface,
282{
283    type StackFrame: StackFrameInterface;
284}
285
286pub trait GlobalStateInterface {
287    type Ledger;
288    type W: WitnessGenerator<Fp>;
289    type Bool: BoolInterface;
290    type SignedAmount: SignedAmountInterface;
291    type GlobalSlotSinceGenesis: GlobalSlotSinceGenesisInterface;
292
293    fn first_pass_ledger(&self) -> Self::Ledger;
294    fn set_first_pass_ledger(
295        &mut self,
296        should_update: Self::Bool,
297        ledger: &Self::Ledger,
298        w: &mut Self::W,
299    );
300
301    fn second_pass_ledger(&self) -> Self::Ledger;
302    fn set_second_pass_ledger(
303        &mut self,
304        should_update: Self::Bool,
305        ledger: &Self::Ledger,
306        w: &mut Self::W,
307    );
308
309    fn fee_excess(&self) -> Self::SignedAmount;
310    fn set_fee_excess(&mut self, fee_excess: Self::SignedAmount);
311
312    fn supply_increase(&self) -> Self::SignedAmount;
313    fn set_supply_increase(&mut self, supply_increase: Self::SignedAmount);
314
315    fn block_global_slot(&self) -> Self::GlobalSlotSinceGenesis;
316}
317
318pub trait LocalStateInterface {
319    type Z: ZkappApplication;
320    type W: WitnessGenerator<Fp>;
321    type Bool: BoolInterface;
322
323    fn add_check(
324        local: &mut zkapp_logic::LocalState<Self::Z>,
325        failure: TransactionFailure,
326        b: Self::Bool,
327        w: &mut Self::W,
328    );
329    fn add_new_failure_status_bucket(local: &mut zkapp_logic::LocalState<Self::Z>);
330}
331
332pub trait AccountUpdateInterface
333where
334    Self: Sized,
335{
336    type W: WitnessGenerator<Fp>;
337    type SingleData;
338    type CallForest: CallForestInterface;
339    type Bool: BoolInterface;
340    type SignedAmount: SignedAmountInterface;
341    type VerificationKeyHash: VerificationKeyHashInterface;
342
343    // Only difference in our Rust code is the `WithHash`
344    fn body(&self) -> &crate::scan_state::transaction_logic::zkapp_command::Body;
345    fn verification_key_hash(&self) -> Self::VerificationKeyHash;
346    fn is_proved(&self) -> Self::Bool;
347    fn is_signed(&self) -> Self::Bool;
348    fn check_authorization(
349        &self,
350        will_succeed: Self::Bool,
351        commitment: Fp,
352        calls: &Self::CallForest,
353        single_data: &Self::SingleData,
354        w: &mut Self::W,
355    ) -> CheckAuthorizationResult<Self::Bool>;
356    fn increment_nonce(&self) -> Self::Bool;
357    fn use_full_commitment(&self) -> Self::Bool;
358    fn account_precondition_nonce_is_constant(&self, w: &mut Self::W) -> Self::Bool;
359    fn implicit_account_creation_fee(&self) -> Self::Bool;
360    fn balance_change(&self) -> Self::SignedAmount;
361}
362
363pub trait AccountIdInterface
364where
365    Self: Sized,
366{
367    type W: WitnessGenerator<Fp>;
368
369    fn derive_token_id(account_id: &AccountId, w: &mut Self::W) -> TokenId;
370}
371
372pub trait TokenIdInterface
373where
374    Self: Sized,
375{
376    type W: WitnessGenerator<Fp>;
377    type Bool: BoolInterface;
378
379    fn equal(a: &TokenId, b: &TokenId, w: &mut Self::W) -> Self::Bool;
380}
381
382pub trait ControllerInterface {
383    type W: WitnessGenerator<Fp>;
384    type Bool: BoolInterface;
385    type SingleData;
386
387    fn check(
388        proof_verifies: Self::Bool,
389        signature_verifies: Self::Bool,
390        auth: &AuthRequired,
391        single_data: &Self::SingleData,
392        w: &mut Self::W,
393    ) -> Result<Self::Bool, String>;
394
395    fn verification_key_perm_fallback_to_signature_with_older_version(
396        auth: &AuthRequired,
397        w: &mut Self::W,
398    ) -> AuthRequired;
399}
400
401pub trait TxnVersionInterface {
402    type W: WitnessGenerator<Fp>;
403    type Bool: BoolInterface;
404
405    fn equal_to_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool;
406    fn older_than_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool;
407}
408
409pub trait BoolInterface
410where
411    Self: Sized,
412{
413    type W: WitnessGenerator<Fp>;
414    type FailureStatusTable;
415
416    fn as_boolean(&self) -> Boolean;
417    fn of_boolean(b: Boolean) -> Self;
418    fn true_() -> Self;
419    fn false_() -> Self;
420    fn neg(&self) -> Self;
421    fn or(a: Self, b: Self, w: &mut Self::W) -> Self;
422    fn and(a: Self, b: Self, w: &mut Self::W) -> Self;
423    fn equal(a: Self, b: Self, w: &mut Self::W) -> Self;
424    fn all(bs: &[Self], w: &mut Self::W) -> Self;
425    fn assert_any(bs: &[Self], w: &mut Self::W) -> Result<(), String>;
426    fn assert_with_failure_status_tbl(
427        b: Self,
428        table: &Self::FailureStatusTable,
429    ) -> Result<(), String>;
430}
431
432pub trait TransactionCommitmentInterface {
433    type AccountUpdate: AccountUpdateInterface;
434    type CallForest: CallForestInterface;
435    type W: WitnessGenerator<Fp>;
436
437    fn empty() -> Fp;
438    fn commitment(account_updates: &Self::CallForest) -> Fp;
439    fn full_commitment(
440        account_updates: &Self::AccountUpdate,
441        memo_hash: Fp,
442        commitment: Fp,
443        w: &mut Self::W,
444    ) -> Fp;
445}
446
447pub trait AccountInterface
448where
449    Self: Sized,
450{
451    type W: WitnessGenerator<Fp>;
452    type Bool: BoolInterface;
453    type Balance: BalanceInterface;
454    type GlobalSlot: GlobalSlotSinceGenesisInterface;
455    type VerificationKeyHash: VerificationKeyHashInterface;
456    type D;
457
458    fn register_verification_key(&self, data: &Self::D, w: &mut Self::W);
459    fn get(&self) -> &crate::Account;
460    fn get_mut(&mut self) -> &mut crate::Account;
461    fn set_delegate(&mut self, new: CompressedPubKey);
462    fn zkapp(&self) -> MyCow<'_, ZkAppAccount>;
463    fn zkapp_mut(&mut self) -> &mut ZkAppAccount;
464    fn verification_key_hash(&self) -> Self::VerificationKeyHash;
465    fn set_token_id(&mut self, token_id: TokenId);
466    fn is_timed(&self) -> Self::Bool;
467    fn balance(&self) -> Self::Balance;
468    fn set_balance(&mut self, balance: Self::Balance);
469    fn check_timing(
470        &self,
471        txn_global_slot: &Self::GlobalSlot,
472        w: &mut Self::W,
473    ) -> (TimingValidation<Self::Bool>, crate::Timing);
474    fn make_zkapp(&mut self);
475    fn unmake_zkapp(&mut self);
476    fn proved_state(&self) -> Self::Bool;
477    fn set_proved_state(&mut self, proved_state: Self::Bool);
478    fn app_state(&self) -> [Fp; 8];
479    fn last_action_slot(&self) -> Self::GlobalSlot;
480    fn set_last_action_slot(&mut self, slot: Self::GlobalSlot);
481}
482
483pub trait LedgerInterface: LedgerIntf + Clone {
484    type W: WitnessGenerator<Fp>;
485    type AccountUpdate: AccountUpdateInterface;
486    type Account: AccountInterface;
487    type Bool: BoolInterface;
488    type InclusionProof;
489
490    fn empty(depth: usize) -> Self;
491    fn get_account(
492        &self,
493        account_update: &Self::AccountUpdate,
494        w: &mut Self::W,
495    ) -> Result<(Self::Account, Self::InclusionProof), String>;
496    fn set_account(
497        &mut self,
498        account: (Self::Account, Self::InclusionProof),
499        w: &mut Self::W,
500    ) -> Result<(), String>;
501    fn check_inclusion(&self, account: &(Self::Account, Self::InclusionProof), w: &mut Self::W);
502    fn check_account(
503        public_key: &CompressedPubKey,
504        token_id: &TokenId,
505        account: (&Self::Account, &Self::InclusionProof),
506        w: &mut Self::W,
507    ) -> Result<Self::Bool, String>;
508    fn exists_no_check(self, _w: &mut Self::W) -> Self {
509        self
510    }
511    fn exists_no_check_on_bool(self, _b: Self::Bool, _w: &mut Self::W) -> Self {
512        self
513    }
514}
515
516pub trait VerificationKeyHashInterface {
517    type W: WitnessGenerator<Fp>;
518    type Bool: BoolInterface;
519
520    fn equal(a: &Self, b: &Self, w: &mut Self::W) -> Self::Bool;
521}
522
523pub trait SetOrKeepInterface {
524    type Bool: BoolInterface;
525    fn is_keep<T: Clone>(set_or_keep: &SetOrKeep<T>) -> Self::Bool;
526    fn is_set<T: Clone>(set_or_keep: &SetOrKeep<T>) -> Self::Bool;
527}
528
529pub trait ActionsInterface {
530    type W: WitnessGenerator<Fp>;
531    type Bool: BoolInterface;
532
533    fn is_empty(actions: &zkapp_command::Actions, w: &mut Self::W) -> Self::Bool;
534    fn push_events(event: Fp, actions: &zkapp_command::Actions, w: &mut Self::W) -> Fp;
535}
536
537pub enum BranchEvaluation<T, W, F: FnOnce(&mut W) -> T> {
538    Evaluated(T, PhantomData<W>),
539    Pending(F),
540}
541
542impl<T, W, F> BranchEvaluation<T, W, F>
543where
544    F: FnOnce(&mut W) -> T,
545{
546    pub fn eval(self, w: &mut W) -> T {
547        match self {
548            Self::Evaluated(v, _) => {
549                // The value was already run/evaluated
550                v
551            }
552            Self::Pending(fun) => {
553                // Run the branch's closure, to get the branch's value
554                fun(w)
555            }
556        }
557    }
558}
559
560/// - During witness generation (in-snark), we want to evaluate both branches
561///   when there is a condition (`on_if`)
562/// - But during tx application (non-snark), we just want to evaluate 1 branch.
563///   Evaluating both branches in that case would be a waste of cpu/resource
564///   and would result in a slower application
565///
566/// Note that in `zkapp_logic::apply`, we don't always use that interface, we
567/// use it mostly when 1 of the branch is expensive, or when `on_if` is a
568/// specialized implementation (such as `StackFrameInterface::on_if`)
569pub trait BranchInterface {
570    type W: WitnessGenerator<Fp>;
571
572    fn make<T, F>(w: &mut Self::W, run: F) -> BranchEvaluation<T, Self::W, F>
573    where
574        F: FnOnce(&mut Self::W) -> T;
575}
576
577pub trait ZkappApplication
578where
579    Self: Sized,
580{
581    type Ledger: LedgerInterface<
582        W = Self::WitnessGenerator,
583        AccountUpdate = Self::AccountUpdate,
584        Account = Self::Account,
585        Bool = Self::Bool,
586    >;
587    type SignedAmount: SignedAmountInterface<W = Self::WitnessGenerator, Bool = Self::Bool, Amount = Self::Amount>
588        + std::fmt::Debug
589        + Clone;
590    type Amount: AmountInterface<W = Self::WitnessGenerator, Bool = Self::Bool> + Clone;
591    type Balance: BalanceInterface<
592        W = Self::WitnessGenerator,
593        Bool = Self::Bool,
594        Amount = Self::Amount,
595        SignedAmount = Self::SignedAmount,
596    >;
597    type Index: IndexInterface + Clone + ToFieldElements<Fp>;
598    type GlobalSlotSinceGenesis: GlobalSlotSinceGenesisInterface<
599        W = Self::WitnessGenerator,
600        Bool = Self::Bool,
601    >;
602    type StackFrame: StackFrameInterface<W = Self::WitnessGenerator, Calls = Self::CallForest, Bool = Self::Bool>
603        + std::fmt::Debug
604        + Clone;
605    type CallForest: CallForestInterface<
606        W = Self::WitnessGenerator,
607        AccountUpdate = Self::AccountUpdate,
608        Bool = Self::Bool,
609    >;
610    type CallStack: CallStackInterface<W = Self::WitnessGenerator, Elt = Self::StackFrame, Bool = Self::Bool>
611        + ToFieldElements<Fp>
612        + Clone;
613    type GlobalState: GlobalStateInterface<
614        Ledger = Self::Ledger,
615        W = Self::WitnessGenerator,
616        SignedAmount = Self::SignedAmount,
617        GlobalSlotSinceGenesis = Self::GlobalSlotSinceGenesis,
618        Bool = Self::Bool,
619    >;
620    type AccountUpdate: AccountUpdateInterface<
621        W = Self::WitnessGenerator,
622        CallForest = Self::CallForest,
623        SingleData = Self::SingleData,
624        Bool = Self::Bool,
625        SignedAmount = Self::SignedAmount,
626        VerificationKeyHash = Self::VerificationKeyHash,
627    >;
628    type AccountId: AccountIdInterface<W = Self::WitnessGenerator>;
629    type TokenId: TokenIdInterface<W = Self::WitnessGenerator, Bool = Self::Bool>;
630    type Bool: BoolInterface<W = Self::WitnessGenerator, FailureStatusTable = Self::FailureStatusTable>
631        + ToFieldElements<Fp>
632        + Clone
633        + Copy
634        + std::fmt::Debug;
635    type TransactionCommitment: TransactionCommitmentInterface<
636        W = Self::WitnessGenerator,
637        AccountUpdate = Self::AccountUpdate,
638        CallForest = Self::CallForest,
639    >;
640    type FailureStatusTable;
641    type LocalState: LocalStateInterface<W = Self::WitnessGenerator, Z = Self, Bool = Self::Bool>;
642    type Account: AccountInterface<
643        W = Self::WitnessGenerator,
644        D = Self::SingleData,
645        Bool = Self::Bool,
646        Balance = Self::Balance,
647        GlobalSlot = Self::GlobalSlotSinceGenesis,
648        VerificationKeyHash = Self::VerificationKeyHash,
649    >;
650    type VerificationKeyHash: VerificationKeyHashInterface<
651        W = Self::WitnessGenerator,
652        Bool = Self::Bool,
653    >;
654    type Controller: ControllerInterface<
655        W = Self::WitnessGenerator,
656        Bool = Self::Bool,
657        SingleData = Self::SingleData,
658    >;
659    type TxnVersion: TxnVersionInterface<W = Self::WitnessGenerator, Bool = Self::Bool>;
660    type SetOrKeep: SetOrKeepInterface<Bool = Self::Bool>;
661    type GlobalSlotSpan: GlobalSlotSpanInterface<
662        W = Self::WitnessGenerator,
663        Bool = Self::Bool,
664        SlotSpan = SlotSpan,
665    >;
666    type Actions: ActionsInterface<W = Self::WitnessGenerator, Bool = Self::Bool>;
667    type ReceiptChainHash: ReceiptChainHashInterface<
668        W = Self::WitnessGenerator,
669        Index = Self::Index,
670    >;
671    type SingleData;
672    type Handler: ZkappHandler<
673        Z = Self,
674        AccountUpdate = Self::AccountUpdate,
675        Account = Self::Account,
676        Bool = Self::Bool,
677        W = Self::WitnessGenerator,
678        GlobalState = Self::GlobalState,
679    >;
680    type Branch: BranchInterface<W = Self::WitnessGenerator>;
681    type WitnessGenerator: WitnessGenerator<Fp, Bool = Self::Bool>;
682}