diff --git a/src/centralized_telescope/params.rs b/src/centralized_telescope/params.rs index fa0f6cf6..806428c8 100644 --- a/src/centralized_telescope/params.rs +++ b/src/centralized_telescope/params.rs @@ -16,132 +16,239 @@ pub struct Params { pub dfs_bound: u64, } -impl Params { - /// Setup algorithm taking as input the security parameters, the set size - /// and the lower bound and returning the internal parameters Params - pub(super) fn new( - soundness_param: f64, - completeness_param: f64, - set_size: u64, - lower_bound: u64, - ) -> Self { - let set_size_f64 = set_size as f64; - let lower_bound_f64 = lower_bound as f64; +pub(super) struct Small { + completeness_param: f64, +} - let proof_size_f64 = { - let numerator = soundness_param + completeness_param.log2() + 5.0 - LOG2_E.log2(); - let denominator = (set_size_f64 / lower_bound_f64).log2(); - (numerator / denominator).ceil() - }; +pub(super) struct Mid { + completeness_param: f64, + completeness_param1: f64, + set_size: u64, +} + +pub(super) struct High { + completeness_param: f64, + completeness_param2: f64, +} + +pub(super) enum Cases { + Small, + Mid, + High, +} + +/// Trait to compute internal parameters depending on which case we are +pub(super) trait Case { + /// Trait constructor + fn new(completeness_param: f64, set_size: u64, proof_size: f64) -> Self; + + /// Returns the maximum number of retries + fn max_retries(&self) -> u64; + + /// Returns the search width + fn search_width(&self, proof_size: f64) -> u64; + + /// Returns the valid proof probability + fn valid_proof_probability(&self, search_width: u64) -> f64; + + /// Returns the DFS bound + fn dfs_bound(&self, proof_size: f64, search_width: u64) -> u64; + + /// Returns Params + fn create_params(&self, proof_size: f64) -> Params { + let search_width = self.search_width(proof_size); + Params { + proof_size: proof_size as u64, + max_retries: self.max_retries(), + search_width, + valid_proof_probability: self.valid_proof_probability(search_width), + dfs_bound: self.dfs_bound(proof_size, search_width), + } + } +} +impl Cases { + pub(super) fn which(completeness_param: f64, set_size: u64, proof_size: u64) -> Cases { + let set_size_f64 = set_size as f64; + let proof_size_f64 = proof_size as f64; let ratio = 9.0 * set_size_f64 * LOG2_E / ((17.0 * proof_size_f64).powi(2)); let s1 = ratio - 7.0; let s2 = ratio - 2.0; if s1 < 1.0 || s2 < 1.0 { // Small case, i.e. set_size <= λ^2 - Params::param_small_case(completeness_param, proof_size_f64) + Cases::Small } else { let completeness_param2 = completeness_param.min(s2); if proof_size_f64 < completeness_param2 { // Case 3, Theorem 14, i.e. set_size >= λ^3 - Params::param_high_case( - completeness_param, - set_size, - proof_size_f64, - completeness_param2, - ) + Cases::High } else { // Case 2, Theorem 13, i.e. λ^2 < set_size < λ^3 - Params::param_mid_case(completeness_param, set_size, proof_size_f64, s1) + Cases::Mid } } } +} - /// Helper function that returns Params, used when set_size <= λ^2 - fn param_small_case(completeness_param: f64, proof_size_f64: f64) -> Params { - let ln12 = (12f64).ln(); - let search_width = (32.0 * ln12 * proof_size_f64).ceil(); - Params { - proof_size: proof_size_f64 as u64, - max_retries: completeness_param as u64, - search_width: search_width as u64, - valid_proof_probability: 2.0 * ln12 / search_width, - dfs_bound: (8.0 * (proof_size_f64 + 1.0) * search_width / ln12).floor() as u64, - } +impl Case for Small { + fn new(completeness_param: f64, _set_size: u64, _proof_size: f64) -> Self { + Self { completeness_param } } - /// Helper function that returns Params, used when set_size >= λ^3 - fn param_high_case( - completeness_param: f64, - set_size: u64, - proof_size_f64: f64, - completeness_param2: f64, - ) -> Params { - let l2 = completeness_param2 + 2.0; - let search_width = (16.0 * proof_size_f64 * l2 / LOG2_E).ceil(); - debug_assert!(set_size as f64 >= search_width * search_width * LOG2_E / (9.0 * l2)); - Params { - proof_size: proof_size_f64 as u64, - max_retries: (completeness_param / completeness_param2).ceil() as u64, - search_width: search_width as u64, - valid_proof_probability: 2.0 * l2 / (search_width * LOG2_E), - dfs_bound: (((l2 + proof_size_f64.log2()) / l2) - * (3.0 * proof_size_f64 * search_width / 4.0) - + search_width - + proof_size_f64) - .floor() as u64, + fn max_retries(&self) -> u64 { + self.completeness_param as u64 + } + + fn search_width(&self, proof_size: f64) -> u64 { + (32.0 * (12f64).ln() * proof_size).ceil() as u64 + } + + fn valid_proof_probability(&self, search_width: u64) -> f64 { + 2.0 * 12f64.ln() / search_width as f64 + } + + fn dfs_bound(&self, proof_size: f64, search_width: u64) -> u64 { + (8.0 * (proof_size + 1.0) * search_width as f64 / (12f64).ln()).ceil() as u64 + } +} + +impl Case for High { + fn new(completeness_param: f64, set_size: u64, proof_size: f64) -> Self { + let ratio = 9.0 * set_size as f64 * LOG2_E / ((17.0 * proof_size).powi(2)); + let s2 = ratio - 2.0; + let completeness_param2 = completeness_param.min(s2); + + Self { + completeness_param, + completeness_param2, } } - /// Helper function that returns Params, used when λ^2 < set_size < λ^3 - fn param_mid_case( - completeness_param: f64, - set_size: u64, - proof_size_f64: f64, - s1: f64, - ) -> Params { - fn max_vertices_visited(proof_size: f64, l1: f64) -> f64 { - fn factorial_check(max_v: f64, l1: f64) -> bool { - let bound = (-l1).exp2(); - let mut factor = (max_v.ceil() as u64).saturating_add(1); - let max_v_2 = max_v + 2.0; - let exp_1_over_max_v = max_v.recip().exp(); - let mut ratio = (14.0 * max_v * max_v * max_v_2 * exp_1_over_max_v) - / (max_v_2 - exp_1_over_max_v); - while factor != 0 { - ratio /= factor as f64; - if ratio <= bound { - return true; - } - factor = factor.saturating_sub(1); + fn max_retries(&self) -> u64 { + (self.completeness_param / self.completeness_param2).ceil() as u64 + } + + fn search_width(&self, proof_size: f64) -> u64 { + (16.0 * proof_size * (self.completeness_param2 + 2.0) / LOG2_E).ceil() as u64 + } + + fn valid_proof_probability(&self, search_width: u64) -> f64 { + (4.0 + 2.0 * self.completeness_param2) / (search_width as f64 * LOG2_E) + } + + fn dfs_bound(&self, proof_size: f64, search_width: u64) -> u64 { + let search_width_f64 = search_width as f64; + ((1.0 + proof_size.log2() * (self.completeness_param2 + 2.0).recip()) + * 3.0 + * proof_size + * search_width_f64 + / 4.0 + + proof_size + + search_width_f64) + .floor() as u64 + } +} + +impl Mid { + fn max_vertices_visited(proof_size: f64, l1: f64) -> f64 { + fn factorial_check(max_v: f64, l1: f64) -> bool { + let bound = (-l1).exp2(); + let mut factor = (max_v.ceil() as u64).saturating_add(1); + let max_v_2 = max_v + 2.0; + let exp_1_over_max_v = max_v.recip().exp(); + let mut ratio = + (14.0 * max_v * max_v * max_v_2 * exp_1_over_max_v) / (max_v_2 - exp_1_over_max_v); + while factor != 0 { + ratio /= factor as f64; + if ratio <= bound { + return true; } - false + factor = factor.saturating_sub(1); } - let mut max_v = proof_size; - while !factorial_check(max_v, l1) { - max_v += 1.0; - } - max_v + false + } + let mut max_v = proof_size; + while !factorial_check(max_v, l1) { + max_v += 1.0; } + max_v + } +} + +impl Case for Mid { + fn new(completeness_param: f64, set_size: u64, proof_size: f64) -> Self { + let ratio = 9.0 * set_size as f64 * LOG2_E / ((17.0 * proof_size).powi(2)); + let s1 = ratio - 7.0; let completeness_param1 = completeness_param.min(s1); - let lbar = (completeness_param1 + 7.0) / LOG2_E; - let search_width = (16.0 * proof_size_f64 * lbar).ceil(); - let lbar_over_sw = lbar / search_width; - debug_assert!(set_size as f64 >= search_width * search_width / (9.0 * lbar)); - - let max_v = max_vertices_visited(proof_size_f64, completeness_param1); - let exponential = (2.0 * proof_size_f64 * max_v * lbar / set_size as f64 - + 7.0 * proof_size_f64 / max_v) + + Self { + completeness_param, + completeness_param1, + set_size, + } + } + + fn max_retries(&self) -> u64 { + (self.completeness_param / self.completeness_param1).ceil() as u64 + } + + fn search_width(&self, proof_size: f64) -> u64 { + (16.0 * proof_size * (self.completeness_param1 + 7.0) / LOG2_E).ceil() as u64 + } + + fn valid_proof_probability(&self, search_width: u64) -> f64 { + 2.0 * (self.completeness_param1 + 7.0) / (LOG2_E * search_width as f64) + } + + fn dfs_bound(&self, proof_size: f64, search_width: u64) -> u64 { + let search_width_f64 = search_width as f64; + let lbar = (self.completeness_param1 + 7.0) / LOG2_E; + let max_v = Mid::max_vertices_visited(proof_size, self.completeness_param1); + let exponential = (2.0 * proof_size * max_v * lbar / self.set_size as f64 + + 7.0 * proof_size / max_v) .exp(); - Params { - proof_size: proof_size_f64 as u64, - max_retries: (completeness_param / completeness_param1).ceil() as u64, - search_width: search_width as u64, - valid_proof_probability: 2.0 * lbar_over_sw, - dfs_bound: ((max_v * lbar_over_sw + 1.0) * exponential * search_width * proof_size_f64 - + search_width) - .floor() as u64, + + ((max_v * lbar + search_width_f64) * proof_size * exponential + search_width_f64).floor() + as u64 + } +} + +impl Params { + /// Setup algorithm taking as input the security parameters, the set size + /// and the lower bound and returning the internal parameters Params + pub(super) fn new( + soundness_param: f64, + completeness_param: f64, + set_size: u64, + lower_bound: u64, + ) -> Self { + let proof_size_f64 = Self::proof_size( + soundness_param, + completeness_param, + set_size as f64, + lower_bound as f64, + ); + + match Cases::which(completeness_param, set_size, proof_size_f64 as u64) { + Cases::Small => Small::new(completeness_param, set_size, proof_size_f64) + .create_params(proof_size_f64), + Cases::Mid => { + Mid::new(completeness_param, set_size, proof_size_f64).create_params(proof_size_f64) + } + Cases::High => High::new(completeness_param, set_size, proof_size_f64) + .create_params(proof_size_f64), } } + + pub(super) fn proof_size( + soundness_param: f64, + completeness_param: f64, + set_size: f64, + lower_bound: f64, + ) -> f64 { + let numerator = soundness_param + completeness_param.log2() + 5.0 - LOG2_E.log2(); + let denominator = (set_size / lower_bound).log2(); + (numerator / denominator).ceil() + } }