use {
provekit_common::{utils::next_power_of_two, WhirR1CSScheme, WhirZkConfig, R1CS},
whir::parameters::ProtocolParameters,
};
const MIN_WHIR_NUM_VARIABLES: usize = 14;
const MIN_SUMCHECK_NUM_VARIABLES: usize = 1;
pub trait WhirR1CSSchemeBuilder {
fn new_for_r1cs(
r1cs: &R1CS,
w1_size: usize,
num_challenges: usize,
challenge_offsets: Vec<usize>,
has_public_inputs: bool,
) -> Self;
fn new_whir_zk_config_for_size(num_variables: usize) -> WhirZkConfig;
}
impl WhirR1CSSchemeBuilder for WhirR1CSScheme {
fn new_for_r1cs(
r1cs: &R1CS,
w1_size: usize,
num_challenges: usize,
challenge_offsets: Vec<usize>,
has_public_inputs: bool,
) -> Self {
assert_eq!(
num_challenges,
challenge_offsets.len(),
"num_challenges ({num_challenges}) must equal challenge_offsets.len() ({})",
challenge_offsets.len()
);
let total_witnesses = r1cs.num_witnesses();
assert!(
w1_size <= total_witnesses,
"w1_size exceeds total witnesses"
);
let w2_size = total_witnesses - w1_size;
let m1_raw = next_power_of_two(w1_size);
let m2_raw = next_power_of_two(w2_size);
let m0_raw = next_power_of_two(r1cs.num_constraints());
let mut m_raw = m1_raw.max(m2_raw).max(MIN_WHIR_NUM_VARIABLES);
let m_0 = m0_raw.max(MIN_SUMCHECK_NUM_VARIABLES);
if (1usize << m_raw) - w1_size < 4 * m_0 {
m_raw += 1;
}
Self {
m: m_raw,
w1_size,
m_0,
a_num_terms: next_power_of_two(r1cs.a().iter().count()),
num_challenges,
challenge_offsets,
whir_witness: Self::new_whir_zk_config_for_size(m_raw),
has_public_inputs,
r1cs_hash: r1cs.hash(),
}
}
fn new_whir_zk_config_for_size(num_variables: usize) -> WhirZkConfig {
let nv = num_variables.max(MIN_WHIR_NUM_VARIABLES);
let whir_params = ProtocolParameters {
unique_decoding: false,
security_level: 128,
pow_bits: 10,
initial_folding_factor: 3,
folding_factor: 3,
starting_log_inv_rate: 2,
batch_size: 1,
hash_id: whir::hash::SHA2,
};
WhirZkConfig::new(nv, &whir_params)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_security_level() {
let config = WhirR1CSScheme::new_whir_zk_config_for_size(20);
let sec_blinded = config
.blinded_polynomial
.security_level(config.blinded_polynomial.initial_committer.num_vectors, 1);
let sec_blinding = config
.blinding_polynomial
.security_level(config.blinding_polynomial.initial_committer.num_vectors, 1);
assert!(
sec_blinded >= 128.0,
"Blinded commitment security {sec_blinded:.2} < 128 bits"
);
assert!(
sec_blinding >= 128.0,
"Blinding commitment security {sec_blinding:.2} < 128 bits"
);
}
#[test]
fn verify_security_level_min_variables() {
let config = WhirR1CSScheme::new_whir_zk_config_for_size(MIN_WHIR_NUM_VARIABLES);
let sec_blinded = config
.blinded_polynomial
.security_level(config.blinded_polynomial.initial_committer.num_vectors, 1);
let sec_blinding = config
.blinding_polynomial
.security_level(config.blinding_polynomial.initial_committer.num_vectors, 1);
assert!(
sec_blinded >= 128.0,
"Blinded commitment security {sec_blinded:.2} < 128 bits at nv={}",
MIN_WHIR_NUM_VARIABLES
);
assert!(
sec_blinding >= 128.0,
"Blinding commitment security {sec_blinding:.2} < 128 bits at nv={}",
MIN_WHIR_NUM_VARIABLES
);
}
}