#![allow(non_snake_case)]
mod sha512_chip;
mod types;
mod utils;
use ff::PrimeField;
use midnight_proofs::{circuit::Layouter, plonk::Error};
use sha2::Digest;
pub use sha512_chip::{Sha512Chip, Sha512Config, NB_SHA512_ADVICE_COLS, NB_SHA512_FIXED_COLS};
use crate::{
instructions::{hash::HashCPU, DecompositionInstructions, HashInstructions},
types::AssignedByte,
};
impl<F: PrimeField> HashCPU<u8, [u8; 64]> for Sha512Chip<F> {
fn hash(inputs: &[u8]) -> [u8; 64] {
let output = sha2::Sha512::digest(inputs);
output.into_iter().collect::<Vec<_>>().try_into().unwrap()
}
}
impl<F: PrimeField> HashInstructions<F, AssignedByte<F>, [AssignedByte<F>; 64]> for Sha512Chip<F> {
fn hash(
&self,
layouter: &mut impl Layouter<F>,
inputs: &[AssignedByte<F>],
) -> Result<[AssignedByte<F>; 64], Error> {
let mut output_bytes = Vec::with_capacity(64);
for word in self.sha512(layouter, inputs)? {
let bytes = self.native_gadget.assigned_to_be_bytes(layouter, &word.0, Some(8))?;
output_bytes.extend(bytes)
}
Ok(output_bytes.try_into().unwrap())
}
}
#[cfg(test)]
mod tests {
use midnight_curves::Fq as Scalar;
use crate::{
field::NativeGadget, hash::sha512::Sha512Chip, instructions::hash::tests::test_hash,
types::AssignedByte,
};
#[test]
fn test_sha512_hash() {
const SHA512_BLOCK_SIZE: usize = 128;
let additional_sizes = [
SHA512_BLOCK_SIZE - 2,
SHA512_BLOCK_SIZE - 1,
SHA512_BLOCK_SIZE,
SHA512_BLOCK_SIZE + 1,
SHA512_BLOCK_SIZE + 2,
2 * SHA512_BLOCK_SIZE - 2,
2 * SHA512_BLOCK_SIZE - 1,
2 * SHA512_BLOCK_SIZE,
2 * SHA512_BLOCK_SIZE + 1,
2 * SHA512_BLOCK_SIZE + 2,
];
test_hash::<
Scalar,
AssignedByte<Scalar>,
[AssignedByte<Scalar>; 64],
Sha512Chip<Scalar>,
NativeGadget<Scalar, _, _>,
>(true, "SHA512", &additional_sizes, 14);
}
}