Skip to main content

midnight_circuits/hash/sha512/
mod.rs

1// This file is part of MIDNIGHT-ZK.
2// Copyright (C) Midnight Foundation
3// SPDX-License-Identifier: Apache-2.0
4// Licensed under the Apache License, Version 2.0 (the "License");
5// You may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7// http://www.apache.org/licenses/LICENSE-2.0
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14//! Implementation in-circuit of the SHA512 hash function.
15
16#![allow(non_snake_case)]
17
18mod sha512_chip;
19mod types;
20mod utils;
21
22use midnight_proofs::{circuit::Layouter, plonk::Error};
23use sha2::Digest;
24pub use sha512_chip::{Sha512Chip, Sha512Config, NB_SHA512_ADVICE_COLS, NB_SHA512_FIXED_COLS};
25
26use crate::{
27    instructions::{hash::HashCPU, DecompositionInstructions, HashInstructions},
28    types::AssignedByte,
29    CircuitField,
30};
31
32impl<F: CircuitField> HashCPU<u8, [u8; 64]> for Sha512Chip<F> {
33    fn hash(inputs: &[u8]) -> [u8; 64] {
34        let output = sha2::Sha512::digest(inputs);
35        output.into_iter().collect::<Vec<_>>().try_into().unwrap()
36    }
37}
38
39impl<F: CircuitField> HashInstructions<F, AssignedByte<F>, [AssignedByte<F>; 64]>
40    for Sha512Chip<F>
41{
42    fn hash(
43        &self,
44        layouter: &mut impl Layouter<F>,
45        inputs: &[AssignedByte<F>],
46    ) -> Result<[AssignedByte<F>; 64], Error> {
47        let mut output_bytes = Vec::with_capacity(64);
48
49        // We convert each `AssignedPlain<64>` returned by `self.sha512` into 8 bytes.
50        for word in self.sha512(layouter, inputs)? {
51            let bytes = self.native_gadget.assigned_to_be_bytes(layouter, &word.0, Some(8))?;
52            output_bytes.extend(bytes)
53        }
54
55        Ok(output_bytes.try_into().unwrap())
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use midnight_curves::Fq as Scalar;
62
63    use crate::{
64        field::NativeGadget, hash::sha512::Sha512Chip, instructions::hash::tests::test_hash,
65        types::AssignedByte,
66    };
67
68    #[test]
69    fn test_sha512_hash() {
70        fn test_wrapper(input_size: usize, cost_model: bool) {
71            test_hash::<
72                Scalar,
73                AssignedByte<Scalar>,
74                [AssignedByte<Scalar>; 64],
75                Sha512Chip<Scalar>,
76                NativeGadget<Scalar, _, _>,
77            >(cost_model, "SHA512", input_size)
78        }
79
80        const SHA512_BLOCK_SIZE: usize = 128;
81        const SHA512_EDGE_PADDING: usize = 111;
82
83        // Cost model update with input size = 256
84        test_wrapper(2 * SHA512_BLOCK_SIZE, true);
85
86        test_wrapper(SHA512_BLOCK_SIZE, false);
87        test_wrapper(SHA512_BLOCK_SIZE - 1, false);
88        test_wrapper(SHA512_BLOCK_SIZE - 2, false);
89        test_wrapper(4 * SHA512_BLOCK_SIZE, false);
90
91        test_wrapper(SHA512_EDGE_PADDING, false);
92        test_wrapper(SHA512_EDGE_PADDING - 1, false);
93
94        test_wrapper(0, false);
95        test_wrapper(1, false);
96        test_wrapper(2, false);
97    }
98}