Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/risc0/risc0/llms.txt

Use this file to discover all available pages before exploring further.

Cryptographic Precompiles

RISC Zero’s zkVM includes specialized extension circuits called “precompiles” for cryptographic and algebraic functions. These accelerators provide 10-100x speedups for supported operations.

Overview

Precompiles are specialized circuits implemented directly in the “hardware” of the zkVM, similar to AES-NI or SHA extensions in x86 processors. Programs that use precompiles:
  • Execute faster (fewer cycles)
  • Prove with significantly less resources
  • Require no code changes when using patched crates

Supported Operations

  • SHA-256: ~68 cycles per 64-byte block
  • Keccak-256: Optimized hashing
  • RSA: Modular exponentiation
  • Elliptic Curves: secp256k1 (k256), secp256r1 (p256), ed25519, BLS12-381, BN254
  • 256-bit Modular Multiplication: ~10 cycles
Use RISC0_INFO=1 when running your program to see statistics on precompile usage.

Using Patched Crates

RISC Zero provides patched versions of popular cryptographic crates that automatically use precompiles. Simply add the patch to your guest’s Cargo.toml.

Available Patched Crates

CrateVersions SupportedUse Case
sha20.10.9, 0.10.8, 0.10.7, 0.10.6, 0.9.9SHA-256, SHA-512
tiny-keccak2.0.2Keccak-256
k2560.13.4, 0.13.3, 0.13.2, 0.13.1secp256k1 (Bitcoin, Ethereum)
p2560.13.2secp256r1 (NIST P-256)
curve25519-dalek4.1.3, 4.1.2, 4.1.1, 4.1.0Ed25519 signatures
rsa0.9.9RSA encryption/signatures
substrate-bn0.6.0BN254 pairing
bls12_3810.8.0BLS12-381 pairing
blst0.3.16, 0.3.15, 0.3.14BLS signatures
crypto-bigint0.5.5, 0.5.4, 0.5.3, 0.5.2Big integer arithmetic
c-kzg1.0.3, 2.1.0, 2.1.1, 2.1.5KZG commitments (EIP-4844)
For the most up-to-date versions and tags, check the /releases page in each fork’s GitHub repository.

How to Apply Patches

Step 1: Add the Dependency

In your guest’s Cargo.toml, specify the exact version:
methods/guest/Cargo.toml
[dependencies]
sha2 = "=0.10.9"

Step 2: Apply the Patch

In the same Cargo.toml, add the patch:
methods/guest/Cargo.toml
[patch.crates-io]
sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.9-risczero.0" }

Step 3: Update Cargo.lock

If needed, update the lockfile to the specific version:
cargo update -p sha2 --precise 0.10.9

Step 4: Verify the Patch

Check that the patch is applied by searching for the crate in your guest’s Cargo.lock:
grep -A 5 "name = \"sha2\"" methods/guest/Cargo.lock
You should see the fork repository URL in the source field.
Make sure the patch version matches your dependency version exactly. Using sha2 = "0.10" with a 0.10.9 patch may not work correctly.

Example: ECDSA Signature Verification

Here’s a complete example using precompiled k256 for ECDSA verification:

Guest Cargo.toml

methods/guest/Cargo.toml
[dependencies]
k256 = "=0.13.4"
sha2 = "=0.10.9"
crypto-bigint = "=0.5.5"

[patch.crates-io]
k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.4-risczero.1" }
sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.9-risczero.0" }
crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.5-risczero.0" }

Guest Code

methods/guest/src/main.rs
use k256::ecdsa::{Signature, VerifyingKey, signature::Verifier};
use risc0_zkvm::guest::env;

fn main() {
    // Read the public key and signature
    let public_key: VerifyingKey = env::read();
    let message: Vec<u8> = env::read();
    let signature: Signature = env::read();
    
    // Verify the signature (uses precompiled elliptic curve operations)
    let is_valid = public_key.verify(&message, &signature).is_ok();
    
    env::commit(&is_valid);
}
See the complete ECDSA example for more details.

Performance Comparison

SHA-256 Hashing

ImplementationCycles per 64-byte block
Pure Rust~2,000
Precompile~68

secp256k1 Operations

OperationWithout PrecompileWith Precompile
Point multiplication~800,000 cycles~80,000 cycles
ECDSA verification~1,600,000 cycles~160,000 cycles
Linear combination (lincomb)~1,500,000 cycles~150,000 cycles
Precompiles typically provide 10-30x speedups for cryptographic operations. Always use them when available!

Indirect Usage

Some crates use cryptography indirectly through dependencies. You can still benefit from precompiles by applying Cargo patches without code changes.

Example: OAuth2 Crate

The oauth2 crate uses sha2 internally. To accelerate it:
methods/guest/Cargo.toml
[dependencies]
oauth2 = "4.4"

[patch.crates-io]
sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.9-risczero.0" }

Selecting Backend Crates

Some crates allow choosing different cryptographic backends:
methods/guest/Cargo.toml
[dependencies]
# Revm's precompile crate uses k256 by default (we have a patch)
revm-precompile = { version = "2.0", default-features = false }

[patch.crates-io]
k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.4-risczero.1" }
If you need a crate that’s not listed, reach out on Discord to request it!

Adding Precompile Support to Your Crates

You can add precompile support to your own crates. Here’s the general approach:

Example: Adding to k256

The k256 fork diff shows how to:
  1. Detect when running in the zkVM using #[cfg(target_os = "zkvm")]
  2. Replace core operations with precompiled equivalents
  3. Use zkVM-specific intrinsics for accelerated operations

Key Implementation Example

#[cfg(target_os = "zkvm")]
pub fn lincomb(
    base1: &ProjectivePoint,
    scalar1: &Scalar,
    base2: &ProjectivePoint,
    scalar2: &Scalar,
) -> ProjectivePoint {
    // Call zkVM's optimized linear combination precompile
    zkvm::ec::lincomb_secp256k1(base1, scalar1, base2, scalar2)
}

#[cfg(not(target_os = "zkvm"))]
pub fn lincomb(
    base1: &ProjectivePoint,
    scalar1: &Scalar,
    base2: &ProjectivePoint,
    scalar2: &Scalar,
) -> ProjectivePoint {
    // Standard implementation for non-zkVM targets
    (base1 * scalar1) + (base2 * scalar2)
}
See the lincomb implementation for details.

Security Considerations

Timing Attacks

Precompiles do not currently provide strict guarantees about constant-time execution and proving time.
Be very careful if using precompiles with private data, such as:
  • Signing messages within the zkVM where observers can measure proving time
  • Operations where cycle counts could leak information about secrets
For production use with sensitive data, consult the RISC Zero security documentation and consider constant-time guarantees.

Troubleshooting

Patch Not Applied

Problem: The patch doesn’t seem to be working. Solutions:
  1. Check that versions match exactly: sha2 = "=0.10.9" not sha2 = "0.10"
  2. Run cargo update -p sha2 --precise 0.10.9
  3. Delete Cargo.lock and target/ and rebuild
  4. Verify in Cargo.lock that the source points to the fork repository

Version Conflicts

Problem: Multiple versions of a crate are required. Solutions:
  1. Use cargo tree -d to find duplicate dependencies
  2. Patch all versions that are used:
    [patch.crates-io]
    sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.9-risczero.0" }
    
  3. Consider updating dependencies to use compatible versions

Missing Precompile Stats

Problem: Not seeing precompile usage in output. Solution: Run with RISC0_INFO=1:
RISC0_INFO=1 cargo run

Next Steps