poulpy/core/src/noise.rs
core/src/noise.rsRaw
1#[allow(dead_code)]
2pub(crate) fn var_noise_gglwe_product(
3 n: f64,
4 basek: usize,
5 var_xs: f64,
6 var_msg: f64,
7 var_a_err: f64,
8 var_gct_err_lhs: f64,
9 var_gct_err_rhs: f64,
10 rank_in: f64,
11 a_logq: usize,
12 b_logq: usize,
13) -> f64 {
14 let a_logq: usize = a_logq.min(b_logq);
15 let a_cols: usize = a_logq.div_ceil(basek);
16
17 let b_scale: f64 = (b_logq as f64).exp2();
18 let a_scale: f64 = ((b_logq - a_logq) as f64).exp2();
19
20 let base: f64 = (basek as f64).exp2();
21 let var_base: f64 = base * base / 12f64;
22
23 // lhs = a_cols * n * (var_base * var_gct_err_lhs + var_e_a * var_msg * p^2)
24 // rhs = a_cols * n * var_base * var_gct_err_rhs * var_xs
25 let mut noise: f64 = (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs);
26 noise += var_msg * var_a_err * a_scale * a_scale * n;
27 noise *= rank_in;
28 noise /= b_scale * b_scale;
29 noise
30}
31
32#[allow(dead_code)]
33pub(crate) fn log2_std_noise_gglwe_product(
34 n: f64,
35 basek: usize,
36 var_xs: f64,
37 var_msg: f64,
38 var_a_err: f64,
39 var_gct_err_lhs: f64,
40 var_gct_err_rhs: f64,
41 rank_in: f64,
42 a_logq: usize,
43 b_logq: usize,
44) -> f64 {
45 let mut noise: f64 = var_noise_gglwe_product(
46 n,
47 basek,
48 var_xs,
49 var_msg,
50 var_a_err,
51 var_gct_err_lhs,
52 var_gct_err_rhs,
53 rank_in,
54 a_logq,
55 b_logq,
56 );
57 noise = noise.sqrt();
58 noise.log2().min(-1.0).max(-(a_logq as f64)) // max noise is [-2^{-1}, 2^{-1}]
59}
60
61#[allow(dead_code)]
62pub(crate) fn noise_ggsw_product(
63 n: f64,
64 basek: usize,
65 var_xs: f64,
66 var_msg: f64,
67 var_a0_err: f64,
68 var_a1_err: f64,
69 var_gct_err_lhs: f64,
70 var_gct_err_rhs: f64,
71 rank: f64,
72 k_in: usize,
73 k_ggsw: usize,
74) -> f64 {
75 let a_logq: usize = k_in.min(k_ggsw);
76 let a_cols: usize = a_logq.div_ceil(basek);
77
78 let b_scale: f64 = (k_ggsw as f64).exp2();
79 let a_scale: f64 = ((k_ggsw - a_logq) as f64).exp2();
80
81 let base: f64 = (basek as f64).exp2();
82 let var_base: f64 = base * base / 12f64;
83
84 // lhs = a_cols * n * (var_base * var_gct_err_lhs + var_e_a * var_msg * p^2)
85 // rhs = a_cols * n * var_base * var_gct_err_rhs * var_xs
86 let mut noise: f64 = (rank + 1.0) * (a_cols as f64) * n * var_base * (var_gct_err_lhs + var_xs * var_gct_err_rhs);
87 noise += var_msg * var_a0_err * a_scale * a_scale * n;
88 noise += var_msg * var_a1_err * a_scale * a_scale * n * var_xs * rank;
89 noise = noise.sqrt();
90 noise /= b_scale;
91 noise.log2().min(-1.0) // max noise is [-2^{-1}, 2^{-1}]
92}
93
94#[allow(dead_code)]
95pub(crate) fn noise_ggsw_keyswitch(
96 n: f64,
97 basek: usize,
98 col: usize,
99 var_xs: f64,
100 var_a_err: f64,
101 var_gct_err_lhs: f64,
102 var_gct_err_rhs: f64,
103 rank: f64,
104 k_ct: usize,
105 k_ksk: usize,
106 k_tsk: usize,
107) -> f64 {
108 let var_si_x_sj: f64 = n * var_xs * var_xs;
109
110 // Initial KS for col = 0
111 let mut noise: f64 = var_noise_gglwe_product(
112 n,
113 basek,
114 var_xs,
115 var_xs,
116 var_a_err,
117 var_gct_err_lhs,
118 var_gct_err_rhs,
119 rank,
120 k_ct,
121 k_ksk,
122 );
123
124 // Other GGSW reconstruction for col > 0
125 if col > 0 {
126 noise += var_noise_gglwe_product(
127 n,
128 basek,
129 var_xs,
130 var_si_x_sj,
131 var_a_err + 1f64 / 12.0,
132 var_gct_err_lhs,
133 var_gct_err_rhs,
134 rank,
135 k_ct,
136 k_tsk,
137 );
138 noise += n * noise * var_xs * 0.5;
139 }
140
141 noise = noise.sqrt();
142 noise.log2().min(-1.0) // max noise is [-2^{-1}, 2^{-1}]
143}