binius_circuits/bitcoin/
double_sha256.rs1use binius_frontend::{CircuitBuilder, Wire};
6
7use crate::{bytes::swap_bytes_32, sha256::sha256_fixed, util::clear_high_bits};
8
9pub fn double_sha256(builder: &CircuitBuilder, message: &[Wire]) -> [Wire; 4] {
15 let mut message_be: Vec<Wire> = Vec::with_capacity(message.len() * 2);
20 for &w in message {
21 let swapped = swap_bytes_32(builder, w);
22 message_be.push(clear_high_bits(builder, swapped, 32));
23 message_be.push(builder.shr(swapped, 32));
24 }
25 let digest_0_be = sha256_fixed(builder, &message_be, message.len() * 8); let digest_1_be = sha256_fixed(builder, &digest_0_be, 32); std::array::from_fn(|i| {
34 let lo = swap_bytes_32(builder, digest_1_be[2 * i]);
35 let hi = swap_bytes_32(builder, digest_1_be[2 * i + 1]);
36 builder.bxor(lo, builder.shl(hi, 32))
37 })
38}
39
40#[cfg(test)]
41mod tests {
42 use std::array;
43
44 use hex_literal::hex;
45
46 use super::*;
47
48 fn check_double_sha256(header_value: &[u8], hash_value: &[u8]) -> anyhow::Result<()> {
51 let builder = CircuitBuilder::new();
52 let block_header: [Wire; 10] = array::from_fn(|_| builder.add_witness());
53 let block_hash: [Wire; 4] = array::from_fn(|_| builder.add_witness());
54 builder.assert_eq_v("block hash", double_sha256(&builder, &block_header), block_hash);
55 let circuit = builder.build();
56
57 let mut filler = circuit.new_witness_filler();
58 filler.pack_bytes_le(&block_header, header_value);
59 filler.pack_bytes_le(&block_hash, hash_value);
60 circuit.populate_wire_witness(&mut filler)?;
61
62 let constraint_system = circuit.constraint_system();
63 constraint_system.verify(&filler.into_value_vec())?;
64 Ok(())
65 }
66
67 const BLOCK_HEADER: [u8; 80] = hex!(
68 "000000264a14e21adad047d981c06a26446e345eda3d8beb807401000000000000000000fc01df2139954b36cebc3fa6fbf6a7160a67d34b67e5c4aa2a7ce46f5bb42a83642ea468b32c0217d14ba4d1"
69 );
70
71 #[test]
72 fn test_valid() {
73 let block_hash = hex!("228561b085b7524957e515605725901238299ff2793300000000000000000000");
74 check_double_sha256(&BLOCK_HEADER, &block_hash).unwrap();
75 }
76
77 #[test]
78 fn test_invalid() {
79 let block_hash = hex!("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
80 check_double_sha256(&BLOCK_HEADER, &block_hash).unwrap_err();
81 }
82}