provekit-whir 0.1.1

An implementation of the WHIR polynomial commitment scheme
Documentation
//! Benchmark commit time across all fields with optimized parameters.
//!
//! Run with:
//! ```
//! RUSTFLAGS="-C target-cpu=native" cargo run --release --features asm --bin bench_fields
//! ```

use std::time::Instant;

use ark_ff::FftField;
use ark_std::rand::{distributions::Standard, prelude::Distribution, thread_rng, Rng};
use provekit_whir::{
    algebra::{
        fields::{Field128, Field192, Field256, Field64, Field64_2, Field64_3},
        linear_form::MultilinearExtension,
    },
    parameters::ProtocolParameters,
    protocols::whir_zk::Config,
    transcript::{codecs::Empty, Codec, DomainSeparator, ProverState},
};

const NUM_POLYNOMIALS: usize = 42;
const NUM_VARIABLES: usize = 19;
const NUM_COEFFS: usize = 1 << NUM_VARIABLES;

fn main() {
    println!("=====================================================");
    println!("Commit Benchmark: {} poly × 2^{}", NUM_POLYNOMIALS, NUM_VARIABLES);
    println!("Flags: opt-level=3, lto=fat, codegen-units=1");
    println!("       target-cpu=native, --features asm");
    println!("=====================================================\n");

    // Warmup run (discard)
    println!("Warming up...");
    bench::<Field192>("warmup", 128, 20, 1, 4, 4);

    println!("\n--- Head-to-head: 128-bit security, 3 runs each ---");
    for i in 1..=3 {
        println!("\nRun {i}:");
        bench::<Field64_3>("  Field64_3 (Goldilocks^3)", 128, 20, 1, 4, 4);
        bench::<Field192>("  Field192 (192-bit prime)", 128, 20, 1, 4, 4);
        bench::<Field256>("  Field256/BN254", 128, 20, 1, 4, 4);
    }
}

fn bench<F>(label: &str, security_level: usize, pow_bits: usize, rate: usize, iff: usize, ff: usize)
where
    F: FftField + Codec,
    Standard: Distribution<F>,
{
    print!("{label:<55} ");

    let whir_params = ProtocolParameters {
        security_level,
        pow_bits,
        initial_folding_factor: iff,
        folding_factor: ff,
        unique_decoding: false,
        starting_log_inv_rate: rate,
        batch_size: NUM_POLYNOMIALS,
        hash_id: provekit_whir::hash::BLAKE3,
    };

    // Config::new may panic if PoW > 60
    let result = std::panic::catch_unwind(|| {
        let params = Config::<F>::new(NUM_VARIABLES, &whir_params);

        let ds = DomainSeparator::protocol(&params)
            .session(&String::from("bench"))
            .instance(&Empty);
        let mut prover_state = ProverState::new_std(&ds);

        let mut rng = thread_rng();
        let vectors: Vec<Vec<F>> = (0..NUM_POLYNOMIALS)
            .map(|_| (0..NUM_COEFFS).map(|_| rng.gen()).collect())
            .collect();
        let vec_refs: Vec<&[F]> = vectors.iter().map(Vec::as_slice).collect();

        let t = Instant::now();
        let _witness = params.commit(&mut prover_state, &vec_refs);
        t.elapsed()
    });

    match result {
        Ok(elapsed) => println!("{elapsed:.2?}  (sec={security_level}, pow={pow_bits}, rate={rate})"),
        Err(_) => println!("FAILED  (PoW > 60 or config error)"),
    }
}