1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147
//! A [`StarkConfig`] defines all the parameters to be used when proving a
//! [`Stark`][crate::stark::Stark].
//!
//! The default configuration is aimed for speed, yielding fast but large
//! proofs, with a targeted security level of 100 bits.
#[cfg(not(feature = "std"))]
use alloc::format;
use anyhow::{anyhow, Result};
use plonky2::field::extension::Extendable;
use plonky2::field::types::Field;
use plonky2::fri::reduction_strategies::FriReductionStrategy;
use plonky2::fri::{FriConfig, FriParams};
use plonky2::hash::hash_types::RichField;
/// A configuration containing the different parameters used by the STARK prover.
#[derive(Clone, Debug)]
pub struct StarkConfig {
/// The targeted security level for the proofs generated with this configuration.
pub security_bits: usize,
/// The number of challenge points to generate, for IOPs that have soundness errors of (roughly)
/// `degree / |F|`.
pub num_challenges: usize,
/// The configuration of the FRI sub-protocol.
pub fri_config: FriConfig,
}
impl Default for StarkConfig {
fn default() -> Self {
Self::standard_fast_config()
}
}
impl StarkConfig {
/// Returns a custom STARK configuration.
pub const fn new(security_bits: usize, num_challenges: usize, fri_config: FriConfig) -> Self {
Self {
security_bits,
num_challenges,
fri_config,
}
}
/// A typical configuration with a rate of 2, resulting in fast but large proofs.
/// Targets ~100 bit conjectured security.
pub const fn standard_fast_config() -> Self {
Self {
security_bits: 100,
num_challenges: 2,
fri_config: FriConfig {
rate_bits: 1,
cap_height: 4,
proof_of_work_bits: 16,
reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5),
num_query_rounds: 84,
},
}
}
/// Outputs the [`FriParams`] used during the FRI sub-protocol by this [`StarkConfig`].
pub fn fri_params(&self, degree_bits: usize) -> FriParams {
self.fri_config.fri_params(degree_bits, false)
}
/// Checks that this STARK configuration is consistent, i.e. that the different
/// parameters meet the targeted security level.
pub fn check_config<F: RichField + Extendable<D>, const D: usize>(&self) -> Result<()> {
let StarkConfig {
security_bits,
fri_config:
FriConfig {
rate_bits,
proof_of_work_bits,
num_query_rounds,
..
},
..
} = &self;
// Conjectured FRI security; see the ethSTARK paper.
let fri_field_bits = F::Extension::order().bits() as usize;
let fri_query_security_bits = num_query_rounds * rate_bits + *proof_of_work_bits as usize;
let fri_security_bits = fri_field_bits.min(fri_query_security_bits);
if fri_security_bits < *security_bits {
Err(anyhow!(format!(
"FRI params fall short of target security {}, reaching only {}",
security_bits, fri_security_bits
)))
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use plonky2::field::goldilocks_field::GoldilocksField;
use super::*;
#[test]
fn test_valid_config() {
type F = GoldilocksField;
const D: usize = 2;
let config = StarkConfig::standard_fast_config();
assert!(config.check_config::<F, D>().is_ok());
let high_rate_config = StarkConfig::new(
100,
2,
FriConfig {
rate_bits: 3,
cap_height: 4,
proof_of_work_bits: 16,
reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5),
num_query_rounds: 28,
},
);
assert!(high_rate_config.check_config::<F, D>().is_ok());
}
#[test]
fn test_invalid_config() {
type F = GoldilocksField;
const D: usize = 2;
let too_few_queries_config = StarkConfig::new(
100,
2,
FriConfig {
rate_bits: 1,
cap_height: 4,
proof_of_work_bits: 16,
reduction_strategy: FriReductionStrategy::ConstantArityBits(4, 5),
num_query_rounds: 50,
},
);
// The conjectured security yields `rate_bits` * `num_query_rounds` + `proof_of_work_bits` = 66
// bits of security for FRI, which falls short of the 100 bits of security target.
assert!(too_few_queries_config.check_config::<F, D>().is_err());
}
}