From c7ed2fc7174231ba9a42c0f7a4cbae6c0af07c98 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Fri, 12 Jan 2024 10:37:12 +0100 Subject: [PATCH] chore: make dependence on number of openings explicit and correct its use fix: rustfmt test: add sanity tests for proven security test: add test for 128 bits of security test: add 96 bits test and extension degree sanity test chore: minor nits --- air/src/proof/mod.rs | 301 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 278 insertions(+), 23 deletions(-) diff --git a/air/src/proof/mod.rs b/air/src/proof/mod.rs index 9cd1fa180..8a329d789 100644 --- a/air/src/proof/mod.rs +++ b/air/src/proof/mod.rs @@ -288,11 +288,30 @@ fn proven_security_protocol_for_m( let m = m as f64; let rho = 1.0 / options.blowup_factor() as f64; let alpha = (1.0 + 0.5 / m) * sqrt(rho); - let theta = 1.0 - alpha; - let max_deg = options.blowup_factor() as f64; + let max_deg = options.blowup_factor() as f64 + 1.0; + // To apply Theorem 8 in https://eprint.iacr.org/2022/1216.pdf, we need to apply FRI with + // a slightly larger agreement parameter alpha. + // More concretely, we need alpha > rho_plus.sqrt() where rho_plus is the rate in function field + // F(Z) and defined as (trace_domain_size + 2.0) / lde_domain_size . + // This means that the range of m needs to be restricted in order to ensure that + // alpha := 1 - theta := rho.sqrt() * (1 + 1/2m) is greater than rho_plus.sqrt(). + // Determining the range of m is the responsibility of the calling function. + // Now, once m is fixed, we need to make sure that we choose an m_plus such that + // alpha <= rho_plus.sqrt() * (1 + 1/2m_plus). This m_plus will be used to define + // the list-decoding list size in F(Z). + + // Modified rate in function field F(Z) let lde_domain_size = (trace_domain_size * options.blowup_factor()) as f64; let trace_domain_size = trace_domain_size as f64; + let num_openings = 2.0; + let rho_plus = (trace_domain_size + num_openings) / lde_domain_size; + + // New proximity parameter m_plus, corresponding to rho_plus, needed to make sure that + // alpha < rho_plus.sqrt() * (1 + 1 / (2 * m_plus)) + let m_plus = ceil(1.0 / (2.0 * (alpha / sqrt(rho_plus) - 1.0))); + let alpha_plus = (1.0 + 0.5 / m_plus) * sqrt(rho_plus); + let theta_plus = 1.0 - alpha_plus; // Computes FRI commit-phase (i.e., pre-query) soundness error. // This considers only the first term given in eq. 7 in https://eprint.iacr.org/2022/1216.pdf, @@ -302,7 +321,7 @@ fn proven_security_protocol_for_m( // Compute FRI query-phase soundness error let fri_queries_err_bits = - options.grinding_factor() as f64 - log2(powf(1.0 - theta, num_fri_queries)); + options.grinding_factor() as f64 - log2(powf(1.0 - theta_plus, num_fri_queries)); // Combined error for FRI let fri_err_bits = cmp::min(fri_commit_err_bits as u64, fri_queries_err_bits as u64); @@ -311,23 +330,6 @@ fn proven_security_protocol_for_m( } let fri_err_bits = fri_err_bits - 1; - // To apply Theorem 8 in https://eprint.iacr.org/2022/1216.pdf, we need to apply FRI with - // a slightly larger agreement parameter alpha. - // More concretely, we need alpha > rho_plus.sqrt() where rho_plus is the rate in function field - // F(Z) and defined as (trace_domain_size + 2.0) / lde_domain_size . - // This means that the range of m needs to be restricted in order to ensure that - // alpha := 1 - theta := rho.sqrt() * (1 + 1/2m) is greater than rho_plus.sqrt(). - // Determining the range of m is the responsibility of the calling function. - // Now, once m is fixed, we need to make sure that we choose an m_plus such that - // alpha <= rho_plus.sqrt() * (1 + 1/2m_plus). This m_plus will be used to define - // the list-decoding list size in F(Z). - - // Modified rate in function field F(Z) - let rho_plus = (trace_domain_size + 2.0) / lde_domain_size; - // New proximity parameter m_plus, corresponding to rho_plus, needed to make sure that - // alpha < rho_plus.sqrt() * (1 + 1 / (2 * m_plus)) - let m_plus = ceil(1.0 / (2.0 * (alpha / sqrt(rho_plus) - 1.0))); - // List size let l_plus = (2.0 * m_plus + 1.0) / (2.0 * sqrt(rho_plus)); @@ -338,9 +340,9 @@ fn proven_security_protocol_for_m( // DEEP related soundness error. Note that this uses that the denominator |F| - |D ∪ H| // can be approximated by |F| for all practical domain sizes. We also use the blow-up factor // as an upper bound for the maximal constraint degree. - let deep_err_bits = - -log2(l_plus * (max_deg * (trace_domain_size + 1.0) + (trace_domain_size - 1.0))) - + extension_field_bits; + let deep_err_bits = -log2( + l_plus * (max_deg * (trace_domain_size + num_openings - 1.0) + (trace_domain_size - 1.0)), + ) + extension_field_bits; let min = cmp::min(cmp::min(fri_err_bits, ali_err_bits as u64), deep_err_bits as u64); if min < 1 { @@ -404,3 +406,256 @@ pub fn ceil(value: f64) -> f64 { pub fn ceil(value: f64) -> f64 { libm::ceil(value) } + +#[cfg(test)] +mod prove_security_tests { + use super::ProofOptions; + use crate::{proof::get_proven_security, FieldExtension}; + use math::{fields::f64::BaseElement, StarkField}; + + #[test] + fn get_96_bits_security() { + let field_extension = FieldExtension::Cubic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 4; + let num_queries = 80; + let collision_resistance = 128; + let trace_length = 2_usize.pow(18); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_1, 97); + + // increasing the blowup factor should increase the bits of security gained per query + let blowup_factor = 8; + let num_queries = 53; + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_2, 97); + } + + #[test] + fn get_128_bits_security() { + let field_extension = FieldExtension::Cubic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 8; + let num_queries = 85; + let collision_resistance = 128; + let trace_length = 2_usize.pow(18); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_1, 128); + + // increasing the blowup factor should increase the bits of security gained per query + let blowup_factor = 16; + let num_queries = 65; + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_2, 128); + } + + #[test] + fn extension_degree() { + let field_extension = FieldExtension::Quadratic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 8; + let num_queries = 85; + let collision_resistance = 128; + let trace_length = 2_usize.pow(18); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_1, 67); + + // increasing the extension degree improves the FRI commit phase soundness error and permits + // reaching 128 bits security + let field_extension = FieldExtension::Cubic; + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert_eq!(security_2, 128); + } + + #[test] + fn trace_length() { + let field_extension = FieldExtension::Cubic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 8; + let num_queries = 80; + let collision_resistance = 128; + let trace_length = 2_usize.pow(20); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + let trace_length = 2_usize.pow(16); + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert!(security_1 < security_2); + } + + #[test] + fn num_fri_queries() { + let field_extension = FieldExtension::Cubic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 8; + let num_queries = 60; + let collision_resistance = 128; + let trace_length = 2_usize.pow(20); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + let num_queries = 80; + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert!(security_1 < security_2); + } + + #[test] + fn blowup_factor() { + let field_extension = FieldExtension::Cubic; + let base_field_bits = BaseElement::MODULUS_BITS; + let fri_folding_factor = 8; + let fri_remainder_max_degree = 127; + let grinding_factor = 20; + let blowup_factor = 8; + let num_queries = 30; + let collision_resistance = 128; + let trace_length = 2_usize.pow(20); + + let mut options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_1 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + let blowup_factor = 16; + + options = ProofOptions::new( + num_queries, + blowup_factor, + grinding_factor, + field_extension, + fri_folding_factor as usize, + fri_remainder_max_degree as usize, + ); + let security_2 = + get_proven_security(&options, base_field_bits, trace_length, collision_resistance); + + assert!(security_1 < security_2); + } +}