Skip to main content

risc0-circuit-keccak

The risc0-circuit-keccak crate implements a specialized circuit for accelerating Keccak-256 (SHA-3) hash computations within the RISC Zero zkVM.

Installation

[dependencies]
risc0-circuit-keccak = { version = "1.3.0", features = ["prove"] }

Overview

Keccak-256 is computationally expensive in the zkVM. This circuit provides hardware acceleration for Keccak operations, making them significantly faster and cheaper in terms of cycles.
Most users don’t need to use this crate directly. The zkVM automatically uses the Keccak circuit when you call Keccak functions in guest code.

Feature Flags

prove
feature
Enables proof generation for Keccak operations.
  • Implies: std
cuda
feature
Enables CUDA GPU acceleration.
  • Implies: prove
std
feature
Enables standard library support.

Constants

KECCAK_DEFAULT_PO2
const
Default power-of-2 size for Keccak circuit.
pub const KECCAK_DEFAULT_PO2: usize = 17;
Provides capacity for 2^17 cycles = 131,072 cycles
KECCAK_PO2_RANGE
const
Valid power-of-2 range for Keccak circuit.
pub const KECCAK_PO2_RANGE: RangeInclusive<usize> = 14..=18;
Supports 2^14 to 2^18 cycles
RECURSION_PO2
const
Power-of-2 for recursion of Keccak receipts.
pub const RECURSION_PO2: usize = 18;
KECCAK_PERMUTE_CYCLES
const
Cycles per Keccak permutation.
pub const KECCAK_PERMUTE_CYCLES: usize = 200;

Types

KeccakState
type
Keccak state representation.
pub type KeccakState = [u64; 25];
Represents the 1600-bit (25 × 64-bit) Keccak sponge state.

Functions

get_control_id

get_control_id
function
Get the control ID for a specific circuit size.
pub fn get_control_id(po2: usize) -> &'static Digest
Parameters:
  • po2: Power-of-2 size (must be in KECCAK_PO2_RANGE)
Returns: Control ID for verificationExample:
let control_id = get_control_id(17);
println!("Control ID: {}", control_id);

max_keccak_inputs

max_keccak_inputs
function
Calculate maximum number of Keccak inputs for a circuit size.
pub fn max_keccak_inputs(po2: usize) -> usize
Parameters:
  • po2: Power-of-2 circuit size
Returns: Maximum number of Keccak permutationsExample:
let max_inputs = max_keccak_inputs(17);
println!("Max Keccak inputs: {}", max_inputs); // ~655

compute_keccak_digest (with prove feature)

compute_keccak_digest
function
Compute the SHA-256 digest of Keccak states.
#[cfg(feature = "prove")]
pub fn compute_keccak_digest(input: &[u8]) -> Digest
Parameters:
  • input: Slice of bytes representing KeccakStates
Returns: SHA-256 digest matching circuit outputExample:
let states: Vec<KeccakState> = vec![/* ... */];
let bytes = bytemuck::cast_slice(&states);
let digest = compute_keccak_digest(bytes);

Control IDs

KECCAK_CONTROL_IDS
const
Array of control IDs for different circuit sizes.
pub const KECCAK_CONTROL_IDS: &[Digest];
One control ID per po2 in KECCAK_PO2_RANGE.
KECCAK_CONTROL_ROOT
const
Root control ID for all Keccak circuits.
pub const KECCAK_CONTROL_ROOT: &Digest;

Usage in Guest Code

Using sha3 Crate

The zkVM automatically accelerates sha3 crate operations:
use sha3::{Digest, Keccak256};

fn hash_data(data: &[u8]) -> [u8; 32] {
    let mut hasher = Keccak256::new();
    hasher.update(data);
    let result = hasher.finalize();
    result.into()
}

Direct State Manipulation

use risc0_circuit_keccak::KeccakState;

fn keccak_permute(state: &mut KeccakState) {
    // The zkVM will accelerate this via the Keccak circuit
    keccak::f1600(state);
}

Performance

Cost Comparison

OperationWithout CircuitWith CircuitSpeedup
Single Keccak-256~50,000 cycles~200 cycles250x
100 hashes~5M cycles~20K cycles250x
The Keccak circuit provides dramatic cycle savings for hash-intensive applications.

Capacity Planning

use risc0_circuit_keccak::{max_keccak_inputs, KECCAK_DEFAULT_PO2};

fn plan_keccak_usage(num_hashes: usize) -> usize {
    let capacity = max_keccak_inputs(KECCAK_DEFAULT_PO2);
    let circuits_needed = (num_hashes + capacity - 1) / capacity;
    circuits_needed
}

// Example: hashing 1000 items
let circuits = plan_keccak_usage(1000);
// Needs 2 circuits (default can handle ~655)

Circuit Batching

The zkVM automatically batches Keccak operations:
  1. Accumulation Phase: Collect all Keccak operations
  2. Circuit Invocation: Prove all operations in one circuit
  3. Result Delivery: Return results to guest

Proving (with prove feature)

prove
module
Keccak circuit proving.Implements proof generation for batched Keccak operations.

Examples

Basic Keccak Usage

use sha3::{Digest, Keccak256};

fn guest_main() {
    let data = b"Hello, RISC Zero!";
    
    // Automatically uses Keccak circuit
    let mut hasher = Keccak256::new();
    hasher.update(data);
    let hash = hasher.finalize();
    
    risc0_zkvm::guest::env::commit(&hash);
}

Batch Hashing

use sha3::{Digest, Keccak256};

fn batch_hash(items: Vec<Vec<u8>>) -> Vec<[u8; 32]> {
    items
        .iter()
        .map(|item| {
            let mut hasher = Keccak256::new();
            hasher.update(item);
            hasher.finalize().into()
        })
        .collect()
}

// All hashes will be batched into Keccak circuits automatically
let hashes = batch_hash(data);

Merkle Tree

use sha3::{Digest, Keccak256};

fn merkle_root(leaves: &[[u8; 32]]) -> [u8; 32] {
    let mut layer = leaves.to_vec();
    
    while layer.len() > 1 {
        layer = layer
            .chunks(2)
            .map(|pair| {
                let mut hasher = Keccak256::new();
                hasher.update(&pair[0]);
                if pair.len() > 1 {
                    hasher.update(&pair[1]);
                }
                hasher.finalize().into()
            })
            .collect();
    }
    
    layer[0]
}

// Efficient: all hashes use Keccak circuit

Ethereum Compatibility

The Keccak-256 implementation matches Ethereum’s hash function:
use sha3::{Digest, Keccak256};

// Compute Ethereum address from public key
fn eth_address(public_key: &[u8; 64]) -> [u8; 20] {
    let mut hasher = Keccak256::new();
    hasher.update(public_key);
    let hash = hasher.finalize();
    
    let mut address = [0u8; 20];
    address.copy_from_slice(&hash[12..32]);
    address
}

GPU Acceleration

With CUDA enabled, Keccak proving is accelerated:
# Build with CUDA support
cargo build --release --features cuda
Performance improvement:
  • CPU: ~1 second for 1000 Keccak operations
  • GPU: ~0.1 seconds for 1000 Keccak operations

Circuit Size Selection

Choose appropriate circuit size based on usage:
PO2Max HashesUse Case
14~81Minimal usage
15~163Light usage
16~327Moderate usage
17~655Default, heavy usage
18~1310Very heavy usage

Zirgen Implementation

zirgen
module
Low-level circuit implementation.Generated constraint code for the Keccak permutation.

Build docs developers (and LLMs) love