mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-08 11:35:02 -05:00
add concrete-cpu-noise-model crate
This commit is contained in:
11
Cargo.toml
Normal file
11
Cargo.toml
Normal file
@@ -0,0 +1,11 @@
|
||||
[package]
|
||||
# see https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
name = "concrete-cpu-noise-model"
|
||||
version = "0.1.0"
|
||||
authors = [""]
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
3
src/gaussian_noise.rs
Normal file
3
src/gaussian_noise.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod conversion;
|
||||
pub mod noise;
|
||||
pub mod security;
|
||||
15
src/gaussian_noise/conversion.rs
Normal file
15
src/gaussian_noise/conversion.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
fn modular_variance_variance_ratio(ciphertext_modulus_log: u32) -> f64 {
|
||||
2_f64.powi(2 * ciphertext_modulus_log as i32)
|
||||
}
|
||||
|
||||
pub fn modular_variance_to_variance(modular_variance: f64, ciphertext_modulus_log: u32) -> f64 {
|
||||
modular_variance / modular_variance_variance_ratio(ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
pub fn variance_to_modular_variance(variance: f64, ciphertext_modulus_log: u32) -> f64 {
|
||||
variance * modular_variance_variance_ratio(ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
pub fn variance_to_std_dev(variance: f64) -> f64 {
|
||||
variance.sqrt()
|
||||
}
|
||||
7
src/gaussian_noise/noise.rs
Normal file
7
src/gaussian_noise/noise.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
pub mod blind_rotate;
|
||||
pub mod cmux;
|
||||
pub mod external_product_glwe;
|
||||
pub mod keyswitch;
|
||||
pub mod keyswitch_one_bit;
|
||||
pub mod modulus_switching;
|
||||
pub mod private_packing_keyswitch;
|
||||
100
src/gaussian_noise/noise/blind_rotate.rs
Normal file
100
src/gaussian_noise/noise/blind_rotate.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use super::cmux::variance_cmux;
|
||||
|
||||
pub const FFT_SCALING_WEIGHT: f64 = -2.577_224_94;
|
||||
|
||||
/// Final reduced noise generated by the final bootstrap step.
|
||||
/// Note that it does not depends from input noise, assuming the bootstrap is successful
|
||||
pub fn variance_blind_rotate(
|
||||
in_lwe_dimension: u64,
|
||||
out_glwe_dimension: u64,
|
||||
out_polynomial_size: u64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_bsk: f64,
|
||||
) -> f64 {
|
||||
in_lwe_dimension as f64
|
||||
* variance_cmux(
|
||||
out_glwe_dimension,
|
||||
out_polynomial_size,
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::gaussian_noise::conversion::variance_to_modular_variance;
|
||||
use crate::gaussian_noise::security::minimal_variance_glwe;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn security_variance_bootstrap_1() {
|
||||
let ref_modular_variance = 4.078_296_369_990_673e31;
|
||||
|
||||
let polynomial_size = 1 << 12;
|
||||
let glwe_dimension = 2;
|
||||
|
||||
let ciphertext_modulus_log = 64;
|
||||
let security = 128;
|
||||
let variance_bsk = minimal_variance_glwe(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
);
|
||||
|
||||
let actual = variance_blind_rotate(
|
||||
2048,
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
24,
|
||||
2,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
);
|
||||
|
||||
approx::assert_relative_eq!(
|
||||
variance_to_modular_variance(actual, ciphertext_modulus_log),
|
||||
ref_modular_variance,
|
||||
max_relative = 1e-8
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn golden_python_prototype_security_variance_bootstrap_2() {
|
||||
// golden value include fft correction
|
||||
let golden_modular_variance = 3.269_722_907_894_341e55;
|
||||
|
||||
let polynomial_size = 1 << 12;
|
||||
let glwe_dimension = 4;
|
||||
|
||||
let ciphertext_modulus_log = 128;
|
||||
let security = 128;
|
||||
let variance_bsk = minimal_variance_glwe(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
);
|
||||
|
||||
let actual = variance_blind_rotate(
|
||||
1024,
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
5,
|
||||
9,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
);
|
||||
|
||||
approx::assert_relative_eq!(
|
||||
variance_to_modular_variance(actual, ciphertext_modulus_log),
|
||||
golden_modular_variance,
|
||||
max_relative = 1e-8
|
||||
);
|
||||
}
|
||||
}
|
||||
20
src/gaussian_noise/noise/cmux.rs
Normal file
20
src/gaussian_noise/noise/cmux.rs
Normal file
@@ -0,0 +1,20 @@
|
||||
use super::external_product_glwe::variance_external_product_glwe;
|
||||
|
||||
// only valid in the blind rotate case
|
||||
pub fn variance_cmux(
|
||||
glwe_dimension: u64,
|
||||
polynomial_size: u64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ggsw: f64,
|
||||
) -> f64 {
|
||||
variance_external_product_glwe(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_ggsw,
|
||||
)
|
||||
}
|
||||
84
src/gaussian_noise/noise/external_product_glwe.rs
Normal file
84
src/gaussian_noise/noise/external_product_glwe.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use crate::gaussian_noise::conversion::modular_variance_to_variance;
|
||||
use crate::utils::square;
|
||||
|
||||
pub fn variance_external_product_glwe(
|
||||
glwe_dimension: u64,
|
||||
polynomial_size: u64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ggsw: f64,
|
||||
) -> f64 {
|
||||
theoretical_variance_external_product_glwe(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_ggsw,
|
||||
) + fft_noise_variance_external_product_glwe(
|
||||
glwe_dimension,
|
||||
polynomial_size,
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
}
|
||||
|
||||
fn theoretical_variance_external_product_glwe(
|
||||
glwe_dimension: u64,
|
||||
polynomial_size: u64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ggsw: f64,
|
||||
) -> f64 {
|
||||
let variance_key_coefficient_binary: f64 =
|
||||
modular_variance_to_variance(1. / 4., ciphertext_modulus_log);
|
||||
|
||||
let square_expectation_key_coefficient_binary: f64 =
|
||||
modular_variance_to_variance(square(1. / 2.), ciphertext_modulus_log);
|
||||
|
||||
let k = glwe_dimension as f64;
|
||||
let b = 2_f64.powi(log2_base as i32);
|
||||
let b2l = 2_f64.powi((log2_base * 2 * level) as i32);
|
||||
let l = level as f64;
|
||||
let big_n = polynomial_size as f64;
|
||||
let q_square = 2_f64.powi(2 * ciphertext_modulus_log as i32);
|
||||
|
||||
let res_1 = l * (k + 1.) * big_n * (square(b) + 2.) / 12. * variance_ggsw;
|
||||
let res_2 = (q_square - b2l) / (24. * b2l)
|
||||
* (modular_variance_to_variance(1., ciphertext_modulus_log)
|
||||
+ k * big_n
|
||||
* (variance_key_coefficient_binary + square_expectation_key_coefficient_binary))
|
||||
+ k * big_n / 8. * variance_key_coefficient_binary
|
||||
+ 1. / 16. * square(1. - k * big_n) * square_expectation_key_coefficient_binary;
|
||||
|
||||
res_1 + res_2
|
||||
}
|
||||
|
||||
const FFT_SCALING_WEIGHT: f64 = -2.577_224_94;
|
||||
|
||||
/// Additional noise generated by fft computation
|
||||
|
||||
fn fft_noise_variance_external_product_glwe(
|
||||
glwe_dimension: u64,
|
||||
polynomial_size: u64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> f64 {
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/bootstrap.py#L25
|
||||
let b = 2_f64.powi(log2_base as i32);
|
||||
let l = level as f64;
|
||||
let big_n = polynomial_size as f64;
|
||||
let k = glwe_dimension;
|
||||
assert!(k > 0, "k = {k}");
|
||||
assert!(k < 7, "k = {k}");
|
||||
|
||||
// 22 = 2 x 11, 11 = 64 -53
|
||||
let scale_margin = (1_u64 << 22) as f64;
|
||||
let res =
|
||||
f64::exp2(FFT_SCALING_WEIGHT) * scale_margin * l * b * b * big_n.powi(2) * (k as f64 + 1.);
|
||||
modular_variance_to_variance(res, ciphertext_modulus_log)
|
||||
}
|
||||
76
src/gaussian_noise/noise/keyswitch.rs
Normal file
76
src/gaussian_noise/noise/keyswitch.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
use super::keyswitch_one_bit::variance_keyswitch_one_bit;
|
||||
|
||||
/// Additional noise generated by the keyswitch step.
|
||||
pub fn variance_keyswitch(
|
||||
input_lwe_dimension: u64, //n_big
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ksk: f64,
|
||||
) -> f64 {
|
||||
input_lwe_dimension as f64
|
||||
* variance_keyswitch_one_bit(log2_base, level, ciphertext_modulus_log, variance_ksk)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::gaussian_noise::conversion::variance_to_modular_variance;
|
||||
use crate::gaussian_noise::security::minimal_variance_lwe;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn golden_python_prototype_security_variance_keyswitch_1() {
|
||||
let golden_modular_variance = 5.997_880_135_602_194e68;
|
||||
let internal_ks_output_lwe_dimension = 1024;
|
||||
let ciphertext_modulus_log = 128;
|
||||
let security = 128;
|
||||
|
||||
let actual = variance_keyswitch(
|
||||
4096,
|
||||
5,
|
||||
9,
|
||||
ciphertext_modulus_log,
|
||||
minimal_variance_lwe(
|
||||
internal_ks_output_lwe_dimension,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
),
|
||||
);
|
||||
|
||||
approx::assert_relative_eq!(
|
||||
variance_to_modular_variance(actual, ciphertext_modulus_log),
|
||||
golden_modular_variance,
|
||||
max_relative = 1e-8
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn golden_python_prototype_security_variance_keyswitch_2() {
|
||||
// let golden_modular_variance = 8.580795457940938e+66;
|
||||
// the full npe implements a part of the full estimation
|
||||
let golden_modular_variance = 7.407_691_550_271_225e48; // full estimation
|
||||
let internal_ks_output_lwe_dimension = 512;
|
||||
let ciphertext_modulus_log = 64;
|
||||
let security = 128;
|
||||
|
||||
let actual = variance_keyswitch(
|
||||
2048,
|
||||
24,
|
||||
2,
|
||||
ciphertext_modulus_log,
|
||||
minimal_variance_lwe(
|
||||
internal_ks_output_lwe_dimension,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
),
|
||||
);
|
||||
|
||||
approx::assert_relative_eq!(
|
||||
variance_to_modular_variance(actual, ciphertext_modulus_log),
|
||||
golden_modular_variance,
|
||||
max_relative = 1e-8
|
||||
);
|
||||
}
|
||||
}
|
||||
32
src/gaussian_noise/noise/keyswitch_one_bit.rs
Normal file
32
src/gaussian_noise/noise/keyswitch_one_bit.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use crate::gaussian_noise::conversion::modular_variance_to_variance;
|
||||
use crate::utils::square;
|
||||
|
||||
/// Additional noise generated by the bit multiplication
|
||||
pub fn variance_keyswitch_one_bit(
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ksk: f64,
|
||||
) -> f64 {
|
||||
let variance_key_coefficient_binary: f64 =
|
||||
modular_variance_to_variance(1. / 4., ciphertext_modulus_log);
|
||||
|
||||
let square_expectation_key_coefficient_binary: f64 =
|
||||
modular_variance_to_variance(square(1. / 2.), ciphertext_modulus_log);
|
||||
|
||||
let base = 2_f64.powi(log2_base as i32);
|
||||
let b2l = 2_f64.powi((log2_base * 2 * level) as i32);
|
||||
let q_square = 2_f64.powi((2 * ciphertext_modulus_log) as i32);
|
||||
|
||||
// res 2
|
||||
let res_2 = (q_square / (12. * b2l) - 1. / 12.)
|
||||
* (variance_key_coefficient_binary + square_expectation_key_coefficient_binary);
|
||||
|
||||
// res 3
|
||||
let res_3 = 1. / 4. * variance_key_coefficient_binary;
|
||||
|
||||
// res 4
|
||||
let res_4 = (level as f64) * variance_ksk * (square(base) + 2.) / 12.;
|
||||
|
||||
res_2 + res_3 + res_4
|
||||
}
|
||||
16
src/gaussian_noise/noise/modulus_switching.rs
Normal file
16
src/gaussian_noise/noise/modulus_switching.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use crate::gaussian_noise::conversion::modular_variance_to_variance;
|
||||
use crate::utils::square;
|
||||
|
||||
pub fn estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_ks_output_lwe_dimension: u64,
|
||||
glwe_log2_polynomial_size: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> f64 {
|
||||
let nb_msb = glwe_log2_polynomial_size + 1;
|
||||
|
||||
let w = 2_f64.powi(nb_msb as i32);
|
||||
let n = internal_ks_output_lwe_dimension as f64;
|
||||
|
||||
(1. / 12. + n / 24.) / square(w)
|
||||
+ modular_variance_to_variance(-1. / 12. + n / 48., ciphertext_modulus_log)
|
||||
}
|
||||
39
src/gaussian_noise/noise/private_packing_keyswitch.rs
Normal file
39
src/gaussian_noise/noise/private_packing_keyswitch.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::gaussian_noise::conversion::modular_variance_to_variance;
|
||||
use crate::utils::square;
|
||||
|
||||
// packing private keyswitch for WoP-PBS, described in algorithm 3 of https://eprint.iacr.org/2018/421.pdf (TFHE paper)
|
||||
pub fn estimate_packing_private_keyswitch(
|
||||
var_glwe: f64,
|
||||
var_ggsw: f64,
|
||||
log2_base: u64,
|
||||
level: u64,
|
||||
output_glwe_dimension: u64,
|
||||
output_polynomial_size: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> f64 {
|
||||
let variance_key_coefficient_binary: f64 = 1. / 4.;
|
||||
let expectation_key_coefficient_binary: f64 = 1. / 2.;
|
||||
|
||||
let l = level as f64;
|
||||
let b = (1 << log2_base) as f64;
|
||||
let n = (output_glwe_dimension * output_polynomial_size) as f64; // param.internal_lwe_dimension.0 as f64;
|
||||
let b2l = f64::powi(b, 2 * level as i32);
|
||||
let var_s_w = 1. / 4.;
|
||||
let mean_s_w = 1. / 2.;
|
||||
let res_1 = l * (n + 1.) * var_ggsw * (square(b) + 2.) / 12.;
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let res_3 = (f64::powi(2., 2 * ciphertext_modulus_log as i32) - b2l) / (12. * b2l)
|
||||
* modular_variance_to_variance(
|
||||
1. + n * variance_key_coefficient_binary + square(expectation_key_coefficient_binary),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
+ n / 4.
|
||||
* modular_variance_to_variance(variance_key_coefficient_binary, ciphertext_modulus_log)
|
||||
+ var_glwe * (var_s_w + square(mean_s_w));
|
||||
|
||||
let res_5 = modular_variance_to_variance(var_s_w, ciphertext_modulus_log) * 1. / 4.
|
||||
* square(1. - n * expectation_key_coefficient_binary);
|
||||
|
||||
res_1 + res_3 + res_5
|
||||
}
|
||||
65
src/gaussian_noise/security.rs
Normal file
65
src/gaussian_noise/security.rs
Normal file
@@ -0,0 +1,65 @@
|
||||
mod security_weight;
|
||||
|
||||
pub use security_weight::{security_weight, supported_security_levels};
|
||||
|
||||
/// Noise ensuring security
|
||||
pub fn minimal_variance_lwe(
|
||||
lwe_dimension: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> f64 {
|
||||
minimal_variance_glwe(lwe_dimension, 1, ciphertext_modulus_log, security_level)
|
||||
}
|
||||
|
||||
/// Noise ensuring security
|
||||
pub fn minimal_variance_glwe(
|
||||
glwe_dimension: u64,
|
||||
polynomial_size: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> f64 {
|
||||
let equiv_lwe_dimension = glwe_dimension * polynomial_size;
|
||||
let security_weights = security_weight(security_level)
|
||||
.unwrap_or_else(|| panic!("{security_level} bits of security is not supported"));
|
||||
|
||||
let secure_log2_std =
|
||||
security_weights.secure_log2_std(equiv_lwe_dimension, ciphertext_modulus_log as f64);
|
||||
let log2_var = 2.0 * secure_log2_std;
|
||||
f64::exp2(log2_var)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::super::conversion::variance_to_std_dev;
|
||||
use super::minimal_variance_glwe;
|
||||
|
||||
#[test]
|
||||
fn golden_python_prototype_security_security_glwe_variance_low() {
|
||||
// python securityFunc(10,14,64)= 0.3120089883926036
|
||||
let integer_size = 64;
|
||||
let golden_std_dev = 2.168_404_344_971_009e-19;
|
||||
let security_level = 128;
|
||||
|
||||
let actual = minimal_variance_glwe(10, 1 << 14, integer_size, security_level);
|
||||
approx::assert_relative_eq!(
|
||||
golden_std_dev,
|
||||
variance_to_std_dev(actual),
|
||||
epsilon = f64::EPSILON
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn golden_python_prototype_security_security_glwe_variance_high() {
|
||||
// python securityFunc(3,8,32)= 2.6011445832514504
|
||||
let integer_size = 32;
|
||||
let golden_std_dev = 4.392_824_146_816_922_4e-6;
|
||||
let security_level = 128;
|
||||
|
||||
let actual = minimal_variance_glwe(3, 1 << 8, integer_size, security_level);
|
||||
approx::assert_relative_eq!(
|
||||
golden_std_dev,
|
||||
variance_to_std_dev(actual),
|
||||
epsilon = f64::EPSILON
|
||||
);
|
||||
}
|
||||
}
|
||||
116
src/gaussian_noise/security/security_weight.rs
Normal file
116
src/gaussian_noise/security/security_weight.rs
Normal file
@@ -0,0 +1,116 @@
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct SecurityWeights {
|
||||
slope: f64,
|
||||
bias: f64,
|
||||
minimal_lwe_dimension: u64,
|
||||
}
|
||||
|
||||
impl SecurityWeights {
|
||||
pub fn secure_log2_std(&self, lwe_dimension: u64, ciphertext_modulus_log: f64) -> f64 {
|
||||
// ensure to have a minimal on std deviation covering the 2 lowest bits on modular scale
|
||||
let epsilon_log2_std_modular = 2.0;
|
||||
let epsilon_log2_std = epsilon_log2_std_modular - (ciphertext_modulus_log);
|
||||
// ensure the requested lwe_dimension is bigger than the minimal lwe dimension
|
||||
if self.minimal_lwe_dimension <= lwe_dimension {
|
||||
f64::max(
|
||||
self.slope * lwe_dimension as f64 + self.bias,
|
||||
epsilon_log2_std,
|
||||
)
|
||||
} else {
|
||||
ciphertext_modulus_log
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Security curves generated using the lattice-estimator
|
||||
// (https://github.com/malb/lattice-estimator) on the 24th of June 2022
|
||||
const SECURITY_WEIGHTS_ARRAY: [(u64, SecurityWeights); 9] = [
|
||||
(
|
||||
80,
|
||||
SecurityWeights {
|
||||
slope: -0.040_426_331_193_645_89,
|
||||
bias: 1.660_978_864_143_672_2,
|
||||
minimal_lwe_dimension: 450,
|
||||
},
|
||||
),
|
||||
(
|
||||
96,
|
||||
SecurityWeights {
|
||||
slope: -0.034_147_803_608_670_51,
|
||||
bias: 2.017_310_258_660_345,
|
||||
minimal_lwe_dimension: 450,
|
||||
},
|
||||
),
|
||||
(
|
||||
112,
|
||||
SecurityWeights {
|
||||
slope: -0.029_670_137_081_135_885,
|
||||
bias: 2.162_463_714_083_856,
|
||||
minimal_lwe_dimension: 450,
|
||||
},
|
||||
),
|
||||
(
|
||||
128,
|
||||
SecurityWeights {
|
||||
slope: -0.026_405_028_765_226_22,
|
||||
bias: 2.482_642_269_104_317_7,
|
||||
minimal_lwe_dimension: 450,
|
||||
},
|
||||
),
|
||||
(
|
||||
144,
|
||||
SecurityWeights {
|
||||
slope: -0.023_821_437_305_989_134,
|
||||
bias: 2.717_778_944_063_667_3,
|
||||
minimal_lwe_dimension: 450,
|
||||
},
|
||||
),
|
||||
(
|
||||
160,
|
||||
SecurityWeights {
|
||||
slope: -0.021_743_582_187_160_36,
|
||||
bias: 2.938_810_548_493_322,
|
||||
minimal_lwe_dimension: 498,
|
||||
},
|
||||
),
|
||||
(
|
||||
176,
|
||||
SecurityWeights {
|
||||
slope: -0.019_904_056_582_117_684,
|
||||
bias: 2.816_125_280_154_224_7,
|
||||
minimal_lwe_dimension: 551,
|
||||
},
|
||||
),
|
||||
(
|
||||
192,
|
||||
SecurityWeights {
|
||||
slope: -0.018_610_403_247_590_085,
|
||||
bias: 3.299_623_684_839_900_8,
|
||||
minimal_lwe_dimension: 606,
|
||||
},
|
||||
),
|
||||
(
|
||||
256,
|
||||
SecurityWeights {
|
||||
slope: -0.014_606_812_351_714_953,
|
||||
bias: 3.849_362_923_469_300_3,
|
||||
minimal_lwe_dimension: 826,
|
||||
},
|
||||
),
|
||||
];
|
||||
|
||||
pub fn supported_security_levels() -> impl std::iter::Iterator<Item = u64> {
|
||||
SECURITY_WEIGHTS_ARRAY
|
||||
.iter()
|
||||
.map(|(security_level, _)| *security_level)
|
||||
}
|
||||
|
||||
pub fn security_weight(security_level: u64) -> Option<SecurityWeights> {
|
||||
let index = SECURITY_WEIGHTS_ARRAY
|
||||
.binary_search_by_key(&security_level, |(security_level, _weights)| {
|
||||
*security_level
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
Some(SECURITY_WEIGHTS_ARRAY[index].1)
|
||||
}
|
||||
23
src/lib.rs
Normal file
23
src/lib.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
#![warn(clippy::nursery)]
|
||||
#![warn(clippy::pedantic)]
|
||||
#![warn(clippy::style)]
|
||||
#![allow(clippy::cast_lossless)]
|
||||
#![allow(clippy::cast_precision_loss)] // u64 to f64
|
||||
#![allow(clippy::cast_possible_truncation)] // u64 to usize
|
||||
#![allow(clippy::missing_panics_doc)]
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
#![allow(clippy::must_use_candidate)]
|
||||
#![allow(clippy::suboptimal_flops)]
|
||||
#![allow(clippy::cast_possible_wrap)]
|
||||
#![warn(unused_results)]
|
||||
|
||||
pub mod gaussian_noise;
|
||||
|
||||
pub(crate) mod utils {
|
||||
pub fn square<V>(v: V) -> V
|
||||
where
|
||||
V: std::ops::Mul<Output = V> + Copy,
|
||||
{
|
||||
v * v
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user