Skip to content

Commit fe33e19

Browse files
committed
Add utility for validating a Merkle inclusion proof
... as retrieved via `transaction_get_merkle`.
1 parent dd872d6 commit fe33e19

File tree

2 files changed

+44
-0
lines changed

2 files changed

+44
-0
lines changed

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ mod config;
6363
pub mod raw_client;
6464
mod stream;
6565
mod types;
66+
pub mod utils;
6667

6768
pub use api::ElectrumApi;
6869
pub use batch::Batch;

src/utils.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//! Utilities helping to handle Electrum-related data.
2+
3+
use bitcoin::hash_types::TxMerkleNode;
4+
use bitcoin::hashes::sha256d::Hash as Sha256d;
5+
use bitcoin::hashes::Hash;
6+
use bitcoin::Txid;
7+
use types::GetMerkleRes;
8+
9+
/// Verifies a Merkle inclusion proof as retrieved via [`transaction_get_merkle`] for a transaction with the
10+
/// given `txid` and `merkle_root` as included in the [`BlockHeader`].
11+
///
12+
/// Returns `true` if the transaction is included in the corresponding block, and `false`
13+
/// otherwise.
14+
///
15+
/// [`transaction_get_merkle`]: crate::ElectrumApi::transaction_get_merkle
16+
/// [`BlockHeader`]: bitcoin::BlockHeader
17+
pub fn validate_merkle_proof(
18+
txid: &Txid,
19+
merkle_root: &TxMerkleNode,
20+
merkle_res: &GetMerkleRes,
21+
) -> bool {
22+
let mut index = merkle_res.pos;
23+
let mut cur = txid.to_raw_hash();
24+
for bytes in &merkle_res.merkle {
25+
let mut reversed = [0u8; 32];
26+
reversed.copy_from_slice(bytes);
27+
reversed.reverse();
28+
// unwrap() safety: `reversed` has len 32 so `from_slice` can never fail.
29+
let next_hash = Sha256d::from_slice(&reversed).unwrap();
30+
31+
let (left, right) = if index % 2 == 0 {
32+
(cur, next_hash)
33+
} else {
34+
(next_hash, cur)
35+
};
36+
37+
let data = [&left[..], &right[..]].concat();
38+
cur = Sha256d::hash(&data);
39+
index /= 2;
40+
}
41+
42+
cur == merkle_root.to_raw_hash()
43+
}

0 commit comments

Comments
 (0)