Skip to content

Commit dee803e

Browse files
kppeyusufatik
andauthored
Override compute_wtxid() and compute_txid() functions with patched sha256 impl (#1715)
Co-authored-by: eyusufatik <esadyusufatik@gmail.com>
1 parent b5cc058 commit dee803e

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

crates/bitcoin-da/src/helpers/merkle_tree.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ mod tests {
114114
use bitcoin::hashes::Hash;
115115

116116
use super::*;
117+
use crate::helpers::calculate_wtxid;
117118
use crate::helpers::parsers::parse_hex_transaction;
118119

119120
#[test]
@@ -149,7 +150,7 @@ mod tests {
149150
.unwrap()
150151
.lines()
151152
.map(|tx_hex| parse_hex_transaction(tx_hex).unwrap())
152-
.map(|tx| tx.compute_wtxid().to_byte_array())
153+
.map(|tx| calculate_wtxid(&tx))
153154
.collect::<Vec<_>>();
154155
compare_merkle_tree_against_bitcoin_impl(txs);
155156
}

crates/bitcoin-da/src/helpers/mod.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
use core::num::NonZeroU16;
22

3+
use bitcoin::consensus::Encodable;
4+
use bitcoin::Transaction;
35
use sha2::{Digest, Sha256};
46

57
#[cfg(feature = "native")]
@@ -98,3 +100,64 @@ pub fn calculate_sha256(input: &[u8]) -> [u8; 32] {
98100
hasher.update(input);
99101
hasher.finalize().into()
100102
}
103+
104+
/// Computes the [`Txid`].
105+
///
106+
/// Hashes the transaction **excluding** the segwit data (i.e. the marker, flag bytes, and the
107+
/// witness fields themselves). For non-segwit transactions which do not have any segwit data,
108+
/// this will be equal to [`Transaction::compute_wtxid()`].
109+
pub fn calculate_txid(tx: &Transaction) -> [u8; 32] {
110+
let mut enc = vec![];
111+
tx.version
112+
.consensus_encode(&mut enc)
113+
.expect("engines don't error");
114+
tx.input
115+
.consensus_encode(&mut enc)
116+
.expect("engines don't error");
117+
tx.output
118+
.consensus_encode(&mut enc)
119+
.expect("engines don't error");
120+
tx.lock_time
121+
.consensus_encode(&mut enc)
122+
.expect("engines don't error");
123+
calculate_double_sha256(&enc)
124+
}
125+
126+
/// Computes the segwit version of the transaction id.
127+
///
128+
/// Hashes the transaction **including** all segwit data (i.e. the marker, flag bytes, and the
129+
/// witness fields themselves). For non-segwit transactions which do not have any segwit data,
130+
/// this will be equal to [`Transaction::txid()`].
131+
pub fn calculate_wtxid(tx: &Transaction) -> [u8; 32] {
132+
let mut enc = vec![];
133+
tx.consensus_encode(&mut enc).expect("engines don't error");
134+
calculate_double_sha256(&enc)
135+
}
136+
137+
#[cfg(test)]
138+
mod tests {
139+
use bitcoin::hashes::Hash;
140+
use bitcoin::Transaction;
141+
142+
use crate::helpers::{calculate_txid, calculate_wtxid};
143+
144+
#[test]
145+
fn calculate_txid_wtxid() {
146+
let hex_tx = "020000000001013a66019bfcc719ba12586a83ebbb0b3debdc945f563cd64fd44c8044e3d3a1790100000000fdffffff028fa2aa060000000017a9147ba15d4e0d8334de3a68cf3687594e2d1ee5b00d879179e0090000000016001493c93ad222e57d65438545e048822ede2d418a3d0247304402202432e6c422b93705fbc57b350ea43e4ef9441c0907988eff051eaac807fc8cf2022046c92b540b5f04f8da11febb5d2a478aed1b8bc088e769da8b78fffcae8c9a9a012103e2991b47d9c788f55379f9ef519b642d79d7dfe0e7555ec5575ee934b2dca1223f5d0c00";
147+
let taproot = "02000000000101a196aca845bc2974cf6fe319b261b507c6ccd50e1d4caea8d354a2f604bce56b0000000000ffffffff01d02410000000000022512041a287c2929429246f946b6ed5fb0e09b4603ce1ba37304f1465095bfa1507ef0c000040c941f8f22379e3ee06516746364294b5bd0e8817bfdd5ba453823faafe0650f72b89f0a90e8157a72c3172524598ad339e6bba52b01e47c3858f54008038e7c740dfe1c1a9871cf63498a30711abf7f4464ac355d87e109a5efff5194886655e30cf64b5aa0632cbef05dcc3c55733b755320003b983def2d8f4a9ec25f2df0d0f40868be49f22d7b7c461480658d32e922387153b74c52167cab3a764f7f7722d8f40e56cdf3b6e87dc64f4a7ec86d8c36bb71ec577b502472ddd53b0b15a3bcc9800407a9ef2501f18be9db4971806bc9711c2c6a729c8a516f95b5f5f26b52fc61f1dc57632112c09bd08f7be0c067ebd2f5881bbc089ffd0eb360e6d548dbd577e7440cae7c292336738cbf3523762359595b398af1805da66f0c429516cf89a48786de289789278431f52a0806c896ef87a3005db874be0aba90108e7b77ceb53977e40f499e7e1b99b980aa4352465c5bb3db2a13705ebe53512dd15a75c26ba802514327a09de7894b053829963ec1ff958029ddf7729be49a79bf8bf5cbb2afd172a40389a3b1f15c2d4a2c7c6b6d65e8ba56e8a5dbaed2f9750d7bbd0ad79920eb2d07cbdb92221b9952157294fa6e570a8a3144f88ca33b1bafb368d13d48df0c0e9fd5601203adc3c668fe1bd096bf0088e9b51469fb706292b4c4c77c9436275f17e9530abad2023b29f89b45f4af41588dcaf0ca572ada32872a88224f311373917f1b37d08d1ac204b15848e495a3a62283daaadb3f458a00859fe48e321f0121ebabbdd6698f9faba208242640732773249312c47ca7bdb50ca79f15f2ecc32b9c83ceebba44fb74df7ba20cbdd028cfe32c1c1f2d84bfec71e19f92df509bba7b8ad31ca6c1a134fe09204ba20d3c79b99ac4d265c2f97ac11e3232c07a598b020cf56c6f055472c893c0967aeba20d45c70d28f169e1f0c7f4a78e2bc73497afe585b70aa897955989068f3350aaaba20de13fc96ea6899acbdc5db3afaa683f62fe35b60ff6eb723dad28a11d2b12f8cba20e36200aaa8dce9453567bba108bdc51f7f1174b97a65e4dc4402fc5de779d41cba20f178fcce82f95c524b53b077e6180bd2d779a9057fdff4255a0af95af918cee0ba569c61c150929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac046e5d29daed70ecd9d769aba5109997be4ff474e853e28256d5eb64d1327f934419b9d368c90acef45745e70de113270bfbe970d7bf73624a468f878519e92e100000000";
148+
let segwit = "01000000000101805dc5cccfdbd08dfa4f86381bbd6355494884596fa48db3767df89d4a166a4a0100000000ffffffff022d450500000000002251201a2128fb15aed5eb41c8a1ee326308c9d1df9456c678bf6121da7727a91f8c340931ba000000000016001400b4a8c8806c2ea75094b3762b29d0d6c4356d6a02483045022100a1e377b19aaac488e0a2d91d1a5eaefa994a1d33176a9478bf30088e311a3955022057694eef88ca2ec10fabdcdb5ccab8aa7ebc3a286e627299fd198867bbf0bc020121022310eb6b8c4e4c3611bdee21704963654042c9d52d2d820beb86f22deff90e2300000000";
149+
let non_segwit = "0100000001032e38e9c0a84c6046d687d10556dcacc41d275ec55fc00779ac88fdf357a187000000008c493046022100c352d3dd993a981beba4a63ad15c209275ca9470abfcd57da93b58e4eb5dce82022100840792bc1f456062819f15d33ee7055cf7b5ee1af1ebcc6028d9cdb1c3af7748014104f46db5e9d61a9dc27b8d64ad23e7383a4e6ca164593c2527c038c0857eb67ee8e825dca65046b82c9331586c82e0fd1f633f25f87c161bc6f8a630121df2b3d3ffffffff0200e32321000000001976a914c398efa9c392ba6013c5e04ee729755ef7f58b3288ac000fe208010000001976a914948c765a6914d43f2a7ac177da2c2f6b52de3d7c88ac00000000";
150+
151+
compare_txid_wtxid(hex_tx);
152+
compare_txid_wtxid(taproot);
153+
compare_txid_wtxid(segwit);
154+
compare_txid_wtxid(non_segwit);
155+
}
156+
157+
fn compare_txid_wtxid(tx: &str) {
158+
let tx: Transaction = bitcoin::consensus::deserialize(&hex::decode(tx).unwrap()).unwrap();
159+
160+
assert_eq!(tx.compute_txid().to_byte_array(), calculate_txid(&tx));
161+
assert_eq!(tx.compute_wtxid().to_byte_array(), calculate_wtxid(&tx));
162+
}
163+
}

crates/bitcoin-da/src/verifier.rs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use bitcoin::hashes::Hash;
21
use citrea_primitives::compression::decompress_blob;
32
use crypto_bigint::{Encoding, U256};
43
use itertools::Itertools;
@@ -11,7 +10,7 @@ use crate::helpers::parsers::{
1110
parse_batch_proof_transaction, parse_light_client_transaction, ParsedBatchProofTransaction,
1211
ParsedLightClientTransaction, VerifyParsed,
1312
};
14-
use crate::helpers::{calculate_double_sha256, merkle_tree};
13+
use crate::helpers::{calculate_double_sha256, calculate_txid, calculate_wtxid, merkle_tree};
1514
use crate::network_constants::{
1615
INITIAL_MAINNET_STATE, INITIAL_SIGNET_STATE, INITIAL_TESTNET4_STATE, MAINNET_CONSTANTS,
1716
REGTEST_CONSTANTS, SIGNET_CONSTANTS, TESTNET4_CONSTANTS,
@@ -104,7 +103,7 @@ impl DaVerifier for BitcoinVerifier {
104103
.filter(|wtxid| wtxid.starts_with(prefix));
105104
for (wtxid, tx) in relevant_wtxid_iter.zip_eq(&completeness_proof) {
106105
// ensure completeness proof tx matches the inclusion tx
107-
if tx.compute_wtxid().as_byte_array() != wtxid {
106+
if &calculate_wtxid(tx) != wtxid {
108107
return Err(ValidationError::RelevantTxNotInProof);
109108
}
110109

@@ -222,11 +221,7 @@ impl DaVerifier for BitcoinVerifier {
222221
}
223222

224223
let claimed_root = merkle_tree::BitcoinMerkleTree::calculate_root_with_merkle_proof(
225-
inclusion_proof
226-
.coinbase_tx
227-
.compute_txid()
228-
.as_raw_hash()
229-
.to_byte_array(),
224+
calculate_txid(&inclusion_proof.coinbase_tx),
230225
0,
231226
inclusion_proof.coinbase_merkle_proof,
232227
);

0 commit comments

Comments
 (0)