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

Method new_mid_state

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

Constructs a "mid-state" Merkle tree, designed for generating secure SPV (Simplified Payment Verification) proofs. This structure, when used with the corresponding `calculate_root_with_merkle_proof` (or `BlockInclusionProof::get_root`) method, helps mitigate vulnerabilities associated with standard Bitcoin Merkle trees in SPV contexts, such as certain forms of hash duplication or ambiguity attacks

(transactions: &[CircuitTransaction])

Source from the content-addressed store, hash-verified

103 /// This acts as a domain separation, ensuring that the internal nodes of this mid-state tree cannot be misinterpreted
104 /// as leaf txids or other hash types during verification.
105 pub fn new_mid_state(transactions: &[CircuitTransaction]) -> Self {
106 if transactions.len() == 1 {
107 // root is the coinbase mid-state txid (which is a standard txid)
108 return BitcoinMerkleTree {
109 nodes: vec![vec![transactions[0].mid_state_txid()]],
110 };
111 }
112
113 let mid_state_txids: Vec<[u8; 32]> =
114 transactions.iter().map(|tx| tx.mid_state_txid()).collect();
115
116 let mut tree = BitcoinMerkleTree {
117 nodes: vec![mid_state_txids], // Level 0: Leaf nodes (txids)
118 };
119
120 // Construct the tree
121 let mut curr_level_offset: usize = 1;
122 let mut prev_level_size = tree.nodes[0].len();
123 let mut prev_level_index_offset = 0;
124 let mut preimage: [u8; 64] = [0; 64]; // Preimage for SHA256(SHA256(LeftChild) || SHA256(RightChild))
125 while prev_level_size > 1 {
126 tree.nodes.push(vec![]);
127 for i in 0..(prev_level_size / 2) {
128 let left_child_node =
129 tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2];
130 let right_child_node =
131 tree.nodes[curr_level_offset - 1][prev_level_index_offset + i * 2 + 1];
132
133 if left_child_node == right_child_node {
134 // This check is also present in the mid-state tree construction.
135 // While the primary defense is in the proof verification, preventing duplicate
136 // inputs at this stage is good practice.
137 panic!("Duplicate hashes in the Merkle tree, indicating mutation");
138 }
139 // Preimage construction: SHA256(LeftChildNode) || SHA256(RightChildNode)
140 preimage[..32].copy_from_slice(&calculate_sha256(&left_child_node));
141 preimage[32..].copy_from_slice(&calculate_sha256(&right_child_node));
142 // The new node is SHA256 of this preimage
143 let combined_mid_state_hash = calculate_sha256(&preimage);
144 tree.nodes[curr_level_offset].push(combined_mid_state_hash);
145 }
146 // Handle odd number of nodes at the previous level by duplicating the last node's hash processing
147 if prev_level_size % 2 == 1 {
148 let mut preimage: [u8; 64] = [0; 64];
149 let last_node = tree.nodes[curr_level_offset - 1]
150 [prev_level_index_offset + prev_level_size - 1];
151 // Preimage: SHA256(LastNode) || SHA256(LastNode)
152 preimage[..32].copy_from_slice(&calculate_sha256(&last_node));
153 preimage[32..].copy_from_slice(&calculate_sha256(&last_node));
154 let combined_mid_state_hash = calculate_sha256(&preimage);
155 tree.nodes[curr_level_offset].push(combined_mid_state_hash);
156 }
157 curr_level_offset += 1;
158 prev_level_size = prev_level_size.div_ceil(2);
159 prev_level_index_offset = 0;
160 }
161 tree
162 }

Callers

nothing calls this directly

Calls 4

lenMethod · 0.80
mid_state_txidMethod · 0.80
calculate_sha256Function · 0.70
pushMethod · 0.45

Tested by

no test coverage detected