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