From a46d61e6aa541fd5de9298aecf8662e3cd29ef10 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 8 Oct 2024 11:42:20 +0100 Subject: [PATCH 01/90] Extending .gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 23b78761..fee53a8d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ dist-newstyle *~ \#* .DS_Store +target +Cargo.lock From 5f7d36224e79b88c531a572f0ce4aae7e99845db Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 8 Oct 2024 11:46:52 +0100 Subject: [PATCH 02/90] Caledonia: Adding centralised bounded scheme --- Cargo.toml | 9 + src/centralised.rs | 506 +++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 + src/utils.rs | 198 ++++++++++++++++++ 4 files changed, 716 insertions(+) create mode 100644 src/centralised.rs create mode 100644 src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 91616df6..78af015a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,15 @@ include = ["**/*.rs", "Cargo.toml", "README.md", ".gitignore"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +blake2 = "0.10.6" +rand_core = "0.6.4" +rayon = "1.10.0" + +[dev-dependencies] +rand = "0.8.5" +rand_chacha = "0.3.1" + [lints.rust] missing_docs = "warn" unsafe_code = "warn" diff --git a/src/centralised.rs b/src/centralised.rs new file mode 100644 index 00000000..f679285c --- /dev/null +++ b/src/centralised.rs @@ -0,0 +1,506 @@ +//! ALBA's bounded DFS scheme using Blake2b as hash function. +//! (c.f. Section 3.2.2 of Alba paper) + +use rayon::prelude::*; +use std::sync::atomic::{self, AtomicUsize}; + +extern crate core; +use crate::utils; + +use std::f64::consts::E; +use std::sync::Arc; + +const DATA_LENGTH: usize = 32; +const DIGEST_SIZE: usize = 32; + +type Data = [u8; DATA_LENGTH]; +type Hash = [u8; DIGEST_SIZE]; + +/// Setup input parameters +#[derive(Debug, Clone)] +pub struct Params { + /// Soundness security parameter + pub lambda_sec: usize, + /// Completeness security parameter + pub lambda_rel: usize, + /// Approximate size of set Sp to lower bound + pub n_p: usize, + /// Target lower bound + pub n_f: usize, +} +pub enum Cases { + /// Case where u =< λ^2 + Small, + /// Case where λ^2 < u < λ^3 + Mid, + /// Case where u >= λ^3 + High, +} + +impl Params { + /// Returns information on which case corresponds some parameter + pub fn which_case(&self) -> (Cases, usize) { + let lsec = self.lambda_sec as f64; + let lrel = self.lambda_rel as f64; + let np = self.n_p as f64; + let nf = self.n_f as f64; + let loge = E.log2(); + + let lognpnf = (np / nf).log2(); + let u_f64 = (lsec + lrel.log2() + 5.0 - loge.log2()) / lognpnf; + let u = u_f64.ceil() as u64; + + let ratio = 9.0 * np * loge / ((17 * u).pow(2) as f64); + let s1 = ratio - 7.0; + let s2 = ratio - 2.0; + + if s1 < 1.0 || s2 < 1.0 { + return (Cases::Small, u as usize); + } + + let lrel2 = lrel.min(s2); + if (u as f64) < lrel2 { + return (Cases::Mid, u as usize); + } else { + return (Cases::High, u as usize); + } + } +} + +/// Setup output parameters +#[derive(Debug, Clone)] +pub struct Setup { + /// Approximate size of set Sp to lower bound + pub n_p: usize, + /// Proof size (in Sp elements) + pub u: usize, + /// Proof max counter + pub r: usize, + /// Proof max 2nd counter + pub d: usize, + /// Inverse of probability p_q + pub q: usize, + /// Computation bound + pub b: usize, +} +impl Setup { + /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) + pub fn new(params: &Params) -> Self { + let loge = E.log2(); + fn compute_w(u: f64, l: f64) -> f64 { + fn factorial_check(w: f64, l: f64) -> bool { + let bound = 0.5f64.powf(l); + let factors: Vec = (1..=(w as u64 + 1)).rev().collect(); + let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) + / (E * (w + 2.0 - E.powf(1.0 / w))); + + for f in factors { + ratio /= f as f64; + if ratio <= bound { + return true; + } + } + return false; + } + let mut w: f64 = u; + while !factorial_check(w, l) { + w += 1.0; + } + w + } + + let n_p_f64 = params.n_p as f64; + let n_f_f64 = params.n_f as f64; + let lognpnf = (n_p_f64 / n_f_f64).log2(); + let lambda_rel = params.lambda_rel as f64; + let logrel = lambda_rel.log2(); + let lambda_sec = (params.lambda_sec as f64) + logrel; + + let u_f64 = ((lambda_sec + logrel + 5.0 - loge.log2()) / lognpnf).ceil(); + let u = u_f64 as usize; + + let ratio = 9.0 * n_p_f64 * loge / ((17 * u).pow(2) as f64); + let s1 = ratio - 7.0; + let s2 = ratio - 2.0; + + if s1 < 1.0 || s2 < 1.0 { + // Small case, ie n_p <= λ^2 + let ln12 = (12f64).ln(); + let d = (32.0 * ln12 * u_f64).ceil(); + return Setup { + n_p: params.n_p, + u, + r: params.lambda_rel, + d: d as usize, + q: (2.0 * ln12 / d).recip().ceil() as usize, + b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as usize, + }; + } + let lambda_rel2 = lambda_rel.min(s2); + if u_f64 < lambda_rel2 { + // Case 3, Theorem 14, ie n_p >= λ^3 + let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); + assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); + return Setup { + n_p: params.n_p, + u, + r: (lambda_rel / lambda_rel2).ceil() as usize, + d: d as usize, + q: (2.0 * (lambda_rel2 + 2.0) / (d * loge)).recip().ceil() as usize, + b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) + * (3.0 * u_f64 * d / 4.0) + + d + + u_f64) + .floor() as usize, + }; + } else { + // Case 2, Theorem 13, ie λ^3 > n_p > λ^2 + let lambda_rel1 = lambda_rel.min(s1); + let lbar = (lambda_rel1 + 7.0) / loge; + let d = (16.0 * u_f64 * lbar).ceil(); + assert!(n_p_f64 >= d * d / (9.0 * lbar)); + + let w = compute_w(u_f64, lambda_rel1); + return Setup { + n_p: params.n_p, + u, + r: (lambda_rel / lambda_rel1).ceil() as usize, + d: d as usize, + q: (2.0 * lbar / d).recip().ceil() as usize, + b: (((w * lbar) / d + 1.0) + * E.powf(2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w) + * d + * u_f64 + + d) + .floor() as usize, + }; + } + } +} + +/// Round parameters +#[derive(Debug, Clone)] +pub struct Round { + /// Proof counter + v: usize, + /// Proof 2nd counter + t: usize, + // Round candidate tuple + s_list: Vec, + /// Round candidate hash + h: Hash, + /// Round candidate hash mapped to [1, n_p] + h_usize: usize, + /// Approximate size of set Sp to lower bound + n_p: usize, +} + +impl Round { + /// Oracle producing a uniformly random value in [1, n_p] used for round candidates + /// We also return hash(data) to follow the optimization presented in Section 3.3 + fn h1(data: Vec>, n_p: usize) -> (Hash, usize) { + let digest = utils::combine_hashes::(data); + return (digest, utils::oracle(&digest, n_p)); + } + + /// Output a round from a proof counter and n_p + /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) + pub fn new(v: usize, t: usize, n_p: usize) -> Round { + let mut data = Vec::new(); + data.push(v.to_ne_bytes().to_vec()); + data.push(t.to_ne_bytes().to_vec()); + let (h, h_usize) = Round::h1(data, n_p); + Round { + v, + t, + s_list: Vec::new(), + h: h, + h_usize, + n_p, + } + } + + /// Updates a round with an element of S_p + /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) + pub fn update(r: &Round, s: Data) -> Round { + let mut s_list = r.s_list.clone(); + s_list.push(s); + let mut data = Vec::new(); + data.push(r.h.clone().to_vec()); + data.push(s.to_vec()); + let (h, h_usize) = Round::h1(data, r.n_p); + Round { + v: r.v, + t: r.t, + s_list, + h: h, + h_usize, + n_p: r.n_p, + } + } +} + +#[derive(Debug, Clone)] +/// Alba proof +pub struct Proof { + /// Proof counter + r: usize, + /// Proof 2nd counter + d: usize, + /// Proof tuple + items: Vec, +} + +impl Proof { + /// Returns a new proof + fn new() -> Self { + Proof { + r: 0, + d: 0, + items: Vec::new(), + } + } + + /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p + fn h0(setup: &Setup, v: usize, s: Data) -> usize { + let mut data = Vec::new(); + data.push(v.to_ne_bytes().to_vec()); + data.push(s.to_vec()); + let digest = utils::combine_hashes::(data); + return utils::oracle(&digest, setup.n_p); + } + + /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise + fn h2(setup: &Setup, r: &Round) -> bool { + let mut data = Vec::new(); + data.push(r.v.to_ne_bytes().to_vec()); + data.push(r.t.to_ne_bytes().to_vec()); + for s in &r.s_list { + data.push(s.clone().to_vec()); + } + let digest = utils::combine_hashes::(data); + return utils::oracle(&digest, setup.q) == 0; + } + + /// Depth-first search which goes through all potential round candidates + /// and returns first round candidate Round{t, x_1, ..., x_u)} such that: + /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] + /// - H2(t, x_0, ..., x_u) = true + fn dfs( + setup: &Setup, + bins: &Vec>, + round: &Round, + // nb_steps: Arc>, + nb_steps: Arc, + ) -> Option { + if round.s_list.len() == setup.u { + if Proof::h2(setup, round) { + let r = round.v; + let d = round.t; + let items = round.s_list.clone(); + return Some(Proof { r, d, items }); + } else { + return None; + } + } + let result = bins[round.h_usize].par_iter().find_map_first(|&s| { + // if *nb_steps.lock().unwrap() == setup.b { + if nb_steps.load(atomic::Ordering::Relaxed) == setup.d { + return None; + } + + // *nb_steps.lock().unwrap() += 1; + nb_steps.fetch_add(1, atomic::Ordering::Relaxed); + Self::dfs(setup, bins, &Round::update(round, s), nb_steps.clone()) + }); + return result; + } + + /// Indexed proving algorithm, returns an empty proof if no suitable + /// candidate is found within the setup.b steps. + fn prove_index(setup: &Setup, set: &Vec, v: usize) -> (usize, Option) { + let mut bins: Vec> = Vec::new(); + for _ in 1..(setup.n_p + 1) { + bins.push(Vec::new()); + } + for &s in set.iter() { + bins[Proof::h0(setup, v, s)].push(s); + } + // let nb_steps = Arc::new(Mutex::new(0usize)); + let nb_steps = Arc::new(AtomicUsize::new(0)); + for t in 1..(setup.d + 1) { + // if *nb_steps.lock().unwrap() + if nb_steps.load(atomic::Ordering::Relaxed) == setup.b { + return (0, None); + } + // *nb_steps.lock().unwrap() += 1; + nb_steps.fetch_add(1, atomic::Ordering::Relaxed); + let round = Round::new(v, t, setup.n_p); + let res = Proof::dfs(setup, &bins, &round, nb_steps.clone()); + if res.is_some() { + // return (*nb_steps.lock().unwrap(), res); + return (nb_steps.load(atomic::Ordering::Relaxed), res); + } + } + // return (*nb_steps.lock().unwrap(), None); + return (nb_steps.load(atomic::Ordering::Relaxed), None); + } + + /// Alba's proving algorithm, based on a depth-first search algorithm. + /// Calls up to setup.r times the prove_index function and returns an empty + /// proof if no suitable candidate is found. + pub fn prove(setup: &Setup, set: &Vec) -> Self { + for v in 0..setup.r { + if let (_, Some(proof)) = Proof::prove_index(setup, set, v) { + return proof; + } + } + return Proof::new(); + } + + /// Alba's proving algorithm used for benchmarking, returning a proof as + /// well as the number of steps ran to find it. + pub fn bench(setup: &Setup, set: &Vec) -> (usize, usize, Self) { + let mut nb_steps = 0; + for v in 0..setup.r { + let (steps, opt) = Proof::prove_index(setup, set, v); + nb_steps += steps; + if let Some(proof) = opt { + return (nb_steps, proof.r, proof); + } + } + return (nb_steps, setup.r, Proof::new()); + } + + /// Alba's verification algorithm, follows proving algorithm by running the + /// same depth-first search algorithm. + pub fn verify(setup: &Setup, proof: Proof) -> bool { + if proof.d == 0 || proof.d > setup.d || proof.r > setup.r || proof.items.len() != setup.u { + return false; + } + let r0 = Round::new(proof.r, proof.d, setup.n_p); + let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { + ( + b && r.h_usize == Proof::h0(setup, proof.r, s), + Round::update(&r, s), + ) + }); + return b && Proof::h2(setup, &round); + } +} + +#[cfg(test)] +mod tests { + + use super::*; + use rand_chacha::ChaCha20Rng; + use rand_core::{RngCore, SeedableRng}; + + #[test] + fn test_params() { + let lambdas = [10, 80, 100, 128]; + let pows: Vec = (2..10).collect(); + let sps: Vec = pows.iter().map(|&i| 10_u32.pow(i) as usize).collect(); + let ratios = [60, 66, 80, 95, 99]; + let mut params = Vec::new(); + for l in lambdas { + for &sp in &sps { + for r in ratios { + params.push(Params { + lambda_sec: l, + lambda_rel: l, + n_p: (sp * r) / 100, + n_f: (sp * (100 - r)) / 100, + }) + } + } + } + + let mut smalls = Vec::new(); + let mut mids = Vec::new(); + let mut highs = Vec::new(); + for p in params { + match Params::which_case(&p) { + (Cases::Small, u) => smalls.push((p.clone(), u)), + (Cases::Mid, u) => mids.push((p.clone(), u)), + (Cases::High, u) => highs.push((p.clone(), u)), + } + } + + println!("------------ Small cases"); + for s in smalls { + println!("{:?}", s); + } + println!("\n------------ Mid cases"); + for s in mids { + println!("{:?}", s); + } + println!("\n------------ High cases"); + for s in highs { + println!("{:?}", s); + } + } + + #[test] + fn test_verify() { + let mut rng = ChaCha20Rng::from_seed(Default::default()); + let nb_tests = 1_000; + let set_size = 1_000; + for _t in 0..nb_tests { + let seed = rng.next_u32().to_ne_bytes().to_vec(); + let s_p = utils::gen_items::(seed, set_size); + let params = Params { + lambda_sec: 10, + lambda_rel: 10, + n_p: 80, + n_f: 20, + }; + let setup = Setup::new(¶ms); + let proof = Proof::prove(&setup, &s_p); + assert!(Proof::verify(&setup, proof.clone())); + let proof_0 = Proof { + r: proof.r, + d: 0, + items: proof.items.clone(), + }; + assert!(!Proof::verify(&setup, proof_0)); + let proof_d = Proof { + r: proof.r, + d: proof.d.wrapping_add(1), + items: proof.items.clone(), + }; + assert!(!Proof::verify(&setup, proof_d)); + let proof_r = Proof { + r: proof.r.wrapping_add(1), + d: proof.d, + items: proof.items.clone(), + }; + assert!(!Proof::verify(&setup, proof_r)); + let proof_item = Proof { + r: proof.r, + d: proof.d, + items: Vec::new(), + }; + assert!(!Proof::verify(&setup, proof_item)); + let mut wrong_items = proof.items.clone(); + let last_item = wrong_items.pop().unwrap(); + let mut penultimate_item = wrong_items.pop().unwrap(); + let proof_itembis = Proof { + r: proof.r, + d: proof.d, + items: wrong_items.clone(), + }; + assert!(!Proof::verify(&setup, proof_itembis)); + // Modifying the penultimate item to check correctness of H1 check and not H2 + penultimate_item[0] = penultimate_item[0].wrapping_add(42u8); + wrong_items.push(penultimate_item); + wrong_items.push(last_item); + let proof_itembis = Proof { + r: proof.r, + d: proof.d, + items: wrong_items.clone(), + }; + assert!(!Proof::verify(&setup, proof_itembis)); + } + } +} diff --git a/src/lib.rs b/src/lib.rs index babedf61..a353d853 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,2 +1,5 @@ //! An implementation of Approximate Lower Bound Arguments //! (ALBA, ). +pub mod utils; + +pub mod centralised; diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 00000000..16b0d7d2 --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,198 @@ +use blake2::digest::{Update, VariableOutput}; +use blake2::Blake2bVar; +use std::cmp::min; + +/// Binary Random Oracles (c.f. Appendix B, Alba paper) +/// Takes as input a hash and inverse probability and returns an integer +pub fn oracle(hash: &[u8], n: usize) -> usize { + if n.is_power_of_two() { + mod_power_of_2(hash, n) + } else { + mod_non_power_of_2(hash, n) + } +} + +fn mod_non_power_of_2(hash: &[u8], n: usize) -> usize { + fn log_base2(x: usize) -> usize { + usize::BITS as usize - x.leading_zeros() as usize - 1 + } + let epsilon_fail: usize = 1 << 40; // roughly 1 in 10 billion + let k: usize = log_base2(n * epsilon_fail); + let k_prime: usize = 1 << k; + let d: usize = k_prime.div_ceil(n); + + let i = mod_power_of_2(hash, k_prime); + + if i >= d * n { + panic!("failed: i = {}, d = {}, n = {}, k = {}", i, d, n, k); + } else { + i % n + } +} + +fn mod_power_of_2(hash: &[u8], n: usize) -> usize { + fn from_bytes_le(bytes: &[u8]) -> usize { + let mut array = [0u8; 8]; + let bytes = &bytes[..min(8, bytes.len())]; + array[..bytes.len()].copy_from_slice(bytes); + usize::from_le_bytes(array) + } + let r = from_bytes_le(hash); + (n - 1) & r +} + +/// Compute the Probability Mass Function (PMF) of a Binomial Distribution B(n,p) +pub fn bin_pmf(n: usize, k: usize, p: f64) -> f64 { + // Compute the binomial coefficient (k out of n) + fn bin_coeff(n: usize, k: usize) -> usize { + if k == 0 { + return 1; + }; + ((n as u128 * bin_coeff(n - 1, k - 1) as u128) / k as u128) as usize + } + let coeff = bin_coeff(n, k) as f64; + coeff * p.powi(k as i32) * (1f64 - p).powi((n - k) as i32) +} + +/// Compute the discrete Cumulative Distribution Function (CDF) of a Binomial Distribution B(n,p) +pub fn bin_cdf(n: usize, k: usize, p: f64) -> f64 { + if k == n { + return 1.0; + }; + (0..=k).map(|i| bin_pmf(n, i, p)).sum() +} + +// Hash helpers + +/// Return a N-byte long hash of the given data +pub fn hash_bytes(data: &[u8]) -> [u8; N] { + let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); + hasher.update(data); + let mut buf = [0u8; N]; + hasher + .finalize_variable(&mut buf) + .expect("Failed to finalize hashing"); + buf +} + +/// Return a N-byte long hash of the given list of data +pub fn combine_hashes(hash_list: Vec>) -> [u8; N] { + let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); + for data in hash_list.iter() { + hasher.update(data); + } + let mut buf = [0u8; N]; + hasher + .finalize_variable(&mut buf) + .expect("Failed to finalize hashing"); + buf +} + +// Test & Bench helpers + +/// Generate a set of items given the set size and a seed +/// Items are generated by hashing the current index +pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> { + let mut s_p = Vec::with_capacity(set_size); + for b in 0..set_size { + let mut data = Vec::new(); + data.push(seed.clone()); + data.push(b.to_ne_bytes().to_vec()); + let item = combine_hashes::(data); + s_p.push(item); + } + s_p +} + +/// Generate a set of weighted items given the total weight size, number of items and a seed +/// Items are generated by hashing the current index +pub fn gen_weighted_items( + seed: Vec, + total_weight: usize, + set_size: usize, +) -> Vec<([u8; N], usize)> { + assert!(set_size <= total_weight); + let mut s_p = Vec::with_capacity(set_size); + let mut s_n = Vec::with_capacity(set_size); + let mut sum: u64 = 0; + // Initialising items with random weights + for b in 0..set_size { + let mut data = Vec::new(); + data.push(seed.clone()); + data.push(b.to_ne_bytes().to_vec()); + let item = combine_hashes::(data); + let weight = u32::from_be_bytes(hash_bytes::<4>(&item)); + sum += weight as u64; + s_p.push(item); + s_n.push(weight); + } + // Updating weights to add up to around total_weight, with minimum weight of 1 + let denominator = sum as f32 / (total_weight - set_size) as f32; + let mut new_sum: u64 = 0; + s_n.iter_mut().for_each(|w| { + *w = 1 + (*w as f32 / denominator).ceil() as u32; + new_sum += *w as u64; + }); + // Fixing ceiling error + let total_weight = total_weight as u64; + let b = total_weight < new_sum; + let mut delta = if b { + new_sum - total_weight + } else { + total_weight - new_sum + }; + + while delta != 0 { + s_n = s_n + .iter() + .map(|&w| match (delta, b) { + (0, _) => w, + (_, true) => { + delta -= 1; + w - if w > 1 { 1 } else { 0 } + } + (_, false) => { + delta -= 1; + w + 1 + } + }) + .collect(); + } + let mut result: Vec<([u8; N], usize)> = Vec::new(); + for i in 0..set_size { + result.push((s_p[i], s_n[i] as usize)); + } + return result; +} + +pub fn format_time(nanos: u128) -> String { + let mut time = nanos; + let bounds = [1000, 1000, 1000, 60, 60, 60]; + let units = ["ns", "μs", "ms", "s", "min", "h"]; + for (&bound, &unit) in bounds.iter().zip(units.iter()) { + if time < bound { + return time.to_string() + unit; + } + time = time / bound; + } + (time * 60).to_string() + "h" +} + +pub fn format_nb(x: usize) -> String { + let mut y = x; + let mut s = String::new(); + let mut b = true; + while y / 1000 != 0 { + let to_add = (y % 1000).to_string(); + let preppend = "0".repeat(3 - to_add.len()) + &to_add; + let append = if b { "" } else { &("_".to_string() + &s) }; + s = preppend + append; + b = false; + y = y / 1000; + } + if b { + y.to_string() + } else { + (y % 1000).to_string() + "_" + &s + } +} From 1c014ce2d7d1d30e1186e9aeb3b9049d08619dfe Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 8 Oct 2024 12:18:53 +0100 Subject: [PATCH 03/90] Adding time bench --- Cargo.toml | 5 ++ benches/centralised_time.rs | 146 +++++++++++++++++++++++++++++++++++ benches/criterion_helpers.rs | 17 ++++ benches/utils.rs | 24 ++++++ 4 files changed, 192 insertions(+) create mode 100644 benches/centralised_time.rs create mode 100644 benches/criterion_helpers.rs create mode 100644 benches/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 78af015a..bb9d1a50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,11 @@ rayon = "1.10.0" [dev-dependencies] rand = "0.8.5" rand_chacha = "0.3.1" +criterion = { version = "0.5.1", features = ["html_reports"] } + +[[bench]] +name = "centralised_time" +harness = false [lints.rust] missing_docs = "warn" diff --git a/benches/centralised_time.rs b/benches/centralised_time.rs new file mode 100644 index 00000000..b6706b93 --- /dev/null +++ b/benches/centralised_time.rs @@ -0,0 +1,146 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use std::time::{Duration, Instant}; + +use caledonia::centralised::Proof; + +pub mod criterion_helpers; +pub mod utils; + +fn prove(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { + let mut group = c.benchmark_group("Centralised".to_string()); + + fn prove_duration( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> Duration { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_duration = Duration::ZERO; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = + utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + dataset.truncate(truncate_size); + // Bench + let start = Instant::now(); + black_box({ + Proof::prove(&bench_setup, &dataset); + }); + total_duration = total_duration.saturating_add(start.elapsed()); + } + total_duration + } + + for &l in lambdas { + for &sp in s_p { + for &np in n_p { + for &nf in n_f { + // Bench with all of np% of Sp + let low = (sp * np).div_ceil(100); + group.bench_function( + criterion_helpers::bench_id("Proving time", np, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, low, n)), + ); + + // Bench with (100+np)/2% of Sp + let mean = (100 + np).div_ceil(2); + let mid = (sp + low).div_ceil(2); + group.bench_function( + criterion_helpers::bench_id("Proving time", mean, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, mid, n)), + ); + + // Bench with all of Sp + group.bench_function( + criterion_helpers::bench_id("Proving time", 100, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, sp, n)), + ); + } + } + } + } + group.finish(); +} + +fn verify(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { + let mut group = c.benchmark_group("Centralised".to_string()); + + fn verify_duration( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> Duration { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_duration = Duration::ZERO; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = + utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + dataset.truncate(truncate_size); + // Prove + let proof = Proof::prove(&bench_setup, &dataset); + // Bench + let start = Instant::now(); + black_box({ + Proof::verify(&bench_setup, proof); + }); + total_duration = total_duration.saturating_add(start.elapsed()); + } + total_duration + } + + for &l in lambdas { + for &sp in s_p { + for &np in n_p { + for &nf in n_f { + // Bench with all of np% of Sp + let low = (sp * np).div_ceil(100); + group.bench_function( + criterion_helpers::bench_id("Verification time", np, l, sp, np, nf), + move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, low, n)), + ); + + // Bench with (100+np)/2% of Sp + let mean = (100 + np).div_ceil(2); + let mid = (sp + low).div_ceil(2); + group.bench_function( + criterion_helpers::bench_id("Verification time", mean, l, sp, np, nf), + move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, mid, n)), + ); + + // Bench with all of Sp + group.bench_function( + criterion_helpers::bench_id("Verification time", 100, l, sp, np, nf), + move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, sp, n)), + ); + } + } + } + } + group.finish(); +} + +fn prove_benches(c: &mut Criterion) { + prove(c, &[50, 128], &[1_000], &[80, 90, 95, 98], &[67, 75]); +} + +fn verify_benches(c: &mut Criterion) { + verify(c, &[50, 128], &[1_000], &[80, 90, 95, 98], &[67, 75]); +} + +criterion_group!(name = benches; + config = Criterion::default().measurement_time(Duration::from_secs(30)); + targets = + prove_benches, + verify_benches +); + +criterion_main!(benches); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs new file mode 100644 index 00000000..6b30f74b --- /dev/null +++ b/benches/criterion_helpers.rs @@ -0,0 +1,17 @@ +use criterion::BenchmarkId; + +// Criterion helpers + +pub fn bench_id( + bench_name: &str, + pc: usize, + l: usize, + sp: usize, + np: usize, + nf: usize, +) -> BenchmarkId { + BenchmarkId::new( + bench_name, + format!("Security parameter: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf}"), + ) +} diff --git a/benches/utils.rs b/benches/utils.rs new file mode 100644 index 00000000..3ee4dafb --- /dev/null +++ b/benches/utils.rs @@ -0,0 +1,24 @@ +use rand_chacha::ChaCha20Rng; +use rand_core::RngCore; + +use caledonia::utils::gen_items; + +pub fn setup_centralised_wrapper( + rng: &mut ChaCha20Rng, + l: usize, + sp: usize, + np: usize, + nf: usize, +) -> (Vec<[u8; 32]>, caledonia::centralised::Setup) { + use caledonia::centralised::*; + let seed_u32 = rng.next_u32(); + let seed = seed_u32.to_ne_bytes().to_vec(); + let dataset: Vec<[u8; 32]> = gen_items(seed, sp); + let params = Params { + lambda_sec: l, + lambda_rel: l, + n_p: (np * sp).div_ceil(100), + n_f: (nf * sp).div_ceil(100), + }; + (dataset, Setup::new(¶ms)) +} From 5fb08aed4deaad402f480d3fc0f69da9f868d489 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 8 Oct 2024 12:23:05 +0100 Subject: [PATCH 04/90] Adding step bench --- Cargo.toml | 4 ++ benches/centralised_step.rs | 78 +++++++++++++++++++++++++++++++ benches/criterion_helpers.rs | 90 +++++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 benches/centralised_step.rs diff --git a/Cargo.toml b/Cargo.toml index bb9d1a50..32272d2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,10 @@ criterion = { version = "0.5.1", features = ["html_reports"] } name = "centralised_time" harness = false +[[bench]] +name = "centralised_step" +harness = false + [lints.rust] missing_docs = "warn" unsafe_code = "warn" diff --git a/benches/centralised_step.rs b/benches/centralised_step.rs new file mode 100644 index 00000000..00c62ef5 --- /dev/null +++ b/benches/centralised_step.rs @@ -0,0 +1,78 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use std::time::Duration; + +use caledonia::centralised::Proof; + +pub mod criterion_helpers; +pub mod utils; + +fn psteps( + c: &mut Criterion, + lambdas: &[usize], + s_p: &[usize], + n_p: &[usize], + n_f: &[usize], +) { + let mut group = c.benchmark_group("Centralised".to_string()); + + fn prove_steps(l: usize, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_steps = 0; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = + utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + dataset.truncate(truncate_size); + // Bench + black_box({ + let (steps, _, _) = Proof::bench(&bench_setup, &dataset); + total_steps += steps; + }); + } + total_steps as u64 + } + + for &l in lambdas { + for &sp in s_p { + for &np in n_p { + for &nf in n_f { + // Bench with all of np% of Sp + let low = (sp * np).div_ceil(100); + group.bench_function( + criterion_helpers::bench_id("Proving steps", np, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, low, n)), + ); + + // Bench with (100+np)/2 percent of Sp + let mean = (100 + np).div_ceil(2); + let mid = (sp + low).div_ceil(2); + group.bench_function( + criterion_helpers::bench_id("Proving steps", mean, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, mid, n)), + ); + + // Bench with all of Sp + group.bench_function( + criterion_helpers::bench_id("Proving steps", 100, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, sp, n)), + ); + } + } + } + } + group.finish(); +} + +fn prove_step_benches(c: &mut Criterion) { + psteps(c, &[50, 128], &[1000], &[80, 90, 95, 98], &[67, 75]); +} + +criterion_group!(name = benches; + config = Criterion::default().with_measurement(criterion_helpers::Steps).measurement_time(Duration::from_secs(30)); + targets = + prove_step_benches +); + +criterion_main!(benches); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs index 6b30f74b..df319663 100644 --- a/benches/criterion_helpers.rs +++ b/benches/criterion_helpers.rs @@ -1,4 +1,7 @@ -use criterion::BenchmarkId; +use criterion::{ + measurement::{Measurement, ValueFormatter}, + BenchmarkId, Throughput, +}; // Criterion helpers @@ -15,3 +18,88 @@ pub fn bench_id( format!("Security parameter: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf}"), ) } + +// Measurements + +/// Nb of DFS call per proof +pub struct Steps; +impl Measurement for Steps { + type Intermediate = u64; + type Value = u64; + + fn start(&self) -> Self::Intermediate { + 0 + } + + fn end(&self, _i: Self::Intermediate) -> Self::Value { + 0 + } + + fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { + v1 + v2 + } + + fn zero(&self) -> Self::Value { + 0 + } + + fn to_f64(&self, value: &Self::Value) -> f64 { + *value as f64 + } + + fn formatter(&self) -> &dyn ValueFormatter { + &StepsFormatter + } +} + +struct StepsFormatter; + +impl ValueFormatter for StepsFormatter { + fn format_value(&self, value: f64) -> String { + format!("{:.4} steps", value) + } + + fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { + match throughput { + Throughput::Bytes(b) => format!("{:.4} spb", value / *b as f64), + Throughput::Elements(b) => format!("{:.4} steps/{}", value, b), + Throughput::BytesDecimal(b) => format!("{:.4} spb (decimal)", value / *b as f64), + } + } + + fn scale_values(&self, _typical_value: f64, _values: &mut [f64]) -> &'static str { + "steps" + } + + fn scale_throughputs( + &self, + _typical_value: f64, + throughput: &Throughput, + values: &mut [f64], + ) -> &'static str { + match throughput { + Throughput::Bytes(n) => { + for val in values { + *val /= *n as f64; + } + "spb" + } + Throughput::Elements(n) => { + for val in values { + *val /= *n as f64; + } + "spe" + } + Throughput::BytesDecimal(n) => { + for val in values { + *val /= *n as f64; + } + "spb (decimal)" + } + } + } + + fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { + "steps" + } +} From 93aeb04e0458897cd8b139b4ed1c54866417d54c Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 8 Oct 2024 12:23:28 +0100 Subject: [PATCH 05/90] Adding disabled and broken repetition bench --- benches/centralised_repetition.rs | 85 +++++++++++++++++++++++++++++++ benches/criterion_helpers.rs | 84 ++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 benches/centralised_repetition.rs diff --git a/benches/centralised_repetition.rs b/benches/centralised_repetition.rs new file mode 100644 index 00000000..641f7063 --- /dev/null +++ b/benches/centralised_repetition.rs @@ -0,0 +1,85 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; +use rand_chacha::ChaCha20Rng; +use rand_core::SeedableRng; +use std::time::Duration; + +use caledonia::centralised::Proof; + +pub mod criterion_helpers; +pub mod utils; + +fn prepetitions( + c: &mut Criterion, + lambdas: &[usize], + s_p: &[usize], + n_p: &[usize], + n_f: &[usize], +) { + let mut group = c.benchmark_group("Centralised".to_string()); + + fn prove_repetitions( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> u64 { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_repetitions = 0; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = + utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + dataset.truncate(truncate_size); + // Bench + black_box({ + let (_, r, _) = Proof::bench(&bench_setup, &dataset); + total_repetitions += 1 + r; + }); + } + total_repetitions as u64 + } + + for &l in lambdas { + for &sp in s_p { + for &np in n_p { + for &nf in n_f { + // Bench with all of np% of Sp + let low = (sp * np).div_ceil(100); + group.bench_function( + criterion_helpers::bench_id("Proving repetitions", np, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, low, n)), + ); + + // Bench with (100+np)/2 percent of Sp + let mean = (100 + np).div_ceil(2); + let mid = (sp + low).div_ceil(2); + group.bench_function( + criterion_helpers::bench_id("Proving repetitions", mean, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, mid, n)), + ); + + // Bench with all of Sp + group.bench_function( + criterion_helpers::bench_id("Proving repetitions", 100, l, sp, np, nf), + move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, sp, n)), + ); + } + } + } + } + group.finish(); +} + +fn prove_step_benches(c: &mut Criterion) { + prepetitions(c, &[50, 128], &[100], &[80, 90, 95, 98], &[67, 75]); +} + +criterion_group!(name = benches; + config = Criterion::default().with_measurement(criterion_helpers::Repetitions).measurement_time(Duration::from_secs(30)); + targets = + prove_step_benches +); + +criterion_main!(benches); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs index df319663..795d2902 100644 --- a/benches/criterion_helpers.rs +++ b/benches/criterion_helpers.rs @@ -103,3 +103,87 @@ impl ValueFormatter for StepsFormatter { "steps" } } + +/// Nb of repet, times prove_index was called, per proof +/// +pub struct Repetitions; +impl Measurement for Repetitions { + type Intermediate = u64; + type Value = u64; + + fn start(&self) -> Self::Intermediate { + 0 + } + + fn end(&self, _i: Self::Intermediate) -> Self::Value { + 0 + } + + fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { + v1 + v2 + } + + fn zero(&self) -> Self::Value { + 0 + } + + fn to_f64(&self, value: &Self::Value) -> f64 { + *value as f64 + } + + fn formatter(&self) -> &dyn ValueFormatter { + &RepetitionsFormatter + } +} + +struct RepetitionsFormatter; + +impl ValueFormatter for RepetitionsFormatter { + fn format_value(&self, value: f64) -> String { + format!("{:.4} repet", value) + } + + fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { + match throughput { + Throughput::Bytes(b) => format!("{:.4} rpb", value / *b as f64), + Throughput::Elements(b) => format!("{:.4} repet/{}", value, b), + Throughput::BytesDecimal(b) => format!("{:.4} rpb (decimal)", value / *b as f64), + } + } + + fn scale_values(&self, _typical_value: f64, _values: &mut [f64]) -> &'static str { + "repet" + } + + fn scale_throughputs( + &self, + _typical_value: f64, + throughput: &Throughput, + values: &mut [f64], + ) -> &'static str { + match throughput { + Throughput::Bytes(n) => { + for val in values { + *val /= *n as f64; + } + "rpb" + } + Throughput::Elements(n) => { + for val in values { + *val /= *n as f64; + } + "rpe" + } + Throughput::BytesDecimal(n) => { + for val in values { + *val /= *n as f64; + } + "rpb (decimal)" + } + } + } + + fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { + "repet" + } +} From 5f52a88913ea251d6a4d1e01656929de970c78e4 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 9 Oct 2024 14:52:38 +0100 Subject: [PATCH 06/90] Removing codes unnecessary for centralised scheme --- src/utils.rs | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 16b0d7d2..0dab26c9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -41,27 +41,6 @@ fn mod_power_of_2(hash: &[u8], n: usize) -> usize { (n - 1) & r } -/// Compute the Probability Mass Function (PMF) of a Binomial Distribution B(n,p) -pub fn bin_pmf(n: usize, k: usize, p: f64) -> f64 { - // Compute the binomial coefficient (k out of n) - fn bin_coeff(n: usize, k: usize) -> usize { - if k == 0 { - return 1; - }; - ((n as u128 * bin_coeff(n - 1, k - 1) as u128) / k as u128) as usize - } - let coeff = bin_coeff(n, k) as f64; - coeff * p.powi(k as i32) * (1f64 - p).powi((n - k) as i32) -} - -/// Compute the discrete Cumulative Distribution Function (CDF) of a Binomial Distribution B(n,p) -pub fn bin_cdf(n: usize, k: usize, p: f64) -> f64 { - if k == n { - return 1.0; - }; - (0..=k).map(|i| bin_pmf(n, i, p)).sum() -} - // Hash helpers /// Return a N-byte long hash of the given data From 050daa23aeb8888405c9368552b1acf5c3ba93d2 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 9 Oct 2024 14:54:20 +0100 Subject: [PATCH 07/90] Removing commented Arc/Mutex code --- src/centralised.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/centralised.rs b/src/centralised.rs index f679285c..58ec599e 100644 --- a/src/centralised.rs +++ b/src/centralised.rs @@ -290,7 +290,6 @@ impl Proof { setup: &Setup, bins: &Vec>, round: &Round, - // nb_steps: Arc>, nb_steps: Arc, ) -> Option { if round.s_list.len() == setup.u { @@ -304,12 +303,9 @@ impl Proof { } } let result = bins[round.h_usize].par_iter().find_map_first(|&s| { - // if *nb_steps.lock().unwrap() == setup.b { if nb_steps.load(atomic::Ordering::Relaxed) == setup.d { return None; } - - // *nb_steps.lock().unwrap() += 1; nb_steps.fetch_add(1, atomic::Ordering::Relaxed); Self::dfs(setup, bins, &Round::update(round, s), nb_steps.clone()) }); @@ -326,23 +322,18 @@ impl Proof { for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } - // let nb_steps = Arc::new(Mutex::new(0usize)); let nb_steps = Arc::new(AtomicUsize::new(0)); for t in 1..(setup.d + 1) { - // if *nb_steps.lock().unwrap() if nb_steps.load(atomic::Ordering::Relaxed) == setup.b { return (0, None); } - // *nb_steps.lock().unwrap() += 1; nb_steps.fetch_add(1, atomic::Ordering::Relaxed); let round = Round::new(v, t, setup.n_p); let res = Proof::dfs(setup, &bins, &round, nb_steps.clone()); if res.is_some() { - // return (*nb_steps.lock().unwrap(), res); return (nb_steps.load(atomic::Ordering::Relaxed), res); } } - // return (*nb_steps.lock().unwrap(), None); return (nb_steps.load(atomic::Ordering::Relaxed), None); } From 70d3f5bd236d103c33154bca85553bfb23acd7b6 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 10:08:09 +0100 Subject: [PATCH 08/90] Removing unneeded functions --- src/utils.rs | 93 ---------------------------------------------------- 1 file changed, 93 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 0dab26c9..46f1c294 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -82,96 +82,3 @@ pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> } s_p } - -/// Generate a set of weighted items given the total weight size, number of items and a seed -/// Items are generated by hashing the current index -pub fn gen_weighted_items( - seed: Vec, - total_weight: usize, - set_size: usize, -) -> Vec<([u8; N], usize)> { - assert!(set_size <= total_weight); - let mut s_p = Vec::with_capacity(set_size); - let mut s_n = Vec::with_capacity(set_size); - let mut sum: u64 = 0; - // Initialising items with random weights - for b in 0..set_size { - let mut data = Vec::new(); - data.push(seed.clone()); - data.push(b.to_ne_bytes().to_vec()); - let item = combine_hashes::(data); - let weight = u32::from_be_bytes(hash_bytes::<4>(&item)); - sum += weight as u64; - s_p.push(item); - s_n.push(weight); - } - // Updating weights to add up to around total_weight, with minimum weight of 1 - let denominator = sum as f32 / (total_weight - set_size) as f32; - let mut new_sum: u64 = 0; - s_n.iter_mut().for_each(|w| { - *w = 1 + (*w as f32 / denominator).ceil() as u32; - new_sum += *w as u64; - }); - // Fixing ceiling error - let total_weight = total_weight as u64; - let b = total_weight < new_sum; - let mut delta = if b { - new_sum - total_weight - } else { - total_weight - new_sum - }; - - while delta != 0 { - s_n = s_n - .iter() - .map(|&w| match (delta, b) { - (0, _) => w, - (_, true) => { - delta -= 1; - w - if w > 1 { 1 } else { 0 } - } - (_, false) => { - delta -= 1; - w + 1 - } - }) - .collect(); - } - let mut result: Vec<([u8; N], usize)> = Vec::new(); - for i in 0..set_size { - result.push((s_p[i], s_n[i] as usize)); - } - return result; -} - -pub fn format_time(nanos: u128) -> String { - let mut time = nanos; - let bounds = [1000, 1000, 1000, 60, 60, 60]; - let units = ["ns", "μs", "ms", "s", "min", "h"]; - for (&bound, &unit) in bounds.iter().zip(units.iter()) { - if time < bound { - return time.to_string() + unit; - } - time = time / bound; - } - (time * 60).to_string() + "h" -} - -pub fn format_nb(x: usize) -> String { - let mut y = x; - let mut s = String::new(); - let mut b = true; - while y / 1000 != 0 { - let to_add = (y % 1000).to_string(); - let preppend = "0".repeat(3 - to_add.len()) + &to_add; - let append = if b { "" } else { &("_".to_string() + &s) }; - s = preppend + append; - b = false; - y = y / 1000; - } - if b { - y.to_string() - } else { - (y % 1000).to_string() + "_" + &s - } -} From 74eda3ddc2ccee032ee1f4dca0b00c51151156db Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 10:10:04 +0100 Subject: [PATCH 09/90] Adding second oracle --- src/centralised.rs | 16 ++++----- src/utils.rs | 85 +++++++++++++++++++++++++++++++--------------- 2 files changed, 66 insertions(+), 35 deletions(-) diff --git a/src/centralised.rs b/src/centralised.rs index 58ec599e..3251cff3 100644 --- a/src/centralised.rs +++ b/src/centralised.rs @@ -78,8 +78,8 @@ pub struct Setup { pub r: usize, /// Proof max 2nd counter pub d: usize, - /// Inverse of probability p_q - pub q: usize, + /// Probability q + pub q: f64, /// Computation bound pub b: usize, } @@ -132,7 +132,7 @@ impl Setup { u, r: params.lambda_rel, d: d as usize, - q: (2.0 * ln12 / d).recip().ceil() as usize, + q: (2.0 * ln12 / d), b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as usize, }; } @@ -146,7 +146,7 @@ impl Setup { u, r: (lambda_rel / lambda_rel2).ceil() as usize, d: d as usize, - q: (2.0 * (lambda_rel2 + 2.0) / (d * loge)).recip().ceil() as usize, + q: (2.0 * (lambda_rel2 + 2.0) / (d * loge)), b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) * (3.0 * u_f64 * d / 4.0) + d @@ -166,7 +166,7 @@ impl Setup { u, r: (lambda_rel / lambda_rel1).ceil() as usize, d: d as usize, - q: (2.0 * lbar / d).recip().ceil() as usize, + q: (2.0 * lbar / d).recip(), b: (((w * lbar) / d + 1.0) * E.powf(2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w) * d @@ -200,7 +200,7 @@ impl Round { /// We also return hash(data) to follow the optimization presented in Section 3.3 fn h1(data: Vec>, n_p: usize) -> (Hash, usize) { let digest = utils::combine_hashes::(data); - return (digest, utils::oracle(&digest, n_p)); + return (digest, utils::oracle_uniform(&digest, n_p)); } /// Output a round from a proof counter and n_p @@ -267,7 +267,7 @@ impl Proof { data.push(v.to_ne_bytes().to_vec()); data.push(s.to_vec()); let digest = utils::combine_hashes::(data); - return utils::oracle(&digest, setup.n_p); + return utils::oracle_uniform(&digest, setup.n_p); } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise @@ -279,7 +279,7 @@ impl Proof { data.push(s.clone().to_vec()); } let digest = utils::combine_hashes::(data); - return utils::oracle(&digest, setup.q) == 0; + return utils::oracle_binomial(&digest, setup.q); } /// Depth-first search which goes through all potential round candidates diff --git a/src/utils.rs b/src/utils.rs index 46f1c294..561bba22 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -2,9 +2,37 @@ use blake2::digest::{Update, VariableOutput}; use blake2::Blake2bVar; use std::cmp::min; -/// Binary Random Oracles (c.f. Appendix B, Alba paper) -/// Takes as input a hash and inverse probability and returns an integer -pub fn oracle(hash: &[u8], n: usize) -> usize { +// Oracles + +/// Takes as input a hash and inverse probability $np$ and returns a +/// uniformly distributed integer in [1, np] (c.f. Appendix B, Alba paper). +pub fn oracle_uniform(hash: &[u8], n: usize) -> usize { + // Computes the integer reprensation of hash* modulo n when n is not a + // power of two. *(up to 8 bytes, in little endian) + fn mod_non_power_of_2(hash: &[u8], n: usize) -> usize { + fn log_base2(x: usize) -> usize { + usize::BITS as usize - x.leading_zeros() as usize - 1 + } + let epsilon_fail: usize = 1 << 40; // roughly 1 trillion + let k: usize = log_base2(n * epsilon_fail); + let k_prime: usize = 1 << k; + let d: usize = k_prime.div_ceil(n); + + let i = mod_power_of_2(hash, k_prime); + + if i >= d * n { + panic!("failed: i = {}, d = {}, n = {}, k = {}", i, d, n, k); + } else { + i % n + } + } + // Computes the integer reprensation of hash* modulo n when n is a power of + // two. *(up to 8 bytes, in little endian) + fn mod_power_of_2(hash: &[u8], n: usize) -> usize { + assert!(8 * hash.len() >= (n as f32).log2() as usize); + from_bytes_le(hash) & (n - 1) + } + if n.is_power_of_two() { mod_power_of_2(hash, n) } else { @@ -12,33 +40,36 @@ pub fn oracle(hash: &[u8], n: usize) -> usize { } } -fn mod_non_power_of_2(hash: &[u8], n: usize) -> usize { - fn log_base2(x: usize) -> usize { - usize::BITS as usize - x.leading_zeros() as usize - 1 - } - let epsilon_fail: usize = 1 << 40; // roughly 1 in 10 billion - let k: usize = log_base2(n * epsilon_fail); - let k_prime: usize = 1 << k; - let d: usize = k_prime.div_ceil(n); - - let i = mod_power_of_2(hash, k_prime); - - if i >= d * n { - panic!("failed: i = {}, d = {}, n = {}, k = {}", i, d, n, k); - } else { - i % n +/// Takes as input a hash and probability $q$ and returns true with +/// probability q otherwise false according to a Binomial distribution +/// (c.f. Appendix B, Alba paper). +pub fn oracle_binomial(hash: &[u8], q: f64) -> bool { + // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² + // such that 0 < q - x/y <= ɛ̝ + let epsilon_fail: usize = 1 << 40; // roughly 1 trillion + let mut x: usize = q.ceil() as usize; + let mut y: usize = 1; + while { + let difference = q - (x as f64 / y as f64); + difference >= 1.0 / epsilon_fail as f64 || difference < 0.0 + } { + y = y * 2; + x = (q * (y as f64)).round() as usize; } + // Output i in [0; y-1] from hash + assert!(8 * hash.len() >= (y as f32).log2() as usize); + let i = from_bytes_le(&hash) & (y - 1); + // Return true if i < x + i < x } -fn mod_power_of_2(hash: &[u8], n: usize) -> usize { - fn from_bytes_le(bytes: &[u8]) -> usize { - let mut array = [0u8; 8]; - let bytes = &bytes[..min(8, bytes.len())]; - array[..bytes.len()].copy_from_slice(bytes); - usize::from_le_bytes(array) - } - let r = from_bytes_le(hash); - (n - 1) & r +// Returns the integer representation of, up to the 8 first bytes of, the +// input bytes in little endian +fn from_bytes_le(bytes: &[u8]) -> usize { + let mut array = [0u8; 8]; + let bytes = &bytes[..min(8, bytes.len())]; + array[..bytes.len()].copy_from_slice(bytes); + usize::from_le_bytes(array) } // Hash helpers From a8c1a60aa16df436ebbf71a302696091e8b9b110 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 10:48:07 +0100 Subject: [PATCH 10/90] Fixing clippy --- src/centralised.rs | 69 ++++++++++++++++++++++------------------------ src/utils.rs | 7 ++--- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/centralised.rs b/src/centralised.rs index 3251cff3..4e3467d4 100644 --- a/src/centralised.rs +++ b/src/centralised.rs @@ -60,9 +60,9 @@ impl Params { let lrel2 = lrel.min(s2); if (u as f64) < lrel2 { - return (Cases::Mid, u as usize); + (Cases::Mid, u as usize) } else { - return (Cases::High, u as usize); + (Cases::High, u as usize) } } } @@ -100,7 +100,7 @@ impl Setup { return true; } } - return false; + false } let mut w: f64 = u; while !factorial_check(w, l) { @@ -141,7 +141,7 @@ impl Setup { // Case 3, Theorem 14, ie n_p >= λ^3 let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); - return Setup { + Setup { n_p: params.n_p, u, r: (lambda_rel / lambda_rel2).ceil() as usize, @@ -152,7 +152,7 @@ impl Setup { + d + u_f64) .floor() as usize, - }; + } } else { // Case 2, Theorem 13, ie λ^3 > n_p > λ^2 let lambda_rel1 = lambda_rel.min(s1); @@ -161,7 +161,7 @@ impl Setup { assert!(n_p_f64 >= d * d / (9.0 * lbar)); let w = compute_w(u_f64, lambda_rel1); - return Setup { + Setup { n_p: params.n_p, u, r: (lambda_rel / lambda_rel1).ceil() as usize, @@ -173,7 +173,7 @@ impl Setup { * u_f64 + d) .floor() as usize, - }; + } } } } @@ -200,21 +200,20 @@ impl Round { /// We also return hash(data) to follow the optimization presented in Section 3.3 fn h1(data: Vec>, n_p: usize) -> (Hash, usize) { let digest = utils::combine_hashes::(data); - return (digest, utils::oracle_uniform(&digest, n_p)); + (digest, utils::oracle_uniform(&digest, n_p)) } /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) pub fn new(v: usize, t: usize, n_p: usize) -> Round { - let mut data = Vec::new(); - data.push(v.to_ne_bytes().to_vec()); + let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); let (h, h_usize) = Round::h1(data, n_p); Round { v, t, - s_list: Vec::new(), - h: h, + s_list: vec![], + h, h_usize, n_p, } @@ -225,15 +224,14 @@ impl Round { pub fn update(r: &Round, s: Data) -> Round { let mut s_list = r.s_list.clone(); s_list.push(s); - let mut data = Vec::new(); - data.push(r.h.clone().to_vec()); + let mut data = vec![r.h.clone().to_vec()]; data.push(s.to_vec()); let (h, h_usize) = Round::h1(data, r.n_p); Round { v: r.v, t: r.t, s_list, - h: h, + h, h_usize, n_p: r.n_p, } @@ -257,29 +255,28 @@ impl Proof { Proof { r: 0, d: 0, - items: Vec::new(), + items: vec![], } } /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p fn h0(setup: &Setup, v: usize, s: Data) -> usize { - let mut data = Vec::new(); - data.push(v.to_ne_bytes().to_vec()); + let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(s.to_vec()); let digest = utils::combine_hashes::(data); - return utils::oracle_uniform(&digest, setup.n_p); + utils::oracle_uniform(&digest, setup.n_p) } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise fn h2(setup: &Setup, r: &Round) -> bool { - let mut data = Vec::new(); + let mut data = vec![]; data.push(r.v.to_ne_bytes().to_vec()); data.push(r.t.to_ne_bytes().to_vec()); for s in &r.s_list { data.push(s.clone().to_vec()); } let digest = utils::combine_hashes::(data); - return utils::oracle_binomial(&digest, setup.q); + utils::oracle_binomial(&digest, setup.q) } /// Depth-first search which goes through all potential round candidates @@ -309,15 +306,15 @@ impl Proof { nb_steps.fetch_add(1, atomic::Ordering::Relaxed); Self::dfs(setup, bins, &Round::update(round, s), nb_steps.clone()) }); - return result; + result } /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. - fn prove_index(setup: &Setup, set: &Vec, v: usize) -> (usize, Option) { - let mut bins: Vec> = Vec::new(); + fn prove_index(setup: &Setup, set: &[Data], v: usize) -> (usize, Option) { + let mut bins: Vec> = vec![]; for _ in 1..(setup.n_p + 1) { - bins.push(Vec::new()); + bins.push(vec![]); } for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); @@ -334,24 +331,24 @@ impl Proof { return (nb_steps.load(atomic::Ordering::Relaxed), res); } } - return (nb_steps.load(atomic::Ordering::Relaxed), None); + (nb_steps.load(atomic::Ordering::Relaxed), None) } /// Alba's proving algorithm, based on a depth-first search algorithm. /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. - pub fn prove(setup: &Setup, set: &Vec) -> Self { + pub fn prove(setup: &Setup, set: &[Data]) -> Self { for v in 0..setup.r { if let (_, Some(proof)) = Proof::prove_index(setup, set, v) { return proof; } } - return Proof::new(); + Proof::new() } /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &Vec) -> (usize, usize, Self) { + pub fn bench(setup: &Setup, set: &[Data]) -> (usize, usize, Self) { let mut nb_steps = 0; for v in 0..setup.r { let (steps, opt) = Proof::prove_index(setup, set, v); @@ -360,7 +357,7 @@ impl Proof { return (nb_steps, proof.r, proof); } } - return (nb_steps, setup.r, Proof::new()); + (nb_steps, setup.r, Proof::new()) } /// Alba's verification algorithm, follows proving algorithm by running the @@ -376,7 +373,7 @@ impl Proof { Round::update(&r, s), ) }); - return b && Proof::h2(setup, &round); + b && Proof::h2(setup, &round) } } @@ -393,7 +390,7 @@ mod tests { let pows: Vec = (2..10).collect(); let sps: Vec = pows.iter().map(|&i| 10_u32.pow(i) as usize).collect(); let ratios = [60, 66, 80, 95, 99]; - let mut params = Vec::new(); + let mut params = vec![]; for l in lambdas { for &sp in &sps { for r in ratios { @@ -407,9 +404,9 @@ mod tests { } } - let mut smalls = Vec::new(); - let mut mids = Vec::new(); - let mut highs = Vec::new(); + let mut smalls = vec![]; + let mut mids = vec![]; + let mut highs = vec![]; for p in params { match Params::which_case(&p) { (Cases::Small, u) => smalls.push((p.clone(), u)), @@ -470,7 +467,7 @@ mod tests { let proof_item = Proof { r: proof.r, d: proof.d, - items: Vec::new(), + items: vec![], }; assert!(!Proof::verify(&setup, proof_item)); let mut wrong_items = proof.items.clone(); diff --git a/src/utils.rs b/src/utils.rs index 561bba22..1e62acfd 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -53,12 +53,12 @@ pub fn oracle_binomial(hash: &[u8], q: f64) -> bool { let difference = q - (x as f64 / y as f64); difference >= 1.0 / epsilon_fail as f64 || difference < 0.0 } { - y = y * 2; + y *= 2; x = (q * (y as f64)).round() as usize; } // Output i in [0; y-1] from hash assert!(8 * hash.len() >= (y as f32).log2() as usize); - let i = from_bytes_le(&hash) & (y - 1); + let i = from_bytes_le(hash) & (y - 1); // Return true if i < x i < x } @@ -105,8 +105,7 @@ pub fn combine_hashes(hash_list: Vec>) -> [u8; N] { pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> { let mut s_p = Vec::with_capacity(set_size); for b in 0..set_size { - let mut data = Vec::new(); - data.push(seed.clone()); + let mut data = vec![seed.clone()]; data.push(b.to_ne_bytes().to_vec()); let item = combine_hashes::(data); s_p.push(item); From 852bce32639fcaa600c368214f7670faf805fe21 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 10:57:51 +0100 Subject: [PATCH 11/90] Cleaning up loops --- src/centralised.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/centralised.rs b/src/centralised.rs index 4e3467d4..e229915d 100644 --- a/src/centralised.rs +++ b/src/centralised.rs @@ -90,7 +90,7 @@ impl Setup { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = 0.5f64.powf(l); - let factors: Vec = (1..=(w as u64 + 1)).rev().collect(); + let factors: Vec = (1..=(w as u64 + 2)).rev().collect(); let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) / (E * (w + 2.0 - E.powf(1.0 / w))); @@ -313,19 +313,19 @@ impl Proof { /// candidate is found within the setup.b steps. fn prove_index(setup: &Setup, set: &[Data], v: usize) -> (usize, Option) { let mut bins: Vec> = vec![]; - for _ in 1..(setup.n_p + 1) { + for _ in 0..setup.n_p { bins.push(vec![]); } for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } let nb_steps = Arc::new(AtomicUsize::new(0)); - for t in 1..(setup.d + 1) { + for t in 0..setup.d { if nb_steps.load(atomic::Ordering::Relaxed) == setup.b { return (0, None); } nb_steps.fetch_add(1, atomic::Ordering::Relaxed); - let round = Round::new(v, t, setup.n_p); + let round = Round::new(v, t + 1, setup.n_p); let res = Proof::dfs(setup, &bins, &round, nb_steps.clone()); if res.is_some() { return (nb_steps.load(atomic::Ordering::Relaxed), res); @@ -339,7 +339,7 @@ impl Proof { /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Data]) -> Self { for v in 0..setup.r { - if let (_, Some(proof)) = Proof::prove_index(setup, set, v) { + if let (_, Some(proof)) = Proof::prove_index(setup, set, v + 1) { return proof; } } @@ -351,7 +351,7 @@ impl Proof { pub fn bench(setup: &Setup, set: &[Data]) -> (usize, usize, Self) { let mut nb_steps = 0; for v in 0..setup.r { - let (steps, opt) = Proof::prove_index(setup, set, v); + let (steps, opt) = Proof::prove_index(setup, set, v + 1); nb_steps += steps; if let Some(proof) = opt { return (nb_steps, proof.r, proof); @@ -363,7 +363,12 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. pub fn verify(setup: &Setup, proof: Proof) -> bool { - if proof.d == 0 || proof.d > setup.d || proof.r > setup.r || proof.items.len() != setup.u { + if proof.r == 0 + || proof.d == 0 + || proof.d > setup.d + || proof.r > setup.r + || proof.items.len() != setup.u + { return false; } let r0 = Round::new(proof.r, proof.d, setup.n_p); From a3ce9d6affd6e242c2d09f9f7c089fd400255b1e Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 11:16:35 +0100 Subject: [PATCH 12/90] Renaming lib alba, centralised -> centralized --- Cargo.toml | 6 +++--- ...ralised_repetition.rs => centralized_repetition.rs} | 6 +++--- benches/{centralised_step.rs => centralized_step.rs} | 6 +++--- benches/{centralised_time.rs => centralized_time.rs} | 10 +++++----- benches/utils.rs | 8 ++++---- src/{centralised.rs => centralized.rs} | 0 src/lib.rs | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) rename benches/{centralised_repetition.rs => centralized_repetition.rs} (94%) rename benches/{centralised_step.rs => centralized_step.rs} (93%) rename benches/{centralised_time.rs => centralized_time.rs} (94%) rename src/{centralised.rs => centralized.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index 32272d2a..bf7e41c5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "caledonia" +name = "alba" version = "0.1.0" edition = "2021" description = "A Rust implementation of Approximate Lower Bound Arguments (ALBAs)." @@ -19,11 +19,11 @@ rand_chacha = "0.3.1" criterion = { version = "0.5.1", features = ["html_reports"] } [[bench]] -name = "centralised_time" +name = "centralized_time" harness = false [[bench]] -name = "centralised_step" +name = "centralized_step" harness = false [lints.rust] diff --git a/benches/centralised_repetition.rs b/benches/centralized_repetition.rs similarity index 94% rename from benches/centralised_repetition.rs rename to benches/centralized_repetition.rs index 641f7063..d5545864 100644 --- a/benches/centralised_repetition.rs +++ b/benches/centralized_repetition.rs @@ -3,7 +3,7 @@ use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; use std::time::Duration; -use caledonia::centralised::Proof; +use alba::centralized::Proof; pub mod criterion_helpers; pub mod utils; @@ -15,7 +15,7 @@ fn prepetitions( n_p: &[usize], n_f: &[usize], ) { - let mut group = c.benchmark_group("Centralised".to_string()); + let mut group = c.benchmark_group("centralized".to_string()); fn prove_repetitions( l: usize, @@ -30,7 +30,7 @@ fn prepetitions( for _ in 0..n { // Setup let (mut dataset, bench_setup) = - utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); dataset.truncate(truncate_size); // Bench black_box({ diff --git a/benches/centralised_step.rs b/benches/centralized_step.rs similarity index 93% rename from benches/centralised_step.rs rename to benches/centralized_step.rs index 00c62ef5..b3ce3212 100644 --- a/benches/centralised_step.rs +++ b/benches/centralized_step.rs @@ -3,7 +3,7 @@ use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; use std::time::Duration; -use caledonia::centralised::Proof; +use alba::centralized::Proof; pub mod criterion_helpers; pub mod utils; @@ -15,7 +15,7 @@ fn psteps( n_p: &[usize], n_f: &[usize], ) { - let mut group = c.benchmark_group("Centralised".to_string()); + let mut group = c.benchmark_group("centralized".to_string()); fn prove_steps(l: usize, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { let mut rng = ChaCha20Rng::from_entropy(); @@ -23,7 +23,7 @@ fn psteps( for _ in 0..n { // Setup let (mut dataset, bench_setup) = - utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); dataset.truncate(truncate_size); // Bench black_box({ diff --git a/benches/centralised_time.rs b/benches/centralized_time.rs similarity index 94% rename from benches/centralised_time.rs rename to benches/centralized_time.rs index b6706b93..28ac2feb 100644 --- a/benches/centralised_time.rs +++ b/benches/centralized_time.rs @@ -3,13 +3,13 @@ use rand_chacha::ChaCha20Rng; use rand_core::SeedableRng; use std::time::{Duration, Instant}; -use caledonia::centralised::Proof; +use alba::centralized::Proof; pub mod criterion_helpers; pub mod utils; fn prove(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { - let mut group = c.benchmark_group("Centralised".to_string()); + let mut group = c.benchmark_group("centralized".to_string()); fn prove_duration( l: usize, @@ -24,7 +24,7 @@ fn prove(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f for _ in 0..n { // Setup let (mut dataset, bench_setup) = - utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); dataset.truncate(truncate_size); // Bench let start = Instant::now(); @@ -68,7 +68,7 @@ fn prove(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f } fn verify(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { - let mut group = c.benchmark_group("Centralised".to_string()); + let mut group = c.benchmark_group("centralized".to_string()); fn verify_duration( l: usize, @@ -83,7 +83,7 @@ fn verify(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_ for _ in 0..n { // Setup let (mut dataset, bench_setup) = - utils::setup_centralised_wrapper(&mut rng, l, sp, np, nf); + utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); dataset.truncate(truncate_size); // Prove let proof = Proof::prove(&bench_setup, &dataset); diff --git a/benches/utils.rs b/benches/utils.rs index 3ee4dafb..45188e7c 100644 --- a/benches/utils.rs +++ b/benches/utils.rs @@ -1,16 +1,16 @@ use rand_chacha::ChaCha20Rng; use rand_core::RngCore; -use caledonia::utils::gen_items; +use alba::utils::gen_items; -pub fn setup_centralised_wrapper( +pub fn setup_centralized_wrapper( rng: &mut ChaCha20Rng, l: usize, sp: usize, np: usize, nf: usize, -) -> (Vec<[u8; 32]>, caledonia::centralised::Setup) { - use caledonia::centralised::*; +) -> (Vec<[u8; 32]>, alba::centralized::Setup) { + use alba::centralized::*; let seed_u32 = rng.next_u32(); let seed = seed_u32.to_ne_bytes().to_vec(); let dataset: Vec<[u8; 32]> = gen_items(seed, sp); diff --git a/src/centralised.rs b/src/centralized.rs similarity index 100% rename from src/centralised.rs rename to src/centralized.rs diff --git a/src/lib.rs b/src/lib.rs index a353d853..91afd6af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,4 +2,4 @@ //! (ALBA, ). pub mod utils; -pub mod centralised; +pub mod centralized; From 1599dc7744de11008374f9721aea896d631e41ca Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 11 Oct 2024 15:53:51 +0100 Subject: [PATCH 13/90] Aggregating benches in one file, refactoring code --- Cargo.toml | 2 + benches/centralized.rs | 206 ++++++++++++++++++++++++++++++ benches/centralized_repetition.rs | 85 ------------ benches/centralized_step.rs | 78 ----------- benches/centralized_time.rs | 146 --------------------- benches/criterion_helpers.rs | 45 ++++++- benches/utils.rs | 24 ---- 7 files changed, 251 insertions(+), 335 deletions(-) create mode 100644 benches/centralized.rs delete mode 100644 benches/centralized_repetition.rs delete mode 100644 benches/centralized_step.rs delete mode 100644 benches/centralized_time.rs delete mode 100644 benches/utils.rs diff --git a/Cargo.toml b/Cargo.toml index bf7e41c5..52bc5771 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,12 @@ criterion = { version = "0.5.1", features = ["html_reports"] } [[bench]] name = "centralized_time" harness = false +path = "benches/centralized.rs" [[bench]] name = "centralized_step" harness = false +path = "benches/centralized.rs" [lints.rust] missing_docs = "warn" diff --git a/benches/centralized.rs b/benches/centralized.rs new file mode 100644 index 00000000..0da6de7c --- /dev/null +++ b/benches/centralized.rs @@ -0,0 +1,206 @@ +use criterion::{black_box, criterion_group, criterion_main, measurement::WallTime, Criterion}; +use rand_chacha::ChaCha20Rng; +use rand_core::{RngCore, SeedableRng}; +use std::time::{Duration, Instant}; + +use alba::{ + centralized::{Params, Proof, Setup}, + utils::gen_items, +}; + +pub mod criterion_helpers; +use criterion_helpers::{benchmarks, Repetitions, Steps}; + +// Global variables +const NAME: &str = "Centralized"; +// Benchmark parameters +const L: &[usize] = &[50, 128]; // Security parameter +const SP: &[usize] = &[1_000]; // Size of set to lower bound +const NP: &[usize] = &[80, 90, 95, 98]; // Alba's np parameter, |Sp| >= np +const NF: &[usize] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf + +/// Function generating a random set of elements to bench and calling Alba's centralized setup +pub fn centralized_setup( + rng: &mut ChaCha20Rng, + l: usize, + sp: usize, + np: usize, + nf: usize, +) -> (Vec<[u8; 32]>, Setup) { + let seed_u32 = rng.next_u32(); + let seed = seed_u32.to_ne_bytes().to_vec(); + let dataset: Vec<[u8; 32]> = gen_items(seed, sp); + let params = Params { + lambda_sec: l, + lambda_rel: l, + n_p: (np * sp).div_ceil(100), + n_f: (nf * sp).div_ceil(100), + }; + (dataset, Setup::new(¶ms)) +} + +/// Bench the duration of both the proving and verifiying algorithm of Alba centralized +fn time_benches(c: &mut Criterion) { + fn prove_duration( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> Duration { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_duration = Duration::ZERO; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); + // Truncate the dataset to give truncate_size elements to the prover + dataset.truncate(truncate_size); + // Bench + let start = Instant::now(); + black_box({ + Proof::prove(&bench_setup, &dataset); + }); + total_duration = total_duration.saturating_add(start.elapsed()); + } + total_duration + } + + fn verify_duration( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> Duration { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_duration = Duration::ZERO; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); + // Truncate the dataset to give truncate_size elements to the prover + dataset.truncate(truncate_size); + // Prove + let proof = Proof::prove(&bench_setup, &dataset); + // Bench + let start = Instant::now(); + black_box({ + Proof::verify(&bench_setup, proof); + }); + total_duration = total_duration.saturating_add(start.elapsed()); + } + total_duration + } + + benchmarks::( + c, + L, + SP, + NP, + NF, + format!("{} - {}", NAME, "Time"), + "Prove".to_string(), + &prove_duration, + ); + + benchmarks::( + c, + L, + SP, + NP, + NF, + format!("{} - {}", NAME, "Time"), + "Verify".to_string(), + &verify_duration, + ); +} + +/// Bench the number of steps, i.e. DFS calls, of Alba centralized prover +fn step_benches(c: &mut Criterion) { + fn prove_steps(l: usize, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_steps = 0; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); + // Truncate the dataset to give truncate_size elements to the prover + dataset.truncate(truncate_size); + // Bench + black_box({ + let (steps, _, _) = Proof::bench(&bench_setup, &dataset); + total_steps += steps; + }); + } + total_steps as u64 + } + + benchmarks::( + c, + L, + SP, + NP, + NF, + format!("{} - {}", NAME, "Steps"), + "Prove".to_string(), + &prove_steps, + ); +} + +/// Bench the number of repetitions, i.e. the "r" parameter, of Alba centralized prover +fn repetition_benches(c: &mut Criterion) { + fn prove_repetitions( + l: usize, + sp: usize, + np: usize, + nf: usize, + truncate_size: usize, + n: u64, + ) -> u64 { + let mut rng = ChaCha20Rng::from_entropy(); + let mut total_repetitions = 0; + for _ in 0..n { + // Setup + let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); + // Truncate the dataset to give truncate_size elements to the prover + dataset.truncate(truncate_size); + // Bench + black_box({ + let (_, r, _) = Proof::bench(&bench_setup, &dataset); + total_repetitions += 1 + r; + }); + } + total_repetitions as u64 + } + + benchmarks::( + c, + L, + SP, + NP, + NF, + format!("{} - {}", NAME, "Repetitions"), + "Prove".to_string(), + &prove_repetitions, + ); +} + +criterion_group!(name = centralized_time; + config = Criterion::default().measurement_time(Duration::from_secs(30)); + targets = time_benches +); + +criterion_group!(name = centralized_step; + config = Criterion::default().with_measurement(Steps).measurement_time(Duration::from_secs(30)); + targets = step_benches +); + +criterion_group!(name = centralized_repetitions; + config = Criterion::default().with_measurement(Repetitions).measurement_time(Duration::from_secs(30)); + targets = repetition_benches +); + +criterion_main!( + centralized_time, + centralized_step, //centralized_repetitions +); diff --git a/benches/centralized_repetition.rs b/benches/centralized_repetition.rs deleted file mode 100644 index d5545864..00000000 --- a/benches/centralized_repetition.rs +++ /dev/null @@ -1,85 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use rand_chacha::ChaCha20Rng; -use rand_core::SeedableRng; -use std::time::Duration; - -use alba::centralized::Proof; - -pub mod criterion_helpers; -pub mod utils; - -fn prepetitions( - c: &mut Criterion, - lambdas: &[usize], - s_p: &[usize], - n_p: &[usize], - n_f: &[usize], -) { - let mut group = c.benchmark_group("centralized".to_string()); - - fn prove_repetitions( - l: usize, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> u64 { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_repetitions = 0; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = - utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); - dataset.truncate(truncate_size); - // Bench - black_box({ - let (_, r, _) = Proof::bench(&bench_setup, &dataset); - total_repetitions += 1 + r; - }); - } - total_repetitions as u64 - } - - for &l in lambdas { - for &sp in s_p { - for &np in n_p { - for &nf in n_f { - // Bench with all of np% of Sp - let low = (sp * np).div_ceil(100); - group.bench_function( - criterion_helpers::bench_id("Proving repetitions", np, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, low, n)), - ); - - // Bench with (100+np)/2 percent of Sp - let mean = (100 + np).div_ceil(2); - let mid = (sp + low).div_ceil(2); - group.bench_function( - criterion_helpers::bench_id("Proving repetitions", mean, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, mid, n)), - ); - - // Bench with all of Sp - group.bench_function( - criterion_helpers::bench_id("Proving repetitions", 100, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_repetitions(l, sp, np, nf, sp, n)), - ); - } - } - } - } - group.finish(); -} - -fn prove_step_benches(c: &mut Criterion) { - prepetitions(c, &[50, 128], &[100], &[80, 90, 95, 98], &[67, 75]); -} - -criterion_group!(name = benches; - config = Criterion::default().with_measurement(criterion_helpers::Repetitions).measurement_time(Duration::from_secs(30)); - targets = - prove_step_benches -); - -criterion_main!(benches); diff --git a/benches/centralized_step.rs b/benches/centralized_step.rs deleted file mode 100644 index b3ce3212..00000000 --- a/benches/centralized_step.rs +++ /dev/null @@ -1,78 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use rand_chacha::ChaCha20Rng; -use rand_core::SeedableRng; -use std::time::Duration; - -use alba::centralized::Proof; - -pub mod criterion_helpers; -pub mod utils; - -fn psteps( - c: &mut Criterion, - lambdas: &[usize], - s_p: &[usize], - n_p: &[usize], - n_f: &[usize], -) { - let mut group = c.benchmark_group("centralized".to_string()); - - fn prove_steps(l: usize, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_steps = 0; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = - utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); - dataset.truncate(truncate_size); - // Bench - black_box({ - let (steps, _, _) = Proof::bench(&bench_setup, &dataset); - total_steps += steps; - }); - } - total_steps as u64 - } - - for &l in lambdas { - for &sp in s_p { - for &np in n_p { - for &nf in n_f { - // Bench with all of np% of Sp - let low = (sp * np).div_ceil(100); - group.bench_function( - criterion_helpers::bench_id("Proving steps", np, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, low, n)), - ); - - // Bench with (100+np)/2 percent of Sp - let mean = (100 + np).div_ceil(2); - let mid = (sp + low).div_ceil(2); - group.bench_function( - criterion_helpers::bench_id("Proving steps", mean, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, mid, n)), - ); - - // Bench with all of Sp - group.bench_function( - criterion_helpers::bench_id("Proving steps", 100, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_steps(l, sp, np, nf, sp, n)), - ); - } - } - } - } - group.finish(); -} - -fn prove_step_benches(c: &mut Criterion) { - psteps(c, &[50, 128], &[1000], &[80, 90, 95, 98], &[67, 75]); -} - -criterion_group!(name = benches; - config = Criterion::default().with_measurement(criterion_helpers::Steps).measurement_time(Duration::from_secs(30)); - targets = - prove_step_benches -); - -criterion_main!(benches); diff --git a/benches/centralized_time.rs b/benches/centralized_time.rs deleted file mode 100644 index 28ac2feb..00000000 --- a/benches/centralized_time.rs +++ /dev/null @@ -1,146 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use rand_chacha::ChaCha20Rng; -use rand_core::SeedableRng; -use std::time::{Duration, Instant}; - -use alba::centralized::Proof; - -pub mod criterion_helpers; -pub mod utils; - -fn prove(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { - let mut group = c.benchmark_group("centralized".to_string()); - - fn prove_duration( - l: usize, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> Duration { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_duration = Duration::ZERO; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = - utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); - dataset.truncate(truncate_size); - // Bench - let start = Instant::now(); - black_box({ - Proof::prove(&bench_setup, &dataset); - }); - total_duration = total_duration.saturating_add(start.elapsed()); - } - total_duration - } - - for &l in lambdas { - for &sp in s_p { - for &np in n_p { - for &nf in n_f { - // Bench with all of np% of Sp - let low = (sp * np).div_ceil(100); - group.bench_function( - criterion_helpers::bench_id("Proving time", np, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, low, n)), - ); - - // Bench with (100+np)/2% of Sp - let mean = (100 + np).div_ceil(2); - let mid = (sp + low).div_ceil(2); - group.bench_function( - criterion_helpers::bench_id("Proving time", mean, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, mid, n)), - ); - - // Bench with all of Sp - group.bench_function( - criterion_helpers::bench_id("Proving time", 100, l, sp, np, nf), - move |b| b.iter_custom(|n| prove_duration(l, sp, np, nf, sp, n)), - ); - } - } - } - } - group.finish(); -} - -fn verify(c: &mut Criterion, lambdas: &[usize], s_p: &[usize], n_p: &[usize], n_f: &[usize]) { - let mut group = c.benchmark_group("centralized".to_string()); - - fn verify_duration( - l: usize, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> Duration { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_duration = Duration::ZERO; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = - utils::setup_centralized_wrapper(&mut rng, l, sp, np, nf); - dataset.truncate(truncate_size); - // Prove - let proof = Proof::prove(&bench_setup, &dataset); - // Bench - let start = Instant::now(); - black_box({ - Proof::verify(&bench_setup, proof); - }); - total_duration = total_duration.saturating_add(start.elapsed()); - } - total_duration - } - - for &l in lambdas { - for &sp in s_p { - for &np in n_p { - for &nf in n_f { - // Bench with all of np% of Sp - let low = (sp * np).div_ceil(100); - group.bench_function( - criterion_helpers::bench_id("Verification time", np, l, sp, np, nf), - move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, low, n)), - ); - - // Bench with (100+np)/2% of Sp - let mean = (100 + np).div_ceil(2); - let mid = (sp + low).div_ceil(2); - group.bench_function( - criterion_helpers::bench_id("Verification time", mean, l, sp, np, nf), - move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, mid, n)), - ); - - // Bench with all of Sp - group.bench_function( - criterion_helpers::bench_id("Verification time", 100, l, sp, np, nf), - move |b| b.iter_custom(|n| verify_duration(l, sp, np, nf, sp, n)), - ); - } - } - } - } - group.finish(); -} - -fn prove_benches(c: &mut Criterion) { - prove(c, &[50, 128], &[1_000], &[80, 90, 95, 98], &[67, 75]); -} - -fn verify_benches(c: &mut Criterion) { - verify(c, &[50, 128], &[1_000], &[80, 90, 95, 98], &[67, 75]); -} - -criterion_group!(name = benches; - config = Criterion::default().measurement_time(Duration::from_secs(30)); - targets = - prove_benches, - verify_benches -); - -criterion_main!(benches); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs index 795d2902..2b4827af 100644 --- a/benches/criterion_helpers.rs +++ b/benches/criterion_helpers.rs @@ -1,6 +1,6 @@ use criterion::{ measurement::{Measurement, ValueFormatter}, - BenchmarkId, Throughput, + BenchmarkId, Criterion, Throughput, }; // Criterion helpers @@ -15,10 +15,51 @@ pub fn bench_id( ) -> BenchmarkId { BenchmarkId::new( bench_name, - format!("Security parameter: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf}"), + format!("(λ: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf})"), ) } +pub fn benchmarks>( + c: &mut Criterion, + lambdas: &[usize], + s_p: &[usize], + n_p: &[usize], + n_f: &[usize], + group_name: String, + bench_name: String, + f: &dyn Fn(usize, usize, usize, usize, usize, u64) -> V, +) { + let mut group = c.benchmark_group(group_name); + + for &l in lambdas { + for &sp in s_p { + for &np in n_p { + for &nf in n_f { + // Benchmark where the prover only has access to np percent elements of Sp, + // i.e. the minimum number of elements such that the soundness is lower than 2^-λ + let low = (sp * np).div_ceil(100); + group.bench_function(bench_id(&bench_name, np, l, sp, np, nf), move |b| { + b.iter_custom(|n| f(l, sp, np, nf, low, n)) + }); + + // Benchmark where the prover only has access to (np+100)/2 percent elements of Sp + let mean = (100 + np).div_ceil(2); + let mid = (sp + low).div_ceil(2); + group.bench_function(bench_id(&bench_name, mean, l, sp, np, nf), move |b| { + b.iter_custom(|n| f(l, sp, np, nf, mid, n)) + }); + + // Benchmark where the prover only has access to all elements of Sp + group.bench_function(bench_id(&bench_name, 100, l, sp, np, nf), move |b| { + b.iter_custom(|n| f(l, sp, np, nf, sp, n)) + }); + } + } + } + } + group.finish(); +} + // Measurements /// Nb of DFS call per proof diff --git a/benches/utils.rs b/benches/utils.rs deleted file mode 100644 index 45188e7c..00000000 --- a/benches/utils.rs +++ /dev/null @@ -1,24 +0,0 @@ -use rand_chacha::ChaCha20Rng; -use rand_core::RngCore; - -use alba::utils::gen_items; - -pub fn setup_centralized_wrapper( - rng: &mut ChaCha20Rng, - l: usize, - sp: usize, - np: usize, - nf: usize, -) -> (Vec<[u8; 32]>, alba::centralized::Setup) { - use alba::centralized::*; - let seed_u32 = rng.next_u32(); - let seed = seed_u32.to_ne_bytes().to_vec(); - let dataset: Vec<[u8; 32]> = gen_items(seed, sp); - let params = Params { - lambda_sec: l, - lambda_rel: l, - n_p: (np * sp).div_ceil(100), - n_f: (nf * sp).div_ceil(100), - }; - (dataset, Setup::new(¶ms)) -} From 9ca49e5c56a6c40a8ed7305dcd3bb3e780d0c4ea Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 16:12:35 +0100 Subject: [PATCH 14/90] Removint parallelisation --- src/centralized.rs | 43 ++++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index e229915d..6d156c8a 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -1,14 +1,10 @@ //! ALBA's bounded DFS scheme using Blake2b as hash function. //! (c.f. Section 3.2.2 of Alba paper) -use rayon::prelude::*; -use std::sync::atomic::{self, AtomicUsize}; - extern crate core; use crate::utils; use std::f64::consts::E; -use std::sync::Arc; const DATA_LENGTH: usize = 32; const DIGEST_SIZE: usize = 32; @@ -287,26 +283,31 @@ impl Proof { setup: &Setup, bins: &Vec>, round: &Round, - nb_steps: Arc, - ) -> Option { + nb_steps: usize, + ) -> (usize, Option) { if round.s_list.len() == setup.u { if Proof::h2(setup, round) { let r = round.v; let d = round.t; let items = round.s_list.clone(); - return Some(Proof { r, d, items }); + return (nb_steps, Some(Proof { r, d, items })); } else { - return None; + return (nb_steps, None); } } - let result = bins[round.h_usize].par_iter().find_map_first(|&s| { - if nb_steps.load(atomic::Ordering::Relaxed) == setup.d { - return None; + let mut dfs_steps = nb_steps; + for &s in bins[round.h_usize].iter() { + if dfs_steps == setup.b { + return (dfs_steps, None); } - nb_steps.fetch_add(1, atomic::Ordering::Relaxed); - Self::dfs(setup, bins, &Round::update(round, s), nb_steps.clone()) - }); - result + let (steps, proof_opt) = + Self::dfs(setup, bins, &Round::update(round, s), dfs_steps + 1); + if proof_opt.is_some() { + return (steps, proof_opt); + } + dfs_steps = steps; + } + (dfs_steps, None) } /// Indexed proving algorithm, returns an empty proof if no suitable @@ -319,19 +320,19 @@ impl Proof { for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } - let nb_steps = Arc::new(AtomicUsize::new(0)); + let mut nb_steps = 0; for t in 0..setup.d { - if nb_steps.load(atomic::Ordering::Relaxed) == setup.b { + if nb_steps == setup.b { return (0, None); } - nb_steps.fetch_add(1, atomic::Ordering::Relaxed); let round = Round::new(v, t + 1, setup.n_p); - let res = Proof::dfs(setup, &bins, &round, nb_steps.clone()); + let (steps, res) = Proof::dfs(setup, &bins, &round, nb_steps + 1); + nb_steps = steps; if res.is_some() { - return (nb_steps.load(atomic::Ordering::Relaxed), res); + return (nb_steps, res); } } - (nb_steps.load(atomic::Ordering::Relaxed), None) + (nb_steps, None) } /// Alba's proving algorithm, based on a depth-first search algorithm. From 80217a3fcbb74bda0f4689198700b9b2ce81ad6c Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 16:16:49 +0100 Subject: [PATCH 15/90] Renaming nb_steps as limit --- src/centralized.rs | 43 +++++++++++++++++++++---------------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index 6d156c8a..4a59cfaf 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -283,31 +283,30 @@ impl Proof { setup: &Setup, bins: &Vec>, round: &Round, - nb_steps: usize, + limit: usize, ) -> (usize, Option) { if round.s_list.len() == setup.u { if Proof::h2(setup, round) { let r = round.v; let d = round.t; let items = round.s_list.clone(); - return (nb_steps, Some(Proof { r, d, items })); + return (limit, Some(Proof { r, d, items })); } else { - return (nb_steps, None); + return (limit, None); } } - let mut dfs_steps = nb_steps; + let mut dfs_limit = limit; for &s in bins[round.h_usize].iter() { - if dfs_steps == setup.b { - return (dfs_steps, None); + if dfs_limit == setup.b { + return (dfs_limit, None); } - let (steps, proof_opt) = - Self::dfs(setup, bins, &Round::update(round, s), dfs_steps + 1); + let (l, proof_opt) = Self::dfs(setup, bins, &Round::update(round, s), dfs_limit + 1); if proof_opt.is_some() { - return (steps, proof_opt); + return (l, proof_opt); } - dfs_steps = steps; + dfs_limit = l; } - (dfs_steps, None) + (dfs_limit, None) } /// Indexed proving algorithm, returns an empty proof if no suitable @@ -320,19 +319,19 @@ impl Proof { for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } - let mut nb_steps = 0; + let mut limit = 0; for t in 0..setup.d { - if nb_steps == setup.b { + if limit == setup.b { return (0, None); } let round = Round::new(v, t + 1, setup.n_p); - let (steps, res) = Proof::dfs(setup, &bins, &round, nb_steps + 1); - nb_steps = steps; + let (l, res) = Proof::dfs(setup, &bins, &round, limit + 1); if res.is_some() { - return (nb_steps, res); + return (l, res); } + limit = l; } - (nb_steps, None) + (limit, None) } /// Alba's proving algorithm, based on a depth-first search algorithm. @@ -350,15 +349,15 @@ impl Proof { /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. pub fn bench(setup: &Setup, set: &[Data]) -> (usize, usize, Self) { - let mut nb_steps = 0; + let mut limit = 0; for v in 0..setup.r { - let (steps, opt) = Proof::prove_index(setup, set, v + 1); - nb_steps += steps; + let (l, opt) = Proof::prove_index(setup, set, v + 1); + limit += l; if let Some(proof) = opt { - return (nb_steps, proof.r, proof); + return (limit, proof.r, proof); } } - (nb_steps, setup.r, Proof::new()) + (limit, setup.r, Proof::new()) } /// Alba's verification algorithm, follows proving algorithm by running the From 57b664d00a01ef8b65ea8301d5d45d4c307fe50f Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 16:54:41 +0100 Subject: [PATCH 16/90] Updating type of lamnda and r --- benches/centralized.rs | 12 ++++++------ benches/criterion_helpers.rs | 6 +++--- src/centralized.rs | 22 +++++++++++----------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/benches/centralized.rs b/benches/centralized.rs index 0da6de7c..6782ee2a 100644 --- a/benches/centralized.rs +++ b/benches/centralized.rs @@ -14,7 +14,7 @@ use criterion_helpers::{benchmarks, Repetitions, Steps}; // Global variables const NAME: &str = "Centralized"; // Benchmark parameters -const L: &[usize] = &[50, 128]; // Security parameter +const L: &[u32] = &[50, 128]; // Security parameter const SP: &[usize] = &[1_000]; // Size of set to lower bound const NP: &[usize] = &[80, 90, 95, 98]; // Alba's np parameter, |Sp| >= np const NF: &[usize] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf @@ -22,7 +22,7 @@ const NF: &[usize] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf /// Function generating a random set of elements to bench and calling Alba's centralized setup pub fn centralized_setup( rng: &mut ChaCha20Rng, - l: usize, + l: u32, sp: usize, np: usize, nf: usize, @@ -42,7 +42,7 @@ pub fn centralized_setup( /// Bench the duration of both the proving and verifiying algorithm of Alba centralized fn time_benches(c: &mut Criterion) { fn prove_duration( - l: usize, + l: u32, sp: usize, np: usize, nf: usize, @@ -67,7 +67,7 @@ fn time_benches(c: &mut Criterion) { } fn verify_duration( - l: usize, + l: u32, sp: usize, np: usize, nf: usize, @@ -118,7 +118,7 @@ fn time_benches(c: &mut Criterion) { /// Bench the number of steps, i.e. DFS calls, of Alba centralized prover fn step_benches(c: &mut Criterion) { - fn prove_steps(l: usize, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { + fn prove_steps(l: u32, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { let mut rng = ChaCha20Rng::from_entropy(); let mut total_steps = 0; for _ in 0..n { @@ -150,7 +150,7 @@ fn step_benches(c: &mut Criterion) { /// Bench the number of repetitions, i.e. the "r" parameter, of Alba centralized prover fn repetition_benches(c: &mut Criterion) { fn prove_repetitions( - l: usize, + l: u32, sp: usize, np: usize, nf: usize, diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs index 2b4827af..da9d0193 100644 --- a/benches/criterion_helpers.rs +++ b/benches/criterion_helpers.rs @@ -8,7 +8,7 @@ use criterion::{ pub fn bench_id( bench_name: &str, pc: usize, - l: usize, + l: u32, sp: usize, np: usize, nf: usize, @@ -21,13 +21,13 @@ pub fn bench_id( pub fn benchmarks>( c: &mut Criterion, - lambdas: &[usize], + lambdas: &[u32], s_p: &[usize], n_p: &[usize], n_f: &[usize], group_name: String, bench_name: String, - f: &dyn Fn(usize, usize, usize, usize, usize, u64) -> V, + f: &dyn Fn(u32, usize, usize, usize, usize, u64) -> V, ) { let mut group = c.benchmark_group(group_name); diff --git a/src/centralized.rs b/src/centralized.rs index 4a59cfaf..b6b076d8 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -16,9 +16,9 @@ type Hash = [u8; DIGEST_SIZE]; #[derive(Debug, Clone)] pub struct Params { /// Soundness security parameter - pub lambda_sec: usize, + pub lambda_sec: u32, /// Completeness security parameter - pub lambda_rel: usize, + pub lambda_rel: u32, /// Approximate size of set Sp to lower bound pub n_p: usize, /// Target lower bound @@ -71,7 +71,7 @@ pub struct Setup { /// Proof size (in Sp elements) pub u: usize, /// Proof max counter - pub r: usize, + pub r: u32, /// Proof max 2nd counter pub d: usize, /// Probability q @@ -140,7 +140,7 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel2).ceil() as usize, + r: (lambda_rel / lambda_rel2).ceil() as u32, d: d as usize, q: (2.0 * (lambda_rel2 + 2.0) / (d * loge)), b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) @@ -160,7 +160,7 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel1).ceil() as usize, + r: (lambda_rel / lambda_rel1).ceil() as u32, d: d as usize, q: (2.0 * lbar / d).recip(), b: (((w * lbar) / d + 1.0) @@ -178,7 +178,7 @@ impl Setup { #[derive(Debug, Clone)] pub struct Round { /// Proof counter - v: usize, + v: u32, /// Proof 2nd counter t: usize, // Round candidate tuple @@ -201,7 +201,7 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: usize, t: usize, n_p: usize) -> Round { + pub fn new(v: u32, t: usize, n_p: usize) -> Round { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); let (h, h_usize) = Round::h1(data, n_p); @@ -238,7 +238,7 @@ impl Round { /// Alba proof pub struct Proof { /// Proof counter - r: usize, + r: u32, /// Proof 2nd counter d: usize, /// Proof tuple @@ -256,7 +256,7 @@ impl Proof { } /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p - fn h0(setup: &Setup, v: usize, s: Data) -> usize { + fn h0(setup: &Setup, v: u32, s: Data) -> usize { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(s.to_vec()); let digest = utils::combine_hashes::(data); @@ -311,7 +311,7 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. - fn prove_index(setup: &Setup, set: &[Data], v: usize) -> (usize, Option) { + fn prove_index(setup: &Setup, set: &[Data], v: u32) -> (usize, Option) { let mut bins: Vec> = vec![]; for _ in 0..setup.n_p { bins.push(vec![]); @@ -348,7 +348,7 @@ impl Proof { /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &[Data]) -> (usize, usize, Self) { + pub fn bench(setup: &Setup, set: &[Data]) -> (usize, u32, Self) { let mut limit = 0; for v in 0..setup.r { let (l, opt) = Proof::prove_index(setup, set, v + 1); From d0af6b38c8a1624f7bcb4d522c07f58480c97df0 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 17:00:24 +0100 Subject: [PATCH 17/90] Using rust constant for log2(e) --- src/centralized.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index b6b076d8..bea9e246 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -4,7 +4,7 @@ extern crate core; use crate::utils; -use std::f64::consts::E; +use std::{f32::consts::LOG2_E, f64::consts::E}; const DATA_LENGTH: usize = 32; const DIGEST_SIZE: usize = 32; @@ -40,7 +40,7 @@ impl Params { let lrel = self.lambda_rel as f64; let np = self.n_p as f64; let nf = self.n_f as f64; - let loge = E.log2(); + let loge = LOG2_E as f64; let lognpnf = (np / nf).log2(); let u_f64 = (lsec + lrel.log2() + 5.0 - loge.log2()) / lognpnf; @@ -82,7 +82,6 @@ pub struct Setup { impl Setup { /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) pub fn new(params: &Params) -> Self { - let loge = E.log2(); fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = 0.5f64.powf(l); @@ -111,6 +110,7 @@ impl Setup { let lambda_rel = params.lambda_rel as f64; let logrel = lambda_rel.log2(); let lambda_sec = (params.lambda_sec as f64) + logrel; + let loge = LOG2_E as f64; let u_f64 = ((lambda_sec + logrel + 5.0 - loge.log2()) / lognpnf).ceil(); let u = u_f64 as usize; From 2c9ca0be490e8fe895cc530e01279fd0de86c447 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 17:01:49 +0100 Subject: [PATCH 18/90] Renaming type Data as Element --- src/centralized.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index bea9e246..fa36e248 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -9,7 +9,7 @@ use std::{f32::consts::LOG2_E, f64::consts::E}; const DATA_LENGTH: usize = 32; const DIGEST_SIZE: usize = 32; -type Data = [u8; DATA_LENGTH]; +type Element = [u8; DATA_LENGTH]; type Hash = [u8; DIGEST_SIZE]; /// Setup input parameters @@ -182,7 +182,7 @@ pub struct Round { /// Proof 2nd counter t: usize, // Round candidate tuple - s_list: Vec, + s_list: Vec, /// Round candidate hash h: Hash, /// Round candidate hash mapped to [1, n_p] @@ -217,7 +217,7 @@ impl Round { /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - pub fn update(r: &Round, s: Data) -> Round { + pub fn update(r: &Round, s: Element) -> Round { let mut s_list = r.s_list.clone(); s_list.push(s); let mut data = vec![r.h.clone().to_vec()]; @@ -242,7 +242,7 @@ pub struct Proof { /// Proof 2nd counter d: usize, /// Proof tuple - items: Vec, + items: Vec, } impl Proof { @@ -256,7 +256,7 @@ impl Proof { } /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p - fn h0(setup: &Setup, v: u32, s: Data) -> usize { + fn h0(setup: &Setup, v: u32, s: Element) -> usize { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(s.to_vec()); let digest = utils::combine_hashes::(data); @@ -281,7 +281,7 @@ impl Proof { /// - H2(t, x_0, ..., x_u) = true fn dfs( setup: &Setup, - bins: &Vec>, + bins: &Vec>, round: &Round, limit: usize, ) -> (usize, Option) { @@ -311,8 +311,8 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. - fn prove_index(setup: &Setup, set: &[Data], v: u32) -> (usize, Option) { - let mut bins: Vec> = vec![]; + fn prove_index(setup: &Setup, set: &[Element], v: u32) -> (usize, Option) { + let mut bins: Vec> = vec![]; for _ in 0..setup.n_p { bins.push(vec![]); } @@ -337,7 +337,7 @@ impl Proof { /// Alba's proving algorithm, based on a depth-first search algorithm. /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. - pub fn prove(setup: &Setup, set: &[Data]) -> Self { + pub fn prove(setup: &Setup, set: &[Element]) -> Self { for v in 0..setup.r { if let (_, Some(proof)) = Proof::prove_index(setup, set, v + 1) { return proof; @@ -348,7 +348,7 @@ impl Proof { /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &[Data]) -> (usize, u32, Self) { + pub fn bench(setup: &Setup, set: &[Element]) -> (usize, u32, Self) { let mut limit = 0; for v in 0..setup.r { let (l, opt) = Proof::prove_index(setup, set, v + 1); From 854566943e5b3220c86b9340aa791d8d2a4b9655 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 23 Oct 2024 17:08:40 +0100 Subject: [PATCH 19/90] Adding fixed domain separation --- src/centralized.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index fa36e248..904972df 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -194,7 +194,11 @@ pub struct Round { impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(data: Vec>, n_p: usize) -> (Hash, usize) { + fn h1(input: Vec>, n_p: usize) -> (Hash, usize) { + let mut data = vec!["Telescope-H1".as_bytes().to_vec()]; + for i in input { + data.push(i); + } let digest = utils::combine_hashes::(data); (digest, utils::oracle_uniform(&digest, n_p)) } @@ -257,7 +261,8 @@ impl Proof { /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p fn h0(setup: &Setup, v: u32, s: Element) -> usize { - let mut data = vec![v.to_ne_bytes().to_vec()]; + let mut data = vec!["Telescope-H0".as_bytes().to_vec()]; + data.push(v.to_ne_bytes().to_vec()); data.push(s.to_vec()); let digest = utils::combine_hashes::(data); utils::oracle_uniform(&digest, setup.n_p) @@ -265,7 +270,7 @@ impl Proof { /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise fn h2(setup: &Setup, r: &Round) -> bool { - let mut data = vec![]; + let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; data.push(r.v.to_ne_bytes().to_vec()); data.push(r.t.to_ne_bytes().to_vec()); for s in &r.s_list { From 7f89c7bc35b9188097eb718689e0f862f2f9d202 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 10:19:20 +0100 Subject: [PATCH 20/90] Remove Params' derive Clone and removing test_param --- src/centralized.rs | 47 +--------------------------------------------- 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index 904972df..abfeab46 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -13,7 +13,7 @@ type Element = [u8; DATA_LENGTH]; type Hash = [u8; DIGEST_SIZE]; /// Setup input parameters -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct Params { /// Soundness security parameter pub lambda_sec: u32, @@ -394,51 +394,6 @@ mod tests { use rand_chacha::ChaCha20Rng; use rand_core::{RngCore, SeedableRng}; - #[test] - fn test_params() { - let lambdas = [10, 80, 100, 128]; - let pows: Vec = (2..10).collect(); - let sps: Vec = pows.iter().map(|&i| 10_u32.pow(i) as usize).collect(); - let ratios = [60, 66, 80, 95, 99]; - let mut params = vec![]; - for l in lambdas { - for &sp in &sps { - for r in ratios { - params.push(Params { - lambda_sec: l, - lambda_rel: l, - n_p: (sp * r) / 100, - n_f: (sp * (100 - r)) / 100, - }) - } - } - } - - let mut smalls = vec![]; - let mut mids = vec![]; - let mut highs = vec![]; - for p in params { - match Params::which_case(&p) { - (Cases::Small, u) => smalls.push((p.clone(), u)), - (Cases::Mid, u) => mids.push((p.clone(), u)), - (Cases::High, u) => highs.push((p.clone(), u)), - } - } - - println!("------------ Small cases"); - for s in smalls { - println!("{:?}", s); - } - println!("\n------------ Mid cases"); - for s in mids { - println!("{:?}", s); - } - println!("\n------------ High cases"); - for s in highs { - println!("{:?}", s); - } - } - #[test] fn test_verify() { let mut rng = ChaCha20Rng::from_seed(Default::default()); From dde1a231dcc49e925729b775b6bca02bf4cb8703 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 10:23:32 +0100 Subject: [PATCH 21/90] Hash with H2 intermediary hash instead of list of elements --- src/centralized.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index abfeab46..6c98d287 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -271,11 +271,7 @@ impl Proof { /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise fn h2(setup: &Setup, r: &Round) -> bool { let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; - data.push(r.v.to_ne_bytes().to_vec()); - data.push(r.t.to_ne_bytes().to_vec()); - for s in &r.s_list { - data.push(s.clone().to_vec()); - } + data.push(r.h.to_vec()); let digest = utils::combine_hashes::(data); utils::oracle_binomial(&digest, setup.q) } From 8dba2a4a9c4dbb3be33f2145288a779d58959553 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 10:26:07 +0100 Subject: [PATCH 22/90] Cleanup bins instantiation --- src/centralized.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index 6c98d287..c96cf5cb 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -313,10 +313,7 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. fn prove_index(setup: &Setup, set: &[Element], v: u32) -> (usize, Option) { - let mut bins: Vec> = vec![]; - for _ in 0..setup.n_p { - bins.push(vec![]); - } + let mut bins: Vec> = vec![vec![]; setup.n_p]; for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } From 8f9cbc1ea489cbeafd3126163ecee2b3e24c936d Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 10:42:19 +0100 Subject: [PATCH 23/90] Prove returns Option --- benches/centralized.rs | 14 ++++++++------ src/centralized.rs | 40 ++++++++++++++-------------------------- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/benches/centralized.rs b/benches/centralized.rs index 6782ee2a..d33f345f 100644 --- a/benches/centralized.rs +++ b/benches/centralized.rs @@ -82,13 +82,15 @@ fn time_benches(c: &mut Criterion) { // Truncate the dataset to give truncate_size elements to the prover dataset.truncate(truncate_size); // Prove - let proof = Proof::prove(&bench_setup, &dataset); + let proof_opt = Proof::prove(&bench_setup, &dataset); // Bench - let start = Instant::now(); - black_box({ - Proof::verify(&bench_setup, proof); - }); - total_duration = total_duration.saturating_add(start.elapsed()); + if proof_opt.is_some() { + let start = Instant::now(); + black_box({ + Proof::verify(&bench_setup, proof_opt.unwrap()); + }); + total_duration = total_duration.saturating_add(start.elapsed()); + } } total_duration } diff --git a/src/centralized.rs b/src/centralized.rs index c96cf5cb..a5528972 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -250,15 +250,6 @@ pub struct Proof { } impl Proof { - /// Returns a new proof - fn new() -> Self { - Proof { - r: 0, - d: 0, - items: vec![], - } - } - /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p fn h0(setup: &Setup, v: u32, s: Element) -> usize { let mut data = vec!["Telescope-H0".as_bytes().to_vec()]; @@ -335,27 +326,24 @@ impl Proof { /// Alba's proving algorithm, based on a depth-first search algorithm. /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. - pub fn prove(setup: &Setup, set: &[Element]) -> Self { - for v in 0..setup.r { - if let (_, Some(proof)) = Proof::prove_index(setup, set, v + 1) { - return proof; - } - } - Proof::new() + pub fn prove(setup: &Setup, set: &[Element]) -> Option { + (0..setup.r).find_map(|v| { + let (_, proof_opt) = Proof::prove_index(setup, set, v + 1); + proof_opt + }) } /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &[Element]) -> (usize, u32, Self) { - let mut limit = 0; - for v in 0..setup.r { - let (l, opt) = Proof::prove_index(setup, set, v + 1); - limit += l; - if let Some(proof) = opt { - return (limit, proof.r, proof); + pub fn bench(setup: &Setup, set: &[Element]) -> (usize, u32, Option) { + (0..setup.r).fold((0, setup.r, None), |acc, v| { + if acc.2.is_some() { + acc + } else { + let (l, opt) = Proof::prove_index(setup, set, v + 1); + (acc.0 + l, acc.1, opt) } - } - (limit, setup.r, Proof::new()) + }) } /// Alba's verification algorithm, follows proving algorithm by running the @@ -402,7 +390,7 @@ mod tests { n_f: 20, }; let setup = Setup::new(¶ms); - let proof = Proof::prove(&setup, &s_p); + let proof = Proof::prove(&setup, &s_p).unwrap(); assert!(Proof::verify(&setup, proof.clone())); let proof_0 = Proof { r: proof.r, From 04bc5b3b5f5ba7e7b06b6e78e4f24550e3ca7ec9 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 10:51:44 +0100 Subject: [PATCH 24/90] Iterating v (resp. t) from 0 till r (resp. d) --- src/centralized.rs | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index a5528972..6b1931c1 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -313,7 +313,7 @@ impl Proof { if limit == setup.b { return (0, None); } - let round = Round::new(v, t + 1, setup.n_p); + let round = Round::new(v, t, setup.n_p); let (l, res) = Proof::dfs(setup, &bins, &round, limit + 1); if res.is_some() { return (l, res); @@ -328,7 +328,7 @@ impl Proof { /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Element]) -> Option { (0..setup.r).find_map(|v| { - let (_, proof_opt) = Proof::prove_index(setup, set, v + 1); + let (_, proof_opt) = Proof::prove_index(setup, set, v); proof_opt }) } @@ -349,12 +349,7 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. pub fn verify(setup: &Setup, proof: Proof) -> bool { - if proof.r == 0 - || proof.d == 0 - || proof.d > setup.d - || proof.r > setup.r - || proof.items.len() != setup.u - { + if proof.d >= setup.d || proof.r >= setup.r || proof.items.len() != setup.u { return false; } let r0 = Round::new(proof.r, proof.d, setup.n_p); @@ -392,12 +387,6 @@ mod tests { let setup = Setup::new(¶ms); let proof = Proof::prove(&setup, &s_p).unwrap(); assert!(Proof::verify(&setup, proof.clone())); - let proof_0 = Proof { - r: proof.r, - d: 0, - items: proof.items.clone(), - }; - assert!(!Proof::verify(&setup, proof_0)); let proof_d = Proof { r: proof.r, d: proof.d.wrapping_add(1), From 2e2061592639430889ba304c2c7f46db5e8b3b54 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 11:31:51 +0100 Subject: [PATCH 25/90] Cleanup code --- src/centralized.rs | 55 +++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index 6b1931c1..cd86711e 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -287,18 +287,16 @@ impl Proof { return (limit, None); } } - let mut dfs_limit = limit; - for &s in bins[round.h_usize].iter() { - if dfs_limit == setup.b { - return (dfs_limit, None); - } - let (l, proof_opt) = Self::dfs(setup, bins, &Round::update(round, s), dfs_limit + 1); - if proof_opt.is_some() { - return (l, proof_opt); - } - dfs_limit = l; - } - (dfs_limit, None) + + bins[round.h_usize] + .iter() + .fold((limit, None), |(l, proof_opt), &s| { + if proof_opt.is_some() || l == setup.b { + (l, proof_opt) + } else { + Self::dfs(setup, bins, &Round::update(round, s), l + 1) + } + }) } /// Indexed proving algorithm, returns an empty proof if no suitable @@ -308,40 +306,33 @@ impl Proof { for &s in set.iter() { bins[Proof::h0(setup, v, s)].push(s); } - let mut limit = 0; - for t in 0..setup.d { - if limit == setup.b { - return (0, None); - } - let round = Round::new(v, t, setup.n_p); - let (l, res) = Proof::dfs(setup, &bins, &round, limit + 1); - if res.is_some() { - return (l, res); + + (0..setup.d).fold((0, None), |(limit, proof_opt), t| { + if proof_opt.is_some() || limit == setup.b { + (limit, proof_opt) + } else { + let round = Round::new(v, t, setup.n_p); + Proof::dfs(setup, &bins, &round, limit + 1) } - limit = l; - } - (limit, None) + }) } /// Alba's proving algorithm, based on a depth-first search algorithm. /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Element]) -> Option { - (0..setup.r).find_map(|v| { - let (_, proof_opt) = Proof::prove_index(setup, set, v); - proof_opt - }) + (0..setup.r).find_map(|v| Proof::prove_index(setup, set, v).1) } /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. pub fn bench(setup: &Setup, set: &[Element]) -> (usize, u32, Option) { - (0..setup.r).fold((0, setup.r, None), |acc, v| { - if acc.2.is_some() { - acc + (0..setup.r).fold((0, setup.r, None), |(limit, r, proof_opt), v| { + if proof_opt.is_some() { + (limit, r, proof_opt) } else { let (l, opt) = Proof::prove_index(setup, set, v + 1); - (acc.0 + l, acc.1, opt) + (limit + l, r, opt) } }) } From 6fc7201681e743d7b5c0f4f0f9d3c45b929fee07 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 11:43:38 +0100 Subject: [PATCH 26/90] Updaintg oracle_uniform comment --- src/utils.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 1e62acfd..5ee304b4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,8 +4,9 @@ use std::cmp::min; // Oracles -/// Takes as input a hash and inverse probability $np$ and returns a -/// uniformly distributed integer in [1, np] (c.f. Appendix B, Alba paper). +/// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). +/// We do so by interpreting the hash as a random number an returns it modulo n +/// (c.f. Appendix B, Alba paper). pub fn oracle_uniform(hash: &[u8], n: usize) -> usize { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) From fe9fed4ea3bac097f03c5bc4bbee3381f3903e4b Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 11:48:43 +0100 Subject: [PATCH 27/90] Correcting orale name binomial -> bernouilli --- src/centralized.rs | 2 +- src/utils.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index cd86711e..14f01113 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -264,7 +264,7 @@ impl Proof { let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; data.push(r.h.to_vec()); let digest = utils::combine_hashes::(data); - utils::oracle_binomial(&digest, setup.q) + utils::oracle_bernouilli(&digest, setup.q) } /// Depth-first search which goes through all potential round candidates diff --git a/src/utils.rs b/src/utils.rs index 5ee304b4..d86abe53 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -42,9 +42,9 @@ pub fn oracle_uniform(hash: &[u8], n: usize) -> usize { } /// Takes as input a hash and probability $q$ and returns true with -/// probability q otherwise false according to a Binomial distribution +/// probability q otherwise false according to a Bernouilli distribution /// (c.f. Appendix B, Alba paper). -pub fn oracle_binomial(hash: &[u8], q: f64) -> bool { +pub fn oracle_bernouilli(hash: &[u8], q: f64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ let epsilon_fail: usize = 1 << 40; // roughly 1 trillion From e446c96d8b15960db74f6243c4e4df9f42f7f6c0 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 11:59:50 +0100 Subject: [PATCH 28/90] Moving gen_items in test_utils, updating mods --- benches/centralized.rs | 2 +- src/centralized.rs | 5 ++--- src/lib.rs | 1 + src/test_utils.rs | 16 ++++++++++++++++ src/utils.rs | 17 +---------------- 5 files changed, 21 insertions(+), 20 deletions(-) create mode 100644 src/test_utils.rs diff --git a/benches/centralized.rs b/benches/centralized.rs index d33f345f..e5dc8b30 100644 --- a/benches/centralized.rs +++ b/benches/centralized.rs @@ -5,7 +5,7 @@ use std::time::{Duration, Instant}; use alba::{ centralized::{Params, Proof, Setup}, - utils::gen_items, + test_utils::gen_items, }; pub mod criterion_helpers; diff --git a/src/centralized.rs b/src/centralized.rs index 14f01113..3948295c 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -1,7 +1,6 @@ //! ALBA's bounded DFS scheme using Blake2b as hash function. //! (c.f. Section 3.2.2 of Alba paper) -extern crate core; use crate::utils; use std::{f32::consts::LOG2_E, f64::consts::E}; @@ -356,10 +355,10 @@ impl Proof { #[cfg(test)] mod tests { - use super::*; use rand_chacha::ChaCha20Rng; use rand_core::{RngCore, SeedableRng}; + use crate::test_utils::gen_items; #[test] fn test_verify() { @@ -368,7 +367,7 @@ mod tests { let set_size = 1_000; for _t in 0..nb_tests { let seed = rng.next_u32().to_ne_bytes().to_vec(); - let s_p = utils::gen_items::(seed, set_size); + let s_p = gen_items::(seed, set_size); let params = Params { lambda_sec: 10, lambda_rel: 10, diff --git a/src/lib.rs b/src/lib.rs index 91afd6af..5c2b224b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ //! An implementation of Approximate Lower Bound Arguments //! (ALBA, ). pub mod utils; +pub mod test_utils; pub mod centralized; diff --git a/src/test_utils.rs b/src/test_utils.rs new file mode 100644 index 00000000..31fbb9ae --- /dev/null +++ b/src/test_utils.rs @@ -0,0 +1,16 @@ +use crate::utils; + +// Test & Bench helpers + +/// Generate a set of items given the set size and a seed +/// Items are generated by hashing the current index +pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> { + let mut s_p = Vec::with_capacity(set_size); + for b in 0..set_size { + let mut data = vec![seed.clone()]; + data.push(b.to_ne_bytes().to_vec()); + let item = utils::combine_hashes::(data); + s_p.push(item); + } + s_p +} diff --git a/src/utils.rs b/src/utils.rs index d86abe53..f64e5487 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -97,19 +97,4 @@ pub fn combine_hashes(hash_list: Vec>) -> [u8; N] { .finalize_variable(&mut buf) .expect("Failed to finalize hashing"); buf -} - -// Test & Bench helpers - -/// Generate a set of items given the set size and a seed -/// Items are generated by hashing the current index -pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> { - let mut s_p = Vec::with_capacity(set_size); - for b in 0..set_size { - let mut data = vec![seed.clone()]; - data.push(b.to_ne_bytes().to_vec()); - let item = combine_hashes::(data); - s_p.push(item); - } - s_p -} +} \ No newline at end of file From 3afd064c7d7e833d7e0943804f79f68fd37719f4 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:17:55 +0100 Subject: [PATCH 29/90] Renaming variable names --- src/centralized.rs | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/centralized.rs b/src/centralized.rs index 3948295c..9f49595c 100644 --- a/src/centralized.rs +++ b/src/centralized.rs @@ -241,9 +241,9 @@ impl Round { /// Alba proof pub struct Proof { /// Proof counter - r: u32, + v: u32, /// Proof 2nd counter - d: usize, + t: usize, /// Proof tuple items: Vec, } @@ -278,10 +278,10 @@ impl Proof { ) -> (usize, Option) { if round.s_list.len() == setup.u { if Proof::h2(setup, round) { - let r = round.v; - let d = round.t; + let v = round.v; + let t = round.t; let items = round.s_list.clone(); - return (limit, Some(Proof { r, d, items })); + return (limit, Some(Proof { v, t, items })); } else { return (limit, None); } @@ -339,13 +339,13 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. pub fn verify(setup: &Setup, proof: Proof) -> bool { - if proof.d >= setup.d || proof.r >= setup.r || proof.items.len() != setup.u { + if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() != setup.u { return false; } - let r0 = Round::new(proof.r, proof.d, setup.n_p); + let r0 = Round::new(proof.v, proof.t, setup.n_p); let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { ( - b && r.h_usize == Proof::h0(setup, proof.r, s), + b && r.h_usize == Proof::h0(setup, proof.v, s), Round::update(&r, s), ) }); @@ -356,9 +356,9 @@ impl Proof { #[cfg(test)] mod tests { use super::*; + use crate::test_utils::gen_items; use rand_chacha::ChaCha20Rng; use rand_core::{RngCore, SeedableRng}; - use crate::test_utils::gen_items; #[test] fn test_verify() { @@ -378,20 +378,20 @@ mod tests { let proof = Proof::prove(&setup, &s_p).unwrap(); assert!(Proof::verify(&setup, proof.clone())); let proof_d = Proof { - r: proof.r, - d: proof.d.wrapping_add(1), + v: proof.v, + t: proof.t.wrapping_add(1), items: proof.items.clone(), }; assert!(!Proof::verify(&setup, proof_d)); let proof_r = Proof { - r: proof.r.wrapping_add(1), - d: proof.d, + v: proof.v.wrapping_add(1), + t: proof.t, items: proof.items.clone(), }; assert!(!Proof::verify(&setup, proof_r)); let proof_item = Proof { - r: proof.r, - d: proof.d, + v: proof.v, + t: proof.t, items: vec![], }; assert!(!Proof::verify(&setup, proof_item)); @@ -399,8 +399,8 @@ mod tests { let last_item = wrong_items.pop().unwrap(); let mut penultimate_item = wrong_items.pop().unwrap(); let proof_itembis = Proof { - r: proof.r, - d: proof.d, + v: proof.v, + t: proof.t, items: wrong_items.clone(), }; assert!(!Proof::verify(&setup, proof_itembis)); @@ -409,8 +409,8 @@ mod tests { wrong_items.push(penultimate_item); wrong_items.push(last_item); let proof_itembis = Proof { - r: proof.r, - d: proof.d, + v: proof.v, + t: proof.t, items: wrong_items.clone(), }; assert!(!Proof::verify(&setup, proof_itembis)); From 96eef15e401ffdfc4158bc2cafef22a87512dfbd Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:18:20 +0100 Subject: [PATCH 30/90] cargo fmt --- src/lib.rs | 2 +- src/utils.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5c2b224b..b0bd15b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //! An implementation of Approximate Lower Bound Arguments //! (ALBA, ). -pub mod utils; pub mod test_utils; +pub mod utils; pub mod centralized; diff --git a/src/utils.rs b/src/utils.rs index f64e5487..2b641fb0 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -97,4 +97,4 @@ pub fn combine_hashes(hash_list: Vec>) -> [u8; N] { .finalize_variable(&mut buf) .expect("Failed to finalize hashing"); buf -} \ No newline at end of file +} From 51be361245d97779ceff7a533c652b003fd99f00 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:23:21 +0100 Subject: [PATCH 31/90] Renaming centralized -> centralized_telescope --- Cargo.toml | 8 ++++---- benches/{centralized.rs => centralized_telescope.rs} | 12 ++++++------ src/{centralized.rs => centralized_telescope.rs} | 0 src/lib.rs | 2 +- 4 files changed, 11 insertions(+), 11 deletions(-) rename benches/{centralized.rs => centralized_telescope.rs} (95%) rename src/{centralized.rs => centralized_telescope.rs} (100%) diff --git a/Cargo.toml b/Cargo.toml index 52bc5771..9ae7896c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,14 +19,14 @@ rand_chacha = "0.3.1" criterion = { version = "0.5.1", features = ["html_reports"] } [[bench]] -name = "centralized_time" +name = "centralized_telescope_time" harness = false -path = "benches/centralized.rs" +path = "benches/centralized_telescope.rs" [[bench]] -name = "centralized_step" +name = "centralized_telescope_step" harness = false -path = "benches/centralized.rs" +path = "benches/centralized_telescope.rs" [lints.rust] missing_docs = "warn" diff --git a/benches/centralized.rs b/benches/centralized_telescope.rs similarity index 95% rename from benches/centralized.rs rename to benches/centralized_telescope.rs index e5dc8b30..2734868d 100644 --- a/benches/centralized.rs +++ b/benches/centralized_telescope.rs @@ -4,7 +4,7 @@ use rand_core::{RngCore, SeedableRng}; use std::time::{Duration, Instant}; use alba::{ - centralized::{Params, Proof, Setup}, + centralized_telescope::{Params, Proof, Setup}, test_utils::gen_items, }; @@ -187,22 +187,22 @@ fn repetition_benches(c: &mut Criterion) { ); } -criterion_group!(name = centralized_time; +criterion_group!(name = centralized_telescope_time; config = Criterion::default().measurement_time(Duration::from_secs(30)); targets = time_benches ); -criterion_group!(name = centralized_step; +criterion_group!(name = centralized_telescope_step; config = Criterion::default().with_measurement(Steps).measurement_time(Duration::from_secs(30)); targets = step_benches ); -criterion_group!(name = centralized_repetitions; +criterion_group!(name = centralized_telescope_repetitions; config = Criterion::default().with_measurement(Repetitions).measurement_time(Duration::from_secs(30)); targets = repetition_benches ); criterion_main!( - centralized_time, - centralized_step, //centralized_repetitions + centralized_telescope_time, + centralized_telescope_step, // centralized_telescope_repetitions ); diff --git a/src/centralized.rs b/src/centralized_telescope.rs similarity index 100% rename from src/centralized.rs rename to src/centralized_telescope.rs diff --git a/src/lib.rs b/src/lib.rs index b0bd15b6..dfb9317f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,4 +3,4 @@ pub mod test_utils; pub mod utils; -pub mod centralized; +pub mod centralized_telescope; From 1087969ea15805c7dab93a3b626b14e6a9a24a70 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:25:29 +0100 Subject: [PATCH 32/90] Renaming 'oracle'_uni/bernouilli as sample_x --- src/centralized_telescope.rs | 6 +++--- src/utils.rs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 9f49595c..7c6a55ff 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -199,7 +199,7 @@ impl Round { data.push(i); } let digest = utils::combine_hashes::(data); - (digest, utils::oracle_uniform(&digest, n_p)) + (digest, utils::sample_uniform(&digest, n_p)) } /// Output a round from a proof counter and n_p @@ -255,7 +255,7 @@ impl Proof { data.push(v.to_ne_bytes().to_vec()); data.push(s.to_vec()); let digest = utils::combine_hashes::(data); - utils::oracle_uniform(&digest, setup.n_p) + utils::sample_uniform(&digest, setup.n_p) } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise @@ -263,7 +263,7 @@ impl Proof { let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; data.push(r.h.to_vec()); let digest = utils::combine_hashes::(data); - utils::oracle_bernouilli(&digest, setup.q) + utils::sample_bernouilli(&digest, setup.q) } /// Depth-first search which goes through all potential round candidates diff --git a/src/utils.rs b/src/utils.rs index 2b641fb0..ec8adff9 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,7 +7,7 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). /// We do so by interpreting the hash as a random number an returns it modulo n /// (c.f. Appendix B, Alba paper). -pub fn oracle_uniform(hash: &[u8], n: usize) -> usize { +pub fn sample_uniform(hash: &[u8], n: usize) -> usize { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) fn mod_non_power_of_2(hash: &[u8], n: usize) -> usize { @@ -44,7 +44,7 @@ pub fn oracle_uniform(hash: &[u8], n: usize) -> usize { /// Takes as input a hash and probability $q$ and returns true with /// probability q otherwise false according to a Bernouilli distribution /// (c.f. Appendix B, Alba paper). -pub fn oracle_bernouilli(hash: &[u8], q: f64) -> bool { +pub fn sample_bernouilli(hash: &[u8], q: f64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ let epsilon_fail: usize = 1 << 40; // roughly 1 trillion From 3cc46e6fee8ca1422bbf6ddaaf39cb3395e02e0b Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:31:58 +0100 Subject: [PATCH 33/90] Fixing q recip --- src/centralized_telescope.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 7c6a55ff..335c9a01 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -127,7 +127,7 @@ impl Setup { u, r: params.lambda_rel, d: d as usize, - q: (2.0 * ln12 / d), + q: 2.0 * ln12 / d, b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as usize, }; } @@ -141,7 +141,7 @@ impl Setup { u, r: (lambda_rel / lambda_rel2).ceil() as u32, d: d as usize, - q: (2.0 * (lambda_rel2 + 2.0) / (d * loge)), + q: 2.0 * (lambda_rel2 + 2.0) / (d * loge), b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) * (3.0 * u_f64 * d / 4.0) + d @@ -161,7 +161,7 @@ impl Setup { u, r: (lambda_rel / lambda_rel1).ceil() as u32, d: d as usize, - q: (2.0 * lbar / d).recip(), + q: 2.0 * lbar / d, b: (((w * lbar) / d + 1.0) * E.powf(2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w) * d From 19af83b6adebce1fa595112a7c48ba0919eb9dd5 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 12:36:42 +0100 Subject: [PATCH 34/90] cleanup --- src/centralized_telescope.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 335c9a01..21de0639 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -83,8 +83,8 @@ impl Setup { pub fn new(params: &Params) -> Self { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { - let bound = 0.5f64.powf(l); - let factors: Vec = (1..=(w as u64 + 2)).rev().collect(); + let bound = (-l).exp2(); + let factors = (1..=(w as u64 + 2)).rev(); let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) / (E * (w + 2.0 - E.powf(1.0 / w))); @@ -162,8 +162,8 @@ impl Setup { r: (lambda_rel / lambda_rel1).ceil() as u32, d: d as usize, q: 2.0 * lbar / d, - b: (((w * lbar) / d + 1.0) - * E.powf(2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w) + b: ((w * lbar / d + 1.0) + * (2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w).exp() * d * u_f64 + d) From 0a6b7b372c4d68dead6121769531c297a2e54c3c Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 13:06:34 +0100 Subject: [PATCH 35/90] Fixing lambda_sec --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 21de0639..ffc71ce2 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -108,7 +108,7 @@ impl Setup { let lognpnf = (n_p_f64 / n_f_f64).log2(); let lambda_rel = params.lambda_rel as f64; let logrel = lambda_rel.log2(); - let lambda_sec = (params.lambda_sec as f64) + logrel; + let lambda_sec = params.lambda_sec as f64; let loge = LOG2_E as f64; let u_f64 = ((lambda_sec + logrel + 5.0 - loge.log2()) / lognpnf).ceil(); From 350773e9ba623ddcd13774aee84d15ada67782b6 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 13:06:57 +0100 Subject: [PATCH 36/90] Removing unused rayon --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 9ae7896c..344befed 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ include = ["**/*.rs", "Cargo.toml", "README.md", ".gitignore"] [dependencies] blake2 = "0.10.6" rand_core = "0.6.4" -rayon = "1.10.0" [dev-dependencies] rand = "0.8.5" From bf2a05f79c64cb623f632cf85e84f4bbb7199d4a Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 13:15:10 +0100 Subject: [PATCH 37/90] Using &[-] instead of &Vec<-> --- src/centralized_telescope.rs | 8 ++++---- src/test_utils.rs | 2 +- src/utils.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index ffc71ce2..45772524 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -198,7 +198,7 @@ impl Round { for i in input { data.push(i); } - let digest = utils::combine_hashes::(data); + let digest = utils::combine_hashes::(&data); (digest, utils::sample_uniform(&digest, n_p)) } @@ -254,7 +254,7 @@ impl Proof { let mut data = vec!["Telescope-H0".as_bytes().to_vec()]; data.push(v.to_ne_bytes().to_vec()); data.push(s.to_vec()); - let digest = utils::combine_hashes::(data); + let digest = utils::combine_hashes::(&data); utils::sample_uniform(&digest, setup.n_p) } @@ -262,7 +262,7 @@ impl Proof { fn h2(setup: &Setup, r: &Round) -> bool { let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; data.push(r.h.to_vec()); - let digest = utils::combine_hashes::(data); + let digest = utils::combine_hashes::(&data); utils::sample_bernouilli(&digest, setup.q) } @@ -272,7 +272,7 @@ impl Proof { /// - H2(t, x_0, ..., x_u) = true fn dfs( setup: &Setup, - bins: &Vec>, + bins: &[Vec], round: &Round, limit: usize, ) -> (usize, Option) { diff --git a/src/test_utils.rs b/src/test_utils.rs index 31fbb9ae..930e6bd6 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -9,7 +9,7 @@ pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> for b in 0..set_size { let mut data = vec![seed.clone()]; data.push(b.to_ne_bytes().to_vec()); - let item = utils::combine_hashes::(data); + let item = utils::combine_hashes::(&data); s_p.push(item); } s_p diff --git a/src/utils.rs b/src/utils.rs index ec8adff9..c5205f3e 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -87,7 +87,7 @@ pub fn hash_bytes(data: &[u8]) -> [u8; N] { } /// Return a N-byte long hash of the given list of data -pub fn combine_hashes(hash_list: Vec>) -> [u8; N] { +pub fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); for data in hash_list.iter() { hasher.update(data); From ac2bb9310d99de6ea8240ac94bff2e8583d9e29e Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 13:40:35 +0100 Subject: [PATCH 38/90] Using &[-] instead of &Vec<-> --- src/centralized_telescope.rs | 8 ++++---- src/utils.rs | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 45772524..f91a74ae 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -193,10 +193,10 @@ pub struct Round { impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(input: Vec>, n_p: usize) -> (Hash, usize) { + fn h1(input: &[Vec], n_p: usize) -> (Hash, usize) { let mut data = vec!["Telescope-H1".as_bytes().to_vec()]; for i in input { - data.push(i); + data.push(i.to_vec()); } let digest = utils::combine_hashes::(&data); (digest, utils::sample_uniform(&digest, n_p)) @@ -207,7 +207,7 @@ impl Round { pub fn new(v: u32, t: usize, n_p: usize) -> Round { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); - let (h, h_usize) = Round::h1(data, n_p); + let (h, h_usize) = Round::h1(&data, n_p); Round { v, t, @@ -225,7 +225,7 @@ impl Round { s_list.push(s); let mut data = vec![r.h.clone().to_vec()]; data.push(s.to_vec()); - let (h, h_usize) = Round::h1(data, r.n_p); + let (h, h_usize) = Round::h1(&data, r.n_p); Round { v: r.v, t: r.t, diff --git a/src/utils.rs b/src/utils.rs index c5205f3e..c3095e83 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -89,9 +89,8 @@ pub fn hash_bytes(data: &[u8]) -> [u8; N] { /// Return a N-byte long hash of the given list of data pub fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); - for data in hash_list.iter() { - hasher.update(data); - } + hash_list.iter().for_each(|h| hasher.update(h)); + let mut buf = [0u8; N]; hasher .finalize_variable(&mut buf) From c8104f9e356e3a2de28c3e3efedeb3af52555910 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 14:09:53 +0100 Subject: [PATCH 39/90] Fixing w+1! --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index f91a74ae..a48d13c4 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -84,7 +84,7 @@ impl Setup { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = (-l).exp2(); - let factors = (1..=(w as u64 + 2)).rev(); + let factors = (1..=(w as u64 + 1)).rev(); let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) / (E * (w + 2.0 - E.powf(1.0 / w))); From 86e041fbad753f78f6662c6b904254b9a3eb3e75 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 17:33:58 +0100 Subject: [PATCH 40/90] Updating types --- benches/centralized_telescope.rs | 53 +++++----------- benches/criterion_helpers.rs | 19 ++---- src/centralized_telescope.rs | 100 +++++++++++++++---------------- src/test_utils.rs | 4 +- src/utils.rs | 34 +++++------ 5 files changed, 91 insertions(+), 119 deletions(-) diff --git a/benches/centralized_telescope.rs b/benches/centralized_telescope.rs index 2734868d..3181ec58 100644 --- a/benches/centralized_telescope.rs +++ b/benches/centralized_telescope.rs @@ -14,18 +14,18 @@ use criterion_helpers::{benchmarks, Repetitions, Steps}; // Global variables const NAME: &str = "Centralized"; // Benchmark parameters -const L: &[u32] = &[50, 128]; // Security parameter -const SP: &[usize] = &[1_000]; // Size of set to lower bound -const NP: &[usize] = &[80, 90, 95, 98]; // Alba's np parameter, |Sp| >= np -const NF: &[usize] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf +const L: &[f64] = &[50.0, 128.0]; // Security parameter +const SP: &[u64] = &[1_000]; // Size of set to lower bound +const NP: &[u64] = &[80, 90, 95, 98]; // Alba's np parameter, |Sp| >= np +const NF: &[u64] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf /// Function generating a random set of elements to bench and calling Alba's centralized setup pub fn centralized_setup( rng: &mut ChaCha20Rng, - l: u32, - sp: usize, - np: usize, - nf: usize, + l: f64, + sp: u64, + np: u64, + nf: u64, ) -> (Vec<[u8; 32]>, Setup) { let seed_u32 = rng.next_u32(); let seed = seed_u32.to_ne_bytes().to_vec(); @@ -41,21 +41,14 @@ pub fn centralized_setup( /// Bench the duration of both the proving and verifiying algorithm of Alba centralized fn time_benches(c: &mut Criterion) { - fn prove_duration( - l: u32, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> Duration { + fn prove_duration(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> Duration { let mut rng = ChaCha20Rng::from_entropy(); let mut total_duration = Duration::ZERO; for _ in 0..n { // Setup let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size); + dataset.truncate(truncate_size as usize); // Bench let start = Instant::now(); black_box({ @@ -66,21 +59,14 @@ fn time_benches(c: &mut Criterion) { total_duration } - fn verify_duration( - l: u32, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> Duration { + fn verify_duration(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> Duration { let mut rng = ChaCha20Rng::from_entropy(); let mut total_duration = Duration::ZERO; for _ in 0..n { // Setup let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size); + dataset.truncate(truncate_size as usize); // Prove let proof_opt = Proof::prove(&bench_setup, &dataset); // Bench @@ -120,14 +106,14 @@ fn time_benches(c: &mut Criterion) { /// Bench the number of steps, i.e. DFS calls, of Alba centralized prover fn step_benches(c: &mut Criterion) { - fn prove_steps(l: u32, sp: usize, np: usize, nf: usize, truncate_size: usize, n: u64) -> u64 { + fn prove_steps(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> u64 { let mut rng = ChaCha20Rng::from_entropy(); let mut total_steps = 0; for _ in 0..n { // Setup let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size); + dataset.truncate(truncate_size as usize); // Bench black_box({ let (steps, _, _) = Proof::bench(&bench_setup, &dataset); @@ -151,21 +137,14 @@ fn step_benches(c: &mut Criterion) { /// Bench the number of repetitions, i.e. the "r" parameter, of Alba centralized prover fn repetition_benches(c: &mut Criterion) { - fn prove_repetitions( - l: u32, - sp: usize, - np: usize, - nf: usize, - truncate_size: usize, - n: u64, - ) -> u64 { + fn prove_repetitions(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> u64 { let mut rng = ChaCha20Rng::from_entropy(); let mut total_repetitions = 0; for _ in 0..n { // Setup let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size); + dataset.truncate(truncate_size as usize); // Bench black_box({ let (_, r, _) = Proof::bench(&bench_setup, &dataset); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs index da9d0193..1077f844 100644 --- a/benches/criterion_helpers.rs +++ b/benches/criterion_helpers.rs @@ -5,14 +5,7 @@ use criterion::{ // Criterion helpers -pub fn bench_id( - bench_name: &str, - pc: usize, - l: u32, - sp: usize, - np: usize, - nf: usize, -) -> BenchmarkId { +pub fn bench_id(bench_name: &str, pc: u64, l: f64, sp: u64, np: u64, nf: u64) -> BenchmarkId { BenchmarkId::new( bench_name, format!("(λ: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf})"), @@ -21,13 +14,13 @@ pub fn bench_id( pub fn benchmarks>( c: &mut Criterion, - lambdas: &[u32], - s_p: &[usize], - n_p: &[usize], - n_f: &[usize], + lambdas: &[f64], + s_p: &[u64], + n_p: &[u64], + n_f: &[u64], group_name: String, bench_name: String, - f: &dyn Fn(u32, usize, usize, usize, usize, u64) -> V, + f: &dyn Fn(f64, u64, u64, u64, u64, u64) -> V, ) { let mut group = c.benchmark_group(group_name); diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index a48d13c4..e7272f5a 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -15,13 +15,13 @@ type Hash = [u8; DIGEST_SIZE]; #[derive(Debug)] pub struct Params { /// Soundness security parameter - pub lambda_sec: u32, + pub lambda_sec: f64, /// Completeness security parameter - pub lambda_rel: u32, + pub lambda_rel: f64, /// Approximate size of set Sp to lower bound - pub n_p: usize, + pub n_p: u64, /// Target lower bound - pub n_f: usize, + pub n_f: u64, } pub enum Cases { /// Case where u =< λ^2 @@ -34,7 +34,7 @@ pub enum Cases { impl Params { /// Returns information on which case corresponds some parameter - pub fn which_case(&self) -> (Cases, usize) { + pub fn which_case(&self) -> (Cases, u64) { let lsec = self.lambda_sec as f64; let lrel = self.lambda_rel as f64; let np = self.n_p as f64; @@ -45,19 +45,19 @@ impl Params { let u_f64 = (lsec + lrel.log2() + 5.0 - loge.log2()) / lognpnf; let u = u_f64.ceil() as u64; - let ratio = 9.0 * np * loge / ((17 * u).pow(2) as f64); + let ratio = 9.0 * np * loge / ((17.0 * u_f64).powi(2)); let s1 = ratio - 7.0; let s2 = ratio - 2.0; if s1 < 1.0 || s2 < 1.0 { - return (Cases::Small, u as usize); + return (Cases::Small, u); } let lrel2 = lrel.min(s2); if (u as f64) < lrel2 { - (Cases::Mid, u as usize) + (Cases::Mid, u) } else { - (Cases::High, u as usize) + (Cases::High, u) } } } @@ -66,17 +66,17 @@ impl Params { #[derive(Debug, Clone)] pub struct Setup { /// Approximate size of set Sp to lower bound - pub n_p: usize, + pub n_p: u64, /// Proof size (in Sp elements) - pub u: usize, + pub u: u64, /// Proof max counter - pub r: u32, + pub r: u64, /// Proof max 2nd counter - pub d: usize, + pub d: u64, /// Probability q pub q: f64, /// Computation bound - pub b: usize, + pub b: u64, } impl Setup { /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) @@ -112,9 +112,9 @@ impl Setup { let loge = LOG2_E as f64; let u_f64 = ((lambda_sec + logrel + 5.0 - loge.log2()) / lognpnf).ceil(); - let u = u_f64 as usize; + let u = u_f64 as u64; - let ratio = 9.0 * n_p_f64 * loge / ((17 * u).pow(2) as f64); + let ratio = 9.0 * n_p_f64 * loge / ((17.0 * u_f64).powi(2)); let s1 = ratio - 7.0; let s2 = ratio - 2.0; @@ -125,10 +125,10 @@ impl Setup { return Setup { n_p: params.n_p, u, - r: params.lambda_rel, - d: d as usize, + r: params.lambda_rel as u64, + d: d as u64, q: 2.0 * ln12 / d, - b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as usize, + b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as u64, }; } let lambda_rel2 = lambda_rel.min(s2); @@ -139,14 +139,14 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel2).ceil() as u32, - d: d as usize, + r: (lambda_rel / lambda_rel2).ceil() as u64, + d: d as u64, q: 2.0 * (lambda_rel2 + 2.0) / (d * loge), b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) * (3.0 * u_f64 * d / 4.0) + d + u_f64) - .floor() as usize, + .floor() as u64, } } else { // Case 2, Theorem 13, ie λ^3 > n_p > λ^2 @@ -159,15 +159,15 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel1).ceil() as u32, - d: d as usize, + r: (lambda_rel / lambda_rel1).ceil() as u64, + d: d as u64, q: 2.0 * lbar / d, b: ((w * lbar / d + 1.0) * (2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w).exp() * d * u_f64 + d) - .floor() as usize, + .floor() as u64, } } } @@ -177,23 +177,23 @@ impl Setup { #[derive(Debug, Clone)] pub struct Round { /// Proof counter - v: u32, + v: u64, /// Proof 2nd counter - t: usize, + t: u64, // Round candidate tuple s_list: Vec, /// Round candidate hash h: Hash, /// Round candidate hash mapped to [1, n_p] - h_usize: usize, + h_u64: u64, /// Approximate size of set Sp to lower bound - n_p: usize, + n_p: u64, } impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(input: &[Vec], n_p: usize) -> (Hash, usize) { + fn h1(input: &[Vec], n_p: u64) -> (Hash, u64) { let mut data = vec!["Telescope-H1".as_bytes().to_vec()]; for i in input { data.push(i.to_vec()); @@ -204,16 +204,16 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: u32, t: usize, n_p: usize) -> Round { + pub fn new(v: u64, t: u64, n_p: u64) -> Round { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); - let (h, h_usize) = Round::h1(&data, n_p); + let (h, h_u64) = Round::h1(&data, n_p); Round { v, t, s_list: vec![], h, - h_usize, + h_u64, n_p, } } @@ -225,13 +225,13 @@ impl Round { s_list.push(s); let mut data = vec![r.h.clone().to_vec()]; data.push(s.to_vec()); - let (h, h_usize) = Round::h1(&data, r.n_p); + let (h, h_u64) = Round::h1(&data, r.n_p); Round { v: r.v, t: r.t, s_list, h, - h_usize, + h_u64, n_p: r.n_p, } } @@ -241,16 +241,16 @@ impl Round { /// Alba proof pub struct Proof { /// Proof counter - v: u32, + v: u64, /// Proof 2nd counter - t: usize, + t: u64, /// Proof tuple items: Vec, } impl Proof { /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p - fn h0(setup: &Setup, v: u32, s: Element) -> usize { + fn h0(setup: &Setup, v: u64, s: Element) -> u64 { let mut data = vec!["Telescope-H0".as_bytes().to_vec()]; data.push(v.to_ne_bytes().to_vec()); data.push(s.to_vec()); @@ -274,9 +274,9 @@ impl Proof { setup: &Setup, bins: &[Vec], round: &Round, - limit: usize, - ) -> (usize, Option) { - if round.s_list.len() == setup.u { + limit: u64, + ) -> (u64, Option) { + if round.s_list.len() as u64 == setup.u { if Proof::h2(setup, round) { let v = round.v; let t = round.t; @@ -287,7 +287,7 @@ impl Proof { } } - bins[round.h_usize] + bins[round.h_u64 as usize] .iter() .fold((limit, None), |(l, proof_opt), &s| { if proof_opt.is_some() || l == setup.b { @@ -300,10 +300,10 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. - fn prove_index(setup: &Setup, set: &[Element], v: u32) -> (usize, Option) { - let mut bins: Vec> = vec![vec![]; setup.n_p]; + fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { + let mut bins: Vec> = vec![vec![]; setup.n_p as usize]; for &s in set.iter() { - bins[Proof::h0(setup, v, s)].push(s); + bins[Proof::h0(setup, v, s) as usize].push(s); } (0..setup.d).fold((0, None), |(limit, proof_opt), t| { @@ -325,7 +325,7 @@ impl Proof { /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &[Element]) -> (usize, u32, Option) { + pub fn bench(setup: &Setup, set: &[Element]) -> (u64, u64, Option) { (0..setup.r).fold((0, setup.r, None), |(limit, r, proof_opt), v| { if proof_opt.is_some() { (limit, r, proof_opt) @@ -339,13 +339,13 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. pub fn verify(setup: &Setup, proof: Proof) -> bool { - if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() != setup.u { + if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } let r0 = Round::new(proof.v, proof.t, setup.n_p); let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { ( - b && r.h_usize == Proof::h0(setup, proof.v, s), + b && r.h_u64 == Proof::h0(setup, proof.v, s), Round::update(&r, s), ) }); @@ -369,8 +369,8 @@ mod tests { let seed = rng.next_u32().to_ne_bytes().to_vec(); let s_p = gen_items::(seed, set_size); let params = Params { - lambda_sec: 10, - lambda_rel: 10, + lambda_sec: 10.0, + lambda_rel: 10.0, n_p: 80, n_f: 20, }; diff --git a/src/test_utils.rs b/src/test_utils.rs index 930e6bd6..dfc191ef 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -4,8 +4,8 @@ use crate::utils; /// Generate a set of items given the set size and a seed /// Items are generated by hashing the current index -pub fn gen_items(seed: Vec, set_size: usize) -> Vec<[u8; N]> { - let mut s_p = Vec::with_capacity(set_size); +pub fn gen_items(seed: Vec, set_size: u64) -> Vec<[u8; N]> { + let mut s_p = Vec::with_capacity(set_size as usize); for b in 0..set_size { let mut data = vec![seed.clone()]; data.push(b.to_ne_bytes().to_vec()); diff --git a/src/utils.rs b/src/utils.rs index c3095e83..8ce51aa8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -7,17 +7,17 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). /// We do so by interpreting the hash as a random number an returns it modulo n /// (c.f. Appendix B, Alba paper). -pub fn sample_uniform(hash: &[u8], n: usize) -> usize { +pub fn sample_uniform(hash: &[u8], n: u64) -> u64 { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) - fn mod_non_power_of_2(hash: &[u8], n: usize) -> usize { - fn log_base2(x: usize) -> usize { - usize::BITS as usize - x.leading_zeros() as usize - 1 + fn mod_non_power_of_2(hash: &[u8], n: u64) -> u64 { + fn log_base2(x: u64) -> u64 { + u64::BITS as u64 - x.leading_zeros() as u64 - 1u64 } - let epsilon_fail: usize = 1 << 40; // roughly 1 trillion - let k: usize = log_base2(n * epsilon_fail); - let k_prime: usize = 1 << k; - let d: usize = k_prime.div_ceil(n); + let epsilon_fail: u64 = 1 << 40; // roughly 1 trillion + let k = log_base2(n * epsilon_fail); + let k_prime: u64 = 1 << k; + let d = k_prime.div_ceil(n); let i = mod_power_of_2(hash, k_prime); @@ -29,8 +29,8 @@ pub fn sample_uniform(hash: &[u8], n: usize) -> usize { } // Computes the integer reprensation of hash* modulo n when n is a power of // two. *(up to 8 bytes, in little endian) - fn mod_power_of_2(hash: &[u8], n: usize) -> usize { - assert!(8 * hash.len() >= (n as f32).log2() as usize); + fn mod_power_of_2(hash: &[u8], n: u64) -> u64 { + assert!(8 * hash.len() as u32 >= n.ilog2()); from_bytes_le(hash) & (n - 1) } @@ -47,18 +47,18 @@ pub fn sample_uniform(hash: &[u8], n: usize) -> usize { pub fn sample_bernouilli(hash: &[u8], q: f64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ - let epsilon_fail: usize = 1 << 40; // roughly 1 trillion - let mut x: usize = q.ceil() as usize; - let mut y: usize = 1; + let epsilon_fail: u64 = 1 << 40; // roughly 1 trillion + let mut x: u64 = q.ceil() as u64; + let mut y: u64 = 1; while { let difference = q - (x as f64 / y as f64); difference >= 1.0 / epsilon_fail as f64 || difference < 0.0 } { y *= 2; - x = (q * (y as f64)).round() as usize; + x = (q * (y as f64)).round() as u64; } // Output i in [0; y-1] from hash - assert!(8 * hash.len() >= (y as f32).log2() as usize); + assert!(8.0 * hash.len() as f32 >= (y as f32).log2()); let i = from_bytes_le(hash) & (y - 1); // Return true if i < x i < x @@ -66,11 +66,11 @@ pub fn sample_bernouilli(hash: &[u8], q: f64) -> bool { // Returns the integer representation of, up to the 8 first bytes of, the // input bytes in little endian -fn from_bytes_le(bytes: &[u8]) -> usize { +fn from_bytes_le(bytes: &[u8]) -> u64 { let mut array = [0u8; 8]; let bytes = &bytes[..min(8, bytes.len())]; array[..bytes.len()].copy_from_slice(bytes); - usize::from_le_bytes(array) + u64::from_le_bytes(array) } // Hash helpers From 98a478f94968559de41a047d7e7c6427b6aa8e03 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 24 Oct 2024 17:53:09 +0100 Subject: [PATCH 41/90] Setup assert as debug_assert --- src/centralized_telescope.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index e7272f5a..f744a885 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -135,7 +135,7 @@ impl Setup { if u_f64 < lambda_rel2 { // Case 3, Theorem 14, ie n_p >= λ^3 let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); - assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); + debug_assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); Setup { n_p: params.n_p, u, @@ -153,7 +153,7 @@ impl Setup { let lambda_rel1 = lambda_rel.min(s1); let lbar = (lambda_rel1 + 7.0) / loge; let d = (16.0 * u_f64 * lbar).ceil(); - assert!(n_p_f64 >= d * d / (9.0 * lbar)); + debug_assert!(n_p_f64 >= d * d / (9.0 * lbar)); let w = compute_w(u_f64, lambda_rel1); Setup { From 37f4f01a9ab9c6eaec07a3a1983106ca6884564c Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:03:22 +0000 Subject: [PATCH 42/90] Removing which_case --- src/centralized_telescope.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index f744a885..10aa07d8 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -32,36 +32,6 @@ pub enum Cases { High, } -impl Params { - /// Returns information on which case corresponds some parameter - pub fn which_case(&self) -> (Cases, u64) { - let lsec = self.lambda_sec as f64; - let lrel = self.lambda_rel as f64; - let np = self.n_p as f64; - let nf = self.n_f as f64; - let loge = LOG2_E as f64; - - let lognpnf = (np / nf).log2(); - let u_f64 = (lsec + lrel.log2() + 5.0 - loge.log2()) / lognpnf; - let u = u_f64.ceil() as u64; - - let ratio = 9.0 * np * loge / ((17.0 * u_f64).powi(2)); - let s1 = ratio - 7.0; - let s2 = ratio - 2.0; - - if s1 < 1.0 || s2 < 1.0 { - return (Cases::Small, u); - } - - let lrel2 = lrel.min(s2); - if (u as f64) < lrel2 { - (Cases::Mid, u) - } else { - (Cases::High, u) - } - } -} - /// Setup output parameters #[derive(Debug, Clone)] pub struct Setup { From 7f4b018922a92db732ca099a1701454ac6d1c668 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:04:16 +0000 Subject: [PATCH 43/90] Cleaning up lambdas f64 --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 10aa07d8..8bcc0806 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -81,7 +81,7 @@ impl Setup { let lambda_sec = params.lambda_sec as f64; let loge = LOG2_E as f64; - let u_f64 = ((lambda_sec + logrel + 5.0 - loge.log2()) / lognpnf).ceil(); + ((params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2()) / lognpnf).ceil(); let u = u_f64 as u64; let ratio = 9.0 * n_p_f64 * loge / ((17.0 * u_f64).powi(2)); From f56a0609327e0b7b00ae4bf361f649e26e284938 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:04:41 +0000 Subject: [PATCH 44/90] Cleaning up lambdas f64 --- src/centralized_telescope.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 8bcc0806..acec9f59 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -76,11 +76,9 @@ impl Setup { let n_p_f64 = params.n_p as f64; let n_f_f64 = params.n_f as f64; let lognpnf = (n_p_f64 / n_f_f64).log2(); - let lambda_rel = params.lambda_rel as f64; - let logrel = lambda_rel.log2(); - let lambda_sec = params.lambda_sec as f64; let loge = LOG2_E as f64; + let u_f64 = ((params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2()) / lognpnf).ceil(); let u = u_f64 as u64; @@ -101,7 +99,7 @@ impl Setup { b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as u64, }; } - let lambda_rel2 = lambda_rel.min(s2); + let lambda_rel2 = params.lambda_rel.min(s2); if u_f64 < lambda_rel2 { // Case 3, Theorem 14, ie n_p >= λ^3 let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); @@ -109,7 +107,7 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel2).ceil() as u64, + r: (params.lambda_rel / lambda_rel2).ceil() as u64, d: d as u64, q: 2.0 * (lambda_rel2 + 2.0) / (d * loge), b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) @@ -120,7 +118,7 @@ impl Setup { } } else { // Case 2, Theorem 13, ie λ^3 > n_p > λ^2 - let lambda_rel1 = lambda_rel.min(s1); + let lambda_rel1 = params.lambda_rel.min(s1); let lbar = (lambda_rel1 + 7.0) / loge; let d = (16.0 * u_f64 * lbar).ceil(); debug_assert!(n_p_f64 >= d * d / (9.0 * lbar)); @@ -129,7 +127,7 @@ impl Setup { Setup { n_p: params.n_p, u, - r: (lambda_rel / lambda_rel1).ceil() as u64, + r: (params.lambda_rel / lambda_rel1).ceil() as u64, d: d as u64, q: 2.0 * lbar / d, b: ((w * lbar / d + 1.0) From 32a7b555b4049fa73074e8cfd4c7dd2b1ea7831f Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:06:34 +0000 Subject: [PATCH 45/90] Removing benches (new issue) --- Cargo.toml | 10 -- benches/centralized_telescope.rs | 187 -------------------------- benches/criterion_helpers.rs | 223 ------------------------------- 3 files changed, 420 deletions(-) delete mode 100644 benches/centralized_telescope.rs delete mode 100644 benches/criterion_helpers.rs diff --git a/Cargo.toml b/Cargo.toml index 344befed..f959459a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,16 +17,6 @@ rand = "0.8.5" rand_chacha = "0.3.1" criterion = { version = "0.5.1", features = ["html_reports"] } -[[bench]] -name = "centralized_telescope_time" -harness = false -path = "benches/centralized_telescope.rs" - -[[bench]] -name = "centralized_telescope_step" -harness = false -path = "benches/centralized_telescope.rs" - [lints.rust] missing_docs = "warn" unsafe_code = "warn" diff --git a/benches/centralized_telescope.rs b/benches/centralized_telescope.rs deleted file mode 100644 index 3181ec58..00000000 --- a/benches/centralized_telescope.rs +++ /dev/null @@ -1,187 +0,0 @@ -use criterion::{black_box, criterion_group, criterion_main, measurement::WallTime, Criterion}; -use rand_chacha::ChaCha20Rng; -use rand_core::{RngCore, SeedableRng}; -use std::time::{Duration, Instant}; - -use alba::{ - centralized_telescope::{Params, Proof, Setup}, - test_utils::gen_items, -}; - -pub mod criterion_helpers; -use criterion_helpers::{benchmarks, Repetitions, Steps}; - -// Global variables -const NAME: &str = "Centralized"; -// Benchmark parameters -const L: &[f64] = &[50.0, 128.0]; // Security parameter -const SP: &[u64] = &[1_000]; // Size of set to lower bound -const NP: &[u64] = &[80, 90, 95, 98]; // Alba's np parameter, |Sp| >= np -const NF: &[u64] = &[67, 75]; // Alba's nf parameter, |Sp| >= np > nf - -/// Function generating a random set of elements to bench and calling Alba's centralized setup -pub fn centralized_setup( - rng: &mut ChaCha20Rng, - l: f64, - sp: u64, - np: u64, - nf: u64, -) -> (Vec<[u8; 32]>, Setup) { - let seed_u32 = rng.next_u32(); - let seed = seed_u32.to_ne_bytes().to_vec(); - let dataset: Vec<[u8; 32]> = gen_items(seed, sp); - let params = Params { - lambda_sec: l, - lambda_rel: l, - n_p: (np * sp).div_ceil(100), - n_f: (nf * sp).div_ceil(100), - }; - (dataset, Setup::new(¶ms)) -} - -/// Bench the duration of both the proving and verifiying algorithm of Alba centralized -fn time_benches(c: &mut Criterion) { - fn prove_duration(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> Duration { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_duration = Duration::ZERO; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); - // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size as usize); - // Bench - let start = Instant::now(); - black_box({ - Proof::prove(&bench_setup, &dataset); - }); - total_duration = total_duration.saturating_add(start.elapsed()); - } - total_duration - } - - fn verify_duration(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> Duration { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_duration = Duration::ZERO; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); - // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size as usize); - // Prove - let proof_opt = Proof::prove(&bench_setup, &dataset); - // Bench - if proof_opt.is_some() { - let start = Instant::now(); - black_box({ - Proof::verify(&bench_setup, proof_opt.unwrap()); - }); - total_duration = total_duration.saturating_add(start.elapsed()); - } - } - total_duration - } - - benchmarks::( - c, - L, - SP, - NP, - NF, - format!("{} - {}", NAME, "Time"), - "Prove".to_string(), - &prove_duration, - ); - - benchmarks::( - c, - L, - SP, - NP, - NF, - format!("{} - {}", NAME, "Time"), - "Verify".to_string(), - &verify_duration, - ); -} - -/// Bench the number of steps, i.e. DFS calls, of Alba centralized prover -fn step_benches(c: &mut Criterion) { - fn prove_steps(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> u64 { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_steps = 0; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); - // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size as usize); - // Bench - black_box({ - let (steps, _, _) = Proof::bench(&bench_setup, &dataset); - total_steps += steps; - }); - } - total_steps as u64 - } - - benchmarks::( - c, - L, - SP, - NP, - NF, - format!("{} - {}", NAME, "Steps"), - "Prove".to_string(), - &prove_steps, - ); -} - -/// Bench the number of repetitions, i.e. the "r" parameter, of Alba centralized prover -fn repetition_benches(c: &mut Criterion) { - fn prove_repetitions(l: f64, sp: u64, np: u64, nf: u64, truncate_size: u64, n: u64) -> u64 { - let mut rng = ChaCha20Rng::from_entropy(); - let mut total_repetitions = 0; - for _ in 0..n { - // Setup - let (mut dataset, bench_setup) = centralized_setup(&mut rng, l, sp, np, nf); - // Truncate the dataset to give truncate_size elements to the prover - dataset.truncate(truncate_size as usize); - // Bench - black_box({ - let (_, r, _) = Proof::bench(&bench_setup, &dataset); - total_repetitions += 1 + r; - }); - } - total_repetitions as u64 - } - - benchmarks::( - c, - L, - SP, - NP, - NF, - format!("{} - {}", NAME, "Repetitions"), - "Prove".to_string(), - &prove_repetitions, - ); -} - -criterion_group!(name = centralized_telescope_time; - config = Criterion::default().measurement_time(Duration::from_secs(30)); - targets = time_benches -); - -criterion_group!(name = centralized_telescope_step; - config = Criterion::default().with_measurement(Steps).measurement_time(Duration::from_secs(30)); - targets = step_benches -); - -criterion_group!(name = centralized_telescope_repetitions; - config = Criterion::default().with_measurement(Repetitions).measurement_time(Duration::from_secs(30)); - targets = repetition_benches -); - -criterion_main!( - centralized_telescope_time, - centralized_telescope_step, // centralized_telescope_repetitions -); diff --git a/benches/criterion_helpers.rs b/benches/criterion_helpers.rs deleted file mode 100644 index 1077f844..00000000 --- a/benches/criterion_helpers.rs +++ /dev/null @@ -1,223 +0,0 @@ -use criterion::{ - measurement::{Measurement, ValueFormatter}, - BenchmarkId, Criterion, Throughput, -}; - -// Criterion helpers - -pub fn bench_id(bench_name: &str, pc: u64, l: f64, sp: u64, np: u64, nf: u64) -> BenchmarkId { - BenchmarkId::new( - bench_name, - format!("(λ: {l}, Sp:{sp} ({pc}%), n_p:{np}, n_f:{nf})"), - ) -} - -pub fn benchmarks>( - c: &mut Criterion, - lambdas: &[f64], - s_p: &[u64], - n_p: &[u64], - n_f: &[u64], - group_name: String, - bench_name: String, - f: &dyn Fn(f64, u64, u64, u64, u64, u64) -> V, -) { - let mut group = c.benchmark_group(group_name); - - for &l in lambdas { - for &sp in s_p { - for &np in n_p { - for &nf in n_f { - // Benchmark where the prover only has access to np percent elements of Sp, - // i.e. the minimum number of elements such that the soundness is lower than 2^-λ - let low = (sp * np).div_ceil(100); - group.bench_function(bench_id(&bench_name, np, l, sp, np, nf), move |b| { - b.iter_custom(|n| f(l, sp, np, nf, low, n)) - }); - - // Benchmark where the prover only has access to (np+100)/2 percent elements of Sp - let mean = (100 + np).div_ceil(2); - let mid = (sp + low).div_ceil(2); - group.bench_function(bench_id(&bench_name, mean, l, sp, np, nf), move |b| { - b.iter_custom(|n| f(l, sp, np, nf, mid, n)) - }); - - // Benchmark where the prover only has access to all elements of Sp - group.bench_function(bench_id(&bench_name, 100, l, sp, np, nf), move |b| { - b.iter_custom(|n| f(l, sp, np, nf, sp, n)) - }); - } - } - } - } - group.finish(); -} - -// Measurements - -/// Nb of DFS call per proof -pub struct Steps; -impl Measurement for Steps { - type Intermediate = u64; - type Value = u64; - - fn start(&self) -> Self::Intermediate { - 0 - } - - fn end(&self, _i: Self::Intermediate) -> Self::Value { - 0 - } - - fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { - v1 + v2 - } - - fn zero(&self) -> Self::Value { - 0 - } - - fn to_f64(&self, value: &Self::Value) -> f64 { - *value as f64 - } - - fn formatter(&self) -> &dyn ValueFormatter { - &StepsFormatter - } -} - -struct StepsFormatter; - -impl ValueFormatter for StepsFormatter { - fn format_value(&self, value: f64) -> String { - format!("{:.4} steps", value) - } - - fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { - match throughput { - Throughput::Bytes(b) => format!("{:.4} spb", value / *b as f64), - Throughput::Elements(b) => format!("{:.4} steps/{}", value, b), - Throughput::BytesDecimal(b) => format!("{:.4} spb (decimal)", value / *b as f64), - } - } - - fn scale_values(&self, _typical_value: f64, _values: &mut [f64]) -> &'static str { - "steps" - } - - fn scale_throughputs( - &self, - _typical_value: f64, - throughput: &Throughput, - values: &mut [f64], - ) -> &'static str { - match throughput { - Throughput::Bytes(n) => { - for val in values { - *val /= *n as f64; - } - "spb" - } - Throughput::Elements(n) => { - for val in values { - *val /= *n as f64; - } - "spe" - } - Throughput::BytesDecimal(n) => { - for val in values { - *val /= *n as f64; - } - "spb (decimal)" - } - } - } - - fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { - "steps" - } -} - -/// Nb of repet, times prove_index was called, per proof -/// -pub struct Repetitions; -impl Measurement for Repetitions { - type Intermediate = u64; - type Value = u64; - - fn start(&self) -> Self::Intermediate { - 0 - } - - fn end(&self, _i: Self::Intermediate) -> Self::Value { - 0 - } - - fn add(&self, v1: &Self::Value, v2: &Self::Value) -> Self::Value { - v1 + v2 - } - - fn zero(&self) -> Self::Value { - 0 - } - - fn to_f64(&self, value: &Self::Value) -> f64 { - *value as f64 - } - - fn formatter(&self) -> &dyn ValueFormatter { - &RepetitionsFormatter - } -} - -struct RepetitionsFormatter; - -impl ValueFormatter for RepetitionsFormatter { - fn format_value(&self, value: f64) -> String { - format!("{:.4} repet", value) - } - - fn format_throughput(&self, throughput: &Throughput, value: f64) -> String { - match throughput { - Throughput::Bytes(b) => format!("{:.4} rpb", value / *b as f64), - Throughput::Elements(b) => format!("{:.4} repet/{}", value, b), - Throughput::BytesDecimal(b) => format!("{:.4} rpb (decimal)", value / *b as f64), - } - } - - fn scale_values(&self, _typical_value: f64, _values: &mut [f64]) -> &'static str { - "repet" - } - - fn scale_throughputs( - &self, - _typical_value: f64, - throughput: &Throughput, - values: &mut [f64], - ) -> &'static str { - match throughput { - Throughput::Bytes(n) => { - for val in values { - *val /= *n as f64; - } - "rpb" - } - Throughput::Elements(n) => { - for val in values { - *val /= *n as f64; - } - "rpe" - } - Throughput::BytesDecimal(n) => { - for val in values { - *val /= *n as f64; - } - "rpb (decimal)" - } - } - } - - fn scale_for_machines(&self, _values: &mut [f64]) -> &'static str { - "repet" - } -} From 45edc07abb80834f138cf9945efda012f9979296 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:23:31 +0000 Subject: [PATCH 46/90] Using Blake2s directly --- src/centralized_telescope.rs | 25 ++++++++++++++----------- src/test_utils.rs | 17 +++++++++++++++-- src/utils.rs | 27 --------------------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index acec9f59..8c0b8114 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -2,7 +2,7 @@ //! (c.f. Section 3.2.2 of Alba paper) use crate::utils; - +use blake2::{Blake2s256, Digest}; use std::{f32::consts::LOG2_E, f64::consts::E}; const DATA_LENGTH: usize = 32; @@ -162,11 +162,12 @@ impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 fn h1(input: &[Vec], n_p: u64) -> (Hash, u64) { - let mut data = vec!["Telescope-H1".as_bytes().to_vec()]; + let mut hasher = Blake2s256::new(); + hasher.update(b"Telescope-H1"); for i in input { - data.push(i.to_vec()); + hasher.update(i); } - let digest = utils::combine_hashes::(&data); + let digest: Hash = hasher.finalize().into(); (digest, utils::sample_uniform(&digest, n_p)) } @@ -219,18 +220,20 @@ pub struct Proof { impl Proof { /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p fn h0(setup: &Setup, v: u64, s: Element) -> u64 { - let mut data = vec!["Telescope-H0".as_bytes().to_vec()]; - data.push(v.to_ne_bytes().to_vec()); - data.push(s.to_vec()); - let digest = utils::combine_hashes::(&data); + let mut hasher = Blake2s256::new(); + hasher.update(b"Telescope-H0"); + hasher.update(v.to_be_bytes()); + hasher.update(s); + let digest: Hash = hasher.finalize().into(); utils::sample_uniform(&digest, setup.n_p) } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise fn h2(setup: &Setup, r: &Round) -> bool { - let mut data = vec!["Telescope-H2".as_bytes().to_vec()]; - data.push(r.h.to_vec()); - let digest = utils::combine_hashes::(&data); + let mut hasher = Blake2s256::new(); + hasher.update(b"Telescope-H2"); + hasher.update(r.h); + let digest: Hash = hasher.finalize().into(); utils::sample_bernouilli(&digest, setup.q) } diff --git a/src/test_utils.rs b/src/test_utils.rs index dfc191ef..418712f2 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -1,7 +1,20 @@ -use crate::utils; +use blake2::digest::{Update, VariableOutput}; +use blake2::Blake2bVar; // Test & Bench helpers +/// Return a N-byte long hash of the given list of data +fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { + let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); + hash_list.iter().for_each(|h| hasher.update(h)); + + let mut buf = [0u8; N]; + hasher + .finalize_variable(&mut buf) + .expect("Failed to finalize hashing"); + buf +} + /// Generate a set of items given the set size and a seed /// Items are generated by hashing the current index pub fn gen_items(seed: Vec, set_size: u64) -> Vec<[u8; N]> { @@ -9,7 +22,7 @@ pub fn gen_items(seed: Vec, set_size: u64) -> Vec<[u8; N]> { for b in 0..set_size { let mut data = vec![seed.clone()]; data.push(b.to_ne_bytes().to_vec()); - let item = utils::combine_hashes::(&data); + let item = combine_hashes::(&data); s_p.push(item); } s_p diff --git a/src/utils.rs b/src/utils.rs index 8ce51aa8..504088c4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,5 +1,3 @@ -use blake2::digest::{Update, VariableOutput}; -use blake2::Blake2bVar; use std::cmp::min; // Oracles @@ -72,28 +70,3 @@ fn from_bytes_le(bytes: &[u8]) -> u64 { array[..bytes.len()].copy_from_slice(bytes); u64::from_le_bytes(array) } - -// Hash helpers - -/// Return a N-byte long hash of the given data -pub fn hash_bytes(data: &[u8]) -> [u8; N] { - let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); - hasher.update(data); - let mut buf = [0u8; N]; - hasher - .finalize_variable(&mut buf) - .expect("Failed to finalize hashing"); - buf -} - -/// Return a N-byte long hash of the given list of data -pub fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { - let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); - hash_list.iter().for_each(|h| hasher.update(h)); - - let mut buf = [0u8; N]; - hasher - .finalize_variable(&mut buf) - .expect("Failed to finalize hashing"); - buf -} From c2e3ffaf1a689e0aa176be0b484639c9e342bfa6 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:25:21 +0000 Subject: [PATCH 47/90] clean up dfs --- src/centralized_telescope.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 8c0b8114..d7a7076f 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -248,14 +248,16 @@ impl Proof { limit: u64, ) -> (u64, Option) { if round.s_list.len() as u64 == setup.u { - if Proof::h2(setup, round) { - let v = round.v; - let t = round.t; - let items = round.s_list.clone(); - return (limit, Some(Proof { v, t, items })); + let proof_opt = if Proof::h2(setup, round) { + Some(Proof { + v: round.v, + t: round.t, + items: round.s_list.clone(), + }) } else { - return (limit, None); - } + None + }; + return (limit, proof_opt); } bins[round.h_u64 as usize] From f6b67dd036127378c6c2eded0a248ed6f0e68162 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:32:56 +0000 Subject: [PATCH 48/90] Changing back folds to for loops --- src/centralized_telescope.rs | 37 ++++++++++++++++++++---------------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index d7a7076f..065bb992 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -260,15 +260,15 @@ impl Proof { return (limit, proof_opt); } - bins[round.h_u64 as usize] - .iter() - .fold((limit, None), |(l, proof_opt), &s| { - if proof_opt.is_some() || l == setup.b { - (l, proof_opt) - } else { - Self::dfs(setup, bins, &Round::update(round, s), l + 1) - } - }) + let mut l = limit; + for &s in &bins[round.h_u64 as usize] { + let (l_dfs, proof_opt) = Self::dfs(setup, bins, &Round::update(round, s), l + 1); + if proof_opt.is_some() { + return (l_dfs, proof_opt); + } + l = l_dfs; + } + (l, None) } /// Indexed proving algorithm, returns an empty proof if no suitable @@ -279,14 +279,19 @@ impl Proof { bins[Proof::h0(setup, v, s) as usize].push(s); } - (0..setup.d).fold((0, None), |(limit, proof_opt), t| { - if proof_opt.is_some() || limit == setup.b { - (limit, proof_opt) - } else { - let round = Round::new(v, t, setup.n_p); - Proof::dfs(setup, &bins, &round, limit + 1) + let mut limit = 0; + for t in 0..setup.d { + if limit == setup.b { + return (limit, None); } - }) + let round = Round::new(v, t, setup.n_p); + let (l, proof_opt) = Proof::dfs(setup, &bins, &round, limit + 1); + if proof_opt.is_some() { + return (l, proof_opt); + } + limit = l; + } + (limit, None) } /// Alba's proving algorithm, based on a depth-first search algorithm. From 7e63cf470f82527665902737c15aa0ce16db7145 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:33:59 +0000 Subject: [PATCH 49/90] Updating verify to take as input &Proof --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 065bb992..0b3373e9 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -316,7 +316,7 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. - pub fn verify(setup: &Setup, proof: Proof) -> bool { + pub fn verify(setup: &Setup, proof: &Proof) -> bool { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } From 537ebf1aa92c893daa5116d674e12b987ee58bf8 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 21:53:31 +0000 Subject: [PATCH 50/90] Taking up to 2np elements when proving --- src/centralized_telescope.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 0b3373e9..90b7e2ec 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -298,7 +298,16 @@ impl Proof { /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Element]) -> Option { - (0..setup.r).find_map(|v| Proof::prove_index(setup, set, v).1) + // Take only up to 2*np elements for efficiency + let truncated_set = if set.len() >= 2 * setup.n_p as usize { + &set.iter() + .take(setup.n_p as usize) + .map(|&x| x) + .collect::>() + } else { + set + }; + (0..setup.r).find_map(|v| Proof::prove_index(setup, &truncated_set, v).1) } /// Alba's proving algorithm used for benchmarking, returning a proof as From 82a4fa3c59dd3f35411fc994ecf36aba8db83be0 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:14:53 +0000 Subject: [PATCH 51/90] sample_uniform returning option --- src/centralized_telescope.rs | 42 +++++++++++++++++++++--------------- src/utils.rs | 10 ++++----- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 90b7e2ec..0b539cc2 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -161,7 +161,7 @@ pub struct Round { impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(input: &[Vec], n_p: u64) -> (Hash, u64) { + fn h1(input: &[Vec], n_p: u64) -> (Hash, Option) { let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H1"); for i in input { @@ -173,36 +173,36 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: u64, t: u64, n_p: u64) -> Round { + pub fn new(v: u64, t: u64, n_p: u64) -> Option { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); - let (h, h_u64) = Round::h1(&data, n_p); - Round { + let (h, h_u64_opt) = Round::h1(&data, n_p); + h_u64_opt.map(|h_u64| Round { v, t, s_list: vec![], h, h_u64, n_p, - } + }) } /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - pub fn update(r: &Round, s: Element) -> Round { + pub fn update(r: &Round, s: Element) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); let mut data = vec![r.h.clone().to_vec()]; data.push(s.to_vec()); - let (h, h_u64) = Round::h1(&data, r.n_p); - Round { + let (h, h_u64_opt) = Round::h1(&data, r.n_p); + h_u64_opt.map(|h_u64| Round { v: r.v, t: r.t, s_list, h, h_u64, n_p: r.n_p, - } + }) } } @@ -219,7 +219,7 @@ pub struct Proof { impl Proof { /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p - fn h0(setup: &Setup, v: u64, s: Element) -> u64 { + fn h0(setup: &Setup, v: u64, s: Element) -> Option { let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H0"); hasher.update(v.to_be_bytes()); @@ -262,11 +262,13 @@ impl Proof { let mut l = limit; for &s in &bins[round.h_u64 as usize] { - let (l_dfs, proof_opt) = Self::dfs(setup, bins, &Round::update(round, s), l + 1); + if let Some(r) = Round::update(round, s) { + let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l + 1); if proof_opt.is_some() { return (l_dfs, proof_opt); } l = l_dfs; + } } (l, None) } @@ -276,7 +278,12 @@ impl Proof { fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { let mut bins: Vec> = vec![vec![]; setup.n_p as usize]; for &s in set.iter() { - bins[Proof::h0(setup, v, s) as usize].push(s); + match Proof::h0(setup, v, s) { + Some(h) => { + bins[h as usize].push(s); + } + None => return (0, None), + } } let mut limit = 0; @@ -284,12 +291,13 @@ impl Proof { if limit == setup.b { return (limit, None); } - let round = Round::new(v, t, setup.n_p); - let (l, proof_opt) = Proof::dfs(setup, &bins, &round, limit + 1); + if let Some(r) = Round::new(v, t, setup.n_p) { + let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit + 1); if proof_opt.is_some() { return (l, proof_opt); } limit = l; + } } (limit, None) } @@ -329,11 +337,11 @@ impl Proof { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } - let r0 = Round::new(proof.v, proof.t, setup.n_p); + let r0 = Round::new(proof.v, proof.t, setup.n_p).unwrap(); let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { ( - b && r.h_u64 == Proof::h0(setup, proof.v, s), - Round::update(&r, s), + b && r.h_u64 == Proof::h0(setup, proof.v, s).unwrap(), + Round::update(&r, s).unwrap(), ) }); b && Proof::h2(setup, &round) diff --git a/src/utils.rs b/src/utils.rs index 504088c4..9e8ff51a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,10 +5,10 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). /// We do so by interpreting the hash as a random number an returns it modulo n /// (c.f. Appendix B, Alba paper). -pub fn sample_uniform(hash: &[u8], n: u64) -> u64 { +pub fn sample_uniform(hash: &[u8], n: u64) -> Option { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) - fn mod_non_power_of_2(hash: &[u8], n: u64) -> u64 { + fn mod_non_power_of_2(hash: &[u8], n: u64) -> Option { fn log_base2(x: u64) -> u64 { u64::BITS as u64 - x.leading_zeros() as u64 - 1u64 } @@ -20,9 +20,9 @@ pub fn sample_uniform(hash: &[u8], n: u64) -> u64 { let i = mod_power_of_2(hash, k_prime); if i >= d * n { - panic!("failed: i = {}, d = {}, n = {}, k = {}", i, d, n, k); + None } else { - i % n + Some(i % n) } } // Computes the integer reprensation of hash* modulo n when n is a power of @@ -33,7 +33,7 @@ pub fn sample_uniform(hash: &[u8], n: u64) -> u64 { } if n.is_power_of_two() { - mod_power_of_2(hash, n) + Some(mod_power_of_2(hash, n)) } else { mod_non_power_of_2(hash, n) } From 682703bf00ef8046d7abde77c3dba41811f4cb81 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:15:23 +0000 Subject: [PATCH 52/90] fixup verify in test --- src/centralized_telescope.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 0b539cc2..c07e5721 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -371,25 +371,25 @@ mod tests { }; let setup = Setup::new(¶ms); let proof = Proof::prove(&setup, &s_p).unwrap(); - assert!(Proof::verify(&setup, proof.clone())); + assert!(Proof::verify(&setup, &proof.clone())); let proof_d = Proof { v: proof.v, t: proof.t.wrapping_add(1), items: proof.items.clone(), }; - assert!(!Proof::verify(&setup, proof_d)); + assert!(!Proof::verify(&setup, &proof_d)); let proof_r = Proof { v: proof.v.wrapping_add(1), t: proof.t, items: proof.items.clone(), }; - assert!(!Proof::verify(&setup, proof_r)); + assert!(!Proof::verify(&setup, &proof_r)); let proof_item = Proof { v: proof.v, t: proof.t, items: vec![], }; - assert!(!Proof::verify(&setup, proof_item)); + assert!(!Proof::verify(&setup, &proof_item)); let mut wrong_items = proof.items.clone(); let last_item = wrong_items.pop().unwrap(); let mut penultimate_item = wrong_items.pop().unwrap(); @@ -398,7 +398,7 @@ mod tests { t: proof.t, items: wrong_items.clone(), }; - assert!(!Proof::verify(&setup, proof_itembis)); + assert!(!Proof::verify(&setup, &proof_itembis)); // Modifying the penultimate item to check correctness of H1 check and not H2 penultimate_item[0] = penultimate_item[0].wrapping_add(42u8); wrong_items.push(penultimate_item); @@ -408,7 +408,7 @@ mod tests { t: proof.t, items: wrong_items.clone(), }; - assert!(!Proof::verify(&setup, proof_itembis)); + assert!(!Proof::verify(&setup, &proof_itembis)); } } } From 05bc0143cb353f2be0f31bfdcaf9d70d89f840d5 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:15:45 +0000 Subject: [PATCH 53/90] clippied --- src/centralized_telescope.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index c07e5721..3908a34a 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -310,12 +310,12 @@ impl Proof { let truncated_set = if set.len() >= 2 * setup.n_p as usize { &set.iter() .take(setup.n_p as usize) - .map(|&x| x) + .copied() .collect::>() } else { set }; - (0..setup.r).find_map(|v| Proof::prove_index(setup, &truncated_set, v).1) + (0..setup.r).find_map(|v| Proof::prove_index(setup, truncated_set, v).1) } /// Alba's proving algorithm used for benchmarking, returning a proof as From ade56f0187c802773ec926a1575bf6a23db554ed Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:16:08 +0000 Subject: [PATCH 54/90] cargo fmt --- src/centralized_telescope.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 3908a34a..371e30a7 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -264,10 +264,10 @@ impl Proof { for &s in &bins[round.h_u64 as usize] { if let Some(r) = Round::update(round, s) { let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l + 1); - if proof_opt.is_some() { - return (l_dfs, proof_opt); - } - l = l_dfs; + if proof_opt.is_some() { + return (l_dfs, proof_opt); + } + l = l_dfs; } } (l, None) @@ -293,10 +293,10 @@ impl Proof { } if let Some(r) = Round::new(v, t, setup.n_p) { let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit + 1); - if proof_opt.is_some() { - return (l, proof_opt); - } - limit = l; + if proof_opt.is_some() { + return (l, proof_opt); + } + limit = l; } } (limit, None) From 760f2172bd2dd1ae1c4cbe2ac301ac11f0f3a323 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:22:16 +0000 Subject: [PATCH 55/90] Adding security param to sample functions --- src/centralized_telescope.rs | 29 +++++++++++++++++------------ src/utils.rs | 12 ++++++------ 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 371e30a7..a4bdb427 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -35,6 +35,8 @@ pub enum Cases { /// Setup output parameters #[derive(Debug, Clone)] pub struct Setup { + /// Security parameter + pub sec_param: u64, /// Approximate size of set Sp to lower bound pub n_p: u64, /// Proof size (in Sp elements) @@ -91,6 +93,7 @@ impl Setup { let ln12 = (12f64).ln(); let d = (32.0 * ln12 * u_f64).ceil(); return Setup { + sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, n_p: params.n_p, u, r: params.lambda_rel as u64, @@ -105,6 +108,7 @@ impl Setup { let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); debug_assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); Setup { + sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, n_p: params.n_p, u, r: (params.lambda_rel / lambda_rel2).ceil() as u64, @@ -125,6 +129,7 @@ impl Setup { let w = compute_w(u_f64, lambda_rel1); Setup { + sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, n_p: params.n_p, u, r: (params.lambda_rel / lambda_rel1).ceil() as u64, @@ -161,22 +166,22 @@ pub struct Round { impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(input: &[Vec], n_p: u64) -> (Hash, Option) { + fn h1(input: &[Vec], n_p: u64, sec_param: u64) -> (Hash, Option) { let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H1"); for i in input { hasher.update(i); } let digest: Hash = hasher.finalize().into(); - (digest, utils::sample_uniform(&digest, n_p)) + (digest, utils::sample_uniform(&digest, n_p, sec_param)) } /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: u64, t: u64, n_p: u64) -> Option { + pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { let mut data = vec![v.to_ne_bytes().to_vec()]; data.push(t.to_ne_bytes().to_vec()); - let (h, h_u64_opt) = Round::h1(&data, n_p); + let (h, h_u64_opt) = Round::h1(&data, n_p, sec_param); h_u64_opt.map(|h_u64| Round { v, t, @@ -189,12 +194,12 @@ impl Round { /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - pub fn update(r: &Round, s: Element) -> Option { + pub fn update(r: &Round, s: Element, sec_param: u64) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); let mut data = vec![r.h.clone().to_vec()]; data.push(s.to_vec()); - let (h, h_u64_opt) = Round::h1(&data, r.n_p); + let (h, h_u64_opt) = Round::h1(&data, r.n_p, sec_param); h_u64_opt.map(|h_u64| Round { v: r.v, t: r.t, @@ -225,7 +230,7 @@ impl Proof { hasher.update(v.to_be_bytes()); hasher.update(s); let digest: Hash = hasher.finalize().into(); - utils::sample_uniform(&digest, setup.n_p) + utils::sample_uniform(&digest, setup.n_p, setup.sec_param) } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise @@ -234,7 +239,7 @@ impl Proof { hasher.update(b"Telescope-H2"); hasher.update(r.h); let digest: Hash = hasher.finalize().into(); - utils::sample_bernouilli(&digest, setup.q) + utils::sample_bernouilli(&digest, setup.q, setup.sec_param) } /// Depth-first search which goes through all potential round candidates @@ -262,7 +267,7 @@ impl Proof { let mut l = limit; for &s in &bins[round.h_u64 as usize] { - if let Some(r) = Round::update(round, s) { + if let Some(r) = Round::update(round, s, setup.sec_param) { let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l + 1); if proof_opt.is_some() { return (l_dfs, proof_opt); @@ -291,7 +296,7 @@ impl Proof { if limit == setup.b { return (limit, None); } - if let Some(r) = Round::new(v, t, setup.n_p) { + if let Some(r) = Round::new(v, t, setup.n_p, setup.sec_param) { let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit + 1); if proof_opt.is_some() { return (l, proof_opt); @@ -337,11 +342,11 @@ impl Proof { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } - let r0 = Round::new(proof.v, proof.t, setup.n_p).unwrap(); + let r0 = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param).unwrap(); let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { ( b && r.h_u64 == Proof::h0(setup, proof.v, s).unwrap(), - Round::update(&r, s).unwrap(), + Round::update(&r, s, setup.sec_param).unwrap(), ) }); b && Proof::h2(setup, &round) diff --git a/src/utils.rs b/src/utils.rs index 9e8ff51a..c7ea0b4b 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -5,14 +5,14 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). /// We do so by interpreting the hash as a random number an returns it modulo n /// (c.f. Appendix B, Alba paper). -pub fn sample_uniform(hash: &[u8], n: u64) -> Option { +pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) - fn mod_non_power_of_2(hash: &[u8], n: u64) -> Option { + fn mod_non_power_of_2(hash: &[u8], n: u64, sec_param: u64) -> Option { fn log_base2(x: u64) -> u64 { u64::BITS as u64 - x.leading_zeros() as u64 - 1u64 } - let epsilon_fail: u64 = 1 << 40; // roughly 1 trillion + let epsilon_fail: u64 = 1 << sec_param; let k = log_base2(n * epsilon_fail); let k_prime: u64 = 1 << k; let d = k_prime.div_ceil(n); @@ -35,17 +35,17 @@ pub fn sample_uniform(hash: &[u8], n: u64) -> Option { if n.is_power_of_two() { Some(mod_power_of_2(hash, n)) } else { - mod_non_power_of_2(hash, n) + mod_non_power_of_2(hash, n, sec_param) } } /// Takes as input a hash and probability $q$ and returns true with /// probability q otherwise false according to a Bernouilli distribution /// (c.f. Appendix B, Alba paper). -pub fn sample_bernouilli(hash: &[u8], q: f64) -> bool { +pub fn sample_bernouilli(hash: &[u8], q: f64, sec_param: u64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ - let epsilon_fail: u64 = 1 << 40; // roughly 1 trillion + let epsilon_fail: u64 = 1 << sec_param; let mut x: u64 = q.ceil() as u64; let mut y: u64 = 1; while { From f56ba67169bd246f10a24c3b9fbcb168bc70bca8 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 22:47:57 +0000 Subject: [PATCH 56/90] fixup removing cases --- src/centralized_telescope.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index a4bdb427..3d5915e7 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -23,14 +23,6 @@ pub struct Params { /// Target lower bound pub n_f: u64, } -pub enum Cases { - /// Case where u =< λ^2 - Small, - /// Case where λ^2 < u < λ^3 - Mid, - /// Case where u >= λ^3 - High, -} /// Setup output parameters #[derive(Debug, Clone)] From 63c0fc6daae09f512bad446de084d14c4e8e2627 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Tue, 29 Oct 2024 23:09:07 +0000 Subject: [PATCH 57/90] New clippy --- src/centralized_telescope.rs | 24 +++++++++++------------- src/test_utils.rs | 8 ++++---- src/utils.rs | 24 +++++++++++++++--------- 3 files changed, 30 insertions(+), 26 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 3d5915e7..6c5bbff7 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -48,7 +48,7 @@ impl Setup { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = (-l).exp2(); - let factors = (1..=(w as u64 + 1)).rev(); + let factors = (1..=((w as u64).saturating_add(1))).rev(); let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) / (E * (w + 2.0 - E.powf(1.0 / w))); @@ -70,7 +70,7 @@ impl Setup { let n_p_f64 = params.n_p as f64; let n_f_f64 = params.n_f as f64; let lognpnf = (n_p_f64 / n_f_f64).log2(); - let loge = LOG2_E as f64; + let loge = f64::from(LOG2_E); let u_f64 = ((params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2()) / lognpnf).ceil(); @@ -260,7 +260,7 @@ impl Proof { let mut l = limit; for &s in &bins[round.h_u64 as usize] { if let Some(r) = Round::update(round, s, setup.sec_param) { - let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l + 1); + let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l.saturating_add(1)); if proof_opt.is_some() { return (l_dfs, proof_opt); } @@ -274,7 +274,7 @@ impl Proof { /// candidate is found within the setup.b steps. fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { let mut bins: Vec> = vec![vec![]; setup.n_p as usize]; - for &s in set.iter() { + for &s in set { match Proof::h0(setup, v, s) { Some(h) => { bins[h as usize].push(s); @@ -289,7 +289,7 @@ impl Proof { return (limit, None); } if let Some(r) = Round::new(v, t, setup.n_p, setup.sec_param) { - let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit + 1); + let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit.saturating_add(1)); if proof_opt.is_some() { return (l, proof_opt); } @@ -304,11 +304,9 @@ impl Proof { /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Element]) -> Option { // Take only up to 2*np elements for efficiency - let truncated_set = if set.len() >= 2 * setup.n_p as usize { - &set.iter() - .take(setup.n_p as usize) - .copied() - .collect::>() + let two_np = setup.n_p.saturating_mul(2) as usize; + let truncated_set = if set.len() >= two_np { + &set.iter().take(two_np).copied().collect::>() } else { set }; @@ -322,8 +320,8 @@ impl Proof { if proof_opt.is_some() { (limit, r, proof_opt) } else { - let (l, opt) = Proof::prove_index(setup, set, v + 1); - (limit + l, r, opt) + let (l, opt) = Proof::prove_index(setup, set, v.saturating_add(1)); + (limit.saturating_add(l), r, opt) } }) } @@ -359,7 +357,7 @@ mod tests { let set_size = 1_000; for _t in 0..nb_tests { let seed = rng.next_u32().to_ne_bytes().to_vec(); - let s_p = gen_items::(seed, set_size); + let s_p = gen_items::(&seed, set_size); let params = Params { lambda_sec: 10.0, lambda_rel: 10.0, diff --git a/src/test_utils.rs b/src/test_utils.rs index 418712f2..396483fe 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -1,8 +1,8 @@ +//! Test & Bench helpers + use blake2::digest::{Update, VariableOutput}; use blake2::Blake2bVar; -// Test & Bench helpers - /// Return a N-byte long hash of the given list of data fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); @@ -17,10 +17,10 @@ fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { /// Generate a set of items given the set size and a seed /// Items are generated by hashing the current index -pub fn gen_items(seed: Vec, set_size: u64) -> Vec<[u8; N]> { +pub fn gen_items(seed: &[u8], set_size: u64) -> Vec<[u8; N]> { let mut s_p = Vec::with_capacity(set_size as usize); for b in 0..set_size { - let mut data = vec![seed.clone()]; + let mut data = vec![seed.to_vec()]; data.push(b.to_ne_bytes().to_vec()); let item = combine_hashes::(&data); s_p.push(item); diff --git a/src/utils.rs b/src/utils.rs index c7ea0b4b..6da6cde8 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ +//! Helper functions for Alba primitives + use std::cmp::min; // Oracles @@ -10,26 +12,30 @@ pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { // power of two. *(up to 8 bytes, in little endian) fn mod_non_power_of_2(hash: &[u8], n: u64, sec_param: u64) -> Option { fn log_base2(x: u64) -> u64 { - u64::BITS as u64 - x.leading_zeros() as u64 - 1u64 + u64::from( + u64::BITS + .saturating_sub(x.leading_zeros()) + .saturating_sub(1), + ) } let epsilon_fail: u64 = 1 << sec_param; - let k = log_base2(n * epsilon_fail); + let k = log_base2(n.saturating_mul(epsilon_fail)); let k_prime: u64 = 1 << k; let d = k_prime.div_ceil(n); let i = mod_power_of_2(hash, k_prime); - if i >= d * n { + if i >= d.saturating_mul(n) { None } else { - Some(i % n) + Some(i.rem_euclid(n)) } } // Computes the integer reprensation of hash* modulo n when n is a power of // two. *(up to 8 bytes, in little endian) fn mod_power_of_2(hash: &[u8], n: u64) -> u64 { - assert!(8 * hash.len() as u32 >= n.ilog2()); - from_bytes_le(hash) & (n - 1) + debug_assert!(8u32.saturating_mul(hash.len() as u32) >= n.ilog2()); + from_bytes_le(hash) & n.saturating_sub(1) } if n.is_power_of_two() { @@ -52,12 +58,12 @@ pub fn sample_bernouilli(hash: &[u8], q: f64, sec_param: u64) -> bool { let difference = q - (x as f64 / y as f64); difference >= 1.0 / epsilon_fail as f64 || difference < 0.0 } { - y *= 2; + y = y.saturating_mul(2); x = (q * (y as f64)).round() as u64; } // Output i in [0; y-1] from hash - assert!(8.0 * hash.len() as f32 >= (y as f32).log2()); - let i = from_bytes_le(hash) & (y - 1); + debug_assert!(8.0 * hash.len() as f32 >= (y as f32).log2()); + let i = from_bytes_le(hash) & y.saturating_sub(1); // Return true if i < x i < x } From a28f9f01dd5d537a0f05d43029a7443dd6188fac Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 10:33:39 +0000 Subject: [PATCH 58/90] cleaning up setup --- src/centralized_telescope.rs | 123 +++++++++++++++++++---------------- 1 file changed, 66 insertions(+), 57 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 6c5bbff7..7bb91492 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -43,8 +43,37 @@ pub struct Setup { pub b: u64, } impl Setup { - /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) - pub fn new(params: &Params) -> Self { + fn param_small_case(params: &Params, u_f64: f64, sec_param: u64) -> Self { + let ln12 = (12f64).ln(); + let d = (32.0 * ln12 * u_f64).ceil(); + Setup { + sec_param, + n_p: params.n_p, + u: u_f64 as u64, + r: params.lambda_rel as u64, + d: d as u64, + q: 2.0 * ln12 / d, + b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as u64, + } + } + + fn param_high_case(params: &Params, u_f64: f64, lambda_rel2: f64, sec_param: u64) -> Self { + let loge = f64::from(LOG2_E); + let l2 = lambda_rel2 + 2.0; + let d = (16.0 * u_f64 * l2 / loge).ceil(); + debug_assert!(params.n_p as f64 >= d * d * loge / (9.0 * l2)); + Setup { + sec_param, + n_p: params.n_p, + u: u_f64 as u64, + r: (params.lambda_rel / lambda_rel2).ceil() as u64, + d: d as u64, + q: 2.0 * l2 / (d * loge), + b: (((l2 + u_f64.log2()) / l2) * (3.0 * u_f64 * d / 4.0) + d + u_f64).floor() as u64, + } + } + + fn param_mid_case(params: &Params, u_f64: f64, s1: f64, sec_param: u64) -> Self { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = (-l).exp2(); @@ -66,73 +95,53 @@ impl Setup { } w } + let lambda_rel1 = params.lambda_rel.min(s1); + let lbar = (lambda_rel1 + 7.0) / f64::from(LOG2_E); + let d = (16.0 * u_f64 * lbar).ceil(); + let lbar_over_d = lbar / d; + debug_assert!(params.n_p as f64 >= d * d / (9.0 * lbar)); + + let w = compute_w(u_f64, lambda_rel1); + let exponential = (2.0 * u_f64 * w * lbar / params.n_p as f64 + 7.0 * u_f64 / w).exp(); + Setup { + sec_param, + n_p: params.n_p, + u: u_f64 as u64, + r: (params.lambda_rel / lambda_rel1).ceil() as u64, + d: d as u64, + q: 2.0 * lbar_over_d, + b: ((w * lbar_over_d + 1.0) * exponential * d * u_f64 + d).floor() as u64, + } + } + /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) + pub fn new(params: &Params) -> Self { + let sec_param = params.lambda_rel.max(params.lambda_sec).ceil() as u64; let n_p_f64 = params.n_p as f64; let n_f_f64 = params.n_f as f64; - let lognpnf = (n_p_f64 / n_f_f64).log2(); let loge = f64::from(LOG2_E); - let u_f64 = - ((params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2()) / lognpnf).ceil(); - let u = u_f64 as u64; + let u_f64 = { + let numerator = params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2(); + let denominator = (n_p_f64 / n_f_f64).log2(); + (numerator / denominator).ceil() + }; let ratio = 9.0 * n_p_f64 * loge / ((17.0 * u_f64).powi(2)); let s1 = ratio - 7.0; let s2 = ratio - 2.0; if s1 < 1.0 || s2 < 1.0 { - // Small case, ie n_p <= λ^2 - let ln12 = (12f64).ln(); - let d = (32.0 * ln12 * u_f64).ceil(); - return Setup { - sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, - n_p: params.n_p, - u, - r: params.lambda_rel as u64, - d: d as u64, - q: 2.0 * ln12 / d, - b: (8.0 * (u_f64 + 1.0) * d / ln12).floor() as u64, - }; - } - let lambda_rel2 = params.lambda_rel.min(s2); - if u_f64 < lambda_rel2 { - // Case 3, Theorem 14, ie n_p >= λ^3 - let d = (16.0 * u_f64 * (lambda_rel2 + 2.0) / loge).ceil(); - debug_assert!(n_p_f64 >= d * d * loge / (9.0 * (lambda_rel2 + 2.0))); - Setup { - sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, - n_p: params.n_p, - u, - r: (params.lambda_rel / lambda_rel2).ceil() as u64, - d: d as u64, - q: 2.0 * (lambda_rel2 + 2.0) / (d * loge), - b: (((lambda_rel2 + 2.0 + u_f64.log2()) / (lambda_rel2 + 2.0)) - * (3.0 * u_f64 * d / 4.0) - + d - + u_f64) - .floor() as u64, - } + // Small case, i.e. n_p <= λ^2 + Self::param_small_case(params, u_f64, sec_param) } else { - // Case 2, Theorem 13, ie λ^3 > n_p > λ^2 - let lambda_rel1 = params.lambda_rel.min(s1); - let lbar = (lambda_rel1 + 7.0) / loge; - let d = (16.0 * u_f64 * lbar).ceil(); - debug_assert!(n_p_f64 >= d * d / (9.0 * lbar)); - - let w = compute_w(u_f64, lambda_rel1); - Setup { - sec_param: params.lambda_rel.max(params.lambda_sec).ceil() as u64, - n_p: params.n_p, - u, - r: (params.lambda_rel / lambda_rel1).ceil() as u64, - d: d as u64, - q: 2.0 * lbar / d, - b: ((w * lbar / d + 1.0) - * (2.0 * u_f64 * w * lbar / n_p_f64 + 7.0 * u_f64 / w).exp() - * d - * u_f64 - + d) - .floor() as u64, + let lambda_rel2 = params.lambda_rel.min(s2); + if u_f64 < lambda_rel2 { + // Case 3, Theorem 14, i.e. n_p >= λ^3 + Self::param_high_case(params, u_f64, lambda_rel2, sec_param) + } else { + // Case 2, Theorem 13, i.e. λ^3 > n_p > λ^2 + Self::param_mid_case(params, u_f64, s1, sec_param) } } } From 56b851bbb17a7e88700244e9adb1606d660b1f97 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 10:45:51 +0000 Subject: [PATCH 59/90] Cleaning up h1 --- src/centralized_telescope.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 7bb91492..431586bb 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -167,12 +167,16 @@ pub struct Round { impl Round { /// Oracle producing a uniformly random value in [1, n_p] used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1(input: &[Vec], n_p: u64, sec_param: u64) -> (Hash, Option) { + fn h1( + first_input: &[u8], + second_input: &[u8], + n_p: u64, + sec_param: u64, + ) -> (Hash, Option) { let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H1"); - for i in input { - hasher.update(i); - } + hasher.update(first_input); + hasher.update(second_input); let digest: Hash = hasher.finalize().into(); (digest, utils::sample_uniform(&digest, n_p, sec_param)) } @@ -180,9 +184,12 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { - let mut data = vec![v.to_ne_bytes().to_vec()]; - data.push(t.to_ne_bytes().to_vec()); - let (h, h_u64_opt) = Round::h1(&data, n_p, sec_param); + let (h, h_u64_opt) = Round::h1( + v.to_ne_bytes().as_ref(), + t.to_ne_bytes().as_ref(), + n_p, + sec_param, + ); h_u64_opt.map(|h_u64| Round { v, t, @@ -198,9 +205,7 @@ impl Round { pub fn update(r: &Round, s: Element, sec_param: u64) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); - let mut data = vec![r.h.clone().to_vec()]; - data.push(s.to_vec()); - let (h, h_u64_opt) = Round::h1(&data, r.n_p, sec_param); + let (h, h_u64_opt) = Round::h1(r.h.clone().as_ref(), s.as_ref(), r.n_p, sec_param); h_u64_opt.map(|h_u64| Round { v: r.v, t: r.t, From 8d441db97b7105a2083784b6e6c8dfa3aba84e3d Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 10:57:15 +0000 Subject: [PATCH 60/90] Updating Round/Proof with Self --- src/centralized_telescope.rs | 45 ++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 431586bb..f5d73482 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -46,7 +46,7 @@ impl Setup { fn param_small_case(params: &Params, u_f64: f64, sec_param: u64) -> Self { let ln12 = (12f64).ln(); let d = (32.0 * ln12 * u_f64).ceil(); - Setup { + Self { sec_param, n_p: params.n_p, u: u_f64 as u64, @@ -62,7 +62,7 @@ impl Setup { let l2 = lambda_rel2 + 2.0; let d = (16.0 * u_f64 * l2 / loge).ceil(); debug_assert!(params.n_p as f64 >= d * d * loge / (9.0 * l2)); - Setup { + Self { sec_param, n_p: params.n_p, u: u_f64 as u64, @@ -103,7 +103,7 @@ impl Setup { let w = compute_w(u_f64, lambda_rel1); let exponential = (2.0 * u_f64 * w * lbar / params.n_p as f64 + 7.0 * u_f64 / w).exp(); - Setup { + Self { sec_param, n_p: params.n_p, u: u_f64 as u64, @@ -183,14 +183,14 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { - let (h, h_u64_opt) = Round::h1( + pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { + let (h, h_u64_opt) = Self::h1( v.to_ne_bytes().as_ref(), t.to_ne_bytes().as_ref(), n_p, sec_param, ); - h_u64_opt.map(|h_u64| Round { + h_u64_opt.map(|h_u64| Self { v, t, s_list: vec![], @@ -202,11 +202,11 @@ impl Round { /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - pub fn update(r: &Round, s: Element, sec_param: u64) -> Option { + pub fn update(r: &Self, s: Element, sec_param: u64) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); - let (h, h_u64_opt) = Round::h1(r.h.clone().as_ref(), s.as_ref(), r.n_p, sec_param); - h_u64_opt.map(|h_u64| Round { + let (h, h_u64_opt) = Self::h1(r.h.clone().as_ref(), s.as_ref(), r.n_p, sec_param); + h_u64_opt.map(|h_u64| Self { v: r.v, t: r.t, s_list, @@ -252,15 +252,10 @@ impl Proof { /// and returns first round candidate Round{t, x_1, ..., x_u)} such that: /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] /// - H2(t, x_0, ..., x_u) = true - fn dfs( - setup: &Setup, - bins: &[Vec], - round: &Round, - limit: u64, - ) -> (u64, Option) { + fn dfs(setup: &Setup, bins: &[Vec], round: &Round, limit: u64) -> (u64, Option) { if round.s_list.len() as u64 == setup.u { - let proof_opt = if Proof::h2(setup, round) { - Some(Proof { + let proof_opt = if Self::h2(setup, round) { + Some(Self { v: round.v, t: round.t, items: round.s_list.clone(), @@ -286,10 +281,10 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. - fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { + fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { let mut bins: Vec> = vec![vec![]; setup.n_p as usize]; for &s in set { - match Proof::h0(setup, v, s) { + match Self::h0(setup, v, s) { Some(h) => { bins[h as usize].push(s); } @@ -303,7 +298,7 @@ impl Proof { return (limit, None); } if let Some(r) = Round::new(v, t, setup.n_p, setup.sec_param) { - let (l, proof_opt) = Proof::dfs(setup, &bins, &r, limit.saturating_add(1)); + let (l, proof_opt) = Self::dfs(setup, &bins, &r, limit.saturating_add(1)); if proof_opt.is_some() { return (l, proof_opt); } @@ -324,7 +319,7 @@ impl Proof { } else { set }; - (0..setup.r).find_map(|v| Proof::prove_index(setup, truncated_set, v).1) + (0..setup.r).find_map(|v| Self::prove_index(setup, truncated_set, v).1) } /// Alba's proving algorithm used for benchmarking, returning a proof as @@ -334,7 +329,7 @@ impl Proof { if proof_opt.is_some() { (limit, r, proof_opt) } else { - let (l, opt) = Proof::prove_index(setup, set, v.saturating_add(1)); + let (l, opt) = Self::prove_index(setup, set, v.saturating_add(1)); (limit.saturating_add(l), r, opt) } }) @@ -342,18 +337,18 @@ impl Proof { /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. - pub fn verify(setup: &Setup, proof: &Proof) -> bool { + pub fn verify(setup: &Setup, proof: &Self) -> bool { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } let r0 = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param).unwrap(); let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { ( - b && r.h_u64 == Proof::h0(setup, proof.v, s).unwrap(), + b && r.h_u64 == Self::h0(setup, proof.v, s).unwrap(), Round::update(&r, s, setup.sec_param).unwrap(), ) }); - b && Proof::h2(setup, &round) + b && Self::h2(setup, &round) } } From 8e4d0a922aaac1a0c7d8a2168ce7ea5e02cc1c52 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 11:01:42 +0000 Subject: [PATCH 61/90] Fold to For in bench --- src/centralized_telescope.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index f5d73482..5351315d 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -325,14 +325,15 @@ impl Proof { /// Alba's proving algorithm used for benchmarking, returning a proof as /// well as the number of steps ran to find it. pub fn bench(setup: &Setup, set: &[Element]) -> (u64, u64, Option) { - (0..setup.r).fold((0, setup.r, None), |(limit, r, proof_opt), v| { + let mut limit: u64 = 0; + for v in 0..setup.r { + let (l, proof_opt) = Self::prove_index(setup, set, v.saturating_add(1)); + limit = limit.saturating_add(l); if proof_opt.is_some() { - (limit, r, proof_opt) - } else { - let (l, opt) = Self::prove_index(setup, set, v.saturating_add(1)); - (limit.saturating_add(l), r, opt) + return (limit, v, proof_opt); } - }) + } + (limit, setup.r, None) } /// Alba's verification algorithm, follows proving algorithm by running the From 7417e04d0796304af8b8f595de08dcb48190e534 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 11:03:55 +0000 Subject: [PATCH 62/90] Not using ne_bytes --- src/centralized_telescope.rs | 6 +++--- src/test_utils.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 5351315d..3f8da55d 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -185,8 +185,8 @@ impl Round { /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { let (h, h_u64_opt) = Self::h1( - v.to_ne_bytes().as_ref(), - t.to_ne_bytes().as_ref(), + v.to_be_bytes().as_ref(), + t.to_be_bytes().as_ref(), n_p, sec_param, ); @@ -366,7 +366,7 @@ mod tests { let nb_tests = 1_000; let set_size = 1_000; for _t in 0..nb_tests { - let seed = rng.next_u32().to_ne_bytes().to_vec(); + let seed = rng.next_u32().to_be_bytes().to_vec(); let s_p = gen_items::(&seed, set_size); let params = Params { lambda_sec: 10.0, diff --git a/src/test_utils.rs b/src/test_utils.rs index 396483fe..ffe5cc77 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -21,7 +21,7 @@ pub fn gen_items(seed: &[u8], set_size: u64) -> Vec<[u8; N]> { let mut s_p = Vec::with_capacity(set_size as usize); for b in 0..set_size { let mut data = vec![seed.to_vec()]; - data.push(b.to_ne_bytes().to_vec()); + data.push(b.to_be_bytes().to_vec()); let item = combine_hashes::(&data); s_p.push(item); } From 3dee62e92aee5aeaef50b2edbe945b760d4f4f28 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 13:43:02 +0000 Subject: [PATCH 63/90] Simplifiying compute_w --- src/centralized_telescope.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 3f8da55d..d3f1b38a 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -77,15 +77,16 @@ impl Setup { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = (-l).exp2(); - let factors = (1..=((w as u64).saturating_add(1))).rev(); - let mut ratio = (14.0 * w * w * (w + 2.0) * E.powf((w + 1.0) / w)) - / (E * (w + 2.0 - E.powf(1.0 / w))); - - for f in factors { - ratio /= f as f64; + let mut factor = (w.ceil() as u64).saturating_add(1); + let w_2 = w + 2.0; + let exp_1_over_w = E.powf(1.0 / w); + let mut ratio = (14.0 * w * w * w_2 * exp_1_over_w) / (w_2 - exp_1_over_w); + while factor != 0 { + ratio /= factor as f64; if ratio <= bound { return true; } + factor = factor.saturating_sub(1); } false } From 735e1de9a04d0302e5373ca1933a29b22c97f26f Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 15:08:06 +0000 Subject: [PATCH 64/90] Using stack allocated arrays --- src/centralized_telescope.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index d3f1b38a..aad633b4 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -185,12 +185,9 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { - let (h, h_u64_opt) = Self::h1( - v.to_be_bytes().as_ref(), - t.to_be_bytes().as_ref(), - n_p, - sec_param, - ); + let v_bytes: [u8; 8] = v.to_be_bytes(); + let t_bytes: [u8; 8] = t.to_be_bytes(); + let (h, h_u64_opt) = Self::h1(v_bytes.as_ref(), t_bytes.as_ref(), n_p, sec_param); h_u64_opt.map(|h_u64| Self { v, t, @@ -232,9 +229,10 @@ pub struct Proof { impl Proof { /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p fn h0(setup: &Setup, v: u64, s: Element) -> Option { + let v_bytes: [u8; 8] = v.to_be_bytes(); let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H0"); - hasher.update(v.to_be_bytes()); + hasher.update(v_bytes); hasher.update(s); let digest: Hash = hasher.finalize().into(); utils::sample_uniform(&digest, setup.n_p, setup.sec_param) From 69efabafb227aa64abeb698d08d5cdb0201c5d61 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Wed, 30 Oct 2024 15:29:16 +0000 Subject: [PATCH 65/90] Replacing Vec macro by Vec::new --- src/centralized_telescope.rs | 9 ++++++--- src/test_utils.rs | 26 ++++++++++---------------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index aad633b4..6e4ec119 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -191,7 +191,7 @@ impl Round { h_u64_opt.map(|h_u64| Self { v, t, - s_list: vec![], + s_list: Vec::new(), h, h_u64, n_p, @@ -281,7 +281,10 @@ impl Proof { /// Indexed proving algorithm, returns an empty proof if no suitable /// candidate is found within the setup.b steps. fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { - let mut bins: Vec> = vec![vec![]; setup.n_p as usize]; + let mut bins: Vec> = Vec::with_capacity(setup.n_p as usize); + for _ in 0..setup.n_p { + bins.push(Vec::new()); + } for &s in set { match Self::h0(setup, v, s) { Some(h) => { @@ -391,7 +394,7 @@ mod tests { let proof_item = Proof { v: proof.v, t: proof.t, - items: vec![], + items: Vec::new(), }; assert!(!Proof::verify(&setup, &proof_item)); let mut wrong_items = proof.items.clone(); diff --git a/src/test_utils.rs b/src/test_utils.rs index ffe5cc77..79c1ce03 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -3,27 +3,21 @@ use blake2::digest::{Update, VariableOutput}; use blake2::Blake2bVar; -/// Return a N-byte long hash of the given list of data -fn combine_hashes(hash_list: &[Vec]) -> [u8; N] { - let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); - hash_list.iter().for_each(|h| hasher.update(h)); - - let mut buf = [0u8; N]; - hasher - .finalize_variable(&mut buf) - .expect("Failed to finalize hashing"); - buf -} - /// Generate a set of items given the set size and a seed /// Items are generated by hashing the current index pub fn gen_items(seed: &[u8], set_size: u64) -> Vec<[u8; N]> { let mut s_p = Vec::with_capacity(set_size as usize); + let mut data_buf: [u8; 8]; + let mut digest_buf: [u8; N] = [0u8; N]; for b in 0..set_size { - let mut data = vec![seed.to_vec()]; - data.push(b.to_be_bytes().to_vec()); - let item = combine_hashes::(&data); - s_p.push(item); + data_buf = b.to_be_bytes(); + let mut hasher = Blake2bVar::new(N).expect("Failed to construct hasher!"); + hasher.update(seed); + hasher.update(&data_buf); + hasher + .finalize_variable(&mut digest_buf) + .expect("Failed to finalize hashing"); + s_p.push(digest_buf); } s_p } From a87657741b1a629a848f25f8636eaeb5151014fc Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:29:04 +0000 Subject: [PATCH 66/90] Remove unused deps --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f959459a..e338feac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ rand_core = "0.6.4" [dev-dependencies] rand = "0.8.5" rand_chacha = "0.3.1" -criterion = { version = "0.5.1", features = ["html_reports"] } [lints.rust] missing_docs = "warn" From fb03448215726292c977ac862e3e661586584624 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:31:57 +0000 Subject: [PATCH 67/90] f64::log2_e --- src/centralized_telescope.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 6e4ec119..9ca53625 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -3,7 +3,7 @@ use crate::utils; use blake2::{Blake2s256, Digest}; -use std::{f32::consts::LOG2_E, f64::consts::E}; +use std::f64::consts::{E, LOG2_E}; const DATA_LENGTH: usize = 32; const DIGEST_SIZE: usize = 32; @@ -58,17 +58,16 @@ impl Setup { } fn param_high_case(params: &Params, u_f64: f64, lambda_rel2: f64, sec_param: u64) -> Self { - let loge = f64::from(LOG2_E); let l2 = lambda_rel2 + 2.0; - let d = (16.0 * u_f64 * l2 / loge).ceil(); - debug_assert!(params.n_p as f64 >= d * d * loge / (9.0 * l2)); + let d = (16.0 * u_f64 * l2 / LOG2_E).ceil(); + debug_assert!(params.n_p as f64 >= d * d * LOG2_E / (9.0 * l2)); Self { sec_param, n_p: params.n_p, u: u_f64 as u64, r: (params.lambda_rel / lambda_rel2).ceil() as u64, d: d as u64, - q: 2.0 * l2 / (d * loge), + q: 2.0 * l2 / (d * LOG2_E), b: (((l2 + u_f64.log2()) / l2) * (3.0 * u_f64 * d / 4.0) + d + u_f64).floor() as u64, } } @@ -97,7 +96,7 @@ impl Setup { w } let lambda_rel1 = params.lambda_rel.min(s1); - let lbar = (lambda_rel1 + 7.0) / f64::from(LOG2_E); + let lbar = (lambda_rel1 + 7.0) / LOG2_E; let d = (16.0 * u_f64 * lbar).ceil(); let lbar_over_d = lbar / d; debug_assert!(params.n_p as f64 >= d * d / (9.0 * lbar)); @@ -120,15 +119,14 @@ impl Setup { let sec_param = params.lambda_rel.max(params.lambda_sec).ceil() as u64; let n_p_f64 = params.n_p as f64; let n_f_f64 = params.n_f as f64; - let loge = f64::from(LOG2_E); let u_f64 = { - let numerator = params.lambda_sec + params.lambda_rel.log2() + 5.0 - loge.log2(); + let numerator = params.lambda_sec + params.lambda_rel.log2() + 5.0 - LOG2_E.log2(); let denominator = (n_p_f64 / n_f_f64).log2(); (numerator / denominator).ceil() }; - let ratio = 9.0 * n_p_f64 * loge / ((17.0 * u_f64).powi(2)); + let ratio = 9.0 * n_p_f64 * LOG2_E / ((17.0 * u_f64).powi(2)); let s1 = ratio - 7.0; let s2 = ratio - 2.0; From 258dd5f99fd400dd12d31f560b17d55f69e1acd4 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:32:55 +0000 Subject: [PATCH 68/90] e.pow -> .exp() --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 9ca53625..841eb9d8 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -78,7 +78,7 @@ impl Setup { let bound = (-l).exp2(); let mut factor = (w.ceil() as u64).saturating_add(1); let w_2 = w + 2.0; - let exp_1_over_w = E.powf(1.0 / w); + let exp_1_over_w = w.recip().exp(); let mut ratio = (14.0 * w * w * w_2 * exp_1_over_w) / (w_2 - exp_1_over_w); while factor != 0 { ratio /= factor as f64; From c184d31bcc07531a54973c71a2975cb65b134116 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:33:59 +0000 Subject: [PATCH 69/90] fixup loge --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 841eb9d8..e60309a7 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -3,7 +3,7 @@ use crate::utils; use blake2::{Blake2s256, Digest}; -use std::f64::consts::{E, LOG2_E}; +use std::f64::consts::LOG2_E; const DATA_LENGTH: usize = 32; const DIGEST_SIZE: usize = 32; From e37f127ff88086fcabe20f12792162e2173386a9 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:36:01 +0000 Subject: [PATCH 70/90] cleanup --- src/centralized_telescope.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index e60309a7..2c3dd6c4 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -185,7 +185,7 @@ impl Round { pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { let v_bytes: [u8; 8] = v.to_be_bytes(); let t_bytes: [u8; 8] = t.to_be_bytes(); - let (h, h_u64_opt) = Self::h1(v_bytes.as_ref(), t_bytes.as_ref(), n_p, sec_param); + let (h, h_u64_opt) = Self::h1(&v_bytes, &t_bytes, n_p, sec_param); h_u64_opt.map(|h_u64| Self { v, t, @@ -201,7 +201,7 @@ impl Round { pub fn update(r: &Self, s: Element, sec_param: u64) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); - let (h, h_u64_opt) = Self::h1(r.h.clone().as_ref(), s.as_ref(), r.n_p, sec_param); + let (h, h_u64_opt) = Self::h1(&r.h, &s, r.n_p, sec_param); h_u64_opt.map(|h_u64| Self { v: r.v, t: r.t, From d2c6c7266094e5751252f8e31c15b3e03707ebc3 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:42:44 +0000 Subject: [PATCH 71/90] Removing redundant type --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 2c3dd6c4..b9f43af4 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -89,7 +89,7 @@ impl Setup { } false } - let mut w: f64 = u; + let mut w = u; while !factorial_check(w, l) { w += 1.0; } From dee9a19a805446624c14eb5b0a6f1aebc07ec793 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:47:12 +0000 Subject: [PATCH 72/90] Private round --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index b9f43af4..3b54978e 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -148,7 +148,7 @@ impl Setup { /// Round parameters #[derive(Debug, Clone)] -pub struct Round { +struct Round { /// Proof counter v: u64, /// Proof 2nd counter From 83dc56843e1fb9e107c54e2ae1b8bd7e839bb211 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:50:53 +0000 Subject: [PATCH 73/90] Removing bench --- src/centralized_telescope.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 3b54978e..ab2e0bcc 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -322,20 +322,6 @@ impl Proof { (0..setup.r).find_map(|v| Self::prove_index(setup, truncated_set, v).1) } - /// Alba's proving algorithm used for benchmarking, returning a proof as - /// well as the number of steps ran to find it. - pub fn bench(setup: &Setup, set: &[Element]) -> (u64, u64, Option) { - let mut limit: u64 = 0; - for v in 0..setup.r { - let (l, proof_opt) = Self::prove_index(setup, set, v.saturating_add(1)); - limit = limit.saturating_add(l); - if proof_opt.is_some() { - return (limit, v, proof_opt); - } - } - (limit, setup.r, None) - } - /// Alba's verification algorithm, follows proving algorithm by running the /// same depth-first search algorithm. pub fn verify(setup: &Setup, proof: &Self) -> bool { From ad293ba4875ea3a60775f70893d26c66b0eb7eb5 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 10:53:47 +0000 Subject: [PATCH 74/90] Fixing typos and comments in utils --- src/centralized_telescope.rs | 2 +- src/utils.rs | 11 ++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index ab2e0bcc..6c056e8b 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -242,7 +242,7 @@ impl Proof { hasher.update(b"Telescope-H2"); hasher.update(r.h); let digest: Hash = hasher.finalize().into(); - utils::sample_bernouilli(&digest, setup.q, setup.sec_param) + utils::sample_bernoulli(&digest, setup.q, setup.sec_param) } /// Depth-first search which goes through all potential round candidates diff --git a/src/utils.rs b/src/utils.rs index 6da6cde8..9e79b6a7 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,12 +1,9 @@ //! Helper functions for Alba primitives - use std::cmp::min; -// Oracles - /// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). -/// We do so by interpreting the hash as a random number an returns it modulo n -/// (c.f. Appendix B, Alba paper). +/// We do so by interpreting the hash as a random number and returns it modulo +/// n (c.f. Appendix B, Alba paper). pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) @@ -46,9 +43,9 @@ pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { } /// Takes as input a hash and probability $q$ and returns true with -/// probability q otherwise false according to a Bernouilli distribution +/// probability q otherwise false according to a Bernoulli distribution /// (c.f. Appendix B, Alba paper). -pub fn sample_bernouilli(hash: &[u8], q: f64, sec_param: u64) -> bool { +pub fn sample_bernoulli(hash: &[u8], q: f64, sec_param: u64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ let epsilon_fail: u64 = 1 << sec_param; From 8d51b865f3d62d02cec366a253eca9fbecfb1bc0 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:03:29 +0000 Subject: [PATCH 75/90] Update dfs comment --- src/centralized_telescope.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 6c056e8b..442cdad5 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -246,7 +246,9 @@ impl Proof { } /// Depth-first search which goes through all potential round candidates - /// and returns first round candidate Round{t, x_1, ..., x_u)} such that: + /// and returns the total number of recursive DFS calls done and, if found + /// under setup.b calls, the first round candidate Round{t, x_1, ..., x_u)} + /// such that: /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] /// - H2(t, x_0, ..., x_u) = true fn dfs(setup: &Setup, bins: &[Vec], round: &Round, limit: u64) -> (u64, Option) { From dcb55b3ba635e61a2c10e8420d553b1c5222e5bd Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:10:54 +0000 Subject: [PATCH 76/90] Fixing dfs --- src/centralized_telescope.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 442cdad5..8a614da8 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -267,6 +267,9 @@ impl Proof { let mut l = limit; for &s in &bins[round.h_u64 as usize] { + if limit == setup.b { + return (limit, None); + } if let Some(r) = Round::update(round, s, setup.sec_param) { let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l.saturating_add(1)); if proof_opt.is_some() { From 950c802727f4b726ddcd915dd22ffab6a9a1ad12 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:13:39 +0000 Subject: [PATCH 77/90] fixup dfs --- src/centralized_telescope.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 8a614da8..2538bbfc 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -251,7 +251,7 @@ impl Proof { /// such that: /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] /// - H2(t, x_0, ..., x_u) = true - fn dfs(setup: &Setup, bins: &[Vec], round: &Round, limit: u64) -> (u64, Option) { + fn dfs(setup: &Setup, bins: &[Vec], round: &Round, mut limit: u64) -> (u64, Option) { if round.s_list.len() as u64 == setup.u { let proof_opt = if Self::h2(setup, round) { Some(Self { @@ -267,8 +267,8 @@ impl Proof { let mut l = limit; for &s in &bins[round.h_u64 as usize] { - if limit == setup.b { - return (limit, None); + if l == setup.b { + return (l, None); } if let Some(r) = Round::update(round, s, setup.sec_param) { let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l.saturating_add(1)); From df66142ab71a862c6f98ecf84eb7a500a4828815 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:37:10 +0000 Subject: [PATCH 78/90] fixup --- src/centralized_telescope.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 2538bbfc..68614073 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -251,7 +251,7 @@ impl Proof { /// such that: /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] /// - H2(t, x_0, ..., x_u) = true - fn dfs(setup: &Setup, bins: &[Vec], round: &Round, mut limit: u64) -> (u64, Option) { + fn dfs(setup: &Setup, bins: &[Vec], round: &Round, limit: u64) -> (u64, Option) { if round.s_list.len() as u64 == setup.u { let proof_opt = if Self::h2(setup, round) { Some(Self { From 8647f029925a8b1c7117a932284a283bb0dfda77 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:50:09 +0000 Subject: [PATCH 79/90] DFS: Reusing limit var --- src/centralized_telescope.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 68614073..84b99ea6 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -247,11 +247,12 @@ impl Proof { /// Depth-first search which goes through all potential round candidates /// and returns the total number of recursive DFS calls done and, if found - /// under setup.b calls, the first round candidate Round{t, x_1, ..., x_u)} - /// such that: - /// - for all i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(t, x_1, ..., x_i)] - /// - H2(t, x_0, ..., x_u) = true - fn dfs(setup: &Setup, bins: &[Vec], round: &Round, limit: u64) -> (u64, Option) { + fn dfs( + setup: &Setup, + bins: &[Vec], + round: &Round, + mut limit: u64, + ) -> (u64, Option) { if round.s_list.len() as u64 == setup.u { let proof_opt = if Self::h2(setup, round) { Some(Self { @@ -265,20 +266,19 @@ impl Proof { return (limit, proof_opt); } - let mut l = limit; for &s in &bins[round.h_u64 as usize] { - if l == setup.b { - return (l, None); + if limit == setup.b { + return (limit, None); } if let Some(r) = Round::update(round, s, setup.sec_param) { - let (l_dfs, proof_opt) = Self::dfs(setup, bins, &r, l.saturating_add(1)); + let (l, proof_opt) = Self::dfs(setup, bins, &r, limit.saturating_add(1)); if proof_opt.is_some() { - return (l_dfs, proof_opt); + return (l, proof_opt); } - l = l_dfs; + limit = l; } } - (l, None) + (limit, None) } /// Indexed proving algorithm, returns an empty proof if no suitable From 278c086d806a27d9c91841454b7d4f3497be6cd8 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 11:50:26 +0000 Subject: [PATCH 80/90] Updating comments --- src/centralized_telescope.rs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 84b99ea6..e77ac954 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -245,8 +245,13 @@ impl Proof { utils::sample_bernoulli(&digest, setup.q, setup.sec_param) } - /// Depth-first search which goes through all potential round candidates + /// Depth-First Search which goes through all potential round candidates /// and returns the total number of recursive DFS calls done and, if found + /// under setup.b calls, Some(Proof), that is the first round candidate + /// Round{v, t, x_1, ..., x_u)} such that: + /// - ∀i ∈ [0, u-1], H0(x_i+1) ∈ bins[H1(...H1(H1(v, t), x_1), ..., x_i)] + /// - H2(H1(... H1((H1(v, t), x_1), ..., x_u)) = true + /// otherwise None fn dfs( setup: &Setup, bins: &[Vec], @@ -281,8 +286,9 @@ impl Proof { (limit, None) } - /// Indexed proving algorithm, returns an empty proof if no suitable - /// candidate is found within the setup.b steps. + /// Indexed proving algorithm, returns the total number of DFS calls done + /// to find a proof and Some(proof) if found within setup.b calls of DFS, + /// otherwise None fn prove_index(setup: &Setup, set: &[Element], v: u64) -> (u64, Option) { let mut bins: Vec> = Vec::with_capacity(setup.n_p as usize); for _ in 0..setup.n_p { From 5b9f7dc57858465fcbede8d6bfbfc78f659d3d64 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 12:10:58 +0000 Subject: [PATCH 81/90] Updating Vf with for loop --- src/centralized_telescope.rs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index e77ac954..35e49b35 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -339,14 +339,25 @@ impl Proof { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } - let r0 = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param).unwrap(); - let (b, round) = proof.items.iter().fold((true, r0), |(b, r), &s| { - ( - b && r.h_u64 == Self::h0(setup, proof.v, s).unwrap(), - Round::update(&r, s, setup.sec_param).unwrap(), - ) - }); - b && Self::h2(setup, &round) + if let Some(mut round) = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param) { + for element in proof.items.clone() { + if let Some(h) = Self::h0(setup, proof.v, element) { + if round.h_u64 == h { + if let Some(r) = Round::update(&round, element, setup.sec_param) { + round = r; + } else { + return false; + } + } else { + return false; + } + } else { + return false; + } + } + return Self::h2(setup, &round); + } + false } } From 2119a55fbb20c40c553c6ba1464ec59f0d0f0a7b Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 12:12:59 +0000 Subject: [PATCH 82/90] Fixing visibility --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dfb9317f..64f41c1c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,8 @@ //! An implementation of Approximate Lower Bound Arguments //! (ALBA, ). -pub mod test_utils; -pub mod utils; +#[cfg(test)] +mod test_utils; + +mod utils; pub mod centralized_telescope; From 12039cd8ebaeac20657767767d09300c116a02b4 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 12:14:53 +0000 Subject: [PATCH 83/90] Fix comment --- src/utils.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.rs b/src/utils.rs index 9e79b6a7..47644bfc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for Alba primitives use std::cmp::min; -/// Takes as input a hash and range $n$ and samples an integer from Unif(0, n). +/// Takes as input a hash and range $n$ and samples an integer from Unif[0, n). /// We do so by interpreting the hash as a random number and returns it modulo /// n (c.f. Appendix B, Alba paper). pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { From 2f7b77399b70af39eb775003b5c578ecfc6d286a Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 12:20:04 +0000 Subject: [PATCH 84/90] Updating sample distribution to use big endian --- src/utils.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils.rs b/src/utils.rs index 47644bfc..2ae1f0b4 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -32,7 +32,7 @@ pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { // two. *(up to 8 bytes, in little endian) fn mod_power_of_2(hash: &[u8], n: u64) -> u64 { debug_assert!(8u32.saturating_mul(hash.len() as u32) >= n.ilog2()); - from_bytes_le(hash) & n.saturating_sub(1) + from_bytes_be(hash) & n.saturating_sub(1) } if n.is_power_of_two() { @@ -60,16 +60,16 @@ pub fn sample_bernoulli(hash: &[u8], q: f64, sec_param: u64) -> bool { } // Output i in [0; y-1] from hash debug_assert!(8.0 * hash.len() as f32 >= (y as f32).log2()); - let i = from_bytes_le(hash) & y.saturating_sub(1); + let i = from_bytes_be(hash) & y.saturating_sub(1); // Return true if i < x i < x } // Returns the integer representation of, up to the 8 first bytes of, the // input bytes in little endian -fn from_bytes_le(bytes: &[u8]) -> u64 { +fn from_bytes_be(bytes: &[u8]) -> u64 { let mut array = [0u8; 8]; let bytes = &bytes[..min(8, bytes.len())]; array[..bytes.len()].copy_from_slice(bytes); - u64::from_le_bytes(array) + u64::from_be_bytes(array) } From 12ef83a4db098b2569b31fe97294c2ec1bf3ebe1 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 12:22:31 +0000 Subject: [PATCH 85/90] Updating visibility --- src/centralized_telescope.rs | 4 ++-- src/test_utils.rs | 2 +- src/utils.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 35e49b35..c054a62f 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -182,7 +182,7 @@ impl Round { /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - pub fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { + fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { let v_bytes: [u8; 8] = v.to_be_bytes(); let t_bytes: [u8; 8] = t.to_be_bytes(); let (h, h_u64_opt) = Self::h1(&v_bytes, &t_bytes, n_p, sec_param); @@ -198,7 +198,7 @@ impl Round { /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - pub fn update(r: &Self, s: Element, sec_param: u64) -> Option { + fn update(r: &Self, s: Element, sec_param: u64) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); let (h, h_u64_opt) = Self::h1(&r.h, &s, r.n_p, sec_param); diff --git a/src/test_utils.rs b/src/test_utils.rs index 79c1ce03..64b6d242 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -5,7 +5,7 @@ use blake2::Blake2bVar; /// Generate a set of items given the set size and a seed /// Items are generated by hashing the current index -pub fn gen_items(seed: &[u8], set_size: u64) -> Vec<[u8; N]> { +pub(crate) fn gen_items(seed: &[u8], set_size: u64) -> Vec<[u8; N]> { let mut s_p = Vec::with_capacity(set_size as usize); let mut data_buf: [u8; 8]; let mut digest_buf: [u8; N] = [0u8; N]; diff --git a/src/utils.rs b/src/utils.rs index 2ae1f0b4..b8c55af6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,7 +4,7 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif[0, n). /// We do so by interpreting the hash as a random number and returns it modulo /// n (c.f. Appendix B, Alba paper). -pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { +pub(crate) fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) fn mod_non_power_of_2(hash: &[u8], n: u64, sec_param: u64) -> Option { @@ -45,7 +45,7 @@ pub fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { /// Takes as input a hash and probability $q$ and returns true with /// probability q otherwise false according to a Bernoulli distribution /// (c.f. Appendix B, Alba paper). -pub fn sample_bernoulli(hash: &[u8], q: f64, sec_param: u64) -> bool { +pub(crate) fn sample_bernoulli(hash: &[u8], q: f64, sec_param: u64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ let epsilon_fail: u64 = 1 << sec_param; From b406dd708e3f05d3e72f8ba8d91cef83e3aee4f0 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Thu, 31 Oct 2024 16:36:41 +0000 Subject: [PATCH 86/90] Cleaning up truncating --- src/centralized_telescope.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index c054a62f..a8a83c87 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -294,7 +294,8 @@ impl Proof { for _ in 0..setup.n_p { bins.push(Vec::new()); } - for &s in set { + // Take only up to 2*np elements for efficiency + for &s in set.iter().take(setup.n_p.saturating_mul(2) as usize) { match Self::h0(setup, v, s) { Some(h) => { bins[h as usize].push(s); @@ -323,14 +324,7 @@ impl Proof { /// Calls up to setup.r times the prove_index function and returns an empty /// proof if no suitable candidate is found. pub fn prove(setup: &Setup, set: &[Element]) -> Option { - // Take only up to 2*np elements for efficiency - let two_np = setup.n_p.saturating_mul(2) as usize; - let truncated_set = if set.len() >= two_np { - &set.iter().take(two_np).copied().collect::>() - } else { - set - }; - (0..setup.r).find_map(|v| Self::prove_index(setup, truncated_set, v).1) + (0..setup.r).find_map(|v| Self::prove_index(setup, set, v).1) } /// Alba's verification algorithm, follows proving algorithm by running the From 8ceb350b32af24acfecb3c1e155d7c474178de7d Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 1 Nov 2024 14:35:19 +0000 Subject: [PATCH 87/90] Cleaning up test --- src/centralized_telescope.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index a8a83c87..a1ff5a36 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -367,36 +367,41 @@ mod tests { let mut rng = ChaCha20Rng::from_seed(Default::default()); let nb_tests = 1_000; let set_size = 1_000; + let params = Params { + lambda_sec: 10.0, + lambda_rel: 10.0, + n_p: 80 * set_size / 100, + n_f: 20 * set_size / 100, + }; for _t in 0..nb_tests { let seed = rng.next_u32().to_be_bytes().to_vec(); let s_p = gen_items::(&seed, set_size); - let params = Params { - lambda_sec: 10.0, - lambda_rel: 10.0, - n_p: 80, - n_f: 20, - }; let setup = Setup::new(¶ms); let proof = Proof::prove(&setup, &s_p).unwrap(); assert!(Proof::verify(&setup, &proof.clone())); - let proof_d = Proof { + // Checking that the proof fails if proof.t is erroneous + let proof_t = Proof { v: proof.v, t: proof.t.wrapping_add(1), items: proof.items.clone(), }; - assert!(!Proof::verify(&setup, &proof_d)); - let proof_r = Proof { + assert!(!Proof::verify(&setup, &proof_t)); + // Checking that the proof fails if proof.v is erroneous + let proof_v = Proof { v: proof.v.wrapping_add(1), t: proof.t, items: proof.items.clone(), }; - assert!(!Proof::verify(&setup, &proof_r)); + assert!(!Proof::verify(&setup, &proof_v)); + // Checking that the proof fails when no elements are included let proof_item = Proof { v: proof.v, t: proof.t, items: Vec::new(), }; assert!(!Proof::verify(&setup, &proof_item)); + // Checking that the proof fails when wrong elements are included + // We are trying to trigger H2 let mut wrong_items = proof.items.clone(); let last_item = wrong_items.pop().unwrap(); let mut penultimate_item = wrong_items.pop().unwrap(); @@ -406,7 +411,8 @@ mod tests { items: wrong_items.clone(), }; assert!(!Proof::verify(&setup, &proof_itembis)); - // Modifying the penultimate item to check correctness of H1 check and not H2 + // Checking that the proof fails when wrong elements are included + // We are trying to trigger H1 penultimate_item[0] = penultimate_item[0].wrapping_add(42u8); wrong_items.push(penultimate_item); wrong_items.push(last_item); From fc3eb1a1fbdceba1ff2e7aed57c0700809dd4e9f Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 1 Nov 2024 14:46:22 +0000 Subject: [PATCH 88/90] Cleaning up verify --- src/centralized_telescope.rs | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index a1ff5a36..edacfccb 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -333,25 +333,23 @@ impl Proof { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } - if let Some(mut round) = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param) { - for element in proof.items.clone() { - if let Some(h) = Self::h0(setup, proof.v, element) { - if round.h_u64 == h { - if let Some(r) = Round::update(&round, element, setup.sec_param) { - round = r; - } else { - return false; - } - } else { - return false; - } - } else { - return false; + let Some(mut round) = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param) else { + return false; + }; + for &element in &proof.items { + let Some(h) = Self::h0(setup, proof.v, element) else { + return false; + }; + if round.h_u64 == h { + match Round::update(&round, element, setup.sec_param) { + Some(r) => round = r, + None => return false, } + } else { + return false; } - return Self::h2(setup, &round); } - false + Self::h2(setup, &round) } } From ae6f0e33176635678fed0ca59daa0a7aa1accf67 Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 1 Nov 2024 14:51:45 +0000 Subject: [PATCH 89/90] Updating comments --- src/centralized_telescope.rs | 8 ++++---- src/utils.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index edacfccb..138f0717 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -164,7 +164,7 @@ struct Round { } impl Round { - /// Oracle producing a uniformly random value in [1, n_p] used for round candidates + /// Oracle producing a uniformly random value in [0, n_p[ used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 fn h1( first_input: &[u8], @@ -225,7 +225,7 @@ pub struct Proof { } impl Proof { - /// Oracle producing a uniformly random value in [1, n_p] used for prehashing S_p + /// Oracle producing a uniformly random value in [0, n_p[ used for prehashing S_p fn h0(setup: &Setup, v: u64, s: Element) -> Option { let v_bytes: [u8; 8] = v.to_be_bytes(); let mut hasher = Blake2s256::new(); @@ -327,8 +327,8 @@ impl Proof { (0..setup.r).find_map(|v| Self::prove_index(setup, set, v).1) } - /// Alba's verification algorithm, follows proving algorithm by running the - /// same depth-first search algorithm. + /// Alba's verification algorithm, returns true if the proof is + /// successfully verified, following the DFS verification, false otherwise. pub fn verify(setup: &Setup, proof: &Self) -> bool { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; diff --git a/src/utils.rs b/src/utils.rs index b8c55af6..b52d033a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,7 +1,7 @@ //! Helper functions for Alba primitives use std::cmp::min; -/// Takes as input a hash and range $n$ and samples an integer from Unif[0, n). +/// Takes as input a hash and range $n$ and samples an integer from Unif[0, n[. /// We do so by interpreting the hash as a random number and returns it modulo /// n (c.f. Appendix B, Alba paper). pub(crate) fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { From e289e7e1ca54900765ca7dfeffd906ef11ca387b Mon Sep 17 00:00:00 2001 From: Raphael Toledo Date: Fri, 1 Nov 2024 14:58:53 +0000 Subject: [PATCH 90/90] Removing sec_param and hardcoding value in sample functions --- src/centralized_telescope.rs | 47 ++++++++++++++---------------------- src/utils.rs | 12 ++++----- 2 files changed, 24 insertions(+), 35 deletions(-) diff --git a/src/centralized_telescope.rs b/src/centralized_telescope.rs index 138f0717..e4b1c40c 100644 --- a/src/centralized_telescope.rs +++ b/src/centralized_telescope.rs @@ -27,8 +27,6 @@ pub struct Params { /// Setup output parameters #[derive(Debug, Clone)] pub struct Setup { - /// Security parameter - pub sec_param: u64, /// Approximate size of set Sp to lower bound pub n_p: u64, /// Proof size (in Sp elements) @@ -43,11 +41,10 @@ pub struct Setup { pub b: u64, } impl Setup { - fn param_small_case(params: &Params, u_f64: f64, sec_param: u64) -> Self { + fn param_small_case(params: &Params, u_f64: f64) -> Self { let ln12 = (12f64).ln(); let d = (32.0 * ln12 * u_f64).ceil(); Self { - sec_param, n_p: params.n_p, u: u_f64 as u64, r: params.lambda_rel as u64, @@ -57,12 +54,11 @@ impl Setup { } } - fn param_high_case(params: &Params, u_f64: f64, lambda_rel2: f64, sec_param: u64) -> Self { + fn param_high_case(params: &Params, u_f64: f64, lambda_rel2: f64) -> Self { let l2 = lambda_rel2 + 2.0; let d = (16.0 * u_f64 * l2 / LOG2_E).ceil(); debug_assert!(params.n_p as f64 >= d * d * LOG2_E / (9.0 * l2)); Self { - sec_param, n_p: params.n_p, u: u_f64 as u64, r: (params.lambda_rel / lambda_rel2).ceil() as u64, @@ -72,7 +68,7 @@ impl Setup { } } - fn param_mid_case(params: &Params, u_f64: f64, s1: f64, sec_param: u64) -> Self { + fn param_mid_case(params: &Params, u_f64: f64, s1: f64) -> Self { fn compute_w(u: f64, l: f64) -> f64 { fn factorial_check(w: f64, l: f64) -> bool { let bound = (-l).exp2(); @@ -104,7 +100,6 @@ impl Setup { let w = compute_w(u_f64, lambda_rel1); let exponential = (2.0 * u_f64 * w * lbar / params.n_p as f64 + 7.0 * u_f64 / w).exp(); Self { - sec_param, n_p: params.n_p, u: u_f64 as u64, r: (params.lambda_rel / lambda_rel1).ceil() as u64, @@ -116,7 +111,6 @@ impl Setup { /// Setup algorithm taking a Params as input and returning setup parameters (u,d,q) pub fn new(params: &Params) -> Self { - let sec_param = params.lambda_rel.max(params.lambda_sec).ceil() as u64; let n_p_f64 = params.n_p as f64; let n_f_f64 = params.n_f as f64; @@ -132,15 +126,15 @@ impl Setup { if s1 < 1.0 || s2 < 1.0 { // Small case, i.e. n_p <= λ^2 - Self::param_small_case(params, u_f64, sec_param) + Self::param_small_case(params, u_f64) } else { let lambda_rel2 = params.lambda_rel.min(s2); if u_f64 < lambda_rel2 { // Case 3, Theorem 14, i.e. n_p >= λ^3 - Self::param_high_case(params, u_f64, lambda_rel2, sec_param) + Self::param_high_case(params, u_f64, lambda_rel2) } else { // Case 2, Theorem 13, i.e. λ^3 > n_p > λ^2 - Self::param_mid_case(params, u_f64, s1, sec_param) + Self::param_mid_case(params, u_f64, s1) } } } @@ -166,26 +160,21 @@ struct Round { impl Round { /// Oracle producing a uniformly random value in [0, n_p[ used for round candidates /// We also return hash(data) to follow the optimization presented in Section 3.3 - fn h1( - first_input: &[u8], - second_input: &[u8], - n_p: u64, - sec_param: u64, - ) -> (Hash, Option) { + fn h1(first_input: &[u8], second_input: &[u8], n_p: u64) -> (Hash, Option) { let mut hasher = Blake2s256::new(); hasher.update(b"Telescope-H1"); hasher.update(first_input); hasher.update(second_input); let digest: Hash = hasher.finalize().into(); - (digest, utils::sample_uniform(&digest, n_p, sec_param)) + (digest, utils::sample_uniform(&digest, n_p)) } /// Output a round from a proof counter and n_p /// Initilialises the hash with H1(t) and random value as oracle(H1(t), n_p) - fn new(v: u64, t: u64, n_p: u64, sec_param: u64) -> Option { + fn new(v: u64, t: u64, n_p: u64) -> Option { let v_bytes: [u8; 8] = v.to_be_bytes(); let t_bytes: [u8; 8] = t.to_be_bytes(); - let (h, h_u64_opt) = Self::h1(&v_bytes, &t_bytes, n_p, sec_param); + let (h, h_u64_opt) = Self::h1(&v_bytes, &t_bytes, n_p); h_u64_opt.map(|h_u64| Self { v, t, @@ -198,10 +187,10 @@ impl Round { /// Updates a round with an element of S_p /// Replaces the hash $h$ with $h' = H1(h, s)$ and the random value as oracle(h', n_p) - fn update(r: &Self, s: Element, sec_param: u64) -> Option { + fn update(r: &Self, s: Element) -> Option { let mut s_list = r.s_list.clone(); s_list.push(s); - let (h, h_u64_opt) = Self::h1(&r.h, &s, r.n_p, sec_param); + let (h, h_u64_opt) = Self::h1(&r.h, &s, r.n_p); h_u64_opt.map(|h_u64| Self { v: r.v, t: r.t, @@ -233,7 +222,7 @@ impl Proof { hasher.update(v_bytes); hasher.update(s); let digest: Hash = hasher.finalize().into(); - utils::sample_uniform(&digest, setup.n_p, setup.sec_param) + utils::sample_uniform(&digest, setup.n_p) } /// Oracle defined as Bernoulli(q) returning 1 with probability q and 0 otherwise @@ -242,7 +231,7 @@ impl Proof { hasher.update(b"Telescope-H2"); hasher.update(r.h); let digest: Hash = hasher.finalize().into(); - utils::sample_bernoulli(&digest, setup.q, setup.sec_param) + utils::sample_bernoulli(&digest, setup.q) } /// Depth-First Search which goes through all potential round candidates @@ -275,7 +264,7 @@ impl Proof { if limit == setup.b { return (limit, None); } - if let Some(r) = Round::update(round, s, setup.sec_param) { + if let Some(r) = Round::update(round, s) { let (l, proof_opt) = Self::dfs(setup, bins, &r, limit.saturating_add(1)); if proof_opt.is_some() { return (l, proof_opt); @@ -309,7 +298,7 @@ impl Proof { if limit == setup.b { return (limit, None); } - if let Some(r) = Round::new(v, t, setup.n_p, setup.sec_param) { + if let Some(r) = Round::new(v, t, setup.n_p) { let (l, proof_opt) = Self::dfs(setup, &bins, &r, limit.saturating_add(1)); if proof_opt.is_some() { return (l, proof_opt); @@ -333,7 +322,7 @@ impl Proof { if proof.t >= setup.d || proof.v >= setup.r || proof.items.len() as u64 != setup.u { return false; } - let Some(mut round) = Round::new(proof.v, proof.t, setup.n_p, setup.sec_param) else { + let Some(mut round) = Round::new(proof.v, proof.t, setup.n_p) else { return false; }; for &element in &proof.items { @@ -341,7 +330,7 @@ impl Proof { return false; }; if round.h_u64 == h { - match Round::update(&round, element, setup.sec_param) { + match Round::update(&round, element) { Some(r) => round = r, None => return false, } diff --git a/src/utils.rs b/src/utils.rs index b52d033a..099dcbd6 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -4,10 +4,10 @@ use std::cmp::min; /// Takes as input a hash and range $n$ and samples an integer from Unif[0, n[. /// We do so by interpreting the hash as a random number and returns it modulo /// n (c.f. Appendix B, Alba paper). -pub(crate) fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option { +pub(crate) fn sample_uniform(hash: &[u8], n: u64) -> Option { // Computes the integer reprensation of hash* modulo n when n is not a // power of two. *(up to 8 bytes, in little endian) - fn mod_non_power_of_2(hash: &[u8], n: u64, sec_param: u64) -> Option { + fn mod_non_power_of_2(hash: &[u8], n: u64) -> Option { fn log_base2(x: u64) -> u64 { u64::from( u64::BITS @@ -15,7 +15,7 @@ pub(crate) fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option .saturating_sub(1), ) } - let epsilon_fail: u64 = 1 << sec_param; + let epsilon_fail: u64 = 1 << 40; // TODO: update let k = log_base2(n.saturating_mul(epsilon_fail)); let k_prime: u64 = 1 << k; let d = k_prime.div_ceil(n); @@ -38,17 +38,17 @@ pub(crate) fn sample_uniform(hash: &[u8], n: u64, sec_param: u64) -> Option if n.is_power_of_two() { Some(mod_power_of_2(hash, n)) } else { - mod_non_power_of_2(hash, n, sec_param) + mod_non_power_of_2(hash, n) } } /// Takes as input a hash and probability $q$ and returns true with /// probability q otherwise false according to a Bernoulli distribution /// (c.f. Appendix B, Alba paper). -pub(crate) fn sample_bernoulli(hash: &[u8], q: f64, sec_param: u64) -> bool { +pub(crate) fn sample_bernoulli(hash: &[u8], q: f64) -> bool { // For error parameter ɛ̝, find an approximation x/y of q with (x,y) in N² // such that 0 < q - x/y <= ɛ̝ - let epsilon_fail: u64 = 1 << sec_param; + let epsilon_fail: u64 = 1 << 40; // TOOD: update let mut x: u64 = q.ceil() as u64; let mut y: u64 = 1; while {