midnight_circuits/hash/sha256/
mod.rs1#![allow(non_snake_case)]
17
18mod sha256_chip;
19mod sha256_varlen;
20mod types;
21pub(crate) mod utils;
22
23use midnight_proofs::{circuit::Layouter, plonk::Error};
24use sha2::Digest;
25pub use sha256_chip::{Sha256Chip, Sha256Config, NB_SHA256_ADVICE_COLS, NB_SHA256_FIXED_COLS};
26pub use sha256_varlen::VarLenSha256Gadget;
27
28use crate::{
29 instructions::{
30 hash::{HashCPU, VarHashInstructions},
31 DecompositionInstructions, HashInstructions,
32 },
33 types::AssignedByte,
34 vec::AssignedVector,
35 CircuitField,
36};
37
38impl<F: CircuitField> HashCPU<u8, [u8; 32]> for Sha256Chip<F> {
39 fn hash(inputs: &[u8]) -> [u8; 32] {
40 let output = sha2::Sha256::digest(inputs);
41 output.into_iter().collect::<Vec<_>>().try_into().unwrap()
42 }
43}
44
45impl<F: CircuitField> HashInstructions<F, AssignedByte<F>, [AssignedByte<F>; 32]>
46 for Sha256Chip<F>
47{
48 fn hash(
49 &self,
50 layouter: &mut impl Layouter<F>,
51 inputs: &[AssignedByte<F>],
52 ) -> Result<[AssignedByte<F>; 32], Error> {
53 let mut output_bytes = Vec::with_capacity(32);
54
55 for word in self.sha256(layouter, inputs)? {
57 let bytes = self.native_gadget.assigned_to_be_bytes(layouter, &word.0, Some(4))?;
58 output_bytes.extend(bytes)
59 }
60
61 Ok(output_bytes.try_into().unwrap())
62 }
63}
64
65impl<F: CircuitField> HashCPU<u8, [u8; 32]> for VarLenSha256Gadget<F> {
66 fn hash(inputs: &[u8]) -> [u8; 32] {
67 let output = sha2::Sha256::digest(inputs);
68 output.into_iter().collect::<Vec<_>>().try_into().unwrap()
69 }
70}
71
72impl<F: CircuitField, const MAX_LEN: usize>
73 VarHashInstructions<F, MAX_LEN, AssignedByte<F>, [AssignedByte<F>; 32], 64>
74 for VarLenSha256Gadget<F>
75{
76 fn varhash(
77 &self,
78 layouter: &mut impl Layouter<F>,
79 inputs: &AssignedVector<F, AssignedByte<F>, MAX_LEN, 64>,
80 ) -> Result<[AssignedByte<F>; 32], Error> {
81 let mut output_bytes = Vec::with_capacity(32);
82
83 for word in self.sha256_varlen(layouter, inputs)? {
86 let bytes =
87 self.sha256chip.native_gadget.assigned_to_be_bytes(layouter, &word.0, Some(4))?;
88 output_bytes.extend(bytes)
89 }
90
91 Ok(output_bytes.try_into().unwrap())
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use midnight_curves::Fq as Scalar;
98
99 use super::sha256_varlen::VarLenSha256Gadget;
100 use crate::{
101 field::NativeGadget,
102 hash::sha256::Sha256Chip,
103 instructions::hash::tests::{test_hash, test_varhash},
104 types::AssignedByte,
105 };
106
107 #[test]
108 fn test_sha256_hash() {
109 fn test_wrapper(input_size: usize, cost_model: bool) {
110 test_hash::<
111 Scalar,
112 AssignedByte<Scalar>,
113 [AssignedByte<Scalar>; 32],
114 Sha256Chip<Scalar>,
115 NativeGadget<Scalar, _, _>,
116 >(cost_model, "SHA256", input_size)
117 }
118
119 const SHA256_BLOCK_SIZE: usize = 64;
120 const SHA256_EDGE_PADDING: usize = 55;
121
122 test_wrapper(4 * SHA256_BLOCK_SIZE, true);
124
125 test_wrapper(SHA256_BLOCK_SIZE, false);
126 test_wrapper(SHA256_BLOCK_SIZE - 1, false);
127 test_wrapper(SHA256_BLOCK_SIZE - 2, false);
128 test_wrapper(2 * SHA256_BLOCK_SIZE, false);
129
130 test_wrapper(SHA256_EDGE_PADDING, false);
131 test_wrapper(SHA256_EDGE_PADDING - 1, false);
132
133 test_wrapper(0, false);
134 test_wrapper(1, false);
135 test_wrapper(2, false);
136 }
137
138 #[test]
139 fn test_sha256_varhash() {
140 fn test_wrapper<const M: usize>(input_size: usize, cost_model: bool) {
141 test_varhash::<
142 Scalar,
143 AssignedByte<Scalar>,
144 [AssignedByte<Scalar>; 32],
145 VarLenSha256Gadget<Scalar>,
146 M,
147 64,
148 >(cost_model, "VarSHA256", input_size)
149 }
150
151 test_wrapper::<512>(64, false);
152 test_wrapper::<512>(63, false);
153
154 test_wrapper::<256>(128, true);
156 test_wrapper::<256>(127, false);
157
158 test_wrapper::<128>(55, false); test_wrapper::<128>(56, false);
160
161 test_wrapper::<128>(0, false);
162 test_wrapper::<128>(1, false);
163 }
164}