mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-09 12:15:09 -05:00
feat(dep): concrete-cpu-noise-model
This commit is contained in:
@@ -6,8 +6,7 @@ edition = "2021"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
concrete-commons = { git = "ssh://git@github.com/zama-ai/concrete-core.git", rev = "715d4a18a59d13a5a51fee14bc1f6578de665c20" }
|
||||
concrete-npe = { git = "ssh://git@github.com/zama-ai/concrete-core.git", rev = "715d4a18a59d13a5a51fee14bc1f6578de665c20" }
|
||||
concrete-cpu-noise-model = { git = "ssh://git@github.com/zama-ai/concrete-cpu.git", rev = "c185266e55f31b7d4c6e3264d9569eb03b4a785e" }
|
||||
file-lock = "2.1.6"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
bincode = "1.3"
|
||||
|
||||
@@ -24,6 +24,7 @@ pub mod global_parameters;
|
||||
pub mod noise_estimator;
|
||||
pub mod optimization;
|
||||
pub mod parameters;
|
||||
pub mod security;
|
||||
pub mod utils;
|
||||
pub mod weight;
|
||||
|
||||
pub use concrete_cpu_noise_model::gaussian_noise::security::supported_security_levels;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_cpu_noise_model::gaussian_noise::conversion::modular_variance_to_variance;
|
||||
|
||||
use crate::utils::square;
|
||||
|
||||
@@ -33,7 +33,7 @@ fn safe_variance_bound_from_p_error(
|
||||
let safe_sigma = fatal_noise_limit / kappa;
|
||||
let modular_variance = square(safe_sigma);
|
||||
|
||||
Variance::from_modular_variance(modular_variance, ciphertext_modulus_log).get_variance()
|
||||
modular_variance_to_variance(modular_variance, ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
pub fn safe_variance_bound_2padbits(
|
||||
|
||||
@@ -1,152 +1,20 @@
|
||||
use crate::global_parameters::DEFAUT_DOMAINS;
|
||||
use crate::parameters::{
|
||||
AtomicPatternParameters, BrDecompositionParameters, CmuxParameters, GlweParameters,
|
||||
KeyswitchParameters, PbsParameters,
|
||||
};
|
||||
use crate::{parameters, security};
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_commons::key_kinds::BinaryKeyKind;
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
use concrete_commons::parameters::{
|
||||
DecompositionBaseLog, DecompositionLevelCount, GlweDimension, LweDimension, PolynomialSize,
|
||||
};
|
||||
use crate::parameters::AtomicPatternParameters;
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::keyswitch::variance_keyswitch;
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::modulus_switching::estimate_modulus_switching_noise_with_binary_key;
|
||||
use concrete_cpu_noise_model::gaussian_noise::security::minimal_variance_lwe;
|
||||
|
||||
const FFT_SCALING_WEIGHT: f64 = -2.577_224_94;
|
||||
|
||||
/// Additional noise generated by the keyswitch step.
|
||||
pub fn variance_keyswitch(
|
||||
param: KeyswitchParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ksk: Variance,
|
||||
) -> Variance {
|
||||
concrete_npe::estimate_keyswitch_noise_lwe_to_glwe_with_constant_terms::<
|
||||
Variance,
|
||||
Variance,
|
||||
BinaryKeyKind,
|
||||
>(
|
||||
LweDimension(param.input_lwe_dimension.0 as usize),
|
||||
Variance(0.0),
|
||||
variance_ksk,
|
||||
DecompositionBaseLog(param.ks_decomposition_parameter.log2_base as usize),
|
||||
DecompositionLevelCount(param.ks_decomposition_parameter.level as usize),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute the variance parameter of the keyswitch key.
|
||||
pub fn variance_ksk(
|
||||
internal_ks_output_lwe_dimension: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance {
|
||||
let glwe_params = GlweParameters {
|
||||
log2_polynomial_size: 0,
|
||||
glwe_dimension: internal_ks_output_lwe_dimension,
|
||||
};
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/keyswitch.py#L13
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security_level)
|
||||
}
|
||||
|
||||
/// Additional noise generated by fft computation
|
||||
pub fn fft_noise(
|
||||
internal_ks_output_lwe_dimension: u64, //n_small
|
||||
glwe_params: GlweParameters,
|
||||
br_decomposition_parameter: BrDecompositionParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Variance {
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/bootstrap.py#L25
|
||||
let n = internal_ks_output_lwe_dimension as f64;
|
||||
let b = 2_f64.powi(br_decomposition_parameter.log2_base as i32);
|
||||
let l = br_decomposition_parameter.level as f64;
|
||||
let big_n = glwe_params.polynomial_size() as f64;
|
||||
let k = glwe_params.glwe_dimension;
|
||||
assert!(k > 0, "k = {k}");
|
||||
assert!(
|
||||
DEFAUT_DOMAINS.glwe_pbs_constrained.glwe_dimension.end > k,
|
||||
"k={} and bound={}",
|
||||
k,
|
||||
DEFAUT_DOMAINS.glwe_pbs_constrained.glwe_dimension.end
|
||||
);
|
||||
// 22 = 2 x 11, 11 = 64 -53
|
||||
let scale_margin = (1_u64 << 22) as f64;
|
||||
let res = n
|
||||
* f64::exp2(FFT_SCALING_WEIGHT)
|
||||
* scale_margin
|
||||
* l
|
||||
* b
|
||||
* b
|
||||
* big_n.powf(2.)
|
||||
* (k as f64 + 1.);
|
||||
Variance::from_modular_variance(res, ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
/// 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_bootstrap(
|
||||
param: PbsParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_bsk: Variance,
|
||||
) -> Variance {
|
||||
let out_variance_pbs = concrete_npe::estimate_pbs_noise::<Variance, BinaryKeyKind>(
|
||||
LweDimension(param.internal_lwe_dimension.0 as usize),
|
||||
PolynomialSize(param.output_glwe_params.polynomial_size() as usize),
|
||||
GlweDimension(param.output_glwe_params.glwe_dimension as usize),
|
||||
DecompositionBaseLog(param.br_decomposition_parameter.log2_base as usize),
|
||||
DecompositionLevelCount(param.br_decomposition_parameter.level as usize),
|
||||
variance_bsk,
|
||||
ciphertext_modulus_log,
|
||||
);
|
||||
|
||||
let additional_fft_noise = fft_noise(
|
||||
param.internal_lwe_dimension.0,
|
||||
param.output_glwe_params,
|
||||
param.br_decomposition_parameter,
|
||||
ciphertext_modulus_log,
|
||||
);
|
||||
Variance(out_variance_pbs.get_variance() + additional_fft_noise.get_variance())
|
||||
}
|
||||
|
||||
pub fn variance_cmux(
|
||||
cmux_params: CmuxParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_bsk: Variance,
|
||||
) -> Variance {
|
||||
let pbs_params = PbsParameters {
|
||||
internal_lwe_dimension: parameters::LweDimension(1),
|
||||
br_decomposition_parameter: cmux_params.br_decomposition_parameter,
|
||||
output_glwe_params: cmux_params.output_glwe_params,
|
||||
};
|
||||
variance_bootstrap(pbs_params, ciphertext_modulus_log, variance_bsk)
|
||||
}
|
||||
|
||||
pub fn estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_ks_output_lwe_dimension: u64,
|
||||
glwe_polynomial_size: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Variance {
|
||||
#[allow(clippy::cast_sign_loss)]
|
||||
let nb_msb = (f64::log2(glwe_polynomial_size as f64) as usize) + 1;
|
||||
concrete_npe::estimate_modulus_switching_noise_with_binary_key::<Variance>(
|
||||
LweDimension(internal_ks_output_lwe_dimension as usize),
|
||||
nb_msb,
|
||||
Variance(0.0),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn maximal_noise<D>(
|
||||
input_variance: Variance,
|
||||
pub fn maximal_noise(
|
||||
input_variance: f64,
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u32, //log(q)
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
D: DispersionParameter,
|
||||
{
|
||||
) -> f64 {
|
||||
let v_keyswitch = variance_keyswitch(
|
||||
param.ks_parameters(),
|
||||
param.input_lwe_dimension.0,
|
||||
param.ks_decomposition_parameter.log2_base,
|
||||
param.ks_decomposition_parameter.level,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
minimal_variance_lwe(
|
||||
param.internal_lwe_dimension.0,
|
||||
ciphertext_modulus_log,
|
||||
security_level,
|
||||
@@ -154,182 +22,8 @@ where
|
||||
);
|
||||
let v_modulus_switch = estimate_modulus_switching_noise_with_binary_key(
|
||||
param.internal_lwe_dimension.0,
|
||||
param.output_glwe_params.polynomial_size(),
|
||||
param.output_glwe_params.log2_polynomial_size,
|
||||
ciphertext_modulus_log,
|
||||
);
|
||||
Variance(
|
||||
input_variance.get_variance()
|
||||
+ v_keyswitch.get_variance()
|
||||
+ v_modulus_switch.get_variance(),
|
||||
)
|
||||
}
|
||||
|
||||
/// The maximal noise is attained at the end of the modulus switch.
|
||||
pub fn maximal_noise_multi_sum<D, W, Ignored>(
|
||||
dispersions: &[D],
|
||||
weights_tuples: &[(W, Ignored)],
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
D: DispersionParameter,
|
||||
W: UnsignedInteger,
|
||||
{
|
||||
let v_out_multi_sum = if dispersions.is_empty() {
|
||||
let mut weights = vec![];
|
||||
for (weight, _) in weights_tuples.iter() {
|
||||
weights.push(*weight);
|
||||
}
|
||||
concrete_npe::estimate_weighted_sum_noise(dispersions, weights.as_slice())
|
||||
} else {
|
||||
Variance(0.0)
|
||||
};
|
||||
maximal_noise::<D>(
|
||||
v_out_multi_sum,
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
security_level,
|
||||
)
|
||||
}
|
||||
|
||||
/// The output noise is the variance boostrap.
|
||||
pub fn output_noise<D, W>(
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
D: DispersionParameter,
|
||||
W: UnsignedInteger,
|
||||
{
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/bootstrap.py#L66
|
||||
let variance_bsk = security::glwe::minimal_variance(
|
||||
param.output_glwe_params,
|
||||
ciphertext_modulus_log,
|
||||
security_level,
|
||||
);
|
||||
variance_bootstrap(param.pbs_parameters(), ciphertext_modulus_log, variance_bsk)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::parameters::{
|
||||
BrDecompositionParameters, GlweParameters, KsDecompositionParameters, LweDimension,
|
||||
};
|
||||
|
||||
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 param = KeyswitchParameters {
|
||||
input_lwe_dimension: LweDimension(4096),
|
||||
output_lwe_dimension: LweDimension(internal_ks_output_lwe_dimension),
|
||||
ks_decomposition_parameter: KsDecompositionParameters {
|
||||
level: 9,
|
||||
log2_base: 5,
|
||||
},
|
||||
};
|
||||
|
||||
let actual = variance_keyswitch(
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
internal_ks_output_lwe_dimension,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
),
|
||||
)
|
||||
.get_modular_variance(128);
|
||||
approx::assert_relative_eq!(actual, 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 param = KeyswitchParameters {
|
||||
input_lwe_dimension: LweDimension(2048),
|
||||
output_lwe_dimension: LweDimension(internal_ks_output_lwe_dimension),
|
||||
ks_decomposition_parameter: KsDecompositionParameters {
|
||||
level: 2,
|
||||
log2_base: 24,
|
||||
},
|
||||
};
|
||||
|
||||
let actual = variance_keyswitch(
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
internal_ks_output_lwe_dimension,
|
||||
ciphertext_modulus_log,
|
||||
security,
|
||||
),
|
||||
)
|
||||
.get_modular_variance(64);
|
||||
approx::assert_relative_eq!(actual, golden_modular_variance, max_relative = 1e-8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn security_variance_bootstrap_1() {
|
||||
let ref_modular_variance = 4.078_296_369_990_673e31;
|
||||
let glwe_params = GlweParameters {
|
||||
log2_polynomial_size: 12,
|
||||
glwe_dimension: 2,
|
||||
};
|
||||
let ciphertext_modulus_log = 64;
|
||||
let security = 128;
|
||||
let variance_bsk =
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security);
|
||||
|
||||
let param = PbsParameters {
|
||||
internal_lwe_dimension: LweDimension(2048),
|
||||
br_decomposition_parameter: BrDecompositionParameters {
|
||||
level: 2,
|
||||
log2_base: 24,
|
||||
},
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let actual = variance_bootstrap(param, ciphertext_modulus_log, variance_bsk)
|
||||
.get_modular_variance(64);
|
||||
approx::assert_relative_eq!(actual, 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 glwe_params = GlweParameters {
|
||||
log2_polynomial_size: 12,
|
||||
glwe_dimension: 4,
|
||||
};
|
||||
let ciphertext_modulus_log = 128;
|
||||
let security = 128;
|
||||
let variance_bsk =
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security);
|
||||
|
||||
let param = PbsParameters {
|
||||
internal_lwe_dimension: LweDimension(1024),
|
||||
br_decomposition_parameter: BrDecompositionParameters {
|
||||
level: 9,
|
||||
log2_base: 5,
|
||||
},
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let actual = variance_bootstrap(param, ciphertext_modulus_log, variance_bsk)
|
||||
.get_modular_variance(128);
|
||||
approx::assert_relative_eq!(actual, golden_modular_variance, max_relative = 1e-8);
|
||||
}
|
||||
input_variance + v_keyswitch + v_modulus_switch
|
||||
}
|
||||
|
||||
@@ -1,42 +1 @@
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_commons::key_kinds::BinaryKeyKind;
|
||||
use concrete_npe::KeyDispersion;
|
||||
|
||||
use crate::parameters::CmuxParameters;
|
||||
use crate::utils::square;
|
||||
|
||||
pub fn estimate_packing_private_keyswitch<T>(
|
||||
var_glwe: Variance,
|
||||
var_ggsw: Variance,
|
||||
param: CmuxParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Variance {
|
||||
type K = BinaryKeyKind;
|
||||
let l = param.br_decomposition_parameter.level as f64;
|
||||
let b = (1 << param.br_decomposition_parameter.log2_base) as f64;
|
||||
let n = (param.output_glwe_params.glwe_dimension * param.output_glwe_params.polynomial_size())
|
||||
as f64; // param.internal_lwe_dimension.0 as f64;
|
||||
let b2l = f64::powf(b, 2. * l);
|
||||
let var_s_w = 1. / 4.;
|
||||
let mean_s_w = 1. / 2.;
|
||||
// println!("n = {}", n);
|
||||
let res_1 = (l * (n + 1.) * var_ggsw.get_modular_variance(ciphertext_modulus_log))
|
||||
* (square(b) + 2.)
|
||||
/ 12.;
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let res_3 = ((square(f64::powi(2., ciphertext_modulus_log as i32)) - b2l) / (12. * b2l)
|
||||
* (1.
|
||||
+ n * (K::variance_key_coefficient(ciphertext_modulus_log)
|
||||
.get_modular_variance(ciphertext_modulus_log)
|
||||
+ square(K::expectation_key_coefficient())))
|
||||
+ n / 4.
|
||||
* K::variance_key_coefficient(ciphertext_modulus_log)
|
||||
.get_modular_variance(ciphertext_modulus_log)
|
||||
+ var_glwe.get_modular_variance(ciphertext_modulus_log))
|
||||
* (var_s_w + square(mean_s_w));
|
||||
|
||||
let res_5 = var_s_w * (1. / 4. * square(1. - n * K::expectation_key_coefficient()));
|
||||
|
||||
Variance::from_modular_variance(res_1 + res_3 + res_5, ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::modulus_switching::estimate_modulus_switching_noise_with_binary_key;
|
||||
|
||||
use super::config::{Config, SearchSpace};
|
||||
use super::wop_atomic_pattern::optimize::find_p_error;
|
||||
use crate::noise_estimator::error;
|
||||
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
|
||||
use crate::parameters::{BrDecompositionParameters, GlweParameters, KsDecompositionParameters};
|
||||
use crate::utils::square;
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
|
||||
use super::decomposition::{
|
||||
blind_rotate, circuit_bootstrap, keyswitch, pp_switch, DecompCaches, PersistDecompCaches,
|
||||
@@ -58,13 +59,11 @@ fn update_state_with_best_decompositions(
|
||||
) {
|
||||
let glwe_poly_size = glwe_params.polynomial_size();
|
||||
let input_lwe_dimension = glwe_params.glwe_dimension * glwe_poly_size;
|
||||
let noise_modulus_switching =
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_poly_size,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
let noise_modulus_switching = estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_params.log2_polynomial_size,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
);
|
||||
let safe_variance = consts.safe_variance;
|
||||
if CUTS && noise_modulus_switching > safe_variance {
|
||||
return;
|
||||
@@ -111,9 +110,7 @@ fn update_state_with_best_decompositions(
|
||||
}
|
||||
// feasible and at least as good complexity
|
||||
if complexity < best_complexity || noise_max < best_variance {
|
||||
let sigma = Variance(safe_variance).get_standard_dev() * consts.kappa;
|
||||
let sigma_scale = sigma / Variance(noise_max).get_standard_dev();
|
||||
let p_error = error::error_probability_of_sigma_scale(sigma_scale);
|
||||
let p_error = find_p_error(consts.kappa, safe_variance, noise_max);
|
||||
|
||||
let BrDecompositionParameters {
|
||||
level: br_l,
|
||||
@@ -188,15 +185,13 @@ pub fn optimize_one(
|
||||
// cut only on glwe_poly_size based of modulus switching noise
|
||||
// assume this noise is increasing with lwe_intern_dim
|
||||
let min_internal_lwe_dimensions = search_space.internal_lwe_dimensions[0];
|
||||
let lower_bound_cut = |glwe_poly_size| {
|
||||
let lower_bound_cut = |glwe_log_poly_size| {
|
||||
// TODO: cut if min complexity is higher than current best
|
||||
CUTS && noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
CUTS && estimate_modulus_switching_noise_with_binary_key(
|
||||
min_internal_lwe_dimensions,
|
||||
glwe_poly_size,
|
||||
glwe_log_poly_size,
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance()
|
||||
> consts.safe_variance
|
||||
) > consts.safe_variance
|
||||
};
|
||||
|
||||
let mut caches = persistent_caches.caches();
|
||||
@@ -205,8 +200,7 @@ pub fn optimize_one(
|
||||
for &glwe_log_poly_size in &search_space.glwe_log_polynomial_sizes {
|
||||
assert!(8 <= glwe_log_poly_size);
|
||||
assert!(glwe_log_poly_size < 18);
|
||||
let glwe_poly_size = 1 << glwe_log_poly_size;
|
||||
if lower_bound_cut(glwe_poly_size) {
|
||||
if lower_bound_cut(glwe_log_poly_size) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::modulus_switching::estimate_modulus_switching_noise_with_binary_key;
|
||||
|
||||
use super::analyze;
|
||||
use crate::dag::operator::{LevelledComplexity, Precision};
|
||||
use crate::dag::unparametrized;
|
||||
use crate::noise_estimator::error;
|
||||
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
|
||||
use crate::optimization::atomic_pattern::{
|
||||
OptimizationDecompositionsConsts, OptimizationState, Solution,
|
||||
};
|
||||
use crate::optimization::config::{Config, NoiseBoundConfig, SearchSpace};
|
||||
use crate::optimization::decomposition::{DecompCaches, PersistDecompCaches};
|
||||
use crate::parameters::GlweParameters;
|
||||
use crate::security;
|
||||
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn update_best_solution_with_best_decompositions(
|
||||
@@ -195,12 +193,7 @@ fn update_no_luts_solution(
|
||||
}
|
||||
|
||||
fn minimal_variance(config: &Config, glwe_params: GlweParameters) -> f64 {
|
||||
security::glwe::minimal_variance(
|
||||
glwe_params,
|
||||
config.ciphertext_modulus_log,
|
||||
config.security_level,
|
||||
)
|
||||
.get_variance()
|
||||
glwe_params.minimal_variance(config.ciphertext_modulus_log, config.security_level)
|
||||
}
|
||||
|
||||
fn optimize_no_luts(
|
||||
@@ -269,13 +262,12 @@ pub fn optimize(
|
||||
}
|
||||
let mut caches = persistent_caches.caches();
|
||||
|
||||
let noise_modulus_switching = |glwe_poly_size, internal_lwe_dimensions| {
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
let noise_modulus_switching = |glwe_log2_poly_size, internal_lwe_dimensions| {
|
||||
estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_lwe_dimensions,
|
||||
glwe_poly_size,
|
||||
glwe_log2_poly_size,
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance()
|
||||
};
|
||||
|
||||
let not_feasible = |input_noise_out, noise_modulus_switching| {
|
||||
@@ -290,8 +282,8 @@ pub fn optimize(
|
||||
};
|
||||
let input_noise_out = minimal_variance(&config, glwe_params);
|
||||
for &internal_dim in &search_space.internal_lwe_dimensions {
|
||||
let glwe_poly_size = 1 << glwe_log_poly_size;
|
||||
let noise_modulus_switching = noise_modulus_switching(glwe_poly_size, internal_dim);
|
||||
let noise_modulus_switching =
|
||||
noise_modulus_switching(glwe_log_poly_size, internal_dim);
|
||||
if not_feasible(input_noise_out, noise_modulus_switching) {
|
||||
// noise_modulus_switching is increasing with internal_dim
|
||||
break;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
|
||||
use crate::computing_cost::complexity_model::ComplexityModel;
|
||||
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
|
||||
use crate::config;
|
||||
use crate::parameters::{BrDecompositionParameters, GlweParameters, LweDimension, PbsParameters};
|
||||
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
|
||||
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
|
||||
use crate::{config, security};
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::blind_rotate::variance_blind_rotate;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::common::{MacroParam, VERSION};
|
||||
|
||||
@@ -30,16 +26,8 @@ pub fn pareto_quantities(
|
||||
max_log2_base: u64,
|
||||
) -> Vec<BrComplexityNoise> {
|
||||
assert!(ciphertext_modulus_log == 64);
|
||||
let pbs_param = |level, log2_base| {
|
||||
let br_decomposition_parameter = BrDecompositionParameters { level, log2_base };
|
||||
PbsParameters {
|
||||
internal_lwe_dimension: LweDimension(internal_dim),
|
||||
br_decomposition_parameter,
|
||||
output_glwe_params: glwe_params,
|
||||
}
|
||||
};
|
||||
let variance_bsk =
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security_level);
|
||||
|
||||
let variance_bsk = glwe_params.minimal_variance(ciphertext_modulus_log, security_level);
|
||||
|
||||
let mut quantities = Vec::with_capacity(max_log2_base as usize);
|
||||
let mut increasing_complexity = 0.0;
|
||||
@@ -58,12 +46,15 @@ pub fn pareto_quantities(
|
||||
let range = (1..=prev_best_log2_base).rev();
|
||||
|
||||
for log2_base in range {
|
||||
let base_noise = noise_atomic_pattern::variance_bootstrap(
|
||||
pbs_param(level, log2_base),
|
||||
let base_noise = variance_blind_rotate(
|
||||
internal_dim,
|
||||
glwe_params.glwe_dimension,
|
||||
glwe_params.polynomial_size(),
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
)
|
||||
.get_variance();
|
||||
);
|
||||
if base_noise > level_decreasing_base_noise {
|
||||
break;
|
||||
}
|
||||
@@ -81,7 +72,17 @@ pub fn pareto_quantities(
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let params = pbs_param(level, best_log2_base);
|
||||
|
||||
let br_decomposition_parameter = BrDecompositionParameters {
|
||||
level,
|
||||
log2_base: best_log2_base,
|
||||
};
|
||||
let params = PbsParameters {
|
||||
internal_lwe_dimension: LweDimension(internal_dim),
|
||||
br_decomposition_parameter,
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let complexity_pbs = complexity_model.pbs_complexity(params, ciphertext_modulus_log);
|
||||
|
||||
quantities.push(BrComplexityNoise {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::cmux::variance_cmux;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::computing_cost::complexity_model::ComplexityModel;
|
||||
use crate::config;
|
||||
use crate::noise_estimator::operators::atomic_pattern::variance_cmux;
|
||||
use crate::parameters::{BrDecompositionParameters, CmuxParameters, GlweParameters};
|
||||
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
|
||||
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
|
||||
@@ -62,8 +61,14 @@ pub fn pareto_quantities(
|
||||
|
||||
// Compute bias and slove for variance_one_external_product_for_cmux_tree_bias
|
||||
let variance = |variance_bsk| {
|
||||
let variance_bsk = Variance::from_variance(variance_bsk);
|
||||
variance_cmux(params, ciphertext_modulus_log, variance_bsk).get_variance()
|
||||
variance_cmux(
|
||||
glwe_params.glwe_dimension,
|
||||
glwe_params.polynomial_size(),
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
)
|
||||
};
|
||||
let variance_at_0 = variance(0.0);
|
||||
let variance_at_1 = variance(1.0);
|
||||
|
||||
@@ -1,19 +1,15 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
|
||||
use super::common::{MacroParam, VERSION};
|
||||
use crate::computing_cost::complexity_model::ComplexityModel;
|
||||
use crate::config;
|
||||
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
|
||||
use crate::parameters::{
|
||||
GlweParameters, KeyswitchParameters, KsDecompositionParameters, LweDimension,
|
||||
};
|
||||
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
|
||||
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
|
||||
|
||||
use super::common::{MacroParam, VERSION};
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::keyswitch::variance_keyswitch;
|
||||
use concrete_cpu_noise_model::gaussian_noise::security::minimal_variance_lwe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct KsComplexityNoise {
|
||||
@@ -41,8 +37,7 @@ pub fn pareto_quantities(
|
||||
ks_decomposition_parameter,
|
||||
}
|
||||
};
|
||||
let variance_ksk =
|
||||
noise_atomic_pattern::variance_ksk(internal_dim, ciphertext_modulus_log, security_level);
|
||||
let variance_ksk = minimal_variance_lwe(internal_dim, ciphertext_modulus_log, security_level);
|
||||
|
||||
let mut quantities = Vec::with_capacity(64);
|
||||
let mut increasing_complexity = 0.0;
|
||||
@@ -61,12 +56,13 @@ pub fn pareto_quantities(
|
||||
let range = (1..=prev_best_log2_base).rev();
|
||||
|
||||
for log2_base in range {
|
||||
let noise_keyswitch = noise_atomic_pattern::variance_keyswitch(
|
||||
ks_param(level, log2_base),
|
||||
let noise_keyswitch = variance_keyswitch(
|
||||
input_lwe_dimension,
|
||||
log2_base,
|
||||
level,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk,
|
||||
)
|
||||
.get_variance();
|
||||
);
|
||||
if noise_keyswitch > level_decreasing_base_noise {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::blind_rotate;
|
||||
use super::common::{MacroParam, VERSION};
|
||||
use crate::computing_cost::complexity_model::ComplexityModel;
|
||||
|
||||
use crate::noise_estimator::operators::wop_atomic_pattern::estimate_packing_private_keyswitch;
|
||||
use crate::config;
|
||||
use crate::parameters::{
|
||||
BrDecompositionParameters, CmuxParameters, GlweParameters, KeyswitchParameters,
|
||||
KsDecompositionParameters, LweDimension,
|
||||
BrDecompositionParameters, GlweParameters, KeyswitchParameters, KsDecompositionParameters,
|
||||
LweDimension,
|
||||
};
|
||||
use crate::utils::cache::ephemeral::{CacheHashMap, EphemeralCache};
|
||||
use crate::utils::cache::persistent::{default_cache_dir, PersistentCacheHashMap};
|
||||
use crate::{config, security};
|
||||
|
||||
use super::blind_rotate;
|
||||
use super::common::{MacroParam, VERSION};
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::private_packing_keyswitch::estimate_packing_private_keyswitch;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct PpSwitchComplexityNoise {
|
||||
@@ -46,24 +41,22 @@ pub fn pareto_quantities(
|
||||
glwe_params: GlweParameters,
|
||||
br_quantities: &[blind_rotate::BrComplexityNoise],
|
||||
) -> Vec<PpSwitchComplexityNoise> {
|
||||
let variance_bsk =
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security_level);
|
||||
let variance_bsk = glwe_params.minimal_variance(ciphertext_modulus_log, security_level);
|
||||
let mut result = Vec::with_capacity(br_quantities.len());
|
||||
for br in br_quantities {
|
||||
let pp_ks_decomposition_parameter = br.decomp;
|
||||
let ppks_parameter = CmuxParameters {
|
||||
br_decomposition_parameter: pp_ks_decomposition_parameter,
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
// We assume the packing KS and the external product in a PBSto have
|
||||
// the same parameters (base, level)
|
||||
let variance_private_packing_ks = estimate_packing_private_keyswitch::<u64>(
|
||||
Variance(0.),
|
||||
let variance_private_packing_ks = estimate_packing_private_keyswitch(
|
||||
0.,
|
||||
variance_bsk,
|
||||
ppks_parameter,
|
||||
pp_ks_decomposition_parameter.log2_base,
|
||||
pp_ks_decomposition_parameter.level,
|
||||
glwe_params.glwe_dimension,
|
||||
glwe_params.polynomial_size(),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
);
|
||||
|
||||
let sample_extract_lwe_dimension = LweDimension(glwe_params.sample_extract_lwe_dimension());
|
||||
let ppks_parameter_complexity = KeyswitchParameters {
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use concrete_cpu_noise_model::gaussian_noise::conversion::variance_to_std_dev;
|
||||
use concrete_cpu_noise_model::gaussian_noise::noise::modulus_switching::estimate_modulus_switching_noise_with_binary_key;
|
||||
|
||||
use super::crt_decomposition;
|
||||
use crate::dag::operator::Precision;
|
||||
use crate::noise_estimator::error::{
|
||||
error_probability_of_sigma_scale, safe_variance_bound_product_1padbit,
|
||||
sigma_scale_of_error_probability,
|
||||
};
|
||||
use crate::noise_estimator::operators::atomic_pattern as noise_atomic_pattern;
|
||||
use crate::optimization::atomic_pattern;
|
||||
use crate::optimization::atomic_pattern::OptimizationDecompositionsConsts;
|
||||
|
||||
@@ -12,11 +14,11 @@ use crate::optimization::config::{Config, SearchSpace};
|
||||
use crate::optimization::decomposition::circuit_bootstrap::CbComplexityNoise;
|
||||
use crate::optimization::decomposition::{DecompCaches, PersistDecompCaches};
|
||||
use crate::parameters::{BrDecompositionParameters, GlweParameters};
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use crate::utils::square;
|
||||
|
||||
pub fn find_p_error(kappa: f64, variance_bound: f64, current_maximum_noise: f64) -> f64 {
|
||||
let sigma = Variance(variance_bound).get_standard_dev() * kappa;
|
||||
let sigma_scale = sigma / Variance(current_maximum_noise).get_standard_dev();
|
||||
let sigma = variance_to_std_dev(variance_bound) * kappa;
|
||||
let sigma_scale = sigma / variance_to_std_dev(current_maximum_noise);
|
||||
error_probability_of_sigma_scale(sigma_scale)
|
||||
}
|
||||
|
||||
@@ -104,14 +106,14 @@ fn estimate_variance(
|
||||
cb_decomp: &CbComplexityNoise,
|
||||
ks_variance: f64,
|
||||
variance_modulus_switching: f64,
|
||||
log_norm: f64,
|
||||
norm: f64,
|
||||
precisions_sum: u64,
|
||||
max_precision: u64,
|
||||
) -> f64 {
|
||||
assert!(max_precision <= precisions_sum);
|
||||
let variance_ggsw = pp_variance + br_variance / 2.;
|
||||
let variance_coeff_1_cmux_tree =
|
||||
2_f64.powf(2. * log_norm) // variance_coeff for the multisum
|
||||
square(norm) // variance_coeff for the multisum
|
||||
* (precisions_sum // for hybrid packing
|
||||
<< (2 * (max_precision - 1))) as f64 // for left shift
|
||||
;
|
||||
@@ -197,15 +199,13 @@ fn update_state_with_best_decompositions(
|
||||
let nb_blocks = partitionning.len() as u64;
|
||||
|
||||
let safe_variance_bound = consts.safe_variance;
|
||||
let log_norm = consts.noise_factor.log2();
|
||||
let norm = consts.noise_factor;
|
||||
|
||||
let variance_modulus_switching =
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_params.polynomial_size(),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
let variance_modulus_switching = estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_params.log2_polynomial_size,
|
||||
ciphertext_modulus_log,
|
||||
);
|
||||
|
||||
if variance_modulus_switching > consts.safe_variance {
|
||||
return;
|
||||
@@ -285,7 +285,7 @@ fn update_state_with_best_decompositions(
|
||||
cb_decomp,
|
||||
ks_variance,
|
||||
variance_modulus_switching,
|
||||
log_norm,
|
||||
norm,
|
||||
precisions_sum,
|
||||
max_precision,
|
||||
)
|
||||
|
||||
@@ -3,6 +3,7 @@ pub use individual::*;
|
||||
pub use range::*;
|
||||
|
||||
mod individual {
|
||||
use concrete_cpu_noise_model::gaussian_noise::security::minimal_variance_glwe;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Serialize, Deserialize)]
|
||||
@@ -30,6 +31,15 @@ mod individual {
|
||||
pub fn sample_extract_lwe_dimension(self) -> u64 {
|
||||
self.glwe_dimension << self.log2_polynomial_size
|
||||
}
|
||||
|
||||
pub fn minimal_variance(self, ciphertext_modulus_log: u32, security_level: u64) -> f64 {
|
||||
minimal_variance_glwe(
|
||||
self.glwe_dimension,
|
||||
self.polynomial_size(),
|
||||
ciphertext_modulus_log,
|
||||
security_level,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
use super::security_weights::security_weight;
|
||||
use crate::parameters::GlweParameters;
|
||||
use concrete_commons::dispersion::Variance;
|
||||
|
||||
/// Noise ensuring security
|
||||
pub fn minimal_variance(
|
||||
glwe_params: GlweParameters,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance {
|
||||
let equiv_lwe_dimension = glwe_params.glwe_dimension * glwe_params.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;
|
||||
Variance(f64::exp2(log2_var))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
|
||||
#[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 glwe_params = GlweParameters {
|
||||
log2_polynomial_size: 14,
|
||||
glwe_dimension: 10,
|
||||
};
|
||||
let actual = minimal_variance(glwe_params, integer_size, security_level);
|
||||
approx::assert_relative_eq!(
|
||||
golden_std_dev,
|
||||
actual.get_standard_dev(),
|
||||
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 glwe_params = GlweParameters {
|
||||
log2_polynomial_size: 8,
|
||||
glwe_dimension: 3,
|
||||
};
|
||||
|
||||
let actual = minimal_variance(glwe_params, integer_size, security_level);
|
||||
approx::assert_relative_eq!(
|
||||
golden_std_dev,
|
||||
actual.get_standard_dev(),
|
||||
epsilon = f64::EPSILON
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
pub mod glwe;
|
||||
pub mod security_weights;
|
||||
@@ -1,116 +0,0 @@
|
||||
#[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)
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
pub mod cache;
|
||||
use std::ops::Mul;
|
||||
|
||||
pub fn square<V>(v: V) -> V
|
||||
where
|
||||
V: Mul<Output = V> + Copy,
|
||||
V: std::ops::Mul<Output = V> + Copy,
|
||||
{
|
||||
v * v
|
||||
}
|
||||
|
||||
pub fn square_ref<V>(v: &V) -> V
|
||||
where
|
||||
V: Mul<Output = V> + Copy,
|
||||
V: std::ops::Mul<Output = V> + Copy,
|
||||
{
|
||||
square(*v)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
use chrono::{Datelike, Utc};
|
||||
use clap::Parser;
|
||||
use concrete_optimizer::security::security_weights::supported_security_levels;
|
||||
use concrete_optimizer::supported_security_levels;
|
||||
use std::fs::File;
|
||||
use v0_parameters::{compute_print_results, Args};
|
||||
|
||||
|
||||
@@ -240,9 +240,8 @@ pub fn compute_print_results(mut writer: impl Write, args: &Args) -> Result<(),
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use concrete_optimizer::security::security_weights::supported_security_levels;
|
||||
|
||||
use super::*;
|
||||
use concrete_optimizer::supported_security_levels;
|
||||
|
||||
#[test]
|
||||
fn test_reference_output() {
|
||||
|
||||
Reference in New Issue
Block a user