1use std::f64::consts::LN_2;
2
3use openvm_stark_backend::{
4 config::DeepAliParameters, interaction::LogUpSecurityParameters, p3_field::Field,
5};
6use serde::{Deserialize, Serialize};
7
8use crate::config::log_up_params::log_up_security_params_baby_bear_100_bits;
9
10pub const MAX_NUM_CONSTRAINTS: usize = 30_000;
11pub const MAX_BATCH_SIZE_LOG_BLOWUP_1: usize = 80_000;
12pub const MAX_BATCH_SIZE_LOG_BLOWUP_2: usize = 4_000;
13
14#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)]
15pub struct FriParameters {
16 pub log_blowup: usize,
17 pub log_final_poly_len: usize,
18 pub num_queries: usize,
19 pub query_proof_of_work_bits: usize,
20 pub commit_proof_of_work_bits: usize,
21}
22
23impl FriParameters {
24 pub fn get_conjectured_security_bits(&self, challenge_field_bits: usize) -> usize {
30 let fri_query_security_bits =
31 self.num_queries * self.log_blowup + self.query_proof_of_work_bits;
32 challenge_field_bits.min(fri_query_security_bits)
34 }
35
36 pub fn standard_fast() -> Self {
38 standard_fri_params_with_100_bits_security(1)
39 }
40
41 #[deprecated(note = "use standard_with_100_bits_security instead")]
42 pub fn standard_with_100_bits_conjectured_security(log_blowup: usize) -> Self {
43 #[allow(deprecated)]
44 standard_fri_params_with_100_bits_conjectured_security(log_blowup)
45 }
46
47 pub fn standard_with_100_bits_security(log_blowup: usize) -> Self {
49 standard_fri_params_with_100_bits_security(log_blowup)
50 }
51
52 pub fn max_constraint_degree(&self) -> usize {
53 (1 << self.log_blowup) + 1
54 }
55
56 pub fn new_for_testing(log_blowup: usize) -> Self {
62 if let Ok("1") = std::env::var("OPENVM_FAST_TEST").as_deref() {
63 Self {
64 log_blowup,
65 log_final_poly_len: 0,
66 num_queries: 2,
67 commit_proof_of_work_bits: 0,
68 query_proof_of_work_bits: 0,
69 }
70 } else {
71 Self::standard_with_100_bits_security(log_blowup)
72 }
73 }
74
75 pub fn security_bits_fri(
88 &self,
89 challenge_field_bits: f64,
90 num_batch_columns: usize,
91 max_log_domain_size: usize,
92 ) -> f64 {
93 let commit_bits = self.security_bits_fri_commit_phase(
94 challenge_field_bits,
95 num_batch_columns,
96 max_log_domain_size,
97 );
98 tracing::debug!("FRI commit phase security bits: {commit_bits}");
99 let query_bits = self.security_bits_fri_query_phase();
100 tracing::debug!("FRI query phase security bits: {query_bits}");
101 commit_bits.min(query_bits)
102 }
103
104 pub fn security_bits_fri_commit_phase(
110 &self,
111 challenge_field_bits: f64,
112 num_batch_columns: usize,
113 max_log_domain_size: usize,
114 ) -> f64 {
115 let domain_size = 2.0_f64.powi(max_log_domain_size as i32);
116 let field_size = 2.0_f64.powf(challenge_field_bits);
117
118 let batch_term = num_batch_columns - 1;
120 let fold_term = 1; -(batch_term.max(fold_term) as f64 * domain_size / field_size).log2()
123 + self.commit_proof_of_work_bits as f64
124 }
125
126 pub fn security_bits_fri_query_phase(&self) -> f64 {
127 let rho = (2.0_f64).powi(-(self.log_blowup as i32));
128 let theta = (1.0 - rho) / 2.0;
129 -(self.num_queries as f64 * (-theta).ln_1p() / LN_2) + self.query_proof_of_work_bits as f64
130 }
131
132 pub fn security_bits_deep_ali(
135 &self,
136 params: &DeepAliParameters,
137 challenge_field_bits: f64,
138 max_log_domain_size: usize,
139 max_constraint_degree: usize,
140 max_num_constraints: usize,
141 ) -> f64 {
142 assert!(max_constraint_degree <= (1 << self.log_blowup) + 1);
143 let trace_length = 2.0_f64.powi(max_log_domain_size.saturating_sub(self.log_blowup) as i32);
144 let domain_size = 2.0_f64.powi(max_log_domain_size as i32);
145 let field_size = 2.0_f64.powf(challenge_field_bits);
146 let e_deep = (max_constraint_degree as f64) * (trace_length - 1.0)
150 / (field_size - trace_length - domain_size);
151 let e_ali = (max_num_constraints as f64) / field_size;
153 (-e_deep.log2() + params.deep_pow_bits as f64).min(-e_ali.log2())
154 }
155}
156
157pub fn standard_fri_params_with_100_bits_security(log_blowup: usize) -> FriParameters {
179 let fri_params = match log_blowup {
180 1 => FriParameters {
181 log_blowup,
182 log_final_poly_len: 0,
183 num_queries: 193,
184 commit_proof_of_work_bits: 20,
185 query_proof_of_work_bits: 20,
186 },
187 2 => FriParameters {
188 log_blowup,
189 log_final_poly_len: 0,
190 num_queries: 118,
191 commit_proof_of_work_bits: 16,
192 query_proof_of_work_bits: 20,
193 },
194 3 => FriParameters {
195 log_blowup,
196 log_final_poly_len: 0,
197 num_queries: 97,
198 commit_proof_of_work_bits: 16,
199 query_proof_of_work_bits: 20,
200 },
201 4 => FriParameters {
202 log_blowup,
203 log_final_poly_len: 0,
204 num_queries: 88,
205 commit_proof_of_work_bits: 16,
206 query_proof_of_work_bits: 20,
207 },
208 _ => panic!("No standard FRI params defined for log blowup {log_blowup}",),
209 };
210 tracing::debug!("FRI parameters | log_blowup: {log_blowup:<2} | num_queries: {:<2} | commit_proof_of_work_bits: {:<2} | query_proof_of_work_bits: {:<2}", fri_params.num_queries, fri_params.commit_proof_of_work_bits, fri_params.query_proof_of_work_bits);
211 fri_params
212}
213
214#[deprecated(note = "use standard_fri_params_with_100_bits_security instead")]
219pub fn standard_fri_params_with_100_bits_conjectured_security(log_blowup: usize) -> FriParameters {
220 let fri_params = match log_blowup {
221 1 => FriParameters {
224 log_blowup,
225 log_final_poly_len: 0,
226 num_queries: 100,
227 commit_proof_of_work_bits: 0,
228 query_proof_of_work_bits: 16,
229 },
230 2 => FriParameters {
231 log_blowup,
232 log_final_poly_len: 0,
233 num_queries: 44,
234 commit_proof_of_work_bits: 0,
235 query_proof_of_work_bits: 16,
236 },
237 3 => FriParameters {
239 log_blowup,
240 log_final_poly_len: 0,
241 num_queries: 30,
242 commit_proof_of_work_bits: 0,
243 query_proof_of_work_bits: 16,
244 },
245 4 => FriParameters {
246 log_blowup,
247 log_final_poly_len: 0,
248 num_queries: 23,
249 commit_proof_of_work_bits: 0,
250 query_proof_of_work_bits: 16,
251 },
252 _ => panic!("No standard FRI params defined for log blowup {log_blowup}",),
253 };
254 assert!(fri_params.get_conjectured_security_bits(100) >= 100);
255 tracing::debug!("FRI parameters | log_blowup: {log_blowup:<2} | num_queries: {:<2} | commit_pow_bits: {:<2}, query_pow_bits: {:<2}", fri_params.num_queries, fri_params.commit_proof_of_work_bits, fri_params.query_proof_of_work_bits);
256 fri_params
257}
258
259#[derive(Clone, Debug)]
260pub struct SecurityParameters {
261 pub fri_params: FriParameters,
262 pub log_up_params: LogUpSecurityParameters,
263 pub deep_ali_params: DeepAliParameters,
264}
265
266impl SecurityParameters {
267 pub fn standard_fast() -> Self {
269 Self::new_baby_bear_100_bits(FriParameters::standard_fast())
270 }
271
272 pub fn standard_100_bits_with_fri_log_blowup(log_blowup: usize) -> Self {
277 Self::new_baby_bear_100_bits(FriParameters::standard_with_100_bits_security(log_blowup))
278 }
279
280 pub fn new_baby_bear_100_bits(fri_params: FriParameters) -> Self {
281 Self {
282 fri_params,
283 log_up_params: log_up_security_params_baby_bear_100_bits(),
284 deep_ali_params: deep_ali_security_params_baby_bear_100_bits(),
285 }
286 }
287
288 pub fn security_bits<EF: Field>(
289 &self,
290 challenge_field_bits: f64,
291 num_batch_columns: usize,
292 max_log_domain_size: usize,
293 max_constraint_degree: usize,
294 max_num_constraints: usize,
295 ) -> f64 {
296 let fri_bits = self.fri_params.security_bits_fri(
297 challenge_field_bits,
298 num_batch_columns,
299 max_log_domain_size,
300 );
301 tracing::debug!("FRI security bits: {fri_bits}");
302 let deep_ali_bits = self.fri_params.security_bits_deep_ali(
303 &self.deep_ali_params,
304 challenge_field_bits,
305 max_log_domain_size,
306 max_constraint_degree,
307 max_num_constraints,
308 );
309 tracing::debug!("DEEP-ALI security bits: {deep_ali_bits}");
310 let logup_bits = self.log_up_params.bits_of_security::<EF>() as i32;
311 tracing::debug!("LogUp security bits: {logup_bits}");
312
313 fri_bits.min(deep_ali_bits).min(logup_bits as f64)
314 }
315}
316
317pub fn deep_ali_security_params_baby_bear_100_bits() -> DeepAliParameters {
318 DeepAliParameters { deep_pow_bits: 5 }
319}
320
321#[cfg(test)]
322mod security_tests {
323 use openvm_stark_backend::p3_field::{
324 extension::BinomialExtensionField, PrimeField64, TwoAdicField,
325 };
326 use p3_baby_bear::BabyBear;
327 use tracing::Level;
328
329 use super::*;
330 use crate::config::setup_tracing_with_log_level;
331
332 #[test]
333 fn test_params_provable_security() {
334 setup_tracing_with_log_level(Level::DEBUG);
335
336 let challenge_field_bits = (BabyBear::ORDER_U64 as f64).powi(4).log2();
337 for log_blowup in 1..=4 {
338 let params = SecurityParameters::standard_100_bits_with_fri_log_blowup(log_blowup);
339 let num_batch_columns = if log_blowup == 1 {
340 MAX_BATCH_SIZE_LOG_BLOWUP_1
341 } else {
342 MAX_BATCH_SIZE_LOG_BLOWUP_2
343 };
344 let max_constraint_degree = (1 << log_blowup) + 1;
345 let max_log_domain_size = BabyBear::TWO_ADICITY;
346 let bits = params.security_bits::<BinomialExtensionField<BabyBear, 4>>(
347 challenge_field_bits,
348 num_batch_columns,
349 max_log_domain_size,
350 max_constraint_degree,
351 MAX_NUM_CONSTRAINTS,
352 );
353 assert!(
354 bits >= 100.0,
355 "log_blowup: {log_blowup} has {bits} bits of security"
356 );
357 }
358 }
359}