1use crate::{
4 FancyBinary,
5 circuit::{BinaryCircuit, Circuit, CircuitInputMapper},
6 circuits::binary::BinaryConstant,
7};
8use std::io::Cursor;
9use swanky_channel::Channel;
10use swanky_error::Result;
11
12pub struct Sha256CompressionFunctionFixedIV(BinaryCircuit);
15
16impl Sha256CompressionFunctionFixedIV {
17 pub fn new() -> Self {
25 let circuit = BinaryCircuit::parse_bristol_format(Cursor::<&'static [u8]>::new(
26 include_bytes!("../../circuits/bristol-format/sha-256.txt"),
27 ))
28 .expect("`sha-256.txt` file should always parse correctly");
29 Self(circuit)
30 }
31}
32
33impl Default for Sha256CompressionFunctionFixedIV {
34 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl<F: FancyBinary> Circuit<F> for Sha256CompressionFunctionFixedIV {
40 type Input = [F::Item; 512];
41 type Output = [F::Item; 256];
42
43 fn execute(
44 &self,
45 backend: &mut F,
46 input: Self::Input,
47 channel: &mut Channel,
48 ) -> Result<Self::Output> {
49 let output = self.0.execute(backend, input.to_vec(), channel)?;
50 Ok(output
51 .try_into()
52 .expect("SHA-256 compression function output should always be 256 elements"))
53 }
54}
55
56impl<F: FancyBinary> CircuitInputMapper<F> for Sha256CompressionFunctionFixedIV {
57 fn map(&self, inputs: Vec<<F as crate::Fancy>::Item>) -> Self::Input {
58 assert_eq!(inputs.len(), 512);
59 inputs.try_into().unwrap()
60 }
61
62 fn ninputs(&self) -> usize {
63 512
64 }
65
66 fn modulus(&self, _: usize) -> u16 {
67 2
68 }
69}
70
71pub struct Sha256CompressionFunction(BinaryCircuit);
73
74impl Sha256CompressionFunction {
75 pub fn new() -> Self {
82 let circuit = BinaryCircuit::parse_bristol_fashion(Cursor::<&'static [u8]>::new(
83 include_bytes!("../../circuits/bristol-fashion/sha256.txt"),
84 ))
85 .expect("`sha256.txt` file should always parse correctly");
86 Self(circuit)
87 }
88}
89
90impl Default for Sha256CompressionFunction {
91 fn default() -> Self {
92 Self::new()
93 }
94}
95
96impl<F: FancyBinary> Circuit<F> for Sha256CompressionFunction {
97 type Input = ([F::Item; 512], [F::Item; 256]);
98 type Output = [F::Item; 256];
99
100 fn execute(
101 &self,
102 backend: &mut F,
103 inputs: Self::Input,
104 channel: &mut Channel,
105 ) -> Result<Self::Output> {
106 let mut combined = inputs.0.iter().rev().cloned().collect::<Vec<_>>();
110 combined.extend(inputs.1.iter().rev().cloned());
111 let output = self.0.execute(backend, combined, channel)?;
112 Ok(output
113 .try_into()
114 .expect("SHA-256 compression function output should always be 256 elements"))
115 }
116}
117
118impl<F: FancyBinary> CircuitInputMapper<F> for Sha256CompressionFunction {
119 fn map(&self, inputs: Vec<<F as crate::Fancy>::Item>) -> Self::Input {
120 assert_eq!(inputs.len(), 768);
121 let (block, chain) = inputs.split_at(512);
122 (
123 block
124 .to_vec()
125 .try_into()
126 .expect("Block should contain 512 elements"),
127 chain
128 .to_vec()
129 .try_into()
130 .expect("Chain should contain 256 elements"),
131 )
132 }
133
134 fn ninputs(&self) -> usize {
135 768
136 }
137
138 fn modulus(&self, _: usize) -> u16 {
139 2
140 }
141}
142
143pub struct Sha256 {
148 compression: Sha256CompressionFunction,
149}
150
151impl Sha256 {
152 pub fn new() -> Self {
159 Self {
160 compression: Sha256CompressionFunction::new(),
161 }
162 }
163
164 const IV: &'static str = "0110101000001001111001100110011110111011011001111010111010000101\
166 001111000110111011110011011100101010010101001111111101010011101\
167 001010001000011100101001001111111100110110000010101101000100011\
168 000001111110000011110110011010101101011011111000001100110100011001";
169}
170
171impl Default for Sha256 {
172 fn default() -> Self {
173 Self::new()
174 }
175}
176
177impl<F: FancyBinary> Circuit<F> for Sha256 {
178 type Input = Vec<F::Item>;
179 type Output = [F::Item; 256];
180
181 fn execute(
182 &self,
183 backend: &mut F,
184 inputs: Self::Input,
185 channel: &mut Channel,
186 ) -> Result<Self::Output> {
187 let message_len = inputs.len();
188
189 let one = backend.constant(1, 2, channel)?;
190 let zero = backend.constant(0, 2, channel)?;
191
192 let mut chain: [F::Item; 256] = Self::IV
194 .chars()
195 .map(|c| if c == '1' { one.clone() } else { zero.clone() })
196 .collect::<Vec<_>>()
197 .try_into()
198 .unwrap();
199
200 let mut padded = inputs.clone();
202 padded.push(one.clone());
203
204 let current_len = padded.len();
206 let target_len = if current_len <= 448 {
207 448
208 } else {
209 (current_len + 64).div_ceil(512) * 512 - 64
210 };
211 let zeros_needed = target_len - current_len;
212 for _ in 0..zeros_needed {
213 padded.push(zero.clone());
214 }
215
216 let mut length = BinaryConstant::new_with_constants(
218 message_len as u128,
219 64,
220 Some(zero.clone()),
221 Some(one.clone()),
222 )
223 .execute(backend, (), channel)?;
224 length.reverse();
227 padded.extend_from_slice(length.wires());
228
229 for chunk in padded.chunks(512) {
231 let block: [F::Item; 512] =
232 chunk.to_vec().try_into().expect("Chunk should be 512 bits");
233
234 chain = self.compression.execute(backend, (block, chain), channel)?;
235 }
236
237 Ok(chain)
238 }
239}
240
241#[cfg(test)]
242mod test {
243 use crate::circuits::sha::{
244 Sha256, Sha256CompressionFunction, Sha256CompressionFunctionFixedIV,
245 };
246 use crate::dummy::{Dummy, DummyVal};
247
248 #[cfg(test)]
249 fn string_to_bool_vec(str: &str) -> Vec<DummyVal> {
250 str.chars()
251 .map(|c| match c {
252 '0' => DummyVal::new_bool(false),
253 '1' => DummyVal::new_bool(true),
254 _ => panic!("Unexpected character in boolean string"),
255 })
256 .collect()
257 }
258
259 #[test]
260 fn sha256_compression_function() {
261 let sha256_fixed_iv = Sha256CompressionFunctionFixedIV::new();
265 let sha256 = Sha256CompressionFunction::new();
266
267 let iv = string_to_bool_vec(
268 "0110101000001001111001100110011110111011011001111010111010000101001111000110111011110011011100101010010101001111111101010011101001010001000011100101001001111111100110110000010101101000100011000001111110000011110110011010101101011011111000001100110100011001",
269 ).try_into().unwrap();
270
271 let block = [DummyVal::new_bool(false); 512];
272 let output = Dummy::eval(&sha256_fixed_iv, block).unwrap();
273 assert_eq!(
274 output
275 .iter()
276 .map(|i| i.val().to_string())
277 .collect::<String>(),
278 "1101101001010110100110001011111000010111101110011011010001101001011000100011001101010111100110010111011110011111101111101100101010001100111001011101010010010001110000001101001001100010010000111011101011111110111110011110101000011000001101111010100111011000"
279 );
280 let output_with_iv = Dummy::eval(&sha256, (block, iv)).unwrap();
281 assert_eq!(output, output_with_iv);
282
283 let block = string_to_bool_vec(
284 "00000000000000010000001000000011000001000000010100000110000001110000100000001001000010100000101100001100000011010000111000001111000100000001000100010010000100110001010000010101000101100001011100011000000110010001101000011011000111000001110100011110000111110010000000100001001000100010001100100100001001010010011000100111001010000010100100101010001010110010110000101101001011100010111100110000001100010011001000110011001101000011010100110110001101110011100000111001001110100011101100111100001111010011111000111111",
285 ).try_into().unwrap();
286 let output = Dummy::eval(&sha256_fixed_iv, block).unwrap();
287 assert_eq!(
288 output
289 .iter()
290 .map(|i| i.val().to_string())
291 .collect::<String>(),
292 "1111110010011001101000101101111110001000111101000010101001111010011110111011100111010001100000000011001111001101110001101010001000000010010101100111010101011111100111010101101110011010010100000100010010101001110011000011000101011010101111101000010010100111"
293 );
294 let output_with_iv = Dummy::eval(&sha256, (block, iv)).unwrap();
295 assert_eq!(output, output_with_iv);
296
297 let block = [DummyVal::new_bool(true); 512];
298 let output = Dummy::eval(&sha256_fixed_iv, block).unwrap();
299 assert_eq!(
300 output
301 .iter()
302 .map(|i| i.val().to_string())
303 .collect::<String>(),
304 "1110111100001100011101001000110111110100110110100101000010101000110101101100010000111100000000010011111011011100001111001110011101101100100111011001111110101001101000010100010110001010110111100101011011101011100001101100000010100110010001001001001011010010"
305 );
306 let output_with_iv = Dummy::eval(&sha256, (block, iv)).unwrap();
307 assert_eq!(output, output_with_iv);
308
309 let block = string_to_bool_vec(
310 "00100100001111110110101010001000100001011010001100001000110100110001001100011001100010100010111000000011011100000111001101000100101001000000100100111000001000100010100110011111001100011101000000001000001011101111101010011000111011000100111001101100100010010100010100101000001000011110011000111000110100000001001101110111101111100101010001100110110011110011010011101001000011000110110011000000101011000010100110110111110010010111110001010000110111010011111110000100110101011011010110110101010001110000100100010111",
311 ).try_into().unwrap();
312 let output = Dummy::eval(&sha256_fixed_iv, block).unwrap();
313 assert_eq!(
314 output
315 .iter()
316 .map(|i| i.val().to_string())
317 .collect::<String>(),
318 "1100111100001010111001001110101101100111110100111000111111111110101110010100000001101000100110000100101100100010101010111101111001001110100100101011110001010100100011010001010001011000010111100100100011011100101010001000100000101101011110110000100111001110"
319 );
320 let output_with_iv = Dummy::eval(&sha256, (block, iv)).unwrap();
321 assert_eq!(output, output_with_iv);
322 }
323
324 #[test]
325 fn sha256_empty_string() {
326 let sha256 = Sha256::new();
330 let input = vec![];
331 let output = Dummy::eval(&sha256, input).unwrap();
332 assert_eq!(
333 output
334 .iter()
335 .map(|i| i.val().to_string())
336 .collect::<String>(),
337 "1110001110110000110001000100001010011000111111000001110000010100100110101111101111110100110010001001100101101111101110010010010000100111101011100100000111100100011001001001101110010011010011001010010010010101100110010001101101111000010100101011100001010101"
338 );
339 }
340
341 #[test]
342 fn sha256_abc() {
343 let sha256 = Sha256::new();
347
348 let input = string_to_bool_vec("011000010110001001100011");
353 let output = Dummy::eval(&sha256, input).unwrap();
354 assert_eq!(
355 output
356 .iter()
357 .map(|i| i.val().to_string())
358 .collect::<String>(),
359 "1011101001111000000101101011111110001111000000011100111111101010010000010100000101000000110111100101110110101110001000100010001110110000000000110110000110100011100101100001011101111010100111001011010000010000111111110110000111110010000000000001010110101101"
360 );
361 }
362
363 #[test]
364 fn sha256_two_blocks() {
365 let sha256 = Sha256::new();
369 let input = vec![DummyVal::new_bool(false); 448];
370 let output = Dummy::eval(&sha256, input).unwrap();
371 assert_eq!(
372 output
373 .iter()
374 .map(|i| i.val().to_string())
375 .collect::<String>(),
376 "1101010010000001011110101010010101001001011101100010100011100111110001110111111001101011011000000110000100000111000001000010101110111011101000110001001100001000100010001100010111110100011110100011011101011110011000010111100110111110011110001001111110111011"
377 );
378 }
379
380 #[test]
381 fn sha256_three_blocks() {
382 let sha256 = Sha256::new();
386 let abcd = string_to_bool_vec("01100001011000100110001101100100");
388 let mut input = Vec::with_capacity(1024);
389 for _ in 0..32 {
390 input.extend_from_slice(&abcd);
391 }
392 let output = Dummy::eval(&sha256, input).unwrap();
393 assert_eq!(
394 output
395 .iter()
396 .map(|i| i.val().to_string())
397 .collect::<String>(),
398 "0100010100110010111011110111001100010001000010011001001010000110000001011001101010111101100001011101010011000000011001110101011111111001011011010010010001001000101100100101100111111001010100011001001000100010101100101010110001101001101101011110101111110011"
399 );
400 }
401
402 #[test]
403 fn sha256_long_message() {
404 let sha256 = Sha256::new();
405
406 let message = "The quick brown fox jumps over the lazy dog";
407 let input: Vec<DummyVal> = message
408 .bytes()
409 .flat_map(|b| {
410 (0..8)
411 .rev()
412 .map(move |i| DummyVal::new_bool((b >> i) & 1 == 1))
413 })
414 .collect();
415
416 let output = Dummy::eval(&sha256, input).unwrap();
417 assert_eq!(
418 output
419 .iter()
420 .map(|i| i.val().to_string())
421 .collect::<String>(),
422 "1101011110101000111110111011001100000111110101111000000010010100011010011100101010011010101111001011000000001000001011100100111110001101010101100101000111100100011011010011110011011011011101100010110100000010110100001011111100110111110010011110010110010010"
423 );
424 }
425}