### Setup Development Environment Source: https://jolt.a16zcrypto.com/print.html Commands to install necessary dependencies for building Jolt and its documentation, including the Rust toolchain and mdbook. ```bash # Install Rust curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh # Add RISC-V target rustup target add riscv64imac-unknown-none-elf # Install documentation tools cargo install mdbook mdbook-katex mdbook watch book --open ``` -------------------------------- ### Initialize and Manage Jolt Projects Source: https://jolt.a16zcrypto.com/usage/quickstart.html Standard commands for installing the Jolt CLI, creating new projects, and navigating the project directory. ```shell cargo +nightly install --git https://github.com/a16z/jolt --force --bins jolt jolt new cd ``` -------------------------------- ### Install Jolt Command Line Tool Source: https://jolt.a16zcrypto.com/print.html Installs the Jolt command line tool using Cargo. This tool is necessary for managing Jolt projects and generating proofs. ```bash cargo +nightly install --git https://github.com/a16z/jolt --force --bins jolt ``` -------------------------------- ### Create a New Jolt Project Source: https://jolt.a16zcrypto.com/print.html Creates a new Jolt project template using the `jolt new` command. After creation, navigate into the project directory to proceed with further setup. ```bash jolt new ``` ```bash cd ``` -------------------------------- ### Install Jolt Agent Skill Source: https://jolt.a16zcrypto.com/usage/quickstart.html Commands to install the Jolt agent skill for AI coding assistants. Supports both npm and curl-based installation methods. ```shell npx skills add a16z/jolt ``` ```shell curl -sfL jolt.rs/skill | bash ``` -------------------------------- ### Configure Jolt SDK for Zero-Knowledge Proofs (Host) Source: https://jolt.a16zcrypto.com/usage/guests_hosts/guests.html Details the `Cargo.toml` setup for a Jolt host crate when utilizing zero-knowledge (ZK) proofs. It requires enabling both the `host` and `zk` features for the `jolt-sdk` dependency. ```toml [dependencies] jolt-sdk = { features = ["host", "zk"] } ``` -------------------------------- ### View Pprof Profile in Browser Source: https://jolt.a16zcrypto.com/usage/profiling/zkvm_profiling.html Starts a local web server using the pprof tool to visualize CPU profiling data, including flame graphs, top functions, and call graphs. This allows for interactive exploration of performance bottlenecks. ```bash go tool pprof -http=:8080 target/release/jolt-core benchmark-runs/pprof/sha3_prove.pb ``` -------------------------------- ### Execute Proving and Verification on Host Source: https://jolt.a16zcrypto.com/usage/runtime_advice.html Shows how to compile the guest program, generate preprocessing data, and execute the prover and verifier. The host handles the two-pass advice mechanism automatically via generated functions. ```rust pub fn main() { let target_dir = "/tmp/jolt-guest-targets"; let mut program = guest::compile_verify_composite(target_dir); let shared_preprocessing = guest::preprocess_shared_verify_composite(&mut program); let prover_preprocessing = guest::preprocess_prover_verify_composite(shared_preprocessing.clone()); let verifier_setup = prover_preprocessing.generators.to_verifier_setup(); let verifier_preprocessing = guest::preprocess_verifier_verify_composite(shared_preprocessing, verifier_setup); let prove = guest::build_prover_verify_composite(program, prover_preprocessing); let verify = guest::build_verifier_verify_composite(verifier_preprocessing); let n = 221u32; // 13 * 17 let (output, proof, program_io) = prove(n); let is_valid = verify(n, output, program_io.panic, proof); assert!(is_valid); } ``` -------------------------------- ### Compile and Prove SHA3 with JoltBook Host Source: https://jolt.a16zcrypto.com/usage/guests_hosts/hosts.html Demonstrates the host-side process of compiling a SHA3 guest program, generating necessary preprocessing data, and then using the prover and verifier closures to generate and validate a proof. This involves multiple steps including compilation, shared preprocessing, and specific prover/verifier preprocessing. ```rust use std::time::Instant; pub fn main() { let target_dir = "/tmp/jolt-guest-targets"; let mut program = guest::compile_sha3(target_dir); let shared = guest::preprocess_shared_sha3(&mut program); let prover_pp = guest::preprocess_prover_sha3(shared.clone()); let verifier_pp = guest::preprocess_verifier_sha3( shared, prover_pp.generators.to_verifier_setup(), ); let prove_sha3 = guest::build_prover_sha3(program, prover_pp); let verify_sha3 = guest::build_verifier_sha3(verifier_pp); let input: &[u8] = &[5u8; 32]; let now = Instant::now(); let (output, proof, program_io) = prove_sha3(input); println!("Prover runtime: {} s", now.elapsed().as_secs_f64()); let is_valid = verify_sha3(input, output, program_io.panic, proof); println!("output: {}", hex::encode(output)); println!("valid: {is_valid}"); } ``` -------------------------------- ### Define Provable Guest Function Source: https://jolt.a16zcrypto.com/usage/quickstart.html Example of a guest Rust function marked with the #[jolt::provable] macro, which allows it to be compiled into a ZK-proof circuit. ```rust #![allow(unused)] #![cfg_attr(feature = "guest", no_std)] #![no_main] fn main() { #[jolt::provable] fn fib(n: u32) -> u128 { let mut a: u128 = 0; let mut b: u128 = 1; let mut sum: u128; for _ in 1..n { sum = a + b; a = b; b = sum; } b } } ``` -------------------------------- ### Implement Provable Guest Logic with Advice Source: https://jolt.a16zcrypto.com/usage/runtime_advice.html Demonstrates using the #[jolt::advice] and #[jolt::provable] macros. The advice function performs expensive computation off-chain, while the provable function verifies the results within the Jolt proof system. ```rust use jolt::AdviceTapeIO; /// Compute factors of n via advice (expensive trial division runs outside the proof) #[jolt::advice] fn factor(n: u32) -> jolt::UntrustedAdvice<[u32; 2]> { for i in 2..=n { if n % i == 0 { return [i, n / i]; } } [1, n] } /// Prove that n is composite by obtaining and verifying its factors via advice #[jolt::provable] fn verify_composite(n: u32) { let adv = factor(n); let [a, b] = *adv; // Verify the factors are correct and non-trivial jolt::check_advice_eq!((a as u64) * (b as u64), n as u64); jolt::check_advice!(1 < a && a <= b && b < n); } ``` -------------------------------- ### Configure Jolt Input and Output Sizes Source: https://jolt.a16zcrypto.com/usage/troubleshooting.html Sets the maximum size for inputs and outputs in Jolt, which defaults to 4096 bytes. Exceeding this limit will result in errors. This example demonstrates how to configure these limits using the `jolt::provable` macro. ```rust #![allow(unused)] #![cfg_attr(feature = "guest", no_std)] #![no_main] fn main() { #[jolt::provable(max_input_size = 10000, max_output_size = 10000)] fn sum(input: &[u8]) -> u32 { let mut sum = 0; for value in input { sum += *value as u32; } sum } } ``` -------------------------------- ### Execute Host and View Logs Source: https://jolt.a16zcrypto.com/usage/quickstart.html Commands to run the host application with optional logging enabled to observe proof generation metrics. ```shell cargo run --release RUST_LOG=info cargo run --release ``` -------------------------------- ### Increase max_trace_length to resolve trace length errors Source: https://jolt.a16zcrypto.com/usage/troubleshooting.html Demonstrates how to increase the `max_trace_length` in a Rust test setup to resolve 'Execution trace length exceeds max_trace_length' errors. This is typically done by adjusting a constant value in the test's preprocessing configuration. ```rust let shared_preprocessing = JoltSharedPreprocessing::new( bytecode.clone(), io_device.memory_layout.clone(), init_memory_state, - 1 << 16, + 1 << 17, ); ``` -------------------------------- ### Implement Runtime Advice with Jolt Source: https://jolt.a16zcrypto.com/print.html Shows how to define an advice function using the #[jolt::advice] macro. This allows the guest to offload expensive computations to an advice tape, which is populated during a first-pass execution and read during the proving pass. ```rust use jolt::AdviceTapeIO; #[jolt::advice] fn modinv_advice(a: u64, m: u64) -> jolt::UntrustedAdvice<(u64, u64)> { // This body only runs during the compute_advice pass. // During proving, the result is read from the advice tape. let inv = extended_gcd(a, m); let quo = (a as u128 * inv as u128 / m as u128) as u64; (inv, quo) } ``` -------------------------------- ### Start and End Cycle Tracking in Rust Source: https://jolt.a16zcrypto.com/usage/profiling/guest_profiling.html Demonstrates how to use `start_cycle_tracking` and `end_cycle_tracking` functions in Rust to measure the execution time of a specific code segment. These functions emit ECALLs to signal the emulator for tracking. Ensure the `jolt` crate is included as a dependency. ```rust #![allow(unused)] #![cfg_attr(feature = "guest", no_std)] fn main() { use jolt::{start_cycle_tracking, end_cycle_tracking}; #[jolt::provable] fn fib(n: u32) -> u128 { let (mut a, mut b) = (0, 1); start_cycle_tracking("fib_loop"); for _ in 1..n { let sum = a + b; a = b; b = sum; } end_cycle_tracking("fib_loop"); b } } ``` -------------------------------- ### Invoke Jolt Prover and Verifier in Rust Source: https://jolt.a16zcrypto.com/print.html Demonstrates the host-side workflow for compiling a guest, generating preprocessing data, and executing the prover and verifier closures. It shows the end-to-end process of generating a proof and validating it using the Jolt framework. ```rust pub fn main() { let target_dir = "/tmp/jolt-guest-targets"; let mut program = guest::compile_sha3(target_dir); let shared = guest::preprocess_shared_sha3(&mut program); let prover_pp = guest::preprocess_prover_sha3(shared.clone()); let verifier_pp = guest::preprocess_verifier_sha3( shared, prover_pp.generators.to_verifier_setup(), ); let prove_sha3 = guest::build_prover_sha3(program, prover_pp); let verify_sha3 = guest::build_verifier_sha3(verifier_pp); let input: &[u8] = &[5u8; 32]; let now = Instant::now(); let (output, proof, program_io) = prove_sha3(input); println!("Prover runtime: {} s", now.elapsed().as_secs_f64()); let is_valid = verify_sha3(input, output, program_io.panic, proof); println!("output: {}", hex::encode(output)); println!("valid: {is_valid}"); } ``` -------------------------------- ### Implement Host Verification Pipeline Source: https://jolt.a16zcrypto.com/usage/quickstart.html The host code demonstrates the four-stage Jolt pipeline: compiling the guest, preprocessing, proving execution, and verifying the resulting proof. ```rust pub fn main() { let target_dir = "/tmp/jolt-guest-targets"; let mut program = guest::compile_fib(target_dir); let shared = guest::preprocess_shared_fib(&mut program); let prover_pp = guest::preprocess_prover_fib(shared.clone()); let verifier_pp = guest::preprocess_verifier_fib( shared, prover_pp.generators.to_verifier_setup(), ); let prove_fib = guest::build_prover_fib(program, prover_pp); let verify_fib = guest::build_verifier_fib(verifier_pp); let (output, proof, program_io) = prove_fib(50); let is_valid = verify_fib(50, output, program_io.panic, proof); println!("output: {output}"); println!("valid: {is_valid}"); } ``` -------------------------------- ### Rust Chained SHA-256 Hashing with Jolt Inlines Source: https://jolt.a16zcrypto.com/how/optimizations/inlines.html Illustrates a provable function in Rust that chains SHA-256 hashing multiple times using Jolt inlines. This example utilizes the `jolt::provable` macro and the `jolt-inlines-sha2` crate. ```rust #![allow(unused)] fn main() { use jolt_inlines_sha2::Sha256; #[jolt::provable] fn sha2_chain(input: [u8; 32], num_iters: u32) -> [u8; 32] { let mut hash = input; for _ in 0..num_iters { hash = Sha256::digest(&hash); } hash } } ``` -------------------------------- ### Configure Jolt Memory and Stack Sizes Source: https://jolt.a16zcrypto.com/usage/troubleshooting.html Adjusts the default allocated memory and stack size for Jolt to prevent unpredictable errors. It's recommended to increase stack size first as it's more likely to be insufficient. This example shows how to manually specify both heap and stack sizes. ```rust #![allow(unused)] #![cfg_attr(feature = "guest", no_std)] #![no_main] fn main() { extern crate alloc; use alloc::vec::Vec; #[jolt::provable(stack_size = 10000, heap_size = 10000000)] fn waste_memory(size: u32, n: u32) { let mut v = Vec::new(); for i in 0..size { v.push(i); } } } ``` -------------------------------- ### Execute and Debug Jolt Host Programs Source: https://jolt.a16zcrypto.com/print.html Commands to run the host program using Cargo, including options for enabling verbose logging to inspect proof generation metrics. ```bash cargo run --release # Run with logging enabled RUST_LOG=info cargo run --release ``` -------------------------------- ### Implement Private Input Fibonacci in Rust for Jolt ZK Source: https://jolt.a16zcrypto.com/usage/guests_hosts/guests.html Provides a Rust example for a Jolt guest program that calculates Fibonacci numbers using `PrivateInput`. This requires the `zk` feature to be enabled. The `jolt::provable` macro is used with specified `heap_size` and `max_trace_length` for ZK operations. ```rust #![allow(unused)] #![cfg_attr(feature = "guest", no_std)] fn main() { use jolt::PrivateInput; #[jolt::provable(heap_size = 32768, max_trace_length = 65536)] fn fib(n: PrivateInput) -> u128 { let mut a: u128 = 0; let mut b: u128 = 1; for _ in 1..*n { let sum = a + b; a = b; b = sum; } b } } ``` -------------------------------- ### RISC-V Inline Assembly for SHA-256 Operations Source: https://jolt.a16zcrypto.com/how/optimizations/inlines.html Shows how to invoke Jolt SHA-256 inlines directly using RISC-V inline assembly. This example demonstrates the use of `.insn` with specific opcodes, funct3, and funct7 values for SHA256 and SHA256INIT operations. It requires `unsafe` block. ```rust #![allow(unused)] fn main() { unsafe { // SHA256 compression with existing state // opcode=0x0B (core inline), funct3=0x0 (SHA256), funct7=0x00 (SHA2 family) core::arch::asm!( ".insn r 0x0B, 0x0, 0x00, x0, {}, {}", in(reg) input_ptr, // Pointer to 16 u32 words in(reg) state_ptr, // Pointer to 8 u32 words options(nostack) ); // SHA256 compression with initial constants // opcode=0x0B (core inline), funct3=0x1 (SHA256INIT), funct7=0x00 (SHA2 family) core::arch::asm!( ".insn r 0x0B, 0x1, 0x00, x0, {}, {}", in(reg) input_ptr, in(reg) state_ptr, options(nostack) ); } } ``` -------------------------------- ### Dory Library Integration in Jolt Source: https://jolt.a16zcrypto.com/print.html Illustrates how the Jolt project integrates the `a16z/dory` library. Key files are identified, showing the structure for implementing commitment schemes, managing Dory-specific global parameters, and bridging Jolt's polynomial types with Dory's interfaces. ```Rust // File: jolt-core/src/poly/commitment/dory/commitment_scheme.rs use crate::poly::commitment::dory::dory_globals::DoryContext; use a16z_dory::prelude::CommitmentScheme as DoryCommitmentScheme; use ark_std::io::{Result, Write}; use ark_std::vec::Vec; pub struct DoryWrapper { dory_scheme: DoryCommitmentScheme, context: DoryContext, } impl DoryWrapper { pub fn new(context: DoryContext) -> Self { // Initialize the underlying Dory commitment scheme let dory_scheme = DoryCommitmentScheme::new(context.n_poly_coeffs, context.n_rows); DoryWrapper { dory_scheme, context } } // Implement Jolt's CommitmentScheme trait using dory_scheme // ... } // File: jolt-core/src/poly/commitment/dory/wrappers.rs use crate::poly::commitment::dory::dory_globals::DoryContext; use crate::poly::commitment::CommitmentScheme; use crate::poly::multilinear_polynomial::MultilinearPolynomial; use a16z_dory::prelude::G1; use ark_std::io::Result; // Wrapper for Dory's polynomial interface struct DoryPolynomialWrapper<'a, P: MultilinearPolynomial> { poly: &'a P, context: &'a DoryContext, } impl<'a, P: MultilinearPolynomial> DoryPolynomialWrapper<'a, P> { // Methods to adapt Jolt's MultilinearPolynomial to Dory's expected format // ... fn commit_tier_1(&self) -> Result { // Calls specialized commit_tier_1 logic based on poly properties // ... Ok(G1::identity()) // Placeholder } } // File: jolt-core/src/poly/commitment/dory/jolt_dory_routines.rs use crate::utils::group_ops::msm; use ark_std::vec::Vec; // Custom implementations of low-level group operations pub fn custom_msm(scalars: &[Scalar], generators: &[G1]) -> G1 { // Optimized MSM implementation for Jolt's specific needs // ... msm(scalars, generators) // Example using a utility function } // ... other custom routines for vector-scalar multiplication, folding, etc. ```