Skip to main content

blvm_protocol/
bip152.rs

1//! BIP152 high-level compact block types (wire / serde).
2//!
3//! Short-id hashing lives here so protocol reconstruction and the node use one rule.
4//! Conversions to/from [`crate::network::CmpctBlockMessage`] live in `network.rs`.
5
6use crate::{BlockHeader, Transaction};
7use serde::{Deserialize, Serialize};
8
9/// Short transaction ID (6 bytes / 48 bits) per BIP152.
10pub type ShortTxId = [u8; 6];
11
12/// Compact block representation (header + short IDs + prefilled txs).
13#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
14pub struct CompactBlock {
15    /// Block header
16    pub header: BlockHeader,
17    /// Nonce for short ID calculation (64-bit)
18    pub nonce: u64,
19    /// Short transaction IDs (6 bytes each)
20    pub short_ids: Vec<ShortTxId>,
21    /// Prefilled transactions: block index, transaction, and witness stacks.
22    /// `None` means the transaction has no witness.
23    pub prefilled_txs: Vec<(usize, Transaction, Option<Vec<crate::segwit::Witness>>)>,
24}
25
26/// SipHash-2-4. BIP152 short ids use the low 6 bytes of this digest.
27pub fn siphash24(k0: u64, k1: u64, data: &[u8]) -> u64 {
28    use siphasher::sip::SipHasher24;
29    use std::hash::Hasher;
30    let mut hasher = SipHasher24::new_with_keys(k0, k1);
31    hasher.write(data);
32    hasher.finish()
33}
34
35/// BIP152 short id: SipHash-2-4 of the wtxid, keyed by SHA256(header || nonce).
36pub fn short_tx_id(header: &BlockHeader, wtxid: &crate::Hash, nonce: u64) -> ShortTxId {
37    use sha2::{Digest, Sha256};
38    let mut data = crate::serialization::serialize_block_header(header);
39    data.extend_from_slice(&nonce.to_le_bytes());
40    let hash = Sha256::digest(&data);
41    let k0 = u64::from_le_bytes(hash[0..8].try_into().expect("8"));
42    let k1 = u64::from_le_bytes(hash[8..16].try_into().expect("8"));
43    let digest = siphash24(k0, k1, wtxid);
44    let bytes = digest.to_le_bytes();
45    let mut short = [0u8; 6];
46    short.copy_from_slice(&bytes[..6]);
47    short
48}
49
50#[cfg(test)]
51mod siphash_vector {
52    use super::siphash24;
53
54    #[test]
55    fn siphash24_matches_the_reference_vector() {
56        let mut key = [0u8; 16];
57        for (i, byte) in key.iter_mut().enumerate() {
58            *byte = i as u8;
59        }
60        let k0 = u64::from_le_bytes(key[0..8].try_into().unwrap());
61        let k1 = u64::from_le_bytes(key[8..16].try_into().unwrap());
62        let msg: Vec<u8> = (0..15).collect();
63        assert_eq!(siphash24(k0, k1, &msg), 0xa129_ca61_49be_45e5);
64    }
65}