shared_types/transcript/
utils.rs

1use itertools::Itertools;
2use sha2::{Digest, Sha256};
3
4use crate::Field;
5
6/// A heuristic number of hash iterations over SHA-256 which is assumed
7/// to be incomputable by GKR circuits which are written within Remainder.
8///
9/// Note that this value should be increased for particularly high-degree or
10/// deep circuits.
11pub const NUM_SHA_256_ITERATIONS: usize = 1000;
12
13/// This function computes the [NUM_SHA_256_ITERATIONS]-deep SHA-256 hash chain
14/// with input `elems`.
15pub(crate) fn sha256_hash_chain_on_field_elems<F: Field>(elems: &[F]) -> Vec<F> {
16    // First, convert the `elems` which are passed in to a `Vec<u8>`.
17    let elems_bytes = elems
18        .iter()
19        .flat_map(|elem| elem.to_bytes_le())
20        .collect_vec();
21
22    // Next, compute the SHA-256 digest of the input elems as bytes.
23    let mut hasher = Sha256::new();
24    hasher.update(elems_bytes);
25    let sha_256_result = hasher.finalize();
26
27    // Next, compute the [NUM_SHA_256_ITERATIONS] iterated SHA-256 digest.
28    let final_iterated_bytes = (0..NUM_SHA_256_ITERATIONS).fold(sha_256_result, |acc, _| {
29        let mut hasher = Sha256::new();
30        hasher.update(acc);
31        hasher.finalize()
32    });
33
34    // Since the output is 32 bytes and can be out of range,
35    // we split instead into two chunks of 16 bytes each and
36    // absorb two field elements.
37    // TODO(ryancao): Update this by using `REPR_NUM_BYTES` after merging with the testing branch
38    let mut hash_bytes_first_half = [0; 32];
39    let mut hash_bytes_second_half = [0; 32];
40
41    hash_bytes_first_half[..16].copy_from_slice(&final_iterated_bytes.to_vec()[..16]);
42    hash_bytes_second_half[..16].copy_from_slice(&final_iterated_bytes.to_vec()[16..]);
43
44    vec![
45        F::from_bytes_le(hash_bytes_first_half.as_ref()),
46        F::from_bytes_le(hash_bytes_second_half.as_ref()),
47    ]
48}