risc0_circuit_keccak/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
16
17mod control_id;
18#[cfg(feature = "prove")]
19pub mod prove;
20#[cfg(feature = "prove")]
21pub(crate) mod zirgen;
22
23use risc0_zkp::core::digest::Digest;
24
25pub use self::control_id::{KECCAK_CONTROL_IDS, KECCAK_CONTROL_ROOT};
26
27pub const KECCAK_DEFAULT_PO2: usize = 17;
28
29pub const KECCAK_PO2_RANGE: core::ops::RangeInclusive<usize> = 14..=18;
30
31pub const RECURSION_PO2: usize = 18;
32
33pub const KECCAK_PERMUTE_CYCLES: usize = 200;
34
35pub type KeccakState = [u64; 25];
36
37pub fn get_control_id(po2: usize) -> &'static Digest {
38 assert!(KECCAK_PO2_RANGE.contains(&po2), "po2 {po2} out of range");
39 &KECCAK_CONTROL_IDS[po2 - KECCAK_PO2_RANGE.min().unwrap()]
40}
41
42pub fn max_keccak_inputs(po2: usize) -> usize {
43 let max_keccak_cycles: usize = 1 << po2;
44 max_keccak_cycles / KECCAK_PERMUTE_CYCLES
45}
46
47#[cfg(feature = "prove")]
49pub fn compute_keccak_digest(input: &[u8]) -> Digest {
50 use risc0_zkp::core::digest::{Digest, DIGEST_BYTES};
51 use risc0_zkp::core::hash::{
52 sha,
53 sha::{Sha256, SHA256_INIT},
54 };
55
56 let mut transcript = vec![];
57
58 let mut input: Vec<u8> = input.to_vec();
59 let input_states: &mut [KeccakState] = bytemuck::cast_slice_mut(&mut input);
60 for input in input_states.iter_mut() {
61 let mut data = [0u64; 32];
62 data[0..25].clone_from_slice(input);
63 transcript.push(data);
64
65 keccak::f1600(input);
66
67 data[0..25].clone_from_slice(input);
68 transcript.push(data);
69 }
70
71 let mut digest = SHA256_INIT;
72 for halfs in bytemuck::cast_slice::<[u64; 32], [u64; 8]>(transcript.as_slice()) {
73 let mut first_half = [0u8; DIGEST_BYTES];
74 first_half.clone_from_slice(bytemuck::cast_slice(&halfs[0..4]));
75
76 let mut second_half = [0u8; DIGEST_BYTES];
77 second_half.clone_from_slice(bytemuck::cast_slice(&halfs[4..8]));
78
79 digest = *sha::Impl::compress(
80 &digest,
81 &Digest::from_bytes(first_half),
82 &Digest::from_bytes(second_half),
83 );
84 }
85
86 for word in digest.as_mut_words() {
88 *word = word.to_be();
89 }
90 digest
91}