darkfi/blockchain/monero/
utils.rs1use monero::{Hash, VarInt};
20use primitive_types::U256;
21use sha2::{Digest, Sha256};
22
23use super::{MerkleProof, MerkleTreeParameters, MoneroPowData};
24use crate::{blockchain::HeaderHash, Error, Result};
25
26pub fn cn_fast_hash(data: &[u8]) -> Hash {
28 Hash::new(data)
29}
30
31pub fn cn_fast_hash2(hash1: &Hash, hash2: &Hash) -> Hash {
33 let mut tmp = [0u8; 64];
34 tmp[..32].copy_from_slice(hash1.as_bytes());
35 tmp[32..].copy_from_slice(hash2.as_bytes());
36 cn_fast_hash(&tmp)
37}
38
39#[allow(unused)]
43fn tree_hash_count(count: usize) -> Result<usize> {
44 if count < 3 {
45 return Err(Error::MoneroHashingError(format!(
46 "Cannot calculate tree hash root. Expected count to be >3 but got {count}"
47 )));
48 }
49
50 if count > 0x10000000 {
51 return Err(Error::MoneroHashingError(format!(
52 "Cannot calculate tree hash root. Expected count to be less than 0x10000000 but got {count}"
53 )));
54 }
55
56 let mut pow: usize = 2;
58 while pow < count {
59 pow <<= 1;
60 }
61
62 Ok(pow >> 1)
63}
64
65#[allow(unused)]
67pub fn tree_hash(hashes: &[Hash]) -> Result<Hash> {
68 if hashes.is_empty() {
69 return Err(Error::MoneroHashingError(
70 "Cannot calculate Merkle root, no hashes".to_string(),
71 ));
72 }
73
74 match hashes.len() {
75 1 => Ok(hashes[0]),
76 2 => Ok(cn_fast_hash2(&hashes[0], &hashes[1])),
77 n => {
78 let mut cnt = tree_hash_count(n)?;
79 let mut buf = vec![Hash::null(); cnt];
80
81 let c = 2 * cnt - hashes.len();
84
85 buf[..c].copy_from_slice(&hashes[..c]);
86
87 let mut i: usize = c;
89 for b in &mut buf[c..cnt] {
90 *b = cn_fast_hash2(&hashes[i], &hashes[i + 1]);
91 i += 2;
92 }
93
94 if i != hashes.len() {
95 return Err(Error::MoneroHashingError(
96 "Cannot calculate the Merkle root, hashes not equal to count".to_string(),
97 ));
98 }
99
100 while cnt > 2 {
101 cnt >>= 1;
102 let mut i = 0;
103 for j in 0..cnt {
104 buf[j] = cn_fast_hash2(&buf[i], &buf[i + 1]);
105 i += 2;
106 }
107 }
108
109 Ok(cn_fast_hash2(&buf[0], &buf[1]))
110 }
111 }
112}
113
114#[allow(clippy::cognitive_complexity)]
118#[allow(unused)]
119pub fn create_merkle_proof(hashes: &[Hash], hash: &Hash) -> Option<MerkleProof> {
120 match hashes.len() {
121 0 => None,
122 1 => {
123 if hashes[0] != *hash {
124 return None;
125 }
126 MerkleProof::try_construct(vec![], 0)
127 }
128 2 => hashes.iter().enumerate().find_map(|(pos, h)| {
129 if h != hash {
130 return None
131 }
132 let i = usize::from(pos == 0);
133 MerkleProof::try_construct(vec![hashes[i]], u32::from(pos != 0))
134 }),
135 len => {
136 let mut idx = hashes.iter().position(|node| node == hash)?;
137 let mut count = tree_hash_count(len).ok()?;
138
139 let mut ints = vec![Hash::null(); count];
140
141 let c = 2 * count - len;
142 ints[..c].copy_from_slice(&hashes[..c]);
143
144 let mut branch = vec![];
145 let mut path = 0u32;
146 let mut i = c;
147 for (j, val) in ints.iter_mut().enumerate().take(count).skip(c) {
148 if idx == i || idx == i + 1 {
150 let ii = if idx == i { i + 1 } else { i };
151 branch.push(hashes[ii]);
152 path = (path << 1) | u32::from(idx != i);
153 idx = j;
154 }
155 *val = cn_fast_hash2(&hashes[i], &hashes[i + 1]);
156 i += 2;
157 }
158
159 debug_assert_eq!(i, len);
160
161 while count > 2 {
162 count >>= 1;
163 let mut i = 0;
164 for j in 0..count {
165 if idx == i || idx == i + 1 {
166 let ii = if idx == i { i + 1 } else { i };
167 branch.push(ints[ii]);
168 path = (path << 1) | u32::from(idx != i);
169 idx = j;
170 }
171 ints[j] = cn_fast_hash2(&ints[i], &ints[i + 1]);
172 i += 2;
173 }
174 }
175
176 if idx == 0 || idx == 1 {
177 let ii = usize::from(idx == 0);
178 branch.push(ints[ii]);
179 path = (path << 1) | u32::from(idx != 0);
180 }
181
182 MerkleProof::try_construct(branch, path)
183 }
184 }
185}
186
187pub fn create_blockhashing_blob(
189 header: &monero::BlockHeader,
190 merkle_root: &monero::Hash,
191 transaction_count: u64,
192) -> Vec<u8> {
193 let mut blockhashing_blob = monero::consensus::serialize(header);
194 blockhashing_blob.extend_from_slice(merkle_root.as_bytes());
195 let mut count = monero::consensus::serialize(&VarInt(transaction_count));
196 blockhashing_blob.append(&mut count);
197 blockhashing_blob
198}
199
200#[allow(unused)]
201fn check_aux_chains(
202 monero_data: &MoneroPowData,
203 merge_mining_params: VarInt,
204 aux_chain_merkle_root: &monero::Hash,
205 darkfi_hash: HeaderHash,
206 darkfi_genesis_hash: HeaderHash,
207) -> bool {
208 let df_hash = monero::Hash::from_slice(darkfi_hash.as_slice());
209
210 if merge_mining_params == VarInt(0) {
211 if df_hash == *aux_chain_merkle_root {
213 return true
214 }
215 }
216
217 let merkle_tree_params = MerkleTreeParameters::from_varint(merge_mining_params);
218 if merkle_tree_params.number_of_chains() == 0 {
219 return false
220 }
221
222 let hash_position = U256::from_little_endian(
223 &Sha256::new()
224 .chain_update(darkfi_genesis_hash.as_slice())
225 .chain_update(merkle_tree_params.aux_nonce().to_le_bytes())
226 .chain_update((109_u8).to_le_bytes())
227 .finalize(),
228 )
229 .low_u32() %
230 u32::from(merkle_tree_params.number_of_chains());
231
232 let (merkle_root, pos) = monero_data
233 .aux_chain_merkle_proof
234 .calculate_root_with_pos(&df_hash, merkle_tree_params.number_of_chains());
235
236 if hash_position != pos {
237 return false
238 }
239
240 merkle_root == *aux_chain_merkle_root
241}