1use crate::{
2 gen_compressed,
3 proofs::{
4 field::{Boolean, FieldWitness, ToBoolean},
5 numbers::{
6 currency::{CheckedBalance, CheckedCurrency},
7 nat::CheckedSlot,
8 },
9 to_field_elements::ToFieldElements,
10 transaction::{
11 make_group, transaction_snark::checked_min_balance_at_slot, Check, InnerCurve,
12 PlonkVerificationKeyEvals,
13 },
14 witness::Witness,
15 },
16 scan_state::currency::{Amount, Balance, Magnitude, Nonce, Slot, TxnVersion},
17 zkapps::snark::FlaggedOption,
18 AppendToInputs as _, MerklePath, MyCow, ToInputs,
19};
20use ark_ff::{BigInteger256, One, UniformRand, Zero};
21use mina_core::constants::PROTOCOL_VERSION;
22use mina_curves::pasta::Fp;
23use mina_p2p_messages::{
24 binprot::{BinProtRead, BinProtWrite},
25 v2,
26};
27use mina_signer::CompressedPubKey;
28use once_cell::sync::{Lazy, OnceCell};
29use poseidon::hash::{
30 hash_noinputs, hash_with_kimchi,
31 params::{
32 get_merkle_param_for_height, MINA_ACCOUNT, MINA_DERIVE_TOKEN_ID, MINA_SIDELOADED_VK,
33 MINA_ZKAPP_ACCOUNT, MINA_ZKAPP_URI, NO_INPUT_ZKAPP_ACTION_STATE_EMPTY_ELT,
34 },
35 Inputs,
36};
37use rand::{prelude::ThreadRng, seq::SliceRandom, Rng};
38use serde::{Deserialize, Serialize};
39use std::{io::Cursor, str::FromStr, sync::Arc};
40
41use super::common::*;
42
43pub const TXN_VERSION_CURRENT: TxnVersion =
45 TxnVersion::from_u32(PROTOCOL_VERSION.transaction.as_u64() as u32);
46
47#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
48#[serde(into = "v2::MinaBaseTokenIdStableV2")]
49#[serde(try_from = "v2::MinaBaseTokenIdStableV2")]
50pub struct TokenId(pub Fp);
51
52impl std::fmt::Debug for TokenId {
53 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
54 use crate::FpExt;
55 f.write_fmt(format_args!("TokenId({})", self.0.to_decimal()))
56 }
57}
58
59impl Default for TokenId {
60 fn default() -> Self {
61 Self(Fp::one())
62 }
63}
64
65impl From<u64> for TokenId {
66 fn from(num: u64) -> Self {
67 TokenId(Fp::from(num))
68 }
69}
70
71impl TokenId {
72 pub fn is_default(&self) -> bool {
73 self == &Self::default()
74 }
75}
76
77#[derive(Clone, PartialEq, Eq, derive_more::From)]
79pub struct TokenSymbol(pub Vec<u8>);
80
81impl std::fmt::Debug for TokenSymbol {
82 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83 let s = String::from_utf8_lossy(self.as_bytes());
84 let s: &str = &s;
85 f.debug_tuple("TokenSymbol").field(&s).finish()
86 }
87}
88
89impl TokenSymbol {
90 pub fn gen() -> Self {
91 let mut rng = rand::thread_rng();
92
93 let sym: u32 = rng.gen();
94 let mut sym = sym.to_string();
95 sym.truncate(6);
96
97 Self(sym.into_bytes())
98 }
99
100 pub fn len(&self) -> usize {
101 self.0.len()
102 }
103
104 pub fn is_empty(&self) -> bool {
105 self.0.is_empty()
106 }
107
108 pub fn as_bytes(&self) -> &[u8] {
109 &self.0
110 }
111
112 pub fn to_bytes(&self, bytes: &mut [u8]) {
113 if self.0.is_empty() {
114 return;
115 }
116 let len = self.0.len();
117 let s: &[u8] = self.as_bytes();
118 bytes[..len].copy_from_slice(&s[..len.min(6)]);
119 }
120
121 pub fn to_field<F: FieldWitness>(&self) -> F {
122 let mut s = <[u8; 32]>::default();
123 self.to_bytes(&mut s);
124
125 F::from_le_bytes_mod_order(&s)
128 }
129}
130
131#[allow(clippy::derivable_impls)]
132impl Default for TokenSymbol {
133 fn default() -> Self {
134 Self(Vec::new())
137 }
138}
139
140impl From<&mina_p2p_messages::string::TokenSymbol> for TokenSymbol {
141 fn from(value: &mina_p2p_messages::string::TokenSymbol) -> Self {
142 Self(value.as_ref().to_vec())
143 }
144}
145
146impl From<&TokenSymbol> for mina_p2p_messages::string::TokenSymbol {
147 fn from(value: &TokenSymbol) -> Self {
148 value.0.as_slice().into()
149 }
150}
151
152impl ToInputs for TokenSymbol {
153 fn to_inputs(&self, inputs: &mut Inputs) {
154 let mut s = <[u8; 6]>::default();
158 self.to_bytes(&mut s);
159 inputs.append_u48(s);
160 }
161}
162
163#[derive(Clone, Debug, PartialEq, Eq)]
164pub struct SetVerificationKey<Controller> {
165 pub auth: Controller,
166 pub txn_version: TxnVersion,
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
171pub struct Permissions<Controller> {
172 pub edit_state: Controller,
173 pub access: Controller,
174 pub send: Controller,
175 pub receive: Controller,
176 pub set_delegate: Controller,
177 pub set_permissions: Controller,
178 pub set_verification_key: SetVerificationKey<Controller>,
179 pub set_zkapp_uri: Controller,
180 pub edit_action_state: Controller,
181 pub set_token_symbol: Controller,
182 pub increment_nonce: Controller,
183 pub set_voting_for: Controller,
184 pub set_timing: Controller,
185}
186
187pub enum AuthOrVersion<'a, T> {
188 Auth(&'a T),
189 Version(TxnVersion),
190}
191
192impl Permissions<AuthRequired> {
193 pub fn iter_as_bits<F>(&self, mut fun: F)
194 where
195 F: FnMut(AuthOrVersion<'_, bool>),
196 {
197 let Self {
198 edit_state,
199 access,
200 send,
201 receive,
202 set_delegate,
203 set_permissions,
204 set_verification_key:
205 SetVerificationKey {
206 auth: set_verification_key_auth,
207 txn_version,
208 },
209 set_zkapp_uri,
210 edit_action_state,
211 set_token_symbol,
212 increment_nonce,
213 set_voting_for,
214 set_timing,
215 } = self;
216
217 for auth in [
218 AuthOrVersion::Auth(edit_state),
219 AuthOrVersion::Auth(access),
220 AuthOrVersion::Auth(send),
221 AuthOrVersion::Auth(receive),
222 AuthOrVersion::Auth(set_delegate),
223 AuthOrVersion::Auth(set_permissions),
224 AuthOrVersion::Auth(set_verification_key_auth),
225 AuthOrVersion::Version(*txn_version),
226 AuthOrVersion::Auth(set_zkapp_uri),
227 AuthOrVersion::Auth(edit_action_state),
228 AuthOrVersion::Auth(set_token_symbol),
229 AuthOrVersion::Auth(increment_nonce),
230 AuthOrVersion::Auth(set_voting_for),
231 AuthOrVersion::Auth(set_timing),
232 ] {
233 match auth {
234 AuthOrVersion::Auth(auth) => {
235 for bit in auth.encode().to_bits() {
236 fun(AuthOrVersion::Auth(&bit));
237 }
238 }
239 AuthOrVersion::Version(version) => {
240 fun(AuthOrVersion::Version(version));
241 }
242 }
243 }
244 }
245}
246
247impl ToInputs for Permissions<AuthRequired> {
248 fn to_inputs(&self, inputs: &mut Inputs) {
249 self.iter_as_bits(|bit| match bit {
250 AuthOrVersion::Auth(bit) => inputs.append_bool(*bit),
251 AuthOrVersion::Version(version) => inputs.append(&version),
252 });
253 }
254}
255
256impl<F: FieldWitness> Check<F> for Permissions<AuthRequired> {
257 fn check(&self, w: &mut Witness<F>) {
258 let Self {
259 edit_state: _,
260 access: _,
261 send: _,
262 receive: _,
263 set_delegate: _,
264 set_permissions: _,
265 set_verification_key:
266 SetVerificationKey {
267 auth: _,
268 txn_version,
269 },
270 set_zkapp_uri: _,
271 edit_action_state: _,
272 set_token_symbol: _,
273 increment_nonce: _,
274 set_voting_for: _,
275 set_timing: _,
276 } = self;
277
278 txn_version.check(w);
279 }
280}
281
282impl Default for Permissions<AuthRequired> {
283 fn default() -> Self {
284 Self::user_default()
285 }
286}
287
288impl Permissions<AuthRequired> {
289 pub fn user_default() -> Self {
290 use AuthRequired::*;
291 Self {
292 edit_state: Signature,
293 send: Signature,
294 receive: None,
295 set_delegate: Signature,
296 set_permissions: Signature,
297 set_verification_key: SetVerificationKey {
298 auth: Signature,
299 txn_version: TXN_VERSION_CURRENT,
300 },
301 set_zkapp_uri: Signature,
302 edit_action_state: Signature,
303 set_token_symbol: Signature,
304 increment_nonce: Signature,
305 set_voting_for: Signature,
306 set_timing: Signature,
307 access: None,
308 }
309 }
310
311 pub fn empty() -> Self {
312 use AuthRequired::*;
313 Self {
314 edit_state: None,
315 send: None,
316 receive: None,
317 access: None,
318 set_delegate: None,
319 set_permissions: None,
320 set_verification_key: SetVerificationKey {
321 auth: None,
322 txn_version: TXN_VERSION_CURRENT,
323 },
324 set_zkapp_uri: None,
325 edit_action_state: None,
326 set_token_symbol: None,
327 increment_nonce: None,
328 set_voting_for: None,
329 set_timing: None,
330 }
331 }
332
333 pub fn gen(auth_tag: ControlTag) -> Self {
335 let mut rng = rand::thread_rng();
336
337 let auth_required_gen = match auth_tag {
338 ControlTag::Proof => AuthRequired::gen_for_proof_authorization,
339 ControlTag::Signature => AuthRequired::gen_for_signature_authorization,
340 ControlTag::NoneGiven => AuthRequired::gen_for_none_given_authorization,
341 };
342
343 Self {
344 edit_state: auth_required_gen(&mut rng),
345 send: auth_required_gen(&mut rng),
346 receive: auth_required_gen(&mut rng),
347 set_delegate: auth_required_gen(&mut rng),
348 set_permissions: auth_required_gen(&mut rng),
349 set_verification_key: SetVerificationKey {
350 auth: auth_required_gen(&mut rng),
351 txn_version: TXN_VERSION_CURRENT,
352 },
353 set_zkapp_uri: auth_required_gen(&mut rng),
354 edit_action_state: auth_required_gen(&mut rng),
355 set_token_symbol: auth_required_gen(&mut rng),
356 increment_nonce: auth_required_gen(&mut rng),
357 set_voting_for: auth_required_gen(&mut rng),
358 set_timing: auth_required_gen(&mut rng),
359 access: {
360 AuthRequired::gen_for_none_given_authorization(&mut rng)
363 },
364 }
365 }
366}
367
368#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
369pub enum ProofVerified {
370 N0,
371 N1,
372 N2,
373}
374
375impl ProofVerified {
376 pub fn to_int(&self) -> usize {
378 match self {
379 ProofVerified::N0 => 0,
380 ProofVerified::N1 => 1,
381 ProofVerified::N2 => 2,
382 }
383 }
384}
385
386impl ToInputs for ProofVerified {
387 fn to_inputs(&self, inputs: &mut Inputs) {
389 let bits = match self {
390 ProofVerified::N0 => [true, false, false],
391 ProofVerified::N1 => [false, true, false],
392 ProofVerified::N2 => [false, false, true],
393 };
394
395 for bit in bits {
396 inputs.append_bool(bit);
397 }
398 }
399}
400
401impl ToFieldElements<Fp> for ProofVerified {
403 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
404 use Boolean::{False, True};
405
406 let bits = match self {
407 ProofVerified::N0 => [True, False, False],
408 ProofVerified::N1 => [False, True, False],
409 ProofVerified::N2 => [False, False, True],
410 };
411
412 bits.to_field_elements(fields);
413 }
414}
415
416#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
417pub struct VerificationKey {
418 pub max_proofs_verified: ProofVerified,
419 pub actual_wrap_domain_size: ProofVerified,
420 pub wrap_index: Box<PlonkVerificationKeyEvals<Fp>>,
421 pub wrap_vk: Option<()>,
423}
424
425impl Check<Fp> for VerificationKey {
426 fn check(&self, w: &mut Witness<Fp>) {
427 let Self {
428 max_proofs_verified: _,
429 actual_wrap_domain_size: _,
430 wrap_index,
431 wrap_vk: _,
432 } = self;
433
434 wrap_index.check(w);
435 }
436}
437
438impl ToFieldElements<Fp> for VerificationKey {
439 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
440 let Self {
441 max_proofs_verified,
442 actual_wrap_domain_size,
443 wrap_index,
444 wrap_vk: _,
445 } = self;
446
447 let PlonkVerificationKeyEvals {
448 sigma,
449 coefficients,
450 generic,
451 psm,
452 complete_add,
453 mul,
454 emul,
455 endomul_scalar,
456 } = wrap_index.as_ref();
457
458 max_proofs_verified.to_field_elements(fields);
459 actual_wrap_domain_size.to_field_elements(fields);
460
461 sigma.to_field_elements(fields);
462 coefficients.to_field_elements(fields);
463 generic.to_field_elements(fields);
464 psm.to_field_elements(fields);
465 complete_add.to_field_elements(fields);
466 mul.to_field_elements(fields);
467 emul.to_field_elements(fields);
468 endomul_scalar.to_field_elements(fields);
469 }
470}
471
472impl ToInputs for VerificationKey {
473 fn to_inputs(&self, inputs: &mut Inputs) {
474 let Self {
475 max_proofs_verified,
476 actual_wrap_domain_size,
477 wrap_index,
478 wrap_vk: _,
479 } = self;
480
481 let PlonkVerificationKeyEvals {
482 sigma,
483 coefficients,
484 generic,
485 psm,
486 complete_add,
487 mul,
488 emul,
489 endomul_scalar,
490 } = wrap_index.as_ref();
491
492 inputs.append(max_proofs_verified);
493 inputs.append(actual_wrap_domain_size);
494
495 for sigma in sigma {
496 inputs.append(sigma);
497 }
498 for coefficients in coefficients {
499 inputs.append(coefficients);
500 }
501 inputs.append(generic);
502 inputs.append(psm);
503 inputs.append(complete_add);
504 inputs.append(mul);
505 inputs.append(emul);
506 inputs.append(endomul_scalar);
507 }
508}
509
510impl VerificationKey {
511 pub fn dummy() -> Arc<Self> {
513 static VK: OnceCell<Arc<VerificationKey>> = OnceCell::new();
514
515 VK.get_or_init(|| {
516 let g = InnerCurve::of_affine(make_group(
517 Fp::one(),
518 Fp::from_str(
519 "12418654782883325593414442427049395787963493412651469444558597405572177144507",
520 )
521 .unwrap(),
522 ));
523 Arc::new(Self {
524 max_proofs_verified: ProofVerified::N2,
525 actual_wrap_domain_size: ProofVerified::N2,
526 wrap_index: PlonkVerificationKeyEvals {
527 sigma: std::array::from_fn(|_| g.clone()),
528 coefficients: std::array::from_fn(|_| g.clone()),
529 generic: g.clone(),
530 psm: g.clone(),
531 complete_add: g.clone(),
532 mul: g.clone(),
533 emul: g.clone(),
534 endomul_scalar: g,
535 }
536 .into(),
537 wrap_vk: None,
538 })
539 })
540 .clone()
541 }
542
543 pub fn digest(&self) -> Fp {
544 self.hash()
545 }
546
547 pub fn hash(&self) -> Fp {
548 self.hash_with_param(&MINA_SIDELOADED_VK)
549 }
550
551 pub fn gen() -> Self {
552 let mut rng = rand::thread_rng();
553
554 VerificationKey {
555 max_proofs_verified: {
556 let n: u64 = rng.gen();
557
558 if n.is_multiple_of(3) {
559 ProofVerified::N2
560 } else if n.is_multiple_of(2) {
561 ProofVerified::N1
562 } else {
563 ProofVerified::N0
564 }
565 },
566 wrap_index: PlonkVerificationKeyEvals::rand().into(),
567 wrap_vk: None,
568 actual_wrap_domain_size: {
569 let n: u64 = rng.gen();
570
571 if n.is_multiple_of(3) {
572 ProofVerified::N2
573 } else if n.is_multiple_of(2) {
574 ProofVerified::N1
575 } else {
576 ProofVerified::N0
577 }
578 },
579 }
580 }
581}
582
583#[derive(Clone, PartialEq, Eq, derive_more::From)]
584pub struct ZkAppUri(Vec<u8>);
585
586impl std::fmt::Debug for ZkAppUri {
587 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
588 let s = String::from_utf8_lossy(&self.0);
589 let s: &str = &s;
590 f.debug_tuple("ZkAppUri").field(&s).finish()
591 }
592}
593
594fn default_zkapp_uri_hash() -> Fp {
595 static HASH: Lazy<Fp> = Lazy::new(|| {
596 let mut inputs = Inputs::new();
597 inputs.append(&Fp::zero());
598 inputs.append(&Fp::zero());
599 hash_with_kimchi(&MINA_ZKAPP_URI, &inputs.to_fields())
600 });
601 *HASH
602}
603
604impl ZkAppUri {
605 #[allow(clippy::new_without_default)]
606 pub fn new() -> Self {
607 Self(Vec::new())
608 }
609
610 pub fn gen() -> Self {
611 let mut rng = rand::thread_rng();
612
613 let zkapp_uri: u64 = rng.gen();
614 let zkapp_uri = zkapp_uri.to_string();
615
616 Self(zkapp_uri.into_bytes())
617 }
618
619 fn opt_to_field(opt: Option<&ZkAppUri>) -> Fp {
620 let Some(zkapp_uri) = opt else {
621 return default_zkapp_uri_hash();
622 };
623 let mut inputs = Inputs::new();
624 for c in zkapp_uri.0.as_slice() {
625 for j in 0..8 {
626 inputs.append_bool((c & (1 << j)) != 0);
627 }
628 }
629 inputs.append_bool(true);
630 hash_with_kimchi(&MINA_ZKAPP_URI, &inputs.to_fields())
631 }
632}
633
634impl ToFieldElements<Fp> for Option<&ZkAppUri> {
635 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
636 let field_zkapp_uri = ZkAppUri::opt_to_field(*self);
637 field_zkapp_uri.to_field_elements(fields);
638 }
639}
640
641impl ToInputs for Option<&ZkAppUri> {
642 fn to_inputs(&self, inputs: &mut Inputs) {
644 let field_zkapp_uri = ZkAppUri::opt_to_field(*self);
645 inputs.append(&field_zkapp_uri);
646 }
647}
648
649impl std::ops::Deref for ZkAppUri {
650 type Target = [u8];
651
652 fn deref(&self) -> &Self::Target {
653 &self.0
654 }
655}
656
657impl From<&mina_p2p_messages::string::ZkAppUri> for ZkAppUri {
658 fn from(value: &mina_p2p_messages::string::ZkAppUri) -> Self {
659 Self(value.as_ref().to_vec())
660 }
661}
662
663impl From<&ZkAppUri> for mina_p2p_messages::string::ZkAppUri {
664 fn from(value: &ZkAppUri) -> Self {
665 Self::from(value.0.clone())
666 }
667}
668
669#[derive(Clone, Debug)]
672pub struct MutableFp {
673 fp: Arc<std::sync::Mutex<Option<Fp>>>,
674}
675
676#[cfg(feature = "fuzzing")]
679pub static GLOBAL_SKIP_PARTIAL_EQ: Lazy<std::sync::RwLock<bool>> =
680 Lazy::new(|| std::sync::RwLock::new(false));
681
682impl Eq for MutableFp {}
683
684impl PartialEq for MutableFp {
685 fn eq(&self, other: &Self) -> bool {
686 #[cfg(feature = "fuzzing")]
687 if *GLOBAL_SKIP_PARTIAL_EQ.read().unwrap() {
688 return true;
689 }
690
691 self.get().unwrap() == other.get().unwrap()
692 }
693}
694
695impl MutableFp {
696 pub fn empty() -> Self {
697 Self {
698 fp: Arc::new(std::sync::Mutex::new(None)),
699 }
700 }
701 pub fn new(fp: Fp) -> Self {
702 Self {
703 fp: Arc::new(std::sync::Mutex::new(Some(fp))),
704 }
705 }
706 pub fn get(&self) -> Option<Fp> {
707 *self.fp.lock().unwrap()
708 }
709 pub fn set(&self, fp: Fp) {
710 *self.fp.lock().unwrap() = Some(fp)
711 }
712}
713
714#[derive(Clone, Debug)]
715pub struct VerificationKeyWire {
716 vk: VerificationKey,
717 hash: MutableFp,
718}
719
720impl Eq for VerificationKeyWire {}
721
722impl PartialEq for VerificationKeyWire {
723 fn eq(&self, other: &Self) -> bool {
724 match (self.hash.get(), other.hash.get()) {
725 (Some(this), Some(other)) => this == other,
726 _ => self.vk == other.vk,
727 }
728 }
729}
730
731impl VerificationKeyWire {
732 pub fn new(vk: VerificationKey) -> Self {
733 Self {
734 vk,
735 hash: MutableFp::empty(),
736 }
737 }
738
739 pub fn with_hash(vk: VerificationKey, hash: Fp) -> Self {
740 Self {
741 vk,
742 hash: MutableFp::new(hash),
743 }
744 }
745
746 pub fn hash(&self) -> Fp {
747 let Self { vk, hash } = self;
748 if let Some(hash) = hash.get() {
749 return hash;
750 }
751 let vk_hash = vk.hash();
752 hash.set(vk_hash);
753 vk_hash
754 }
755
756 pub fn vk(&self) -> &VerificationKey {
757 let Self { vk, hash: _ } = self;
758 vk
759 }
760
761 pub fn dummy_hash() -> Fp {
762 static DUMMY: OnceCell<Arc<Fp>> = OnceCell::new();
763 **DUMMY.get_or_init(|| {
764 let vk = VerificationKey::dummy();
765 Arc::new(vk.hash())
766 })
767 }
768
769 pub fn dummy() -> Self {
770 Self {
771 vk: (*VerificationKey::dummy()).clone(),
772 hash: MutableFp::new(Self::dummy_hash()),
773 }
774 }
775
776 pub fn gen() -> Self {
777 Self::new(VerificationKey::gen())
778 }
779}
780
781#[derive(Clone, Debug, PartialEq, Eq)]
783pub struct ZkAppAccount {
784 pub app_state: [Fp; 8],
785 pub verification_key: Option<VerificationKeyWire>,
786 pub zkapp_version: u32,
788 pub action_state: [Fp; 5],
789 pub last_action_slot: Slot,
790 pub proved_state: bool,
791 pub zkapp_uri: ZkAppUri,
792}
793
794impl ToInputs for ZkAppAccount {
795 fn to_inputs(&self, inputs: &mut Inputs) {
796 let Self {
797 app_state,
798 verification_key,
799 zkapp_version,
800 action_state,
801 last_action_slot,
802 proved_state,
803 zkapp_uri,
804 } = self;
805
806 inputs.append(&Some(zkapp_uri));
808
809 inputs.append_bool(*proved_state);
810 inputs.append_u32(last_action_slot.as_u32());
811 for fp in action_state {
812 inputs.append_field(*fp);
813 }
814 inputs.append_u32(*zkapp_version);
815 let vk_hash = verification_key
816 .as_ref()
817 .map(VerificationKeyWire::hash)
818 .unwrap_or_else(VerificationKeyWire::dummy_hash);
819 inputs.append_field(vk_hash);
820 for fp in app_state {
821 inputs.append_field(*fp);
822 }
823 }
824}
825
826impl ToFieldElements<Fp> for ZkAppAccount {
827 fn to_field_elements(&self, fields: &mut Vec<Fp>) {
828 let Self {
829 app_state,
830 verification_key,
831 zkapp_version,
832 action_state,
833 last_action_slot,
834 proved_state,
835 zkapp_uri,
836 } = self;
837
838 app_state.to_field_elements(fields);
839 (
840 FlaggedOption::from(
841 verification_key
842 .as_ref()
843 .map(VerificationKeyWire::hash)
844 .as_ref(),
845 ),
846 VerificationKeyWire::dummy_hash,
847 )
848 .to_field_elements(fields);
849 Fp::from(*zkapp_version).to_field_elements(fields);
850 action_state.to_field_elements(fields);
851 last_action_slot.to_field_elements(fields);
852 proved_state.to_field_elements(fields);
853 Some(zkapp_uri).to_field_elements(fields);
854 }
855}
856
857impl Check<Fp> for ZkAppAccount {
858 fn check(&self, w: &mut Witness<Fp>) {
859 let Self {
860 app_state: _,
861 verification_key: _,
862 zkapp_version,
863 action_state: _,
864 last_action_slot,
865 proved_state: _,
866 zkapp_uri: _,
867 } = self;
868
869 zkapp_version.check(w);
870 last_action_slot.check(w);
871 }
872}
873
874impl Default for ZkAppAccount {
875 fn default() -> Self {
876 Self {
877 app_state: [Fp::zero(); 8],
878 verification_key: None,
879 zkapp_version: 0,
880 action_state: {
881 let empty = Self::empty_action_state();
882 [empty, empty, empty, empty, empty]
883 },
884 last_action_slot: Slot::zero(),
885 proved_state: false,
886 zkapp_uri: ZkAppUri::new(),
887 }
888 }
889}
890
891impl ZkAppAccount {
892 pub fn hash(&self) -> Fp {
893 self.hash_with_param(&MINA_ZKAPP_ACCOUNT)
894 }
895
896 pub fn empty_action_state() -> Fp {
898 hash_noinputs(&NO_INPUT_ZKAPP_ACTION_STATE_EMPTY_ELT)
899 }
900
901 pub fn is_default(&self) -> bool {
902 self == &Self::default()
903 }
904}
905
906#[derive(Clone, Eq)]
915pub struct AccountIdOrderable {
916 bigint_public_key_x: BigInteger256,
919 bigint_public_key_is_odd: bool,
920 bigint_token_id: BigInteger256,
921 public_key: CompressedPubKey,
923 token_id: TokenId,
924}
925
926impl PartialEq for AccountIdOrderable {
927 fn eq(&self, other: &Self) -> bool {
928 let Self {
929 bigint_public_key_x: self_x,
930 bigint_public_key_is_odd: self_is_odd,
931 bigint_token_id: self_token_id,
932 public_key: _,
933 token_id: _,
934 } = self;
935 let Self {
936 bigint_public_key_x: other_x,
937 bigint_public_key_is_odd: other_is_odd,
938 bigint_token_id: other_token_id,
939 public_key: _,
940 token_id: _,
941 } = other;
942
943 self_x == other_x && self_is_odd == other_is_odd && self_token_id == other_token_id
944 }
945}
946impl Ord for AccountIdOrderable {
947 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
950 let Self {
951 bigint_public_key_x: self_x,
952 bigint_public_key_is_odd: self_is_odd,
953 bigint_token_id: self_token_id,
954 public_key: _,
955 token_id: _,
956 } = self;
957
958 let Self {
959 bigint_public_key_x: other_x,
960 bigint_public_key_is_odd: other_is_odd,
961 bigint_token_id: other_token_id,
962 public_key: _,
963 token_id: _,
964 } = other;
965
966 match self_x.cmp(other_x) {
967 std::cmp::Ordering::Equal => {}
968 non_eq => return non_eq,
969 }
970 match self_is_odd.cmp(other_is_odd) {
971 std::cmp::Ordering::Equal => {}
972 non_eq => return non_eq,
973 }
974 self_token_id.cmp(other_token_id)
975 }
976}
977
978impl PartialOrd for AccountIdOrderable {
979 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
980 Some(self.cmp(other))
981 }
982}
983
984impl From<AccountId> for AccountIdOrderable {
985 fn from(value: AccountId) -> Self {
986 let AccountId {
987 public_key,
988 token_id,
989 } = value;
990 let CompressedPubKey { x, is_odd } = &public_key;
991
992 Self {
993 bigint_public_key_x: (*x).into(),
994 bigint_public_key_is_odd: *is_odd,
995 bigint_token_id: token_id.0.into(),
996 public_key,
997 token_id,
998 }
999 }
1000}
1001
1002impl From<AccountIdOrderable> for AccountId {
1003 fn from(value: AccountIdOrderable) -> Self {
1004 let AccountIdOrderable {
1005 bigint_public_key_x: _,
1006 bigint_public_key_is_odd: _,
1007 bigint_token_id: _,
1008 public_key,
1009 token_id,
1010 } = value;
1011
1012 Self {
1013 public_key,
1014 token_id,
1015 }
1016 }
1017}
1018
1019#[derive(Clone, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
1020#[serde(into = "v2::MinaBaseAccountIdStableV2")]
1021#[serde(try_from = "v2::MinaBaseAccountIdStableV2")]
1022pub struct AccountId {
1023 pub public_key: CompressedPubKey,
1024 pub token_id: TokenId,
1025}
1026
1027impl ToInputs for AccountId {
1028 fn to_inputs(&self, inputs: &mut Inputs) {
1029 let Self {
1030 public_key,
1031 token_id,
1032 } = self;
1033 inputs.append(public_key);
1034 inputs.append(token_id);
1035 }
1036}
1037
1038impl AccountId {
1039 pub fn empty() -> Self {
1040 Self {
1041 public_key: CompressedPubKey::empty(),
1042 token_id: TokenId::default(),
1043 }
1044 }
1045
1046 pub fn is_empty(&self) -> bool {
1047 self == &Self::empty()
1048 }
1049
1050 pub fn derive_token_id(&self) -> TokenId {
1051 let is_odd_field = match self.public_key.is_odd {
1053 true => Fp::one(),
1054 false => Fp::zero(),
1055 };
1056
1057 TokenId(hash_with_kimchi(
1058 &MINA_DERIVE_TOKEN_ID,
1059 &[self.public_key.x, self.token_id.0, is_odd_field],
1060 ))
1061 }
1062
1063 pub fn new(public_key: CompressedPubKey, token_id: TokenId) -> Self {
1064 Self {
1065 public_key,
1066 token_id,
1067 }
1068 }
1069
1070 pub fn new_with_default_token(public_key: CompressedPubKey) -> Self {
1071 Self::new(public_key, TokenId::default())
1072 }
1073
1074 pub fn create(public_key: CompressedPubKey, token_id: TokenId) -> Self {
1075 Self::new(public_key, token_id)
1076 }
1077
1078 pub fn rand() -> Self {
1079 let mut rng = rand::thread_rng();
1080
1081 Self {
1082 public_key: gen_compressed(),
1083 token_id: TokenId(Fp::rand(&mut rng)),
1084 }
1085 }
1086
1087 pub fn deserialize(bytes: &[u8]) -> Self {
1088 let mut cursor = Cursor::new(bytes);
1089 AccountId::binprot_read(&mut cursor).unwrap()
1090 }
1091
1092 pub fn serialize(&self) -> Vec<u8> {
1093 let mut bytes = Vec::with_capacity(10000);
1094 self.binprot_write(&mut bytes).unwrap();
1095 bytes
1096 }
1097
1098 pub fn checked_equal(&self, other: &Self, w: &mut Witness<Fp>) -> Boolean {
1099 use crate::proofs::field::field;
1100
1101 let pk_equal = checked_equal_compressed_key(&self.public_key, &other.public_key, w);
1103
1104 let tid_equal = field::equal(self.token_id.0, other.token_id.0, w);
1106
1107 pk_equal.and(&tid_equal, w)
1109 }
1110}
1111
1112pub fn checked_equal_compressed_key(
1113 a: &CompressedPubKey,
1114 b: &CompressedPubKey,
1115 w: &mut Witness<Fp>,
1116) -> Boolean {
1117 use crate::proofs::field::field;
1118
1119 let x_eq = field::equal(a.x, b.x, w);
1120 let odd_eq = Boolean::equal(&a.is_odd.to_boolean(), &b.is_odd.to_boolean(), w);
1121 x_eq.and(&odd_eq, w)
1122}
1123
1124pub fn checked_equal_compressed_key_const_and(
1126 a: &CompressedPubKey,
1127 b: &CompressedPubKey,
1128 w: &mut Witness<Fp>,
1129) -> Boolean {
1130 use crate::proofs::field::field;
1131
1132 if b == &CompressedPubKey::empty() {
1133 let x_eq = field::equal(a.x, b.x, w);
1134 let odd_eq = Boolean::const_equal(&a.is_odd.to_boolean(), &b.is_odd.to_boolean());
1135 x_eq.and(&odd_eq, w)
1136 } else {
1137 let x_eq = field::equal(a.x, b.x, w);
1138 let odd_eq = Boolean::equal(&a.is_odd.to_boolean(), &b.is_odd.to_boolean(), w);
1139 x_eq.const_and(&odd_eq)
1140 }
1141}
1142
1143impl std::fmt::Debug for AccountId {
1144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1145 f.debug_struct("AccountId")
1146 .field("public_key", &self.public_key)
1147 .field("token_id", &self.token_id)
1148 .finish()
1149 }
1150}
1151
1152impl std::hash::Hash for AccountId {
1153 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1154 self.public_key.x.hash(state);
1155 self.public_key.is_odd.hash(state);
1156 self.token_id.hash(state);
1157 }
1158}
1159
1160impl PartialEq for AccountId {
1161 fn eq(&self, other: &Self) -> bool {
1162 self.public_key.x == other.public_key.x
1163 && self.public_key.is_odd == other.public_key.is_odd
1164 && self.token_id.0 == other.token_id.0
1165 }
1166}
1167
1168#[derive(Debug)]
1169pub enum PermissionTo {
1170 Access,
1171 Send,
1172 Receive,
1173 SetDelegate,
1174 IncrementNonce,
1175}
1176
1177#[derive(Copy, Clone, Debug)]
1178pub enum ControlTag {
1179 Proof,
1180 Signature,
1181 NoneGiven,
1182}
1183
1184impl ControlTag {
1185 pub fn gen(rng: &mut ThreadRng) -> Self {
1186 match Self::NoneGiven {
1188 ControlTag::Proof => {}
1189 ControlTag::Signature => {}
1190 ControlTag::NoneGiven => {}
1191 };
1192
1193 [Self::Proof, Self::Signature, Self::NoneGiven]
1194 .choose(rng)
1195 .copied()
1196 .unwrap()
1197 }
1198}
1199
1200pub fn check_permission(auth: AuthRequired, tag: ControlTag) -> bool {
1201 use AuthRequired::*;
1202 use ControlTag as Tag;
1203
1204 match (auth, tag) {
1205 (Impossible, _) => false,
1206 (None, _) => true,
1207 (Proof, Tag::Proof) => true,
1208 (Signature, Tag::Signature) => true,
1209 (Either, Tag::Proof | Tag::Signature) => true,
1211 (Signature, Tag::Proof) => false,
1212 (Proof, Tag::Signature) => false,
1213 (Proof | Signature | Either, Tag::NoneGiven) => false,
1214 (Both, _) => unimplemented!("check_permission with `Both` Not implemented in OCaml"),
1215 }
1216}
1217
1218pub fn eval_no_proof<F: FieldWitness>(
1220 auth: AuthRequired,
1221 signature_verifies: Boolean,
1222 is_and_const: bool,
1223 is_or_const: bool,
1224 w: &mut Witness<F>,
1225) -> Boolean {
1226 let AuthRequiredEncoded {
1229 constant,
1230 signature_necessary: _,
1231 signature_sufficient,
1232 } = auth.encode();
1233
1234 let constant = constant.to_boolean();
1235 let signature_sufficient = signature_sufficient.to_boolean();
1236
1237 let a = if is_and_const {
1238 constant.neg().const_and(&signature_verifies)
1239 } else {
1240 constant.neg().and(&signature_verifies, w)
1241 };
1242 let b = if is_or_const {
1243 constant.const_or(&a)
1244 } else {
1245 constant.or(&a, w)
1246 };
1247 signature_sufficient.and(&b, w)
1248}
1249
1250pub struct PermsConst {
1251 pub and_const: bool,
1252 pub or_const: bool,
1253}
1254
1255#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
1277#[serde(into = "v2::MinaBaseAccountBinableArgStableV2")]
1278#[serde(try_from = "v2::MinaBaseAccountBinableArgStableV2")]
1279pub struct Account {
1280 pub public_key: CompressedPubKey,
1283
1284 pub token_id: TokenId,
1288
1289 pub token_symbol: TokenSymbol,
1294
1295 pub balance: Balance,
1298
1299 pub nonce: Nonce,
1305
1306 pub receipt_chain_hash: ReceiptChainHash,
1313
1314 pub delegate: Option<CompressedPubKey>,
1319
1320 pub voting_for: VotingFor,
1324
1325 pub timing: Timing,
1332
1333 pub permissions: Permissions<AuthRequired>,
1338
1339 pub zkapp: Option<Box<ZkAppAccount>>,
1347}
1348
1349impl Account {
1350 #[cfg(test)]
1351 pub fn create() -> Self {
1352 let pubkey = CompressedPubKey::from_address(
1353 "B62qnzbXmRNo9q32n4SNu2mpB8e7FYYLH8NmaX6oFCBYjjQ8SbD7uzV",
1354 )
1355 .unwrap();
1356
1357 Self {
1358 public_key: pubkey.clone(),
1359 token_id: TokenId::default(),
1360 token_symbol: TokenSymbol::default(),
1361 balance: Balance::from_u64(10101),
1362 nonce: Nonce::zero(),
1363 receipt_chain_hash: ReceiptChainHash::empty(),
1364 delegate: Some(pubkey),
1365 voting_for: VotingFor::dummy(),
1366 timing: Timing::Untimed,
1367 permissions: Permissions::user_default(),
1368 zkapp: None,
1369 }
1370 }
1371
1372 pub fn create_with(account_id: AccountId, balance: Balance) -> Self {
1373 let delegate = if account_id.token_id.is_default() {
1374 Some(account_id.public_key.clone())
1376 } else {
1377 None
1378 };
1379
1380 Self {
1381 public_key: account_id.public_key,
1382 token_id: account_id.token_id,
1383 token_symbol: TokenSymbol::default(),
1384 balance,
1385 nonce: Nonce::zero(),
1386 receipt_chain_hash: ReceiptChainHash::empty(),
1387 delegate,
1388 voting_for: VotingFor::dummy(),
1389 timing: Timing::Untimed,
1390 permissions: Permissions::user_default(),
1391 zkapp: None,
1392 }
1393 }
1394
1395 pub fn delegate_or_empty(&self) -> MyCow<'_, CompressedPubKey> {
1396 MyCow::borrow_or_else(&self.delegate, CompressedPubKey::empty)
1397 }
1398
1399 pub fn zkapp_or_empty(&self) -> MyCow<'_, Box<ZkAppAccount>> {
1400 MyCow::borrow_or_else(&self.zkapp, Box::<ZkAppAccount>::default)
1401 }
1402
1403 pub fn initialize(account_id: &AccountId) -> Self {
1404 Self::create_with(account_id.clone(), Balance::zero())
1405 }
1406
1407 pub fn deserialize(bytes: &[u8]) -> Self {
1408 let mut cursor = Cursor::new(bytes);
1409 Account::binprot_read(&mut cursor).unwrap()
1410 }
1411
1412 pub fn serialize(&self) -> Vec<u8> {
1413 let mut bytes = Vec::with_capacity(10000);
1414 self.binprot_write(&mut bytes).unwrap();
1415 bytes
1416 }
1417
1418 pub fn empty() -> Self {
1419 Self {
1420 public_key: CompressedPubKey {
1421 x: Fp::zero(),
1422 is_odd: false,
1423 },
1424 token_id: TokenId::default(),
1425 token_symbol: TokenSymbol::default(),
1426 balance: Balance::zero(),
1427 nonce: Nonce::zero(),
1428 receipt_chain_hash: ReceiptChainHash::empty(),
1429 delegate: None,
1430 voting_for: VotingFor::dummy(),
1431 timing: Timing::Untimed,
1432 permissions: Permissions::user_default(),
1433 zkapp: None,
1434 }
1435 }
1436
1437 pub fn id(&self) -> AccountId {
1438 AccountId {
1439 public_key: self.public_key.clone(),
1440 token_id: self.token_id.clone(),
1441 }
1442 }
1443
1444 pub fn has_locked_tokens(&self, global_slot: Slot) -> bool {
1445 match self.timing {
1446 Timing::Untimed => false,
1447 Timing::Timed { .. } => {
1448 let curr_min_balance = self.min_balance_at_slot(global_slot);
1449
1450 !curr_min_balance.is_zero()
1451 }
1452 }
1453 }
1454
1455 pub fn has_locked_tokens_checked(
1456 &self,
1457 global_slot: &CheckedSlot<Fp>,
1458 w: &mut Witness<Fp>,
1459 ) -> Boolean {
1460 let TimingAsRecordChecked {
1461 is_timed: _,
1462 initial_minimum_balance,
1463 cliff_time,
1464 cliff_amount,
1465 vesting_period,
1466 vesting_increment,
1467 } = self.timing.to_record_checked::<Fp>();
1468
1469 let cur_min_balance = checked_min_balance_at_slot(
1470 global_slot,
1471 &cliff_time,
1472 &cliff_amount,
1473 &vesting_period,
1474 &vesting_increment,
1475 &initial_minimum_balance,
1476 w,
1477 );
1478
1479 let zero_min_balance = CheckedBalance::zero().equal(&cur_min_balance, w);
1480 zero_min_balance.neg()
1481 }
1482
1483 pub fn liquid_balance_at_slot(&self, global_slot: Slot) -> Balance {
1484 match self.timing {
1485 Timing::Untimed => self.balance,
1486 Timing::Timed { .. } => self
1487 .balance
1488 .sub_amount(self.min_balance_at_slot(global_slot).to_amount())
1489 .unwrap(),
1490 }
1491 }
1492
1493 pub fn min_balance_at_slot(&self, global_slot: Slot) -> Balance {
1494 match self.timing {
1495 Timing::Untimed => Balance::zero(),
1496 Timing::Timed {
1497 initial_minimum_balance,
1498 cliff_time,
1499 cliff_amount,
1500 vesting_period,
1501 vesting_increment,
1502 } => {
1503 if global_slot < cliff_time {
1504 initial_minimum_balance
1505 } else if vesting_period.is_zero() {
1506 Balance::zero()
1508 } else {
1509 match initial_minimum_balance.sub_amount(cliff_amount) {
1510 None => Balance::zero(),
1511 Some(min_balance_past_cliff) => {
1512 let num_periods = (global_slot.as_u32() - cliff_time.as_u32())
1515 / vesting_period.as_u32();
1516 let num_periods: u64 = num_periods.into();
1517
1518 let vesting_decrement = {
1519 let vesting_increment = vesting_increment.as_u64();
1520
1521 if u64::MAX
1522 .checked_div(num_periods)
1523 .map(|res| {
1524 matches!(
1525 res.cmp(&vesting_increment),
1526 std::cmp::Ordering::Less
1527 )
1528 })
1529 .unwrap_or(false)
1530 {
1531 Amount::from_u64(u64::MAX)
1533 } else {
1534 Amount::from_u64(
1535 num_periods.checked_mul(vesting_increment).unwrap(),
1536 )
1537 }
1538 };
1539
1540 match min_balance_past_cliff.sub_amount(vesting_decrement) {
1541 None => Balance::zero(),
1542 Some(amount) => amount,
1543 }
1544 }
1545 }
1546 }
1547 }
1548 }
1549 }
1550
1551 pub fn has_permission_to(&self, control: ControlTag, to: PermissionTo) -> bool {
1553 match to {
1554 PermissionTo::Access => check_permission(self.permissions.access, control),
1555 PermissionTo::Send => check_permission(self.permissions.send, control),
1556 PermissionTo::Receive => check_permission(self.permissions.receive, control),
1557 PermissionTo::SetDelegate => check_permission(self.permissions.set_delegate, control),
1558 PermissionTo::IncrementNonce => {
1559 check_permission(self.permissions.increment_nonce, control)
1560 }
1561 }
1562 }
1563
1564 pub fn checked_has_permission_to<F: FieldWitness>(
1565 &self,
1566 consts: PermsConst,
1567 signature_verifies: Option<Boolean>,
1568 to: PermissionTo,
1569 w: &mut Witness<F>,
1570 ) -> Boolean {
1571 let signature_verifies = match signature_verifies {
1572 Some(signature_verifies) => signature_verifies,
1573 None => match to {
1574 PermissionTo::Send => Boolean::True,
1575 PermissionTo::Receive => Boolean::False,
1576 PermissionTo::SetDelegate => Boolean::True,
1577 PermissionTo::IncrementNonce => Boolean::True,
1578 PermissionTo::Access => {
1579 panic!("signature_verifies argument must be given for access permission")
1580 }
1581 },
1582 };
1583
1584 let auth = match to {
1585 PermissionTo::Send => self.permissions.send,
1586 PermissionTo::Receive => self.permissions.receive,
1587 PermissionTo::SetDelegate => self.permissions.set_delegate,
1588 PermissionTo::IncrementNonce => self.permissions.increment_nonce,
1589 PermissionTo::Access => self.permissions.access,
1590 };
1591
1592 eval_no_proof(
1593 auth,
1594 signature_verifies,
1595 consts.and_const,
1596 consts.or_const,
1597 w,
1598 )
1599 }
1600
1601 pub fn has_permission_to_send(&self) -> bool {
1603 self.has_permission_to(ControlTag::Signature, PermissionTo::Access)
1604 && self.has_permission_to(ControlTag::Signature, PermissionTo::Send)
1605 }
1606
1607 pub fn has_permission_to_receive(&self) -> bool {
1609 self.has_permission_to(ControlTag::NoneGiven, PermissionTo::Access)
1610 && self.has_permission_to(ControlTag::NoneGiven, PermissionTo::Receive)
1611 }
1612
1613 pub fn has_permission_to_set_delegate(&self) -> bool {
1615 self.has_permission_to(ControlTag::Signature, PermissionTo::Access)
1616 && self.has_permission_to(ControlTag::Signature, PermissionTo::SetDelegate)
1617 }
1618
1619 pub fn has_permission_to_increment_nonce(&self) -> bool {
1621 self.has_permission_to(ControlTag::Signature, PermissionTo::Access)
1622 && self.has_permission_to(ControlTag::Signature, PermissionTo::IncrementNonce)
1623 }
1624
1625 pub fn hash(&self) -> Fp {
1626 self.hash_with_param(&MINA_ACCOUNT)
1627 }
1628
1629 pub fn checked_hash(&self, w: &mut Witness<Fp>) -> Fp {
1630 use crate::proofs::transaction::transaction_snark::checked_hash;
1631
1632 let inputs = self.to_inputs_owned();
1633
1634 checked_hash(&MINA_ACCOUNT, &inputs.to_fields(), w)
1635 }
1636
1637 pub fn rand() -> Self {
1638 let mut rng = rand::thread_rng();
1639 let rng = &mut rng;
1640
1641 let symbol: u64 = rng.gen();
1642 let mut symbol = symbol.to_string();
1643 symbol.truncate(6);
1644
1645 let zkapp_uri: u64 = rng.gen();
1646 let mut zkapp_uri = zkapp_uri.to_string();
1647 zkapp_uri.truncate(6);
1648
1649 let gen_perm = |rng: &mut ThreadRng| {
1650 let n: u64 = rng.gen();
1651 if n.is_multiple_of(5) {
1652 AuthRequired::Either
1653 } else if n.is_multiple_of(4) {
1654 AuthRequired::Impossible
1655 } else if n.is_multiple_of(3) {
1656 AuthRequired::None
1657 } else if n.is_multiple_of(2) {
1658 AuthRequired::Proof
1659 } else {
1660 AuthRequired::Signature
1661 }
1662 };
1663
1664 Self {
1665 public_key: gen_compressed(),
1666 token_id: TokenId(Fp::rand(rng)),
1667 token_symbol: TokenSymbol(symbol.into_bytes()),
1668 balance: rng.gen(),
1669 nonce: rng.gen(),
1670 receipt_chain_hash: ReceiptChainHash(Fp::rand(rng)),
1671 delegate: if rng.gen() {
1672 Some(gen_compressed())
1673 } else {
1674 None
1675 },
1676 voting_for: VotingFor(Fp::rand(rng)),
1677 timing: if rng.gen() {
1678 Timing::Untimed
1679 } else {
1680 Timing::Timed {
1681 initial_minimum_balance: rng.gen(),
1682 cliff_time: rng.gen(),
1683 cliff_amount: rng.gen(),
1684 vesting_period: rng.gen(),
1685 vesting_increment: rng.gen(),
1686 }
1687 },
1688 permissions: Permissions {
1689 edit_state: gen_perm(rng),
1690 send: gen_perm(rng),
1691 receive: gen_perm(rng),
1692 set_delegate: gen_perm(rng),
1693 set_permissions: gen_perm(rng),
1694 set_verification_key: SetVerificationKey {
1695 auth: gen_perm(rng),
1696 txn_version: TXN_VERSION_CURRENT, },
1698 set_zkapp_uri: gen_perm(rng),
1699 edit_action_state: gen_perm(rng),
1700 set_token_symbol: gen_perm(rng),
1701 increment_nonce: gen_perm(rng),
1702 set_voting_for: gen_perm(rng),
1703 access: gen_perm(rng),
1704 set_timing: gen_perm(rng),
1705 },
1706 zkapp: if rng.gen() {
1707 Some(
1708 ZkAppAccount {
1709 app_state: [
1710 Fp::rand(rng),
1711 Fp::rand(rng),
1712 Fp::rand(rng),
1713 Fp::rand(rng),
1714 Fp::rand(rng),
1715 Fp::rand(rng),
1716 Fp::rand(rng),
1717 Fp::rand(rng),
1718 ],
1719 verification_key: if rng.gen() {
1720 Some(VerificationKeyWire::gen())
1721 } else {
1722 None
1723 },
1724 zkapp_version: rng.gen(),
1725 action_state: [
1726 Fp::rand(rng),
1727 Fp::rand(rng),
1728 Fp::rand(rng),
1729 Fp::rand(rng),
1730 Fp::rand(rng),
1731 ],
1732 last_action_slot: rng.gen(),
1733 proved_state: rng.gen(),
1734 zkapp_uri: ZkAppUri(zkapp_uri.into_bytes()),
1735 }
1736 .into(),
1737 )
1738 } else {
1739 None
1740 },
1741 }
1742 }
1743}
1744
1745pub fn default_zkapp_hash() -> Fp {
1746 static HASH: Lazy<Fp> = Lazy::new(|| {
1747 let default = ZkAppAccount::default();
1748 default.hash()
1749 });
1750 *HASH
1751}
1752
1753impl ToInputs for Account {
1754 fn to_inputs(&self, inputs: &mut Inputs) {
1755 let Self {
1756 public_key,
1757 token_id,
1758 token_symbol,
1759 balance,
1760 nonce,
1761 receipt_chain_hash,
1762 delegate,
1763 voting_for,
1764 timing,
1765 permissions,
1766 zkapp,
1767 } = self;
1768
1769 let field_zkapp = match zkapp.as_ref() {
1771 Some(zkapp) => zkapp.hash(),
1772 None => default_zkapp_hash(),
1773 };
1774 inputs.append(&field_zkapp);
1775 inputs.append(permissions);
1776
1777 let TimingAsRecord {
1779 is_timed,
1780 initial_minimum_balance,
1781 cliff_time,
1782 cliff_amount,
1783 vesting_period,
1784 vesting_increment,
1785 } = timing.to_record();
1786 inputs.append_bool(is_timed);
1787 inputs.append_u64(initial_minimum_balance.as_u64());
1788 inputs.append_u32(cliff_time.as_u32());
1789 inputs.append_u64(cliff_amount.as_u64());
1790 inputs.append_u32(vesting_period.as_u32());
1791 inputs.append_u64(vesting_increment.as_u64());
1792
1793 inputs.append_field(voting_for.0);
1795 let delegate = MyCow::borrow_or_else(delegate, CompressedPubKey::empty);
1797 inputs.append(delegate.as_ref());
1798 inputs.append_field(receipt_chain_hash.0);
1800 inputs.append_u32(nonce.as_u32());
1802 inputs.append_u64(balance.as_u64());
1804 assert!(token_symbol.len() <= 6);
1807 inputs.append(token_symbol);
1808 inputs.append_field(token_id.0);
1810 inputs.append(public_key);
1812 }
1813}
1814
1815fn verify_merkle_path(account: &Account, merkle_path: &[MerklePath]) -> Fp {
1816 let account_hash = account.hash();
1817
1818 merkle_path
1819 .iter()
1820 .enumerate()
1821 .fold(account_hash, |accum, (height, path)| {
1822 let hashes = match path {
1823 MerklePath::Left(right) => [accum, *right],
1824 MerklePath::Right(left) => [*left, accum],
1825 };
1826 let param = get_merkle_param_for_height(height);
1827 hash_with_kimchi(param, &hashes)
1828 })
1829}
1830
1831pub fn checked_verify_merkle_path(
1833 account: &Account,
1834 merkle_path: &[MerklePath],
1835 w: &mut Witness<Fp>,
1836) -> Fp {
1837 use crate::proofs::transaction::transaction_snark::checked_hash;
1838
1839 let account_hash = account.checked_hash(w);
1840
1841 merkle_path
1842 .iter()
1843 .enumerate()
1844 .fold(account_hash, |accum, (height, path)| {
1845 let hashes = match path {
1846 MerklePath::Left(right) => [accum, *right],
1847 MerklePath::Right(left) => [*left, accum],
1848 };
1849 w.exists(hashes);
1850
1851 let param = get_merkle_param_for_height(height);
1852 checked_hash(param, &hashes, w)
1853 })
1854}
1855
1856#[cfg(test)]
1857mod tests {
1858 use o1_utils::FieldHelpers;
1859
1860 #[cfg(target_family = "wasm")]
1861 use wasm_bindgen_test::wasm_bindgen_test as test;
1862
1863 use super::*;
1864
1865 #[test]
1866 fn test_size_account() {
1867 const SIZE_WITH_9LIMBS: usize = 296;
1868
1869 #[cfg(not(target_family = "wasm"))]
1870 const SIZE: usize = 280;
1871
1872 #[cfg(target_family = "wasm")]
1874 const SIZE: usize = 280;
1875
1876 if std::mem::size_of::<BigInteger256>() == 9 * 4 {
1877 assert_eq!(std::mem::size_of::<Account>(), SIZE_WITH_9LIMBS);
1878 } else {
1879 assert_eq!(std::mem::size_of::<Account>(), SIZE);
1880 }
1881 }
1882
1883 #[test]
1884 fn test_hash_account() {
1885 let acc = Account::create();
1886 let hash = acc.hash();
1887
1888 elog!("account_hash={}", hash);
1889 elog!("account_hash={}", hash.to_hex());
1890
1891 assert_eq!(
1892 hash.to_hex(),
1893 "7018596b7a10344908c7582482b1401a3cbdd40212beb428baf629b84ceb7f0b"
1894 );
1895
1896 let acc = Account {
1897 public_key: CompressedPubKey::from_address(
1898 "B62qnzbXmRNo9q32n4SNu2mpB8e7FYYLH8NmaX6oFCBYjjQ8SbD7uzV",
1899 )
1900 .unwrap(),
1901 token_id: TokenId::default(),
1902 token_symbol: TokenSymbol::from("seb".to_string().into_bytes()),
1903 balance: Balance::from_u64(10101),
1904 nonce: Nonce::from_u32(62772),
1905 receipt_chain_hash: ReceiptChainHash::empty(),
1906 delegate: None,
1907 voting_for: VotingFor::dummy(),
1908 timing: Timing::Untimed,
1909 permissions: Permissions::user_default(),
1910 zkapp: None,
1911 };
1912
1913 assert_eq!(
1914 acc.hash().to_hex(),
1915 "8cb53d374b844227d4c63b2dcf198312f8fcb4b60392fee5b165243508d16e32"
1916 );
1917 }
1918
1919 #[test]
1920 fn test_hash_genesis_winner_account() {
1921 let acc = Account {
1922 public_key: CompressedPubKey::from_address(
1923 "B62qiy32p8kAKnny8ZFwoMhYpBppM1DWVCqAPBYNcXnsAHhnfAAuXgg",
1924 )
1925 .unwrap(),
1926 token_id: TokenId::default(),
1927 token_symbol: TokenSymbol::default(),
1928 balance: Balance::from_u64(20000001000),
1929 nonce: Nonce::from_u32(0),
1930 receipt_chain_hash: ReceiptChainHash::parse_str(
1931 "2mzbV7WevxLuchs2dAMY4vQBS6XttnCUF8Hvks4XNBQ5qiSGGBQe",
1932 )
1933 .unwrap(),
1934 delegate: Some(
1935 CompressedPubKey::from_address(
1936 "B62qiy32p8kAKnny8ZFwoMhYpBppM1DWVCqAPBYNcXnsAHhnfAAuXgg",
1937 )
1938 .unwrap(),
1939 ),
1940 voting_for: VotingFor::parse_str(
1941 "3NK2tkzqqK5spR2sZ7tujjqPksL45M3UUrcA4WhCkeiPtnugyE2x",
1942 )
1943 .unwrap(),
1944 timing: Timing::Untimed,
1945 permissions: Permissions {
1946 edit_state: AuthRequired::Signature,
1947 access: AuthRequired::None,
1948 send: AuthRequired::Signature,
1949 receive: AuthRequired::None,
1950 set_delegate: AuthRequired::Signature,
1951 set_permissions: AuthRequired::Signature,
1952 set_verification_key: SetVerificationKey {
1953 auth: AuthRequired::Signature,
1954 txn_version: TxnVersion::from_u32(2),
1955 },
1956 set_zkapp_uri: AuthRequired::Signature,
1957 edit_action_state: AuthRequired::Signature,
1958 set_token_symbol: AuthRequired::Signature,
1959 increment_nonce: AuthRequired::Signature,
1960 set_voting_for: AuthRequired::Signature,
1961 set_timing: AuthRequired::Signature,
1962 },
1963 zkapp: None,
1964 };
1965
1966 println!("{:?}", acc);
1967
1968 assert_eq!(
1969 mina_p2p_messages::v2::LedgerHash::from_fp(acc.hash()).to_string(),
1970 "jwnEz6CjzSYowUsvw5gKpuTkRjBY5dEtc6YmQj1U5d2k5KZzTmc"
1971 );
1972 }
1973
1974 #[test]
1975 fn test_dummy_sideloaded_verification_key() {
1976 assert_eq!(
1977 VerificationKey::dummy().hash().to_hex(),
1978 "d6da18e4091fbcd86843604fb8ff2d9613e76fa16c49b0263a1566a8e7188007"
1979 );
1980 }
1981
1982 #[test]
1983 fn test_rand() {
1984 for _ in 0..1000 {
1985 let rand = Account::rand();
1986 let hash = rand.hash();
1987
1988 let bytes = Account::serialize(&rand);
1989 let rand2: Account = Account::deserialize(&bytes);
1990
1991 assert_eq!(hash, rand2.hash());
1992 }
1993 }
1994
1995 #[cfg(not(target_family = "wasm"))] #[test]
1997 fn test_rand_tree() {
1998 }
2049}