use crate::Types;
use itertools::izip;
pub trait LWE: Sized {
type STorus;
fn single_scalar_mul(variance: f64, n: Self) -> f64;
fn scalar_mul(var_out: &mut [f64], var_in: &[f64], t: &[Self]);
fn scalar_mul_inplace(var: &mut [f64], t: &[Self]);
fn multisum_uncorrelated(variances: &[f64], weights: &[Self]) -> f64;
fn key_switch(
dimension_before: usize,
l_ks: usize,
base_log: usize,
var_ks: f64,
var_input_lwe: f64,
) -> f64;
}
macro_rules! impl_trait_npe_lwe {
($T:ty,$DOC:expr) => {
impl LWE for $T {
type STorus = <$T as Types>::STorus;
#[doc = $DOC]
fn key_switch(
dimension_before: usize,
l_ks: usize,
base_log: usize,
var_ks: f64,
var_input: f64,
) -> f64 {
let q_square = f64::powi(2., 2 * <$T as Types>::TORUS_BIT as i32);
let res_1: f64 = dimension_before as f64
* (1. / 24. * f64::powi(2.0, -2 * (base_log * l_ks) as i32)
+ 1. / (48. * q_square));
let res_2: f64 = dimension_before as f64
* l_ks as f64
* (f64::powi(2., 2 * base_log as i32) / 12. + 1. / 6.)
* var_ks;
let res: f64 = var_input + res_1 + res_2;
return res;
}
#[doc = $DOC]
fn single_scalar_mul(variance: f64, n: Self) -> f64 {
let sn: Self::STorus = n as Self::STorus;
return variance * ((sn * sn) as f64);
}
#[doc = $DOC]
fn multisum_uncorrelated(variances: &[f64], weights: &[Self]) -> f64 {
let mut new_variance: f64 = 0.;
for (var_ref, &w) in variances.iter().zip(weights) {
new_variance += Self::single_scalar_mul(*var_ref, w);
}
return new_variance;
}
#[doc = $DOC]
fn scalar_mul(var_out: &mut [f64], var_in: &[f64], t: &[Self]) {
for (vo, vi, tval) in izip!(var_out.iter_mut(), var_in.iter(), t.iter()) {
*vo = Self::single_scalar_mul(*vi, *tval);
}
}
#[doc = $DOC]
fn scalar_mul_inplace(var: &mut [f64], t: &[Self]) {
for (v, tval) in izip!(var.iter_mut(), t.iter()) {
*v = Self::single_scalar_mul(*v, *tval);
}
}
}
};
}
impl_trait_npe_lwe!(u32, "type Torus = u32;");
impl_trait_npe_lwe!(u64, "type Torus = u64;");
pub fn add_2_uncorrelated(variance_0: f64, variance_1: f64) -> f64 {
variance_0 + variance_1
}
pub fn add_n_uncorrelated(variances: &[f64]) -> f64 {
let mut new_variance: f64 = 0.;
for var in variances.iter() {
new_variance += *var;
}
new_variance
}
pub fn upper_bound_hw_secret_key(n: usize) -> usize {
let n_f: f64 = n as f64;
let sigma: f64 = f64::sqrt(n_f) / 2.;
let mean: f64 = n_f / 2.;
let z: f64 = 3.;
(mean + z * sigma).round() as usize
}
pub fn log2_rounding_noise(n: usize) -> f64 {
let bound_sup: f64 = upper_bound_hw_secret_key(n) as f64;
let sigma: f64 = f64::sqrt(bound_sup / 12.);
let z: f64 = 3.;
f64::log2(sigma * z)
}