mirror of
https://github.com/zama-ai/concrete.git
synced 2026-02-08 19:44:57 -05:00
chore(deps): use concrete-npe repo
This commit is contained in:
@@ -37,7 +37,7 @@ fn optimize_bootstrap(
|
||||
|
||||
let search_space = SearchSpace::default();
|
||||
|
||||
let result = concrete_optimizer::optimization::atomic_pattern::optimize_one::<u64>(
|
||||
let result = concrete_optimizer::optimization::atomic_pattern::optimize_one(
|
||||
sum_size,
|
||||
precision,
|
||||
config,
|
||||
@@ -216,7 +216,7 @@ impl OperationDag {
|
||||
|
||||
let search_space = SearchSpace::default();
|
||||
|
||||
let result = concrete_optimizer::optimization::dag::solo_key::optimize::optimize::<u64>(
|
||||
let result = concrete_optimizer::optimization::dag::solo_key::optimize::optimize(
|
||||
&self.0,
|
||||
config,
|
||||
&search_space,
|
||||
@@ -241,9 +241,12 @@ impl OperationDag {
|
||||
|
||||
let search_space = SearchSpace::default();
|
||||
|
||||
let result = concrete_optimizer::optimization::dag::solo_key::optimize_generic::optimize::<
|
||||
u64,
|
||||
>(&self.0, config, &search_space, default_log_norm2_woppbs);
|
||||
let result = concrete_optimizer::optimization::dag::solo_key::optimize_generic::optimize(
|
||||
&self.0,
|
||||
config,
|
||||
&search_space,
|
||||
default_log_norm2_woppbs,
|
||||
);
|
||||
result.map_or_else(no_dag_solution, |solution| solution.into())
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,11 @@ edition = "2021"
|
||||
[dependencies]
|
||||
delegate = "0.7.0"
|
||||
derive_more = "0.99.17"
|
||||
concrete-commons = { git = "ssh://git@github.com/zama-ai/concrete_internal.git", branch = "fix/optimizer_compat" }
|
||||
concrete-npe = { git = "ssh://git@github.com/zama-ai/concrete_internal.git", branch = "fix/optimizer_compat" }
|
||||
statrs = "0.15.0"
|
||||
statrs = "0.16.0"
|
||||
lazy_static = "1.4.0"
|
||||
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" }
|
||||
|
||||
|
||||
[dev-dependencies]
|
||||
approx = "0.5"
|
||||
|
||||
@@ -6,7 +6,7 @@ pub fn atomic_pattern_complexity(
|
||||
complexity_model: &dyn ComplexityModel,
|
||||
sum_size: u64,
|
||||
params: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
let multisum_complexity = complexity_model.levelled_complexity(
|
||||
sum_size,
|
||||
|
||||
@@ -2,13 +2,13 @@ use super::complexity::Complexity;
|
||||
use crate::parameters::{KeyswitchParameters, LweDimension, PbsParameters};
|
||||
|
||||
pub trait ComplexityModel: Send + Sync {
|
||||
fn pbs_complexity(&self, params: PbsParameters, ciphertext_modulus_log: u64) -> Complexity;
|
||||
fn ks_complexity(&self, params: KeyswitchParameters, ciphertext_modulus_log: u64)
|
||||
fn pbs_complexity(&self, params: PbsParameters, ciphertext_modulus_log: u32) -> Complexity;
|
||||
fn ks_complexity(&self, params: KeyswitchParameters, ciphertext_modulus_log: u32)
|
||||
-> Complexity;
|
||||
fn levelled_complexity(
|
||||
&self,
|
||||
sum_size: u64,
|
||||
lwe_dimension: LweDimension,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Complexity;
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@ pub struct CpuComplexity {
|
||||
}
|
||||
|
||||
impl ComplexityModel for CpuComplexity {
|
||||
fn pbs_complexity(&self, params: PbsParameters, ciphertext_modulus_log: u64) -> Complexity {
|
||||
fn pbs_complexity(&self, params: PbsParameters, ciphertext_modulus_log: u32) -> Complexity {
|
||||
self.pbs.complexity(params, ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
fn ks_complexity(
|
||||
&self,
|
||||
params: KeyswitchParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
self.ks_lwe.complexity(params, ciphertext_modulus_log)
|
||||
}
|
||||
@@ -26,7 +26,7 @@ impl ComplexityModel for CpuComplexity {
|
||||
&self,
|
||||
sum_size: u64,
|
||||
lwe_dimension: LweDimension,
|
||||
_ciphertext_modulus_log: u64,
|
||||
_ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
sum_size as f64 * lwe_dimension.0 as f64
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ pub struct GpuComplexity {
|
||||
|
||||
impl ComplexityModel for GpuComplexity {
|
||||
#[allow(clippy::let_and_return, non_snake_case)]
|
||||
fn pbs_complexity(&self, params: PbsParameters, _ciphertext_modulus_log: u64) -> Complexity {
|
||||
fn pbs_complexity(&self, params: PbsParameters, _ciphertext_modulus_log: u32) -> Complexity {
|
||||
let GpuPbsComplexity {
|
||||
w1,
|
||||
w2,
|
||||
@@ -91,7 +91,7 @@ impl ComplexityModel for GpuComplexity {
|
||||
fn ks_complexity(
|
||||
&self,
|
||||
params: KeyswitchParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
let GpuKsComplexity {
|
||||
w1,
|
||||
@@ -129,7 +129,7 @@ impl ComplexityModel for GpuComplexity {
|
||||
&self,
|
||||
_sum_size: u64,
|
||||
_lwe_dimension: LweDimension,
|
||||
_ciphertext_modulus_log: u64,
|
||||
_ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
0.
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ impl SimpleWithFactors {
|
||||
pub fn fft_complexity(
|
||||
&self,
|
||||
glwe_polynomial_size: f64,
|
||||
_ciphertext_modulus_log: u64,
|
||||
_ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
self.fft.fft_complexity(glwe_polynomial_size) + glwe_polynomial_size
|
||||
}
|
||||
@@ -21,13 +21,13 @@ impl SimpleWithFactors {
|
||||
fn ifft_complexity(
|
||||
&self,
|
||||
glwe_polynomial_size: f64,
|
||||
_ciphertext_modulus_log: u64,
|
||||
_ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
self.fft.ifft_complexity(glwe_polynomial_size) + glwe_polynomial_size
|
||||
}
|
||||
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/bootstrap.py#L145
|
||||
pub fn complexity(&self, params: CmuxParameters, ciphertext_modulus_log: u64) -> Complexity {
|
||||
pub fn complexity(&self, params: CmuxParameters, ciphertext_modulus_log: u32) -> Complexity {
|
||||
let glwe_polynomial_size = params.output_glwe_params.polynomial_size() as f64;
|
||||
|
||||
let f_glwe_size = (params.output_glwe_params.glwe_dimension + 1) as f64;
|
||||
|
||||
@@ -7,7 +7,7 @@ impl KsComplexity {
|
||||
pub fn complexity(
|
||||
&self,
|
||||
params: KeyswitchParameters,
|
||||
_ciphertext_modulus_log: u64,
|
||||
_ciphertext_modulus_log: u32,
|
||||
) -> Complexity {
|
||||
let _ = self;
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/keyswitch.py#L91
|
||||
|
||||
@@ -8,7 +8,7 @@ pub struct PbsComplexity {
|
||||
}
|
||||
|
||||
impl PbsComplexity {
|
||||
pub fn complexity(&self, params: PbsParameters, ciphertext_modulus_log: u64) -> Complexity {
|
||||
pub fn complexity(&self, params: PbsParameters, ciphertext_modulus_log: u32) -> Complexity {
|
||||
// https://github.com/zama-ai/concrete-optimizer/blob/prototype/python/optimizer/noise_formulas/bootstrap.py#L163
|
||||
|
||||
let cmux_cost = self
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
|
||||
use super::utils;
|
||||
use crate::utils::square;
|
||||
|
||||
pub fn sigma_scale_of_error_probability(p_error: f64) -> f64 {
|
||||
@@ -21,15 +20,15 @@ pub fn error_probability_of_sigma_scale(sigma_scale: f64) -> f64 {
|
||||
const LEFT_PADDING_BITS: u64 = 1;
|
||||
const RIGHT_PADDING_BITS: u64 = 1;
|
||||
|
||||
pub fn fatal_variance_limit(padding_bits: u64, precision: u64, ciphertext_modulus_log: u64) -> f64 {
|
||||
pub fn fatal_variance_limit(padding_bits: u64, precision: u64, ciphertext_modulus_log: u32) -> f64 {
|
||||
let no_noise_bits = padding_bits + precision;
|
||||
let noise_bits = ciphertext_modulus_log - no_noise_bits;
|
||||
let noise_bits = ciphertext_modulus_log as u64 - no_noise_bits;
|
||||
2_f64.powi(noise_bits as i32)
|
||||
}
|
||||
|
||||
fn safe_variance_bound_from_p_error(
|
||||
fatal_noise_limit: f64,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
maximum_acceptable_error_probability: f64,
|
||||
) -> f64 {
|
||||
// We want safe_sigma such that:
|
||||
@@ -39,12 +38,13 @@ fn safe_variance_bound_from_p_error(
|
||||
let kappa = sigma_scale_of_error_probability(maximum_acceptable_error_probability);
|
||||
let safe_sigma = fatal_noise_limit / kappa;
|
||||
let modular_variance = square(safe_sigma);
|
||||
utils::from_modular_variance(modular_variance, ciphertext_modulus_log).get_variance()
|
||||
|
||||
Variance::from_modular_variance(modular_variance, ciphertext_modulus_log).get_variance()
|
||||
}
|
||||
|
||||
pub fn safe_variance_bound_2padbits(
|
||||
precision: u64,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
maximum_acceptable_error_probability: f64,
|
||||
) -> f64 {
|
||||
let padding_bits = LEFT_PADDING_BITS + RIGHT_PADDING_BITS;
|
||||
@@ -57,7 +57,7 @@ pub fn safe_variance_bound_2padbits(
|
||||
}
|
||||
|
||||
pub fn safe_variance_bound_1bit_1padbit(
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
maximum_acceptable_error_probability: f64,
|
||||
) -> f64 {
|
||||
// This is hardcoded and only valid for 16bit wop pbs
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
pub mod error;
|
||||
pub mod operators;
|
||||
pub mod utils;
|
||||
|
||||
@@ -32,14 +32,12 @@ const FFT_POLY_WEIGHT: &[f64; DEFAUT_DOMAINS.glwe_pbs_constrained.glwe_dimension
|
||||
];
|
||||
|
||||
/// Additional noise generated by the keyswitch step.
|
||||
pub fn variance_keyswitch<W: UnsignedInteger>(
|
||||
pub fn variance_keyswitch(
|
||||
param: KeyswitchParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_ksk: Variance,
|
||||
) -> Variance {
|
||||
assert_eq!(ciphertext_modulus_log, W::BITS as u64);
|
||||
concrete_npe::estimate_keyswitch_noise_lwe_to_glwe_with_constant_terms::<
|
||||
W,
|
||||
Variance,
|
||||
Variance,
|
||||
BinaryKeyKind,
|
||||
@@ -49,13 +47,14 @@ pub fn variance_keyswitch<W: UnsignedInteger>(
|
||||
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: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance {
|
||||
let glwe_params = GlweParameters {
|
||||
@@ -67,10 +66,11 @@ pub fn variance_ksk(
|
||||
}
|
||||
|
||||
/// Additional noise generated by fft computation
|
||||
pub fn fft_noise<W: UnsignedInteger>(
|
||||
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;
|
||||
@@ -97,62 +97,60 @@ pub fn fft_noise<W: UnsignedInteger>(
|
||||
* b
|
||||
* big_n.powf(poly_weight)
|
||||
* (k as f64 + 1.);
|
||||
Variance::from_modular_variance::<W>(res)
|
||||
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<W: UnsignedInteger>(
|
||||
pub fn variance_bootstrap(
|
||||
param: PbsParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
variance_bsk: Variance,
|
||||
) -> Variance {
|
||||
assert_eq!(ciphertext_modulus_log, W::BITS as u64);
|
||||
let out_variance_pbs = concrete_npe::estimate_pbs_noise::<W, Variance, BinaryKeyKind>(
|
||||
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::<W>(
|
||||
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 estimate_modulus_switching_noise_with_binary_key<W>(
|
||||
pub fn estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_ks_output_lwe_dimension: u64,
|
||||
glwe_polynomial_size: u64,
|
||||
) -> Variance
|
||||
where
|
||||
W: UnsignedInteger,
|
||||
{
|
||||
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::<W, Variance>(
|
||||
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, W>(
|
||||
pub fn maximal_noise<D>(
|
||||
input_variance: Variance,
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u64, //log(q)
|
||||
ciphertext_modulus_log: u32, //log(q)
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
D: DispersionParameter,
|
||||
W: UnsignedInteger,
|
||||
{
|
||||
assert_eq!(ciphertext_modulus_log, W::BITS as u64);
|
||||
let v_keyswitch = variance_keyswitch::<W>(
|
||||
let v_keyswitch = variance_keyswitch(
|
||||
param.ks_parameters(),
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
@@ -161,9 +159,10 @@ where
|
||||
security_level,
|
||||
),
|
||||
);
|
||||
let v_modulus_switch = estimate_modulus_switching_noise_with_binary_key::<W>(
|
||||
let v_modulus_switch = estimate_modulus_switching_noise_with_binary_key(
|
||||
param.internal_lwe_dimension.0,
|
||||
param.output_glwe_params.polynomial_size(),
|
||||
ciphertext_modulus_log,
|
||||
);
|
||||
Variance(
|
||||
input_variance.get_variance()
|
||||
@@ -177,14 +176,13 @@ pub fn maximal_noise_multi_sum<D, W, Ignored>(
|
||||
dispersions: &[D],
|
||||
weights_tuples: &[(W, Ignored)],
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
D: DispersionParameter,
|
||||
W: UnsignedInteger,
|
||||
{
|
||||
assert_eq!(ciphertext_modulus_log, W::BITS as u64);
|
||||
let v_out_multi_sum = if dispersions.is_empty() {
|
||||
let mut weights = vec![];
|
||||
for (weight, _) in weights_tuples.iter() {
|
||||
@@ -194,7 +192,7 @@ where
|
||||
} else {
|
||||
Variance(0.0)
|
||||
};
|
||||
maximal_noise::<D, W>(
|
||||
maximal_noise::<D>(
|
||||
v_out_multi_sum,
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
@@ -205,7 +203,7 @@ where
|
||||
/// The output noise is the variance boostrap.
|
||||
pub fn output_noise<D, W>(
|
||||
param: AtomicPatternParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance
|
||||
where
|
||||
@@ -218,7 +216,7 @@ where
|
||||
ciphertext_modulus_log,
|
||||
security_level,
|
||||
);
|
||||
variance_bootstrap::<W>(param.pbs_parameters(), ciphertext_modulus_log, variance_bsk)
|
||||
variance_bootstrap(param.pbs_parameters(), ciphertext_modulus_log, variance_bsk)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -245,7 +243,7 @@ mod tests {
|
||||
},
|
||||
};
|
||||
|
||||
let actual = variance_keyswitch::<u128>(
|
||||
let actual = variance_keyswitch(
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
@@ -254,7 +252,7 @@ mod tests {
|
||||
security,
|
||||
),
|
||||
)
|
||||
.get_modular_variance::<u128>();
|
||||
.get_modular_variance(128);
|
||||
approx::assert_relative_eq!(actual, golden_modular_variance, max_relative = 1e-8);
|
||||
}
|
||||
|
||||
@@ -276,7 +274,7 @@ mod tests {
|
||||
},
|
||||
};
|
||||
|
||||
let actual = variance_keyswitch::<u64>(
|
||||
let actual = variance_keyswitch(
|
||||
param,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk(
|
||||
@@ -285,7 +283,7 @@ mod tests {
|
||||
security,
|
||||
),
|
||||
)
|
||||
.get_modular_variance::<u64>();
|
||||
.get_modular_variance(64);
|
||||
approx::assert_relative_eq!(actual, golden_modular_variance, max_relative = 1e-8);
|
||||
}
|
||||
|
||||
@@ -310,8 +308,8 @@ mod tests {
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let actual = variance_bootstrap::<u64>(param, ciphertext_modulus_log, variance_bsk)
|
||||
.get_modular_variance::<u64>();
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -337,8 +335,8 @@ mod tests {
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let actual = variance_bootstrap::<u128>(param, ciphertext_modulus_log, variance_bsk)
|
||||
.get_modular_variance::<u128>();
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_commons::key_kinds::BinaryKeyKind;
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
use concrete_npe::KeyDispersion;
|
||||
|
||||
use crate::parameters::PbsParameters;
|
||||
@@ -10,10 +9,8 @@ pub fn estimate_packing_private_keyswitch<T>(
|
||||
var_glwe: Variance,
|
||||
var_ggsw: Variance,
|
||||
param: PbsParameters,
|
||||
) -> Variance
|
||||
where
|
||||
T: UnsignedInteger,
|
||||
{
|
||||
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;
|
||||
@@ -23,21 +20,23 @@ where
|
||||
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::<T>()) as f64 * (square(b) + 2.) / 12.;
|
||||
let res_1 = (l * (n + 1.) * var_ggsw.get_modular_variance(ciphertext_modulus_log)) as f64
|
||||
* (square(b) + 2.)
|
||||
/ 12.;
|
||||
|
||||
#[allow(clippy::cast_possible_wrap)]
|
||||
let log_q = T::BITS as i32;
|
||||
|
||||
let res_3 = ((square(f64::powi(2., log_q)) as f64 - b2l) / (12. * b2l)
|
||||
let res_3 = ((square(f64::powi(2., ciphertext_modulus_log as i32)) as f64 - b2l) / (12. * b2l)
|
||||
* (1.
|
||||
+ n * (K::variance_key_coefficient::<T>().get_modular_variance::<T>()
|
||||
+ 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::<T>().get_modular_variance::<T>()
|
||||
+ var_glwe.get_modular_variance::<T>())
|
||||
+ 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::<T>(res_1 + res_3 + res_5)
|
||||
Variance::from_modular_variance(res_1 + res_3 + res_5, ciphertext_modulus_log)
|
||||
}
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
use concrete_commons::dispersion::Variance;
|
||||
|
||||
pub fn from_modular_variance(modular_variance: f64, ciphertext_modulus_log: u64) -> Variance {
|
||||
match ciphertext_modulus_log {
|
||||
128 => Variance::from_modular_variance::<u128>(modular_variance),
|
||||
64 => Variance::from_modular_variance::<u64>(modular_variance),
|
||||
32 => Variance::from_modular_variance::<u32>(modular_variance),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@ use crate::parameters::{
|
||||
use crate::utils::square;
|
||||
use crate::{pareto, security};
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
|
||||
/* enable to debug */
|
||||
const CHECKS: bool = false;
|
||||
@@ -61,7 +60,7 @@ impl ComplexityNoise {
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn cutted_blind_rotate<W: UnsignedInteger>(
|
||||
pub(crate) fn cutted_blind_rotate(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
internal_dim: u64,
|
||||
glwe_params: GlweParameters,
|
||||
@@ -69,7 +68,7 @@ pub(crate) fn cutted_blind_rotate<W: UnsignedInteger>(
|
||||
cut_noise: f64,
|
||||
) -> Vec<ComplexityNoise> {
|
||||
let pareto_cut = false;
|
||||
pareto_cut_blind_rotate::<W>(
|
||||
pareto_cut_blind_rotate(
|
||||
consts,
|
||||
internal_dim,
|
||||
glwe_params,
|
||||
@@ -79,7 +78,7 @@ pub(crate) fn cutted_blind_rotate<W: UnsignedInteger>(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn pareto_blind_rotate<W: UnsignedInteger>(
|
||||
pub(crate) fn pareto_blind_rotate(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
internal_dim: u64,
|
||||
glwe_params: GlweParameters,
|
||||
@@ -87,7 +86,7 @@ pub(crate) fn pareto_blind_rotate<W: UnsignedInteger>(
|
||||
cut_noise: f64,
|
||||
) -> Vec<ComplexityNoise> {
|
||||
let pareto_cut = true;
|
||||
pareto_cut_blind_rotate::<W>(
|
||||
pareto_cut_blind_rotate(
|
||||
consts,
|
||||
internal_dim,
|
||||
glwe_params,
|
||||
@@ -97,7 +96,7 @@ pub(crate) fn pareto_blind_rotate<W: UnsignedInteger>(
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn pareto_cut_blind_rotate<W: UnsignedInteger>(
|
||||
pub(crate) fn pareto_cut_blind_rotate(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
internal_dim: u64,
|
||||
glwe_params: GlweParameters,
|
||||
@@ -131,7 +130,7 @@ pub(crate) fn pareto_cut_blind_rotate<W: UnsignedInteger>(
|
||||
if cut_complexity < complexity_pbs && CUTS {
|
||||
break; // complexity is increasing
|
||||
}
|
||||
let base_noise = noise_atomic_pattern::variance_bootstrap::<W>(
|
||||
let base_noise = noise_atomic_pattern::variance_bootstrap(
|
||||
pbs_parameters,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
@@ -169,7 +168,7 @@ pub(crate) fn pareto_cut_blind_rotate<W: UnsignedInteger>(
|
||||
quantities
|
||||
}
|
||||
|
||||
pub(crate) fn pareto_keyswitch<W: UnsignedInteger>(
|
||||
pub(crate) fn pareto_keyswitch(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
input_dim: u64,
|
||||
internal_dim: u64,
|
||||
@@ -201,7 +200,7 @@ pub(crate) fn pareto_keyswitch<W: UnsignedInteger>(
|
||||
if cut_complexity < complexity_keyswitch && CUTS {
|
||||
break;
|
||||
}
|
||||
let noise_keyswitch = noise_atomic_pattern::variance_keyswitch::<W>(
|
||||
let noise_keyswitch = noise_atomic_pattern::variance_keyswitch(
|
||||
keyswitch_parameter,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk,
|
||||
@@ -244,7 +243,7 @@ pub struct OptimizationState {
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
fn update_state_with_best_decompositions(
|
||||
state: &mut OptimizationState,
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
internal_dim: u64,
|
||||
@@ -253,9 +252,10 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
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::<W>(
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_poly_size,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
let safe_variance = consts.safe_variance;
|
||||
@@ -270,7 +270,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
let mut cut_complexity = best_complexity - complexity_multisum;
|
||||
let mut cut_noise = safe_variance - noise_modulus_switching;
|
||||
let br_quantities =
|
||||
pareto_blind_rotate::<W>(consts, internal_dim, glwe_params, cut_complexity, cut_noise);
|
||||
pareto_blind_rotate(consts, internal_dim, glwe_params, cut_complexity, cut_noise);
|
||||
if br_quantities.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -278,7 +278,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
cut_noise -= br_quantities[br_quantities.len() - 1].noise;
|
||||
cut_complexity -= br_quantities[0].complexity;
|
||||
}
|
||||
let ks_quantities = pareto_keyswitch::<W>(
|
||||
let ks_quantities = pareto_keyswitch(
|
||||
consts,
|
||||
input_lwe_dimension,
|
||||
internal_dim,
|
||||
@@ -318,7 +318,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
let complexity = complexity_multisum + complexity_keyswitch + complexity_pbs;
|
||||
|
||||
if CHECKS {
|
||||
assert_checks::<W>(
|
||||
assert_checks(
|
||||
consts,
|
||||
internal_dim,
|
||||
glwe_params,
|
||||
@@ -387,7 +387,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
|
||||
// This function provides reference values with unoptimised code, until we have non regeression tests
|
||||
#[allow(clippy::float_cmp)]
|
||||
fn assert_checks<W: UnsignedInteger>(
|
||||
fn assert_checks(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
internal_dim: u64,
|
||||
glwe_params: GlweParameters,
|
||||
@@ -419,7 +419,7 @@ fn assert_checks<W: UnsignedInteger>(
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let base_noise_ = noise_atomic_pattern::variance_bootstrap::<W>(
|
||||
let base_noise_ = noise_atomic_pattern::variance_bootstrap(
|
||||
pbs_parameters,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
@@ -442,7 +442,7 @@ fn assert_checks<W: UnsignedInteger>(
|
||||
ks_decomposition_parameter,
|
||||
};
|
||||
|
||||
let noise_keyswitch_ = noise_atomic_pattern::variance_keyswitch::<W>(
|
||||
let noise_keyswitch_ = noise_atomic_pattern::variance_keyswitch(
|
||||
keyswitch_parameters,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk,
|
||||
@@ -464,7 +464,7 @@ fn assert_checks<W: UnsignedInteger>(
|
||||
output_glwe_params: glwe_params,
|
||||
};
|
||||
|
||||
let check_max_noise = noise_atomic_pattern::maximal_noise::<Variance, W>(
|
||||
let check_max_noise = noise_atomic_pattern::maximal_noise::<Variance>(
|
||||
Variance(noise_in_),
|
||||
atomic_pattern_parameters,
|
||||
ciphertext_modulus_log,
|
||||
@@ -491,7 +491,7 @@ fn assert_checks<W: UnsignedInteger>(
|
||||
|
||||
const REL_EPSILON_PROBA: f64 = 1.0 + 1e-8;
|
||||
|
||||
pub fn optimize_one<W: UnsignedInteger>(
|
||||
pub fn optimize_one(
|
||||
sum_size: u64,
|
||||
precision: u64,
|
||||
config: Config,
|
||||
@@ -508,7 +508,7 @@ pub fn optimize_one<W: UnsignedInteger>(
|
||||
// the security of the noise level of ouput is controlled by
|
||||
// the blind rotate decomposition
|
||||
|
||||
let ciphertext_modulus_log = W::BITS as u64;
|
||||
let ciphertext_modulus_log = config.ciphertext_modulus_log;
|
||||
let safe_variance = error::safe_variance_bound_2padbits(
|
||||
precision,
|
||||
ciphertext_modulus_log,
|
||||
@@ -545,9 +545,10 @@ pub fn optimize_one<W: UnsignedInteger>(
|
||||
let min_internal_lwe_dimensions = search_space.internal_lwe_dimensions[0];
|
||||
let lower_bound_cut = |glwe_poly_size| {
|
||||
// TODO: cut if min complexity is higher than current best
|
||||
CUTS && noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key::<W>(
|
||||
CUTS && noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
min_internal_lwe_dimensions,
|
||||
glwe_poly_size,
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance()
|
||||
> consts.safe_variance
|
||||
@@ -579,7 +580,7 @@ pub fn optimize_one<W: UnsignedInteger>(
|
||||
|
||||
for &internal_dim in &search_space.internal_lwe_dimensions {
|
||||
assert!(256 < internal_dim);
|
||||
update_state_with_best_decompositions::<W>(
|
||||
update_state_with_best_decompositions(
|
||||
&mut state,
|
||||
&consts,
|
||||
internal_dim,
|
||||
|
||||
@@ -5,14 +5,14 @@ use crate::global_parameters::DEFAUT_DOMAINS;
|
||||
pub struct NoiseBoundConfig {
|
||||
pub security_level: u64,
|
||||
pub maximum_acceptable_error_probability: f64,
|
||||
pub ciphertext_modulus_log: u64,
|
||||
pub ciphertext_modulus_log: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Config<'a> {
|
||||
pub security_level: u64,
|
||||
pub maximum_acceptable_error_probability: f64,
|
||||
pub ciphertext_modulus_log: u64,
|
||||
pub ciphertext_modulus_log: u32,
|
||||
pub complexity_model: &'a dyn ComplexityModel,
|
||||
}
|
||||
|
||||
|
||||
@@ -12,14 +12,13 @@ use crate::parameters::{BrDecompositionParameters, GlweParameters, KsDecompositi
|
||||
use crate::pareto;
|
||||
use crate::security::glwe::minimal_variance;
|
||||
use concrete_commons::dispersion::DispersionParameter;
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
|
||||
const CUTS: bool = true;
|
||||
const PARETO_CUTS: bool = true;
|
||||
const CROSS_PARETO_CUTS: bool = PARETO_CUTS && true;
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn update_best_solution_with_best_decompositions<W: UnsignedInteger>(
|
||||
fn update_best_solution_with_best_decompositions(
|
||||
state: &mut OptimizationState,
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
dag: &analyze::OperationDag,
|
||||
@@ -68,13 +67,14 @@ fn update_best_solution_with_best_decompositions<W: UnsignedInteger>(
|
||||
};
|
||||
let br_cut_complexity = cut_complexity;
|
||||
|
||||
let br_pareto = pareto_blind_rotate::<W>(
|
||||
let br_pareto = pareto_blind_rotate(
|
||||
consts,
|
||||
internal_dim,
|
||||
glwe_params,
|
||||
br_cut_complexity,
|
||||
br_cut_noise,
|
||||
);
|
||||
|
||||
if br_pareto.is_empty() {
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ fn update_best_solution_with_best_decompositions<W: UnsignedInteger>(
|
||||
let ks_cut_noise = cut_noise - worst_input_ks_noise;
|
||||
let ks_cut_complexity = cut_complexity - br_pareto[0].complexity;
|
||||
|
||||
let ks_pareto = pareto_keyswitch::<W>(
|
||||
let ks_pareto = pareto_keyswitch(
|
||||
consts,
|
||||
input_lwe_dimension,
|
||||
internal_dim,
|
||||
@@ -220,12 +220,12 @@ fn update_best_solution_with_best_decompositions<W: UnsignedInteger>(
|
||||
|
||||
const REL_EPSILON_PROBA: f64 = 1.0 + 1e-8;
|
||||
|
||||
pub fn optimize<W: UnsignedInteger>(
|
||||
pub fn optimize(
|
||||
dag: &unparametrized::OperationDag,
|
||||
config: Config,
|
||||
search_space: &SearchSpace,
|
||||
) -> OptimizationState {
|
||||
let ciphertext_modulus_log = W::BITS as u64;
|
||||
let ciphertext_modulus_log = config.ciphertext_modulus_log;
|
||||
let noise_config = NoiseBoundConfig {
|
||||
security_level: config.security_level,
|
||||
maximum_acceptable_error_probability: config.maximum_acceptable_error_probability,
|
||||
@@ -267,9 +267,10 @@ pub fn optimize<W: UnsignedInteger>(
|
||||
};
|
||||
|
||||
let noise_modulus_switching = |glwe_poly_size, internal_lwe_dimensions| {
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key::<W>(
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_lwe_dimensions,
|
||||
glwe_poly_size,
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance()
|
||||
};
|
||||
@@ -289,7 +290,7 @@ pub fn optimize<W: UnsignedInteger>(
|
||||
// assume this noise is increasing with internal_dim
|
||||
break;
|
||||
}
|
||||
update_best_solution_with_best_decompositions::<W>(
|
||||
update_best_solution_with_best_decompositions(
|
||||
&mut state,
|
||||
&consts,
|
||||
&dag,
|
||||
@@ -314,7 +315,7 @@ pub fn optimize<W: UnsignedInteger>(
|
||||
state
|
||||
}
|
||||
|
||||
pub fn optimize_v0<W: UnsignedInteger>(
|
||||
pub fn optimize_v0(
|
||||
sum_size: u64,
|
||||
precision: u64,
|
||||
config: Config,
|
||||
@@ -334,7 +335,7 @@ pub fn optimize_v0<W: UnsignedInteger>(
|
||||
let lut1 = dag.add_lut(dot1, FunctionTable::UNKWOWN, precision);
|
||||
let dot2 = dag.add_levelled_op([lut1], complexity, manp, out_shape, comment);
|
||||
let _lut2 = dag.add_lut(dot2, FunctionTable::UNKWOWN, precision);
|
||||
let mut state = optimize::<u64>(&dag, config, search_space);
|
||||
let mut state = optimize(&dag, config, search_space);
|
||||
if let Some(sol) = &mut state.best_solution {
|
||||
sol.complexity /= 2.0;
|
||||
}
|
||||
@@ -384,7 +385,7 @@ mod tests {
|
||||
|
||||
let search_space = SearchSpace::default();
|
||||
|
||||
super::optimize::<u64>(dag, config, &search_space)
|
||||
super::optimize(dag, config, &search_space)
|
||||
}
|
||||
|
||||
struct Times {
|
||||
@@ -424,11 +425,11 @@ mod tests {
|
||||
};
|
||||
|
||||
let chrono = Instant::now();
|
||||
let state = optimize_v0::<u64>(sum_size, precision, config, weight as f64, &search_space);
|
||||
let state = optimize_v0(sum_size, precision, config, weight as f64, &search_space);
|
||||
|
||||
times.dag_time += chrono.elapsed().as_nanos();
|
||||
let chrono = Instant::now();
|
||||
let state_ref = atomic_pattern::optimize_one::<u64>(
|
||||
let state_ref = atomic_pattern::optimize_one(
|
||||
sum_size,
|
||||
precision,
|
||||
config,
|
||||
@@ -500,7 +501,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let state = optimize(&dag);
|
||||
let state_ref = atomic_pattern::optimize_one::<u64>(
|
||||
let state_ref = atomic_pattern::optimize_one(
|
||||
1,
|
||||
precision as u64,
|
||||
config,
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::optimization::config::{Config, SearchSpace};
|
||||
use crate::optimization::dag::solo_key::{analyze, optimize};
|
||||
use crate::optimization::wop_atomic_pattern::optimize::optimize_one as wop_optimize;
|
||||
use crate::optimization::wop_atomic_pattern::Solution as WopSolution;
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
use std::ops::RangeInclusive;
|
||||
|
||||
const MINIMAL_WOP_PRECISION: Precision = 9;
|
||||
@@ -42,7 +41,7 @@ fn updated_global_p_error(nb_luts: u64, sol: WopSolution) -> WopSolution {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn optimize<W: UnsignedInteger>(
|
||||
pub fn optimize(
|
||||
dag: &OperationDag,
|
||||
config: Config,
|
||||
search_space: &SearchSpace,
|
||||
@@ -58,10 +57,10 @@ pub fn optimize<W: UnsignedInteger>(
|
||||
let worst_log_norm = analyze::worst_log_norm(dag);
|
||||
let log_norm = default_log_norm.min(worst_log_norm);
|
||||
let opt_sol =
|
||||
wop_optimize::<W>(fallback_16b_precision, config, log_norm, search_space).best_solution;
|
||||
wop_optimize(fallback_16b_precision, config, log_norm, search_space).best_solution;
|
||||
opt_sol.map(|sol| Solution::WopSolution(updated_global_p_error(nb_luts, sol)))
|
||||
} else {
|
||||
let opt_sol = optimize::optimize::<W>(dag, config, search_space).best_solution;
|
||||
let opt_sol = optimize::optimize(dag, config, search_space).best_solution;
|
||||
opt_sol.map(Solution::WpSolution)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ use crate::parameters::{
|
||||
use crate::security;
|
||||
use crate::utils::square;
|
||||
use concrete_commons::dispersion::{DispersionParameter, Variance};
|
||||
use concrete_commons::numeric::UnsignedInteger;
|
||||
|
||||
pub fn find_p_error(kappa: f64, variance_bound: f64, current_maximum_noise: f64) -> f64 {
|
||||
let sigma = Variance(variance_bound).get_standard_dev() * kappa;
|
||||
@@ -113,7 +112,7 @@ struct NoiseCostByMicroParam {
|
||||
pp_switching: Vec<(f64, Complexity)>,
|
||||
}
|
||||
|
||||
fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
fn compute_noise_cost_by_micro_param(
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
glwe_params: GlweParameters,
|
||||
internal_dim: u64,
|
||||
@@ -131,7 +130,7 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
let cut_complexity = best_complexity / number_br; // saves 0%
|
||||
let cut_variance = (consts.safe_variance - variance_modulus_switching) / variance_coeff; // saves 40%
|
||||
|
||||
let cutted_blind_rotate = cutted_blind_rotate::<W>(
|
||||
let cutted_blind_rotate = cutted_blind_rotate(
|
||||
consts,
|
||||
internal_dim,
|
||||
glwe_params,
|
||||
@@ -152,7 +151,7 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
/ variance_coeff; // saves 25%
|
||||
|
||||
let input_dim = glwe_params.sample_extract_lwe_dimension();
|
||||
let pareto_keyswitch = pareto_keyswitch::<W>(
|
||||
let pareto_keyswitch = pareto_keyswitch(
|
||||
consts,
|
||||
input_dim,
|
||||
internal_dim,
|
||||
@@ -163,10 +162,11 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
return None;
|
||||
}
|
||||
|
||||
let ciphertext_modulus_log = W::BITS as u64;
|
||||
|
||||
let variance_bsk =
|
||||
security::glwe::minimal_variance(glwe_params, ciphertext_modulus_log, security_level);
|
||||
let variance_bsk = security::glwe::minimal_variance(
|
||||
glwe_params,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
security_level,
|
||||
);
|
||||
|
||||
let mut variance_cost_pp_switching = vec![(f64::NAN, f64::NAN); BR_PARETO_DECOMP.len()];
|
||||
for br in &cutted_blind_rotate {
|
||||
@@ -181,9 +181,13 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
};
|
||||
// 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::<W>(Variance(0.), variance_bsk, ppks_parameter)
|
||||
.get_variance();
|
||||
let variance_private_packing_ks = estimate_packing_private_keyswitch::<u64>(
|
||||
Variance(0.),
|
||||
variance_bsk,
|
||||
ppks_parameter,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
|
||||
let ppks_parameter_complexity = KeyswitchParameters {
|
||||
input_lwe_dimension: LweDimension(
|
||||
@@ -197,10 +201,11 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
log2_base: pp_ks_decomposition_parameter.log2_base,
|
||||
},
|
||||
};
|
||||
let complexity_ppks = consts
|
||||
.config
|
||||
.complexity_model
|
||||
.ks_complexity(ppks_parameter_complexity, ciphertext_modulus_log);
|
||||
let complexity_ppks = consts.config.complexity_model.ks_complexity(
|
||||
ppks_parameter_complexity,
|
||||
consts.config.ciphertext_modulus_log,
|
||||
);
|
||||
|
||||
variance_cost_pp_switching[br.index] = (variance_private_packing_ks, complexity_ppks);
|
||||
}
|
||||
|
||||
@@ -212,7 +217,7 @@ fn compute_noise_cost_by_micro_param<W: UnsignedInteger>(
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
fn update_state_with_best_decompositions(
|
||||
state: &mut OptimizationState,
|
||||
consts: &OptimizationDecompositionsConsts,
|
||||
glwe_params: GlweParameters,
|
||||
@@ -228,9 +233,10 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
let log_norm = consts.noise_factor.log2();
|
||||
|
||||
let variance_modulus_switching =
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key::<W>(
|
||||
noise_atomic_pattern::estimate_modulus_switching_noise_with_binary_key(
|
||||
internal_dim,
|
||||
glwe_params.polynomial_size(),
|
||||
ciphertext_modulus_log,
|
||||
)
|
||||
.get_variance();
|
||||
|
||||
@@ -247,7 +253,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
.as_ref()
|
||||
.map_or(f64::INFINITY, |s| s.noise_max);
|
||||
|
||||
let variance_cost_opt = compute_noise_cost_by_micro_param::<W>(
|
||||
let variance_cost_opt = compute_noise_cost_by_micro_param(
|
||||
consts,
|
||||
glwe_params,
|
||||
internal_dim,
|
||||
@@ -375,7 +381,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
// Cutting on complexity here is counter-productive probably because complexity_multi_hybrid_packing is small
|
||||
|
||||
let variance_one_external_product_for_cmux_tree =
|
||||
noise_atomic_pattern::variance_bootstrap::<W>(
|
||||
noise_atomic_pattern::variance_bootstrap(
|
||||
cmux_tree_blind_rotate_parameters,
|
||||
ciphertext_modulus_log,
|
||||
Variance::from_variance(variance_ggsw),
|
||||
@@ -446,7 +452,7 @@ fn update_state_with_best_decompositions<W: UnsignedInteger>(
|
||||
}
|
||||
}
|
||||
|
||||
fn optimize_raw<W: UnsignedInteger>(
|
||||
fn optimize_raw(
|
||||
log_norm: f64, // ?? norm2 of noise multisum, complexity of multisum is neglected
|
||||
config: Config,
|
||||
search_space: &SearchSpace,
|
||||
@@ -456,13 +462,11 @@ fn optimize_raw<W: UnsignedInteger>(
|
||||
assert!(0.0 < config.maximum_acceptable_error_probability);
|
||||
assert!(config.maximum_acceptable_error_probability < 1.0);
|
||||
|
||||
let ciphertext_modulus_log = W::BITS as u64;
|
||||
|
||||
// Circuit BS bound
|
||||
// 1 bit of message only here =)
|
||||
// Bound for first bit extract in BitExtract (dominate others)
|
||||
let safe_variance_bound = safe_variance_bound_1bit_1padbit(
|
||||
ciphertext_modulus_log,
|
||||
config.ciphertext_modulus_log,
|
||||
config.maximum_acceptable_error_probability,
|
||||
);
|
||||
let kappa: f64 = sigma_scale_of_error_probability(config.maximum_acceptable_error_probability);
|
||||
@@ -500,7 +504,7 @@ fn optimize_raw<W: UnsignedInteger>(
|
||||
};
|
||||
|
||||
for &internal_dim in &search_space.internal_lwe_dimensions {
|
||||
update_state_with_best_decompositions::<W>(
|
||||
update_state_with_best_decompositions(
|
||||
&mut state,
|
||||
&consts,
|
||||
glwe_params,
|
||||
@@ -515,7 +519,7 @@ fn optimize_raw<W: UnsignedInteger>(
|
||||
state
|
||||
}
|
||||
|
||||
pub fn optimize_one<W: UnsignedInteger>(
|
||||
pub fn optimize_one(
|
||||
precision: u64,
|
||||
config: Config,
|
||||
log_norm: f64,
|
||||
@@ -524,7 +528,7 @@ pub fn optimize_one<W: UnsignedInteger>(
|
||||
let coprimes = crt_decomposition::default_coprimes(precision as Precision);
|
||||
let partitionning = crt_decomposition::precisions_from_coprimes(&coprimes);
|
||||
let n_functions = 1;
|
||||
let mut state = optimize_raw::<W>(log_norm, config, search_space, n_functions, &partitionning);
|
||||
let mut state = optimize_raw(log_norm, config, search_space, n_functions, &partitionning);
|
||||
state.best_solution = state.best_solution.map(|mut sol| -> Solution {
|
||||
sol.crt_decomposition = coprimes;
|
||||
sol
|
||||
@@ -532,7 +536,7 @@ pub fn optimize_one<W: UnsignedInteger>(
|
||||
state
|
||||
}
|
||||
|
||||
pub fn optimize_one_compat<W: UnsignedInteger>(
|
||||
pub fn optimize_one_compat(
|
||||
_sum_size: u64,
|
||||
precision: u64,
|
||||
config: Config,
|
||||
@@ -540,7 +544,7 @@ pub fn optimize_one_compat<W: UnsignedInteger>(
|
||||
search_space: &SearchSpace,
|
||||
) -> atomic_pattern::OptimizationState {
|
||||
let log_norm = noise_factor.log2();
|
||||
let result = optimize_one::<W>(precision, config, log_norm, search_space);
|
||||
let result = optimize_one(precision, config, log_norm, search_space);
|
||||
atomic_pattern::OptimizationState {
|
||||
best_solution: result.best_solution.map(Solution::into),
|
||||
count_domain: result.count_domain,
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn extract_br_pareto(
|
||||
security_level: u64,
|
||||
output_glwe_range: &GlweParameterRanges,
|
||||
input_lwe_range: &crate::parameters::LweDimensionRange,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Vec<BrDecompositionParameters> {
|
||||
let mut paretos = HashSet::new();
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn extract_br_pareto(
|
||||
for input_lwe_dimension in &input_lwe_range.lwe_dimension {
|
||||
let mut min_variance = Variance(f64::INFINITY);
|
||||
|
||||
for level in 1..=ciphertext_modulus_log {
|
||||
for level in 1..=(ciphertext_modulus_log as u64) {
|
||||
// To compute the PBS, Concrete switches from u32/u64 to f64 to represent the ciphertext
|
||||
// which only keeps the 53 MSB of each u32/u64 (53 is the mantissa size).
|
||||
// There is no need to decompose more bits than 53 as those ones will be erased by the conversion between u32/u64 and f64.
|
||||
@@ -49,7 +49,7 @@ pub fn extract_br_pareto(
|
||||
},
|
||||
};
|
||||
|
||||
let variance = variance_bootstrap::<u64>(
|
||||
let variance = variance_bootstrap(
|
||||
pbs_parameters,
|
||||
ciphertext_modulus_log,
|
||||
variance_bsk,
|
||||
@@ -87,7 +87,7 @@ pub fn extract_ks_pareto(
|
||||
security_level: u64,
|
||||
input_glwe_range: &GlweParameterRanges,
|
||||
output_lwe_range: &crate::parameters::LweDimensionRange,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
) -> Vec<KsDecompositionParameters> {
|
||||
let mut paretos = HashSet::new();
|
||||
|
||||
@@ -109,10 +109,10 @@ pub fn extract_ks_pareto(
|
||||
|
||||
let mut min_variance = Variance(f64::INFINITY);
|
||||
|
||||
for level in 1..=ciphertext_modulus_log {
|
||||
for level in 1..=ciphertext_modulus_log as u64 {
|
||||
let mut log2_base_arg_min = None;
|
||||
|
||||
for log2_base in 1..=(ciphertext_modulus_log / level) {
|
||||
for log2_base in 1..=(ciphertext_modulus_log as u64 / level) {
|
||||
let keyswitch_parameters = KeyswitchParameters {
|
||||
input_lwe_dimension: LweDimension(input_lwe_dimension),
|
||||
output_lwe_dimension: LweDimension(output_lwe_dimension),
|
||||
@@ -122,7 +122,7 @@ pub fn extract_ks_pareto(
|
||||
},
|
||||
};
|
||||
|
||||
let variance = variance_keyswitch::<u64>(
|
||||
let variance = variance_keyswitch(
|
||||
keyswitch_parameters,
|
||||
ciphertext_modulus_log,
|
||||
variance_ksk,
|
||||
|
||||
@@ -5,7 +5,7 @@ use concrete_commons::dispersion::Variance;
|
||||
/// Noise ensuring security
|
||||
pub fn minimal_variance(
|
||||
glwe_params: GlweParameters,
|
||||
ciphertext_modulus_log: u64,
|
||||
ciphertext_modulus_log: u32,
|
||||
security_level: u64,
|
||||
) -> Variance {
|
||||
let equiv_lwe_dimension = glwe_params.glwe_dimension * glwe_params.polynomial_size();
|
||||
|
||||
@@ -111,7 +111,7 @@ pub fn all_results(args: &Args) -> Vec<Vec<OptimizationState>> {
|
||||
.map(|&manp| {
|
||||
let noise_scale = 2_f64.powi(manp);
|
||||
let result = if args.wop_pbs {
|
||||
optimize_wop_atomic_pattern::optimize_one_compat::<u64>(
|
||||
optimize_wop_atomic_pattern::optimize_one_compat(
|
||||
sum_size,
|
||||
precision,
|
||||
config,
|
||||
@@ -119,7 +119,7 @@ pub fn all_results(args: &Args) -> Vec<Vec<OptimizationState>> {
|
||||
&search_space,
|
||||
)
|
||||
} else {
|
||||
optimize_atomic_pattern::optimize_one::<u64>(
|
||||
optimize_atomic_pattern::optimize_one(
|
||||
sum_size,
|
||||
precision,
|
||||
config,
|
||||
|
||||
Reference in New Issue
Block a user