//! Gadget and chips for the [SHA-256] hash function. //! //! [SHA-256]: https://tools.ietf.org/html/rfc6234 /* use std::cmp::min; use std::convert::TryInto; use std::fmt; use halo2::{ arithmetic::FieldExt, circuit::{Chip, Layouter}, plonk::Error, }; mod benches; mod table16; pub use table16::{BlockWord, Table16Chip, Table16Config}; /// The size of a SHA-256 block, in 32-bit words. pub const BLOCK_SIZE: usize = 16; /// The size of a SHA-256 digest, in 32-bit words. const DIGEST_SIZE: usize = 8; /// The set of circuit instructions required to use the [`Sha256`] gadget. pub trait Sha256Instructions: Chip { /// Variable representing the SHA-256 internal state. type State: Clone + fmt::Debug; /// Variable representing a 32-bit word of the input block to the SHA-256 compression /// function. type BlockWord: Copy + fmt::Debug; /// The zero BlockWord fn zero() -> Self::BlockWord; /// Places the SHA-256 IV in the circuit, returning the initial state variable. fn initialization_vector(&self, layouter: &mut impl Layouter) -> Result; /// Creates an initial state from the output state of a previous block fn initialization( &self, layouter: &mut impl Layouter, init_state: &Self::State, ) -> Result; /// Starting from the given initialized state, processes a block of input and returns the /// final state. fn compress( &self, layouter: &mut impl Layouter, initialized_state: &Self::State, input: [Self::BlockWord; BLOCK_SIZE], ) -> Result; /// Converts the given state into a message digest. fn digest( &self, layouter: &mut impl Layouter, state: &Self::State, ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; } /// The output of a SHA-256 circuit invocation. #[derive(Debug)] pub struct Sha256Digest([BlockWord; DIGEST_SIZE]); /// A gadget that constrains a SHA-256 invocation. It supports input at a granularity of /// 32 bits. #[derive(Debug)] pub struct Sha256> { chip: CS, state: CS::State, cur_block: Vec, length: usize, } impl> Sha256 { /// Create a new hasher instance. pub fn new(chip: Sha256Chip, mut layouter: impl Layouter) -> Result { let state = chip.initialization_vector(&mut layouter)?; Ok(Sha256 { chip, state, cur_block: Vec::with_capacity(BLOCK_SIZE), length: 0, }) } /// Digest data, updating the internal state. pub fn update( &mut self, mut layouter: impl Layouter, mut data: &[Sha256Chip::BlockWord], ) -> Result<(), Error> { self.length += data.len() * 32; // Fill the current block, if possible. let remaining = BLOCK_SIZE - self.cur_block.len(); let (l, r) = data.split_at(min(remaining, data.len())); self.cur_block.extend_from_slice(l); data = r; // If we still don't have a full block, we are done. if self.cur_block.len() < BLOCK_SIZE { return Ok(()); } // Process the now-full current block. self.state = self.chip.compress( &mut layouter, &self.state, self.cur_block[..] .try_into() .expect("cur_block.len() == BLOCK_SIZE"), )?; self.cur_block.clear(); // Process any additional full blocks. let mut chunks_iter = data.chunks_exact(BLOCK_SIZE); for chunk in &mut chunks_iter { self.state = self.chip.initialization(&mut layouter, &self.state)?; self.state = self.chip.compress( &mut layouter, &self.state, chunk.try_into().expect("chunk.len() == BLOCK_SIZE"), )?; } // Cache the remaining partial block, if any. let rem = chunks_iter.remainder(); self.cur_block.extend_from_slice(rem); Ok(()) } /// Retrieve result and consume hasher instance. pub fn finalize( mut self, mut layouter: impl Layouter, ) -> Result, Error> { // Pad the remaining block if !self.cur_block.is_empty() { let padding = vec![Sha256Chip::zero(); BLOCK_SIZE - self.cur_block.len()]; self.cur_block.extend_from_slice(&padding); self.state = self.chip.initialization(&mut layouter, &self.state)?; self.state = self.chip.compress( &mut layouter, &self.state, self.cur_block[..] .try_into() .expect("cur_block.len() == BLOCK_SIZE"), )?; } self.chip .digest(&mut layouter, &self.state) .map(Sha256Digest) } /// Convenience function to compute hash of the data. It will handle hasher creation, /// data feeding and finalization. pub fn digest( chip: Sha256Chip, mut layouter: impl Layouter, data: &[Sha256Chip::BlockWord], ) -> Result, Error> { let mut hasher = Self::new(chip, layouter.namespace(|| "init"))?; hasher.update(layouter.namespace(|| "update"), data)?; hasher.finalize(layouter.namespace(|| "finalize")) } } */ fn main() {}