mina_tree/
tree_version.rs

1use crate::account::{get_legacy_hash_of, Account, AccountLegacy, TokenId, TokenIdLegacy};
2use mina_curves::pasta::Fp;
3use poseidon::hash::params::get_merkle_param_for_height;
4use std::{fmt::Debug, hash::Hash};
5
6pub trait TreeVersion {
7    type Account: Debug + Clone;
8    type TokenId: Debug + Clone + Hash + PartialEq;
9
10    fn hash_node(depth: usize, left: Fp, right: Fp) -> Fp;
11    fn hash_leaf(leaf: &Self::Account) -> Fp;
12    fn empty_hash_at_height(height: usize) -> Fp;
13}
14
15#[derive(Clone, Debug)]
16pub struct V1;
17
18#[derive(Clone, Debug)]
19pub struct V2;
20
21impl TreeVersion for V2 {
22    type Account = Account;
23    type TokenId = TokenId;
24
25    fn hash_node(height: usize, left: Fp, right: Fp) -> Fp {
26        let param = get_merkle_param_for_height(height);
27        poseidon::hash::hash_with_kimchi(param, &[left, right])
28    }
29
30    fn hash_leaf(leaf: &Self::Account) -> Fp {
31        leaf.hash()
32    }
33
34    fn empty_hash_at_height(height: usize) -> Fp {
35        (0..height).fold(Account::empty().hash(), |prev_hash, height| {
36            Self::hash_node(height, prev_hash, prev_hash)
37        })
38    }
39}
40
41impl TreeVersion for V1 {
42    type Account = AccountLegacy;
43    type TokenId = TokenIdLegacy;
44
45    fn hash_node(depth: usize, left: Fp, right: Fp) -> Fp {
46        use mina_hasher::{create_legacy, Hashable, Hasher, ROInput};
47
48        #[derive(Clone)]
49        struct TwoHashes(Fp, Fp);
50
51        impl Hashable for TwoHashes {
52            type D = u32; // depth
53
54            fn to_roinput(&self) -> ROInput {
55                let mut roi = ROInput::new();
56                roi = roi.append_field(self.0);
57                roi = roi.append_field(self.1);
58                roi
59            }
60
61            fn domain_string(depth: Self::D) -> Option<String> {
62                Some(format!("CodaMklTree{:03}", depth))
63            }
64        }
65
66        let mut hasher = create_legacy::<TwoHashes>(depth as u32);
67        hasher.update(&TwoHashes(left, right));
68        hasher.digest()
69    }
70
71    fn hash_leaf(leaf: &Self::Account) -> Fp {
72        use mina_hasher::{create_legacy, Hasher};
73
74        let mut hasher = create_legacy::<AccountLegacy>(());
75        hasher.update(leaf);
76        hasher.digest()
77    }
78
79    fn empty_hash_at_height(height: usize) -> Fp {
80        (0..height).fold(account_empty_legacy_hash(), |prev_hash, height| {
81            Self::hash_node(height, prev_hash, prev_hash)
82        })
83    }
84}
85
86pub fn account_empty_legacy_hash() -> Fp {
87    get_legacy_hash_of((), &AccountLegacy::empty())
88}