SHA-256
规范
SHA-256 在 NIST FIPS PUB 180-4 有过规范的定义。
和上述规范定义不同的是,这里我们使用 表示和 的加模运算 ,用 表示域上的加法。 用于表示异或。
组件(gadget)接口
SHA-256 使用8个32位的变量维护一个内部状态。SHA-256算法使用512比特位为一个区块作为输入,在算法内部将这些区块分解成32位的一些 chunk 。因此我们将SHA-256的组件设计为每次使用32位的 chunk 作为其输入。
芯片(chip)指令
SHA-256 gadget 要求芯片具有如下的指令:
#![allow(unused)] fn main() { extern crate halo2; use halo2::plonk::Error; use std::fmt; trait Chip: Sized {} trait Layouter<C: Chip> {} const BLOCK_SIZE: usize = 16; const DIGEST_SIZE: usize = 8; 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; /// Places the SHA-256 IV in the circuit, returning the initial state variable. fn initialization_vector(layouter: &mut impl Layouter<Self>) -> Result<Self::State, Error>; /// Starting from the given initial state, processes a block of input and returns the /// final state. fn compress( layouter: &mut impl Layouter<Self>, initial_state: &Self::State, input: [Self::BlockWord; BLOCK_SIZE], ) -> Result<Self::State, Error>; /// Converts the given state into a message digest. fn digest( layouter: &mut impl Layouter<Self>, state: &Self::State, ) -> Result<[Self::BlockWord; DIGEST_SIZE], Error>; } }
TODO: Add instruction for computing padding.
这些指令的选择考虑到了可复用性和可优化空间的平衡。我们考虑将 compression 函数分割成几个组成部分,然后提供一个实现了不同轮次逻辑的 compression 组件。但是这会使得芯片无法使用同在一个 compression 轮次的不同部分的相对位置引用。使用一条指令实现所有的 compression 轮次非常类似于 Intel 的 SHA 指令集扩展,后者也是提供了一条指令对应多个 compression 轮次。