binius_examples/circuits/
sha512.rs1use std::array;
4
5use anyhow::Result;
6use binius_circuits::{
7 fixed_byte_vec::ByteVec,
8 sha512::{sha512_fixed, sha512_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 Sha512Example {
18 circuit: Sha512Circuit,
19 mode: HasherMode,
20}
21
22enum Sha512Circuit {
24 Fixed {
26 message: Vec<Wire>,
27 digest: [Wire; 8],
28 },
29 Variable { message: ByteVec, digest: [Wire; 8] },
31}
32
33impl ExampleCircuit for Sha512Example {
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-512", true)?;
39
40 let circuit = match mode {
41 HasherMode::Fixed { len_bytes } => {
43 let n_words = len_bytes.div_ceil(8);
44 let message: Vec<Wire> = (0..n_words).map(|_| builder.add_inout()).collect();
45 let computed_digest = sha512_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 Sha512Circuit::Fixed { message, digest }
51 }
52 HasherMode::Variable { max_len_bytes } => {
54 let max_words = max_len_bytes.div_ceil(8);
55 let len_bytes = builder.add_inout();
56 let data: Vec<Wire> = (0..max_words).map(|_| builder.add_inout()).collect();
57 let byte_vec = ByteVec::new(data, len_bytes);
58 let digest: [Wire; 8] = array::from_fn(|_| builder.add_inout());
59 let computed_digest = sha512_varlen(builder, &byte_vec);
60 for i in 0..8 {
61 builder.assert_eq(format!("digest[{i}]"), computed_digest[i], digest[i]);
62 }
63 Sha512Circuit::Variable {
64 message: byte_vec,
65 digest,
66 }
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 = sha2::Sha512::digest(&message);
76
77 let digest_wires = match &self.circuit {
78 Sha512Circuit::Fixed {
79 message: message_wires,
80 digest,
81 } => {
82 for (wire, word) in message_wires
84 .iter()
85 .zip(utils::pack_bytes_u64words(&message, true))
86 {
87 w[*wire] = word;
88 }
89 digest
90 }
91 Sha512Circuit::Variable {
92 message: byte_vec,
93 digest,
94 } => {
95 byte_vec.populate_data(w, &message);
96 byte_vec.populate_len_bytes(w, message.len());
97 digest
98 }
99 };
100
101 for (i, chunk) in digest.chunks(8).enumerate() {
103 w[digest_wires[i]] = Word(u64::from_be_bytes(chunk.try_into().unwrap()));
104 }
105
106 Ok(())
107 }
108
109 fn param_summary(params: &Self::Params) -> Option<String> {
110 utils::hasher_param_summary(params)
111 }
112}