1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use super::*;
use crate::prefixes::*;
use ark_ff::BigInteger256;
use mina_hasher::{create_legacy, Fp, Hashable, Hasher, ROInput};
use once_cell::sync::OnceCell;
use proof_systems::mina_hasher::create_kimchi;
pub struct MinaPoseidonMerkleMergerLegacy;
impl MerkleMerger for MinaPoseidonMerkleMergerLegacy {
type Hash = Fp;
fn merge(
hashes: [Option<Self::Hash>; 2],
metadata: MerkleTreeNodeMetadata,
) -> Option<Self::Hash> {
merge_poseidon_hash_legacy(hashes, metadata.height()).into()
}
}
pub struct MinaPoseidonMerkleMerger;
impl MerkleMerger for MinaPoseidonMerkleMerger {
type Hash = Fp;
fn merge(
hashes: [Option<Self::Hash>; 2],
metadata: MerkleTreeNodeMetadata,
) -> Option<Self::Hash> {
merge_poseidon_hash_kimchi(hashes, metadata.height()).into()
}
}
#[derive(Clone)]
struct MinaPoseidonMerkleTreeNonLeafNode([Option<Fp>; 2], u32);
impl Hashable for MinaPoseidonMerkleTreeNonLeafNode {
type D = u32;
fn to_roinput(&self) -> mina_hasher::ROInput {
let mut roi = ROInput::new();
for hash in self.0.into_iter().flatten() {
roi = roi.append_field(hash);
}
roi
}
fn domain_string(height: Self::D) -> Option<String> {
if height > 0 {
Some(make_prefix_merkle_tree(height - 1))
} else {
None
}
}
}
fn merge_poseidon_hash_legacy(mut hashes: [Option<Fp>; 2], height: u32) -> Fp {
for hash_opt in hashes.iter_mut() {
if hash_opt.is_none() {
*hash_opt = get_empty_hash_legacy(height - 1).into();
}
}
let mut hasher = create_legacy(height);
let hashable = MinaPoseidonMerkleTreeNonLeafNode(hashes, height);
hasher.hash(&hashable)
}
fn get_empty_hash_legacy(height: u32) -> Fp {
if height == 0 {
static EMPTY_HASH: OnceCell<Fp> = OnceCell::new();
*EMPTY_HASH.get_or_init(|| {
const DEFAULT_HASH: BigInteger256 = BigInteger256::new([
618825277339585648,
17206846358602357477,
11135808194678189552,
2326690702673829595,
]);
DEFAULT_HASH.into()
})
} else {
let child_hash = get_empty_hash_legacy(height - 1);
merge_poseidon_hash_legacy([Some(child_hash), Some(child_hash)], height)
}
}
fn merge_poseidon_hash_kimchi(mut hashes: [Option<Fp>; 2], height: u32) -> Fp {
for hash_opt in hashes.iter_mut() {
if hash_opt.is_none() {
*hash_opt = get_empty_hash_kimchi(height - 1).into();
}
}
let mut hasher = create_kimchi(height);
let hashable = MinaPoseidonMerkleTreeNonLeafNode(hashes, height);
hasher.hash(&hashable)
}
fn get_empty_hash_kimchi(height: u32) -> Fp {
if height == 0 {
static EMPTY_HASH: OnceCell<Fp> = OnceCell::new();
*EMPTY_HASH.get_or_init(|| {
const DEFAULT_HASH: BigInteger256 = BigInteger256::new([
17222659083400437799,
16271203913493378952,
8137184135467838648,
1525063794952698544,
]);
DEFAULT_HASH.into()
})
} else {
let child_hash = get_empty_hash_kimchi(height - 1);
merge_poseidon_hash_kimchi([Some(child_hash), Some(child_hash)], height)
}
}