binius_examples/circuits/
bitcoin_block_contains_transaction.rs1use binius_circuits::bitcoin::{double_sha256::double_sha256, merkle_path::merkle_path};
5use binius_frontend::{CircuitBuilder, Wire};
6
7pub fn block_contains_transaction(
14 builder: &CircuitBuilder,
15 transaction_hash: [Wire; 4],
16 siblings: &[([Wire; 4], Wire)],
17 merkle_path_len: Wire,
18 block_header: [Wire; 10],
19 block_hash: [Wire; 4],
20) {
21 let merkle_root = [
23 join(builder, block_header[5], block_header[4]),
24 join(builder, block_header[6], block_header[5]),
25 join(builder, block_header[7], block_header[6]),
26 join(builder, block_header[8], block_header[7]),
27 ];
28
29 builder.assert_eq_v(
31 "merkle root",
32 merkle_path(builder, transaction_hash, siblings, merkle_path_len),
33 merkle_root,
34 );
35
36 builder.assert_eq_v("block hash", double_sha256(builder, &block_header), block_hash);
38}
39
40fn join(builder: &CircuitBuilder, b0: Wire, b1: Wire) -> Wire {
41 let c0 = builder.shl(b0, 32);
42 let c1 = builder.shr(b1, 32);
43 builder.bxor(c0, c1)
44}
45
46#[cfg(test)]
47mod tests {
48 use binius_circuits::bitcoin::merkle_path::SiblingSide;
49 use binius_core::Word;
50 use hex_literal::hex;
51
52 use super::*;
53
54 #[test]
55 fn test_valid() {
56 let builder = CircuitBuilder::new();
58 let transaction_hash: [Wire; 4] = std::array::from_fn(|_| builder.add_witness());
59 let siblings: Vec<([Wire; 4], Wire)> = std::iter::repeat_with(|| {
60 (std::array::from_fn(|_| builder.add_witness()), builder.add_witness())
61 })
62 .take(30)
63 .collect();
64 let merkle_path_len = builder.add_witness();
65 let block_header: [Wire; 10] = std::array::from_fn(|_| builder.add_witness());
66 let block_hash: [Wire; 4] = std::array::from_fn(|_| builder.add_witness());
67 block_contains_transaction(
68 &builder,
69 transaction_hash,
70 &siblings,
71 merkle_path_len,
72 block_header,
73 block_hash,
74 );
75 let circuit = builder.build();
76
77 let mut filler = circuit.new_witness_filler();
79 let block_header_value = hex!(
80 "000000264a14e21adad047d981c06a26446e345eda3d8beb807401000000000000000000fc01df2139954b36cebc3fa6fbf6a7160a67d34b67e5c4aa2a7ce46f5bb42a83642ea468b32c0217d14ba4d1"
81 );
82 let block_hash_value =
83 hex!("228561b085b7524957e515605725901238299ff2793300000000000000000000");
84 let transaction_hash_value =
85 hex!("6f2f044a225e8b293c6e54cf2771bf4d17ba8904b1f61cf9c392965dcbda0b83");
86 let siblings_value = vec![
87 (
88 hex!("783089645b0bc42d44e9d6a7ea62adf7a8a2adc6b7f0173d663369217b771b86"),
89 SiblingSide::Right,
90 ),
91 (
92 hex!("1eeeeb0cac1753a10ade3b34bd5bf0e005cdec82545abdafa38685c45e5f8ce5"),
93 SiblingSide::Right,
94 ),
95 (
96 hex!("e0d7426d603f1a817938cf366c8933d32185625fc821e3b1e964cb5f8e421501"),
97 SiblingSide::Right,
98 ),
99 (
100 hex!("7af6e333025422cf892198d216f146d70efe64119071ce0ee96fd195640230df"),
101 SiblingSide::Left,
102 ),
103 (
104 hex!("d848bf00d7563a26c9a43ad8cc2fa558f6a299629be20a078a6b197dcf15fc31"),
105 SiblingSide::Right,
106 ),
107 (
108 hex!("b643abf3df379ac748494a5eb3025299265fff543571f8b71935e533f672c9e8"),
109 SiblingSide::Right,
110 ),
111 (
112 hex!("b07d3ebc129da3ae9d1b9daee64daf74f8504ca5f9194cd006edee48b1bf4d00"),
113 SiblingSide::Right,
114 ),
115 (
116 hex!("4cd4173f585e793e48aa479269f38cd986b600c494135e9de33118a8e4ac03ed"),
117 SiblingSide::Right,
118 ),
119 (
120 hex!("4b5e59b8d22762cfc2906fa597b29c7eab7cd52d4b0cea9269e84e2aebce4101"),
121 SiblingSide::Right,
122 ),
123 (
124 hex!("2321cd016cb8f1a29f1bad981418bed2776bf61b1a729ca86a54f14790ce822b"),
125 SiblingSide::Right,
126 ),
127 (
128 hex!("fecdc8a219a271a9a969fdebf38068ffeaf25b7af353ee99e759eb0d05604218"),
129 SiblingSide::Right,
130 ),
131 (
132 hex!("1736c19cc6de7296453811916ddedba46c9bbd61a3450ad3dfb8bddb698b6ad0"),
133 SiblingSide::Right,
134 ),
135 ];
136 filler.pack_bytes_le(&block_header, &block_header_value);
137 filler.pack_bytes_le(&block_hash, &block_hash_value);
138 filler.pack_bytes_le(&transaction_hash, &transaction_hash_value);
139 for ((sibling, is_right), (value, side)) in siblings.iter().zip(&siblings_value) {
140 filler.pack_bytes_le(sibling, value);
141 filler[*is_right] = side.to_word();
142 }
143 filler[merkle_path_len] = Word(siblings_value.len() as u64);
144 circuit.populate_wire_witness(&mut filler).unwrap();
145
146 let constraint_system = circuit.constraint_system();
148 constraint_system.verify(&filler.into_value_vec()).unwrap();
149 }
150}