mina_tree/zkapps/
non_snark.rs

1#![allow(unused)]
2
3use std::marker::PhantomData;
4
5use mina_curves::pasta::Fp;
6use mina_signer::CompressedPubKey;
7
8use crate::{
9    check_permission,
10    proofs::{
11        field::{Boolean, FieldWitness, ToBoolean},
12        to_field_elements::ToFieldElements,
13        transaction::Check,
14        witness::Witness,
15        zkapp::StartDataSkeleton,
16    },
17    scan_state::{
18        currency::{Amount, Balance, Index, Magnitude, Signed, Slot, SlotSpan, TxnVersion},
19        transaction_logic::{
20            account_check_timing,
21            local_state::{CallStack, StackFrame},
22            protocol_state::GlobalStateSkeleton,
23            set_with_location,
24            zkapp_command::{
25                self, AccountPreconditions, AccountUpdate, CallForest, CheckAuthorizationResult,
26                SetOrKeep,
27            },
28            zkapp_statement::TransactionCommitment,
29            ExistingOrNew, TimingValidation, TransactionFailure,
30        },
31    },
32    sparse_ledger::{LedgerIntf, SparseLedger},
33    zkapps::checks::ZkappCheck,
34    Account, AccountId, AuthRequired, ControlTag, Mask, MyCow, TokenId, ZkAppAccount,
35    TXN_VERSION_CURRENT,
36};
37
38use super::{
39    checks::NonSnarkOps,
40    intefaces::{
41        AccountIdInterface, AccountInterface, AccountUpdateInterface, ActionsInterface,
42        AmountInterface, BalanceInterface, BoolInterface, BranchEvaluation, BranchInterface,
43        BranchParam, CallForestInterface, CallStackInterface, ControllerInterface,
44        GlobalSlotSinceGenesisInterface, GlobalSlotSpanInterface, GlobalStateInterface,
45        IndexInterface, LedgerInterface, LocalStateInterface, Opt, ReceiptChainHashInterface,
46        SetOrKeepInterface, SignedAmountBranchParam, SignedAmountInterface, StackFrameInterface,
47        StackFrameMakeParams, StackInterface, TokenIdInterface, TransactionCommitmentInterface,
48        TxnVersionInterface, VerificationKeyHashInterface, WitnessGenerator, ZkappApplication,
49        ZkappHandler,
50    },
51    zkapp_logic::{self, ApplyZkappParams, ZkAppCommandElt},
52};
53
54pub type GlobalStateForNonSnark<L> = GlobalStateSkeleton<
55    L,              // ledger
56    Signed<Amount>, // fee_excess & supply_increase
57    Slot,           // block_global_slot
58>;
59
60type NonSnarkVerificationKeyHash = Option<Fp>;
61pub struct NonSnarkController;
62pub struct NonSnarkSetOrKeep;
63pub struct NonSnarkGlobalSlotSpan;
64pub struct NonSnarkActions;
65pub struct NonSnarkReceiptChainHash;
66pub struct NonSnarkHandler<L>(PhantomData<L>);
67
68#[derive(Clone, Debug)]
69pub struct ZkappNonSnark<L>(PhantomData<L>);
70
71/// Helper trait to avoid typing the whole `LedgerInterface<..> everywhere`
72pub trait LedgerNonSnark
73where
74    Self: LedgerInterface<W = (), AccountUpdate = AccountUpdate, Account = Account, Bool = bool>,
75{
76}
77impl<T> LedgerNonSnark for T where
78    T: LedgerInterface<W = (), AccountUpdate = AccountUpdate, Account = Account, Bool = bool>
79{
80}
81
82impl<L: LedgerNonSnark> ZkappApplication for ZkappNonSnark<L> {
83    type Ledger = L;
84    type SignedAmount = Signed<Amount>;
85    type Amount = Amount;
86    type Balance = Balance;
87    type Index = Index;
88    type GlobalSlotSinceGenesis = Slot;
89    type StackFrame = StackFrame;
90    type CallForest = CallForest<AccountUpdate>;
91    type CallStack = CallStack;
92    type GlobalState = GlobalStateForNonSnark<L>;
93    type AccountUpdate = AccountUpdate;
94    type AccountId = AccountId;
95    type TokenId = TokenId;
96    type Bool = bool;
97    type TransactionCommitment = TransactionCommitment;
98    type FailureStatusTable = Vec<Vec<TransactionFailure>>;
99    type LocalState = zkapp_logic::LocalState<Self>;
100    type Account = Account;
101    type VerificationKeyHash = NonSnarkVerificationKeyHash;
102    type SingleData = ();
103    type Controller = NonSnarkController;
104    type TxnVersion = TxnVersion;
105    type SetOrKeep = NonSnarkSetOrKeep;
106    type GlobalSlotSpan = NonSnarkGlobalSlotSpan;
107    type Actions = NonSnarkActions;
108    type ReceiptChainHash = NonSnarkReceiptChainHash;
109    type Handler = NonSnarkHandler<L>;
110    type Branch = NonSnarkBranch;
111    type WitnessGenerator = ();
112}
113
114impl<F: FieldWitness> WitnessGenerator<F> for () {
115    type Bool = bool;
116
117    fn exists<T>(&mut self, data: T) -> T
118    where
119        T: ToFieldElements<F> + Check<F>,
120    {
121        data
122    }
123    fn exists_no_check<T>(&mut self, data: T) -> T
124    where
125        T: ToFieldElements<F>,
126    {
127        data
128    }
129    fn exists_no_check_on_bool<T>(&mut self, _b: Self::Bool, data: T) -> T
130    where
131        T: ToFieldElements<F>,
132    {
133        data
134    }
135}
136
137impl<L: LedgerNonSnark> ZkappHandler for NonSnarkHandler<L> {
138    type Z = ZkappNonSnark<L>;
139    type AccountUpdate = AccountUpdate;
140    type Account = Account;
141    type Bool = bool;
142    type W = ();
143    type GlobalState = GlobalStateForNonSnark<L>;
144
145    fn check_account_precondition(
146        account_update: &Self::AccountUpdate,
147        account: &Self::Account,
148        new_account: Self::Bool,
149        local_state: &mut zkapp_logic::LocalState<ZkappNonSnark<L>>,
150        w: &mut Self::W,
151    ) {
152        let precondition_account = &account_update.body.preconditions.account;
153        let check = |failure, b: Boolean, _: &mut Witness<Fp>| {
154            zkapp_logic::LocalState::<ZkappNonSnark<L>>::add_check(
155                local_state,
156                failure,
157                b.as_bool(),
158                w,
159            );
160        };
161        let mut w = Witness::empty();
162        precondition_account.zcheck::<NonSnarkOps, _>(
163            new_account.to_boolean(),
164            account,
165            check,
166            &mut w,
167        );
168    }
169
170    fn check_protocol_state_precondition(
171        protocol_state_predicate: &zkapp_command::ZkAppPreconditions,
172        global_state: &mut Self::GlobalState,
173        w: &mut Self::W,
174    ) -> Self::Bool {
175        let mut w = Witness::empty();
176        protocol_state_predicate
177            .zcheck::<NonSnarkOps>(&global_state.protocol_state, &mut w)
178            .as_bool()
179    }
180
181    fn check_valid_while_precondition(
182        valid_while: &zkapp_command::Numeric<crate::scan_state::currency::Slot>,
183        global_state: &mut Self::GlobalState,
184        w: &mut Self::W,
185    ) -> Self::Bool {
186        use zkapp_command::ClosedInterval;
187        let mut w = Witness::empty();
188        (valid_while, ClosedInterval::min_max)
189            .zcheck::<NonSnarkOps>(&global_state.block_global_slot, &mut w)
190            .as_bool()
191    }
192
193    fn init_account(
194        _account_update: &Self::AccountUpdate,
195        account: Self::Account,
196    ) -> Self::Account {
197        account
198    }
199}
200
201impl ReceiptChainHashInterface for NonSnarkReceiptChainHash {
202    type W = ();
203    type Index = Index;
204
205    fn cons_zkapp_command_commitment(
206        index: Self::Index,
207        element: Fp,
208        other: crate::ReceiptChainHash,
209        w: &mut Self::W,
210    ) -> crate::ReceiptChainHash {
211        use crate::scan_state::transaction_logic::cons_zkapp_command_commitment;
212
213        cons_zkapp_command_commitment(
214            index,
215            ZkAppCommandElt::ZkAppCommandCommitment(crate::ReceiptChainHash(element)),
216            &other,
217        )
218    }
219}
220
221impl ActionsInterface for NonSnarkActions {
222    type W = ();
223    type Bool = bool;
224
225    fn is_empty(
226        actions: &crate::scan_state::transaction_logic::zkapp_command::Actions,
227        _w: &mut Self::W,
228    ) -> Self::Bool {
229        actions.is_empty()
230    }
231
232    fn push_events(
233        event: Fp,
234        actions: &crate::scan_state::transaction_logic::zkapp_command::Actions,
235        _w: &mut Self::W,
236    ) -> Fp {
237        actions.push_events(event)
238    }
239}
240
241impl SetOrKeepInterface for NonSnarkSetOrKeep {
242    type Bool = bool;
243
244    fn is_keep<T: Clone>(set_or_keep: &SetOrKeep<T>) -> Self::Bool {
245        set_or_keep.is_keep()
246    }
247
248    fn is_set<T: Clone>(set_or_keep: &SetOrKeep<T>) -> Self::Bool {
249        set_or_keep.is_set()
250    }
251}
252
253impl GlobalSlotSpanInterface for NonSnarkGlobalSlotSpan {
254    type W = ();
255    type Bool = bool;
256    type SlotSpan = SlotSpan;
257
258    fn greater_than(this: &Self::SlotSpan, other: &Self::SlotSpan, w: &mut Self::W) -> Self::Bool {
259        this > other
260    }
261}
262
263impl TxnVersionInterface for TxnVersion {
264    type W = ();
265    type Bool = bool;
266
267    fn equal_to_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool {
268        version == TXN_VERSION_CURRENT
269    }
270
271    fn older_than_current(version: TxnVersion, w: &mut Self::W) -> Self::Bool {
272        version < TXN_VERSION_CURRENT
273    }
274}
275
276impl VerificationKeyHashInterface for NonSnarkVerificationKeyHash {
277    type W = ();
278    type Bool = bool;
279
280    fn equal(a: &Self, b: &Self, _w: &mut Self::W) -> Self::Bool {
281        a == b
282    }
283}
284
285impl TransactionCommitmentInterface for TransactionCommitment {
286    type AccountUpdate = AccountUpdate;
287    type CallForest = CallForest<AccountUpdate>;
288    type W = ();
289
290    fn empty() -> Fp {
291        let TransactionCommitment(fp) = TransactionCommitment::empty();
292        fp
293    }
294    fn commitment(account_updates: &Self::CallForest) -> Fp {
295        let account_updates_hash = account_updates.hash();
296        let TransactionCommitment(fp) = TransactionCommitment::create(account_updates_hash);
297        fp
298    }
299    fn full_commitment(
300        account_update: &Self::AccountUpdate,
301        memo_hash: Fp,
302        commitment: Fp,
303        w: &mut Self::W,
304    ) -> Fp {
305        // when called from Zkapp_command_logic.apply, the account_update is the fee payer
306        let fee_payer_hash = account_update.digest();
307        let TransactionCommitment(fp) =
308            TransactionCommitment(commitment).create_complete(memo_hash, fee_payer_hash);
309        fp
310    }
311}
312
313impl AccountIdInterface for AccountId {
314    type W = ();
315
316    fn derive_token_id(account_id: &AccountId, w: &mut Self::W) -> TokenId {
317        account_id.derive_token_id()
318    }
319}
320
321impl TokenIdInterface for TokenId {
322    type W = ();
323    type Bool = bool;
324
325    fn equal(a: &TokenId, b: &TokenId, w: &mut Self::W) -> Self::Bool {
326        a == b
327    }
328}
329
330impl<L: LedgerNonSnark> LocalStateInterface for zkapp_logic::LocalState<ZkappNonSnark<L>> {
331    type Z = ZkappNonSnark<L>;
332    type Bool = bool;
333    type W = ();
334
335    fn add_check(
336        local: &mut zkapp_logic::LocalState<Self::Z>,
337        failure: TransactionFailure,
338        b: Self::Bool,
339        w: &mut Self::W,
340    ) {
341        if !b {
342            local.failure_status_tbl[0].insert(0, failure);
343        }
344        local.success = local.success && b;
345    }
346
347    fn add_new_failure_status_bucket(local: &mut zkapp_logic::LocalState<Self::Z>) {
348        local.failure_status_tbl.insert(0, Vec::new());
349    }
350}
351
352impl AmountInterface for Amount {
353    type W = ();
354    type Bool = bool;
355    fn zero() -> Self {
356        <Amount as Magnitude>::zero()
357    }
358    fn of_constant_fee(fee: crate::scan_state::currency::Fee) -> Self {
359        Amount::of_fee(&fee)
360    }
361}
362
363impl BalanceInterface for Balance {
364    type W = ();
365    type Bool = bool;
366    type Amount = Amount;
367    type SignedAmount = Signed<Amount>;
368
369    fn add_signed_amount_flagged(
370        &self,
371        signed_amount: Self::SignedAmount,
372        _w: &mut Self::W,
373    ) -> (Self, Self::Bool) {
374        self.add_signed_amount_flagged(signed_amount)
375    }
376}
377
378impl SignedAmountInterface for Signed<Amount> {
379    type W = ();
380    type Bool = bool;
381    type Amount = Amount;
382
383    fn zero() -> Self {
384        Self::zero()
385    }
386    fn is_neg(&self) -> Self::Bool {
387        self.is_neg()
388    }
389    fn equal(&self, other: &Self, _w: &mut Self::W) -> Self::Bool {
390        (self == other)
391    }
392    fn is_non_neg(&self) -> Self::Bool {
393        self.is_non_neg()
394    }
395    fn negate(&self) -> Self {
396        self.negate()
397    }
398    fn add_flagged(&self, other: &Self, _w: &mut Self::W) -> (Self, Self::Bool) {
399        self.add_flagged(*other)
400    }
401    fn of_unsigned(unsigned: Self::Amount) -> Self {
402        Self::of_unsigned(unsigned)
403    }
404    fn on_if(b: Self::Bool, param: SignedAmountBranchParam<&Self>, w: &mut Self::W) -> Self {
405        let SignedAmountBranchParam { on_true, on_false } = param;
406        match b {
407            true => *on_true,
408            false => *on_false,
409        }
410    }
411}
412
413impl GlobalSlotSinceGenesisInterface for Slot {
414    type W = ();
415    type Bool = bool;
416
417    fn equal(&self, other: &Self, w: &mut Self::W) -> Self::Bool {
418        self == other
419    }
420
421    fn exists_no_check(self, w: &mut Self::W) -> Self {
422        self
423    }
424}
425
426impl<L: LedgerIntf + Clone> GlobalStateInterface for GlobalStateForNonSnark<L> {
427    type Ledger = L;
428    type W = ();
429    type Bool = bool;
430    type SignedAmount = Signed<Amount>;
431    type GlobalSlotSinceGenesis = Slot;
432
433    fn first_pass_ledger(&self) -> Self::Ledger {
434        self.first_pass_ledger.create_masked()
435    }
436    fn set_first_pass_ledger(
437        &mut self,
438        should_update: Self::Bool,
439        ledger: &Self::Ledger,
440        _w: &mut Self::W,
441    ) {
442        if should_update {
443            self.first_pass_ledger.apply_mask(ledger.clone());
444        }
445    }
446    fn second_pass_ledger(&self) -> Self::Ledger {
447        self.second_pass_ledger.create_masked()
448    }
449    fn set_second_pass_ledger(
450        &mut self,
451        should_update: Self::Bool,
452        ledger: &Self::Ledger,
453        _w: &mut Self::W,
454    ) {
455        if should_update {
456            self.second_pass_ledger.apply_mask(ledger.clone());
457        }
458    }
459    fn fee_excess(&self) -> Self::SignedAmount {
460        self.fee_excess
461    }
462    fn set_fee_excess(&mut self, fee_excess: Self::SignedAmount) {
463        self.fee_excess = fee_excess;
464    }
465    fn supply_increase(&self) -> Self::SignedAmount {
466        self.supply_increase
467    }
468    fn set_supply_increase(&mut self, supply_increase: Self::SignedAmount) {
469        self.supply_increase = supply_increase;
470    }
471    fn block_global_slot(&self) -> Self::GlobalSlotSinceGenesis {
472        self.block_global_slot
473    }
474}
475
476impl StackFrameInterface for StackFrame {
477    type Calls = CallForest<AccountUpdate>;
478    type W = ();
479    type Bool = bool;
480
481    fn caller(&self) -> crate::TokenId {
482        let Self {
483            caller,
484            caller_caller: _,
485            calls: _,
486        } = self;
487        caller.clone()
488    }
489    fn caller_caller(&self) -> crate::TokenId {
490        let Self {
491            caller: _,
492            caller_caller,
493            calls: _,
494        } = self;
495        caller_caller.clone()
496    }
497    fn calls(&self) -> &CallForest<AccountUpdate> {
498        let Self {
499            caller: _,
500            caller_caller: _,
501            calls,
502        } = self;
503        calls
504    }
505    fn make(params: StackFrameMakeParams<'_, Self::Calls>) -> Self {
506        let StackFrameMakeParams {
507            caller,
508            caller_caller,
509            calls,
510        } = params;
511        Self {
512            caller,
513            caller_caller,
514            calls: calls.clone(),
515        }
516    }
517    fn make_default(params: StackFrameMakeParams<'_, Self::Calls>) -> Self {
518        Self::make(params) // No difference in non-snark
519    }
520    fn on_if<F: FnOnce(&mut Self::W) -> Self, F2: FnOnce(&mut Self::W) -> Self>(
521        b: Self::Bool,
522        param: BranchParam<Self, Self::W, F, F2>,
523        w: &mut Self::W,
524    ) -> Self {
525        let BranchParam { on_true, on_false } = param;
526
527        match b {
528            true => on_true.eval(w),
529            false => on_false.eval(w),
530        }
531    }
532}
533
534impl<F: FieldWitness> ToFieldElements<F> for CallStack {
535    fn to_field_elements(&self, fields: &mut Vec<F>) {
536        unreachable!()
537    }
538}
539
540impl StackInterface for CallStack {
541    type Elt = StackFrame;
542    type W = ();
543    type Bool = bool;
544
545    fn empty() -> Self {
546        Self::default()
547    }
548    fn is_empty(&self, _w: &mut Self::W) -> Self::Bool {
549        self.is_empty()
550    }
551    fn pop(&self, _w: &mut Self::W) -> Opt<(Self::Elt, Self)> {
552        Opt::from_option(self.pop())
553    }
554    fn push(elt: Self::Elt, onto: Self, _w: &mut Self::W) -> Self {
555        onto.push(&elt)
556    }
557}
558
559impl CallStackInterface for CallStack {
560    type StackFrame = StackFrame;
561}
562
563impl IndexInterface for Index {
564    fn zero() -> Self {
565        <Index as Magnitude>::zero()
566    }
567    fn succ(&self) -> Self {
568        self.incr()
569    }
570}
571
572impl CallForestInterface for CallForest<AccountUpdate> {
573    type W = ();
574    type AccountUpdate = AccountUpdate;
575    type Bool = bool;
576
577    fn empty() -> Self {
578        Self::empty()
579    }
580    fn is_empty(&self, _w: &mut Self::W) -> Self::Bool {
581        self.is_empty()
582    }
583    fn pop_exn(&self, _w: &mut Self::W) -> ((AccountUpdate, Self), Self) {
584        self.pop_exn()
585    }
586}
587
588impl BoolInterface for bool {
589    type W = ();
590    type FailureStatusTable = Vec<Vec<TransactionFailure>>;
591
592    fn as_boolean(&self) -> Boolean {
593        self.to_boolean()
594    }
595    fn of_boolean(b: Boolean) -> Self {
596        b.as_bool()
597    }
598    fn true_() -> Self {
599        true
600    }
601    fn false_() -> Self {
602        false
603    }
604    fn neg(&self) -> Self {
605        !self
606    }
607    fn or(a: Self, b: Self, w: &mut Self::W) -> Self {
608        a || b
609    }
610    fn and(a: Self, b: Self, w: &mut Self::W) -> Self {
611        a && b
612    }
613    fn equal(a: Self, b: Self, w: &mut Self::W) -> Self {
614        a == b
615    }
616    fn all(bs: &[Self], w: &mut Self::W) -> Self {
617        bs.iter().all(|b| *b)
618    }
619    fn assert_any(bs: &[Self], w: &mut Self::W) -> Result<(), String> {
620        if !bs.iter().any(|b| *b) {
621            return Err("Bool::assert_any failed".to_string());
622        }
623        Ok(())
624    }
625    fn assert_with_failure_status_tbl(
626        b: Self,
627        failure_status_tbl: &Self::FailureStatusTable,
628    ) -> Result<(), String> {
629        if !b && !(failure_status_tbl.is_empty()) {
630            Err(format!("{:?}", failure_status_tbl))
631        } else if !b {
632            Err("assert_with_failure_status_tbl failed".to_string())
633        } else {
634            Ok(())
635        }
636    }
637}
638
639impl AccountInterface for Account {
640    type W = ();
641    type Bool = bool;
642    type Balance = Balance;
643    type GlobalSlot = Slot;
644    type D = ();
645    type VerificationKeyHash = NonSnarkVerificationKeyHash;
646
647    fn register_verification_key(&self, data: &Self::D, w: &mut Self::W) {
648        // Nothing
649    }
650
651    fn get(&self) -> &Account {
652        self
653    }
654
655    fn get_mut(&mut self) -> &mut Account {
656        self
657    }
658
659    fn set_delegate(&mut self, new: CompressedPubKey) {
660        self.delegate = if new == CompressedPubKey::empty() {
661            None
662        } else {
663            Some(new)
664        };
665    }
666
667    fn zkapp(&self) -> MyCow<'_, ZkAppAccount> {
668        match self.zkapp.as_ref() {
669            Some(zkapp) => MyCow::Borrow(zkapp),
670            None => MyCow::Own(ZkAppAccount::default()),
671        }
672    }
673
674    fn zkapp_mut(&mut self) -> &mut ZkAppAccount {
675        // `unwrap`: `make_zkapp` is supposed to be called before `zkapp_mut`
676        self.zkapp.as_mut().unwrap()
677    }
678
679    fn verification_key_hash(&self) -> NonSnarkVerificationKeyHash {
680        Some(self.zkapp.as_ref()?.verification_key.as_ref()?.hash())
681    }
682
683    fn set_token_id(&mut self, token_id: TokenId) {
684        self.token_id = token_id;
685    }
686
687    fn is_timed(&self) -> Self::Bool {
688        match &self.timing {
689            crate::Timing::Untimed => false,
690            crate::Timing::Timed { .. } => true,
691        }
692    }
693
694    fn balance(&self) -> Self::Balance {
695        self.balance
696    }
697
698    fn set_balance(&mut self, balance: Self::Balance) {
699        self.balance = balance;
700    }
701
702    fn check_timing(
703        &self,
704        txn_global_slot: &Self::GlobalSlot,
705        w: &mut Self::W,
706    ) -> (TimingValidation<Self::Bool>, crate::Timing) {
707        account_check_timing(txn_global_slot, self)
708    }
709
710    fn make_zkapp(&mut self) {
711        if self.zkapp.is_none() {
712            // ZkAppAccount::default
713            self.zkapp = Some(Box::default());
714        }
715    }
716
717    fn unmake_zkapp(&mut self) {
718        if self.zkapp.as_ref().map(|z| z.is_default()).unwrap_or(false) {
719            self.zkapp = None;
720        }
721    }
722
723    fn proved_state(&self) -> Self::Bool {
724        self.zkapp().proved_state
725    }
726
727    fn set_proved_state(&mut self, proved_state: Self::Bool) {
728        self.zkapp_mut().proved_state = proved_state;
729    }
730
731    fn app_state(&self) -> [Fp; 8] {
732        self.zkapp().app_state
733    }
734
735    fn last_action_slot(&self) -> Self::GlobalSlot {
736        self.zkapp().last_action_slot
737    }
738
739    fn set_last_action_slot(&mut self, slot: Self::GlobalSlot) {
740        self.zkapp_mut().last_action_slot = slot;
741    }
742}
743
744impl AccountUpdateInterface for AccountUpdate {
745    type W = ();
746    type SingleData = ();
747    type CallForest = CallForest<AccountUpdate>;
748    type Bool = bool;
749    type SignedAmount = Signed<Amount>;
750    type VerificationKeyHash = NonSnarkVerificationKeyHash;
751
752    fn body(&self) -> &crate::scan_state::transaction_logic::zkapp_command::Body {
753        let Self {
754            body,
755            authorization: _,
756        } = self;
757        body
758    }
759    fn is_proved(&self) -> Self::Bool {
760        self.body().authorization_kind.is_proved()
761    }
762    fn is_signed(&self) -> Self::Bool {
763        self.body().authorization_kind.is_signed()
764    }
765    fn verification_key_hash(&self) -> Self::VerificationKeyHash {
766        use crate::scan_state::transaction_logic::zkapp_command::AuthorizationKind::*;
767
768        match &self.body().authorization_kind {
769            Proof(vk_hash) => Some(*vk_hash),
770            NoneGiven | Signature => None,
771        }
772    }
773    fn check_authorization(
774        &self,
775        will_succeed: Self::Bool,
776        commitment: Fp,
777        calls: &Self::CallForest,
778        single_data: &Self::SingleData,
779        w: &mut Self::W,
780    ) -> CheckAuthorizationResult<Self::Bool> {
781        use crate::scan_state::transaction_logic::zkapp_command::Control::*;
782
783        let (proof_verifies, signature_verifies) = match &self.authorization {
784            Signature(_) => (false, true),
785            Proof(_) => (true, false),
786            NoneGiven => (false, false),
787        };
788        CheckAuthorizationResult {
789            proof_verifies,
790            signature_verifies,
791        }
792    }
793    fn increment_nonce(&self) -> Self::Bool {
794        self.body().increment_nonce
795    }
796    fn use_full_commitment(&self) -> Self::Bool {
797        self.body().use_full_commitment
798    }
799    fn account_precondition_nonce_is_constant(&self, w: &mut Self::W) -> Self::Bool {
800        let nonce = self.body().preconditions.account.nonce();
801        nonce.is_constant()
802    }
803    fn implicit_account_creation_fee(&self) -> Self::Bool {
804        self.body().implicit_account_creation_fee
805    }
806    fn balance_change(&self) -> Self::SignedAmount {
807        self.body().balance_change
808    }
809}
810
811fn controller_check(
812    proof_verifies: bool,
813    signature_verifies: bool,
814    perm: AuthRequired,
815) -> Result<bool, String> {
816    // Invariant: We either have a proof, a signature, or neither.
817    if proof_verifies && signature_verifies {
818        return Err("We either have a proof, a signature, or neither.".to_string());
819    }
820    let tag = if proof_verifies {
821        ControlTag::Proof
822    } else if signature_verifies {
823        ControlTag::Signature
824    } else {
825        ControlTag::NoneGiven
826    };
827    Ok(check_permission(perm, tag))
828}
829
830impl ControllerInterface for NonSnarkController {
831    type W = ();
832    type Bool = bool;
833    type SingleData = ();
834
835    fn check(
836        proof_verifies: Self::Bool,
837        signature_verifies: Self::Bool,
838        auth: &AuthRequired,
839        _single_data: &Self::SingleData,
840        _w: &mut Self::W,
841    ) -> Result<Self::Bool, String> {
842        controller_check(proof_verifies, signature_verifies, *auth)
843    }
844
845    fn verification_key_perm_fallback_to_signature_with_older_version(
846        auth: &AuthRequired,
847        w: &mut Self::W,
848    ) -> AuthRequired {
849        auth.verification_key_perm_fallback_to_signature_with_older_version()
850    }
851}
852
853pub struct NonSnarkBranch;
854
855impl BranchInterface for NonSnarkBranch {
856    type W = ();
857
858    fn make<T, F>(_w: &mut Self::W, run: F) -> BranchEvaluation<T, Self::W, F>
859    where
860        F: FnOnce(&mut Self::W) -> T,
861    {
862        // We don't run the closure now.
863        // The closure will be run when `BranchEvaluation::eval` is called.
864        BranchEvaluation::Pending(run)
865    }
866}
867
868fn get_with_location<L>(
869    ledger: &L,
870    account_id: &AccountId,
871) -> Result<(ExistingOrNew<L::Location>, Box<Account>), String>
872where
873    L: LedgerIntf,
874{
875    match ledger.location_of_account(account_id) {
876        Some(location) => match ledger.get(&location) {
877            Some(account) => Ok((ExistingOrNew::Existing(location), account)),
878            None => Err("Ledger location with no account".to_string()),
879        },
880        None => Ok((
881            ExistingOrNew::New,
882            Box::new(Account::create_with(account_id.clone(), Balance::zero())),
883        )),
884    }
885}
886
887mod ledger {
888    use super::*;
889
890    type InclusionProof<L> = ExistingOrNew<<L as LedgerIntf>::Location>;
891
892    pub(super) fn get_account<L: LedgerIntf>(
893        ledger: &L,
894        account_update: &AccountUpdate,
895    ) -> Result<(Account, InclusionProof<L>), String> {
896        let (loc, account) = get_with_location(ledger, &account_update.account_id())?;
897        Ok((*account, loc))
898    }
899    pub(super) fn set_account<L: LedgerIntf>(
900        ledger: &mut L,
901        account: (Account, InclusionProof<L>),
902    ) -> Result<(), String> {
903        let (account, location) = account;
904        set_with_location(ledger, &location, Box::new(account))
905    }
906    pub(super) fn check_account<L: LedgerIntf>(
907        public_key: &CompressedPubKey,
908        token_id: &TokenId,
909        account: (&Account, &InclusionProof<L>),
910    ) -> Result<bool, String> {
911        let (account, loc) = account;
912        if public_key != &account.public_key {
913            return Err("check_account: public_key != &account.public_key".to_string());
914        }
915        if token_id != &account.token_id {
916            return Err("check_account: token_id != &account.token_id".to_string());
917        }
918        match loc {
919            ExistingOrNew::Existing(_) => Ok(false),
920            ExistingOrNew::New => Ok(true),
921        }
922    }
923}
924
925impl LedgerInterface for Mask {
926    type W = ();
927    type AccountUpdate = AccountUpdate;
928    type Account = Account;
929    type Bool = bool;
930    type InclusionProof = ExistingOrNew<<Mask as LedgerIntf>::Location>;
931
932    fn empty(depth: usize) -> Self {
933        <Self as LedgerIntf>::empty(depth)
934    }
935    fn get_account(
936        &self,
937        account_update: &Self::AccountUpdate,
938        _w: &mut Self::W,
939    ) -> Result<(Self::Account, Self::InclusionProof), String> {
940        ledger::get_account(self, account_update)
941    }
942    fn set_account(
943        &mut self,
944        account: (Self::Account, Self::InclusionProof),
945        _w: &mut Self::W,
946    ) -> Result<(), String> {
947        ledger::set_account(self, account)
948    }
949    fn check_inclusion(&self, _account: &(Self::Account, Self::InclusionProof), _w: &mut Self::W) {
950        // Nothing
951    }
952    fn check_account(
953        public_key: &CompressedPubKey,
954        token_id: &TokenId,
955        account: (&Self::Account, &Self::InclusionProof),
956        _w: &mut Self::W,
957    ) -> Result<Self::Bool, String> {
958        ledger::check_account::<Self>(public_key, token_id, account)
959    }
960}
961impl LedgerInterface for SparseLedger {
962    type W = ();
963    type AccountUpdate = AccountUpdate;
964    type Account = Account;
965    type Bool = bool;
966    type InclusionProof = ExistingOrNew<<Mask as LedgerIntf>::Location>;
967
968    fn empty(depth: usize) -> Self {
969        <Self as LedgerIntf>::empty(depth)
970    }
971    fn get_account(
972        &self,
973        account_update: &Self::AccountUpdate,
974        _w: &mut Self::W,
975    ) -> Result<(Self::Account, Self::InclusionProof), String> {
976        ledger::get_account(self, account_update)
977    }
978    fn set_account(
979        &mut self,
980        account: (Self::Account, Self::InclusionProof),
981        _w: &mut Self::W,
982    ) -> Result<(), String> {
983        ledger::set_account(self, account)
984    }
985    fn check_inclusion(&self, _account: &(Self::Account, Self::InclusionProof), _w: &mut Self::W) {
986        // Nothing
987    }
988    fn check_account(
989        public_key: &CompressedPubKey,
990        token_id: &TokenId,
991        account: (&Self::Account, &Self::InclusionProof),
992        _w: &mut Self::W,
993    ) -> Result<Self::Bool, String> {
994        ledger::check_account::<Self>(public_key, token_id, account)
995    }
996}
997
998pub fn step<L>(
999    global_state: &mut GlobalStateForNonSnark<L>,
1000    local_state: &mut zkapp_logic::LocalState<ZkappNonSnark<L>>,
1001) -> Result<(), String>
1002where
1003    L: LedgerNonSnark,
1004{
1005    zkapp_logic::apply(
1006        ApplyZkappParams {
1007            is_start: zkapp_logic::IsStart::No,
1008            global_state,
1009            local_state,
1010            single_data: (),
1011        },
1012        &mut (),
1013    )
1014}
1015
1016pub type StartData = StartDataSkeleton<CallForest<AccountUpdate>, bool>;
1017
1018pub fn start<L>(
1019    global_state: &mut GlobalStateForNonSnark<L>,
1020    local_state: &mut zkapp_logic::LocalState<ZkappNonSnark<L>>,
1021    start_data: StartData,
1022) -> Result<(), String>
1023where
1024    L: LedgerNonSnark,
1025{
1026    zkapp_logic::apply(
1027        ApplyZkappParams {
1028            is_start: zkapp_logic::IsStart::Yes(start_data),
1029            global_state,
1030            local_state,
1031            single_data: (),
1032        },
1033        &mut (),
1034    )
1035}