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