MCPcopy Create free account
hub / github.com/BitVM/BitVM / new

Method new

final-spv/src/merkle_tree.rs:21–78  ·  view source on GitHub ↗

Constructs a standard Bitcoin Merkle tree. Leaf nodes are transaction IDs (txids), which are double-SHA256 hashes of transaction data. Internal nodes are formed by `DSHA256(LeftChildHash || RightChildHash)`.

(transactions: Vec<[u8; 32]>)

Source from the content-addressed store, hash-verified

19 /// Leaf nodes are transaction IDs (txids), which are double-SHA256 hashes of transaction data.
20 /// Internal nodes are formed by `DSHA256(LeftChildHash || RightChildHash)`.
21 pub fn new(transactions: Vec<[u8; 32]>) -> Self {
22 if transactions.len() == 1 {
23 // root is the coinbase txid
24 return BitcoinMerkleTree {
25 nodes: vec![transactions],
26 };
27 }
28
29 let mut tree = BitcoinMerkleTree {
30 nodes: vec![transactions],
31 };
32
33 // Construct the tree
34 let mut curr_level_offset: usize = 1;
35 let mut prev_level_size = tree.nodes[0].len();
36 let mut prev_level_index_offset = 0;
37 let mut preimage: [u8; 64] = [0; 64];
38 while prev_level_size > 1 {
39 tree.nodes.push(vec![]);
40 for i in 0..(prev_level_size / 2) {
41 if tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2]
42 == tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2 + 1]
43 {
44 // This check helps prevent certain attacks involving duplicate hashes,
45 // although the primary defense against CVE-2012-2459 and similar issues
46 // in SPV often requires more structural changes or careful proof verification,
47 // which the `new_mid_state` tree aims to provide. For more, please check:
48 // https://github.com/bitcoin/bitcoin/blob/31d3eebfb92ae0521e18225d69be95e78fb02672/src/consensus/merkle.cpp#L9
49 panic!("Duplicate hashes in the Merkle tree, indicating mutation");
50 }
51 preimage[..32].copy_from_slice(
52 &tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2],
53 );
54 preimage[32..].copy_from_slice(
55 &tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2 + 1],
56 );
57 let combined_hash = calculate_double_sha256(&preimage);
58 tree.nodes[curr_level_offset].push(combined_hash);
59 }
60 if prev_level_size % 2 == 1 {
61 let mut preimage: [u8; 64] = [0; 64];
62 preimage[..32].copy_from_slice(
63 &tree.nodes[curr_level_offset - 1]
64 [prev_level_index_offset + prev_level_size - 1],
65 );
66 preimage[32..].copy_from_slice(
67 &tree.nodes[curr_level_offset - 1]
68 [prev_level_index_offset + prev_level_size - 1],
69 );
70 let combined_hash = calculate_double_sha256(&preimage);
71 tree.nodes[curr_level_offset].push(combined_hash);
72 }
73 curr_level_offset += 1;
74 prev_level_size = prev_level_size.div_ceil(2);
75 prev_level_index_offset = 0;
76 }
77 tree
78 }

Callers

nothing calls this directly

Calls 3

lenMethod · 0.80
calculate_double_sha256Function · 0.70
pushMethod · 0.45

Tested by

no test coverage detected