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