binius_examples/circuits/
sha256.rs1use std::array;
4
5use anyhow::Result;
6use binius_circuits::{
7 fixed_byte_vec::ByteVec,
8 sha256::{sha256_fixed, sha256_varlen},
9};
10use binius_core::word::Word;
11use binius_frontend::{CircuitBuilder, Wire, WitnessFiller};
12use sha2::Digest;
13
14use super::utils::{self, HasherInstance, HasherMode, HasherParams};
15use crate::ExampleCircuit;
16
17pub struct Sha256Example {
18 circuit: Sha256Circuit,
19 mode: HasherMode,
20}
21
22enum Sha256Circuit {
24 Fixed {
26 message: Vec<Wire>,
27 digest: [Wire; 8],
28 },
29 Variable { message: ByteVec, digest: [Wire; 4] },
31}
32
33impl ExampleCircuit for Sha256Example {
34 type Params = HasherParams;
35 type Instance = HasherInstance;
36
37 fn build(params: HasherParams, builder: &mut CircuitBuilder) -> Result<Self> {
38 let mode = utils::resolve_hasher_mode(¶ms, "SHA-256", true)?;
39
40 let circuit = match mode {
41 HasherMode::Fixed { len_bytes } => {
43 let n_words = len_bytes.div_ceil(4);
44 let message: Vec<Wire> = (0..n_words).map(|_| builder.add_inout()).collect();
45 let computed_digest = sha256_fixed(builder, &message, len_bytes);
46 let digest: [Wire; 8] = array::from_fn(|_| builder.add_inout());
47 for i in 0..8 {
48 builder.assert_eq(format!("digest[{i}]"), computed_digest[i], digest[i]);
49 }
50 Sha256Circuit::Fixed { message, digest }
51 }
52 HasherMode::Variable { max_len_bytes } => {
54 let max_words = max_len_bytes.div_ceil(8);
55 let message = ByteVec::new_inout(builder, max_words);
56 let computed_digest = sha256_varlen(builder, &message);
57 let digest: [Wire; 4] = array::from_fn(|_| builder.add_inout());
58 for i in 0..4 {
59 builder.assert_eq(format!("digest[{i}]"), computed_digest[i], digest[i]);
60 }
61 Sha256Circuit::Variable { message, digest }
62 }
63 };
64
65 Ok(Self { circuit, mode })
66 }
67
68 fn populate_witness(&self, instance: HasherInstance, w: &mut WitnessFiller<'_>) -> Result<()> {
69 let message = utils::resolve_hasher_message(&self.mode, &instance)?;
70 let digest = sha2::Sha256::digest(&message);
71
72 match &self.circuit {
73 Sha256Circuit::Fixed {
74 message: message_wires,
75 digest: digest_wires,
76 } => {
77 for (wire, word) in message_wires
79 .iter()
80 .zip(utils::pack_bytes_u32words(&message, true))
81 {
82 w[*wire] = word;
83 }
84 for (i, chunk) in digest.chunks(4).enumerate() {
86 w[digest_wires[i]] = Word(u32::from_be_bytes(chunk.try_into().unwrap()) as u64);
87 }
88 }
89 Sha256Circuit::Variable {
90 message: byte_vec,
91 digest: digest_wires,
92 } => {
93 byte_vec.populate_data(w, &message);
94 byte_vec.populate_len_bytes(w, message.len());
95 for (i, chunk) in digest.chunks(8).enumerate() {
96 w[digest_wires[i]] = Word(u64::from_be_bytes(chunk.try_into().unwrap()));
97 }
98 }
99 }
100
101 Ok(())
102 }
103
104 fn param_summary(params: &Self::Params) -> Option<String> {
105 utils::hasher_param_summary(params)
106 }
107}