1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
use ;
use ;
/// The set of parameters for performing FHE computation with Sunscreen's circuit bootstrapping (CBS)
/// approach.
///
/// # Remarks
/// Computation unfolds over multiple ciphertext types encrypted under different keys and parameters.
/// The key intuition about using CBS for computation is to try to perform computation using
/// cheap CMux operations which require GGSW select inputs and GLWE a, b inputs and output.
/// Unfortunately, this interface is awkward and we must convert between ciphertext types as the
/// computation unfolds.
///
/// Ciphertexts convert in a cycle as follows:
/// ```ignore
/// l0 LWE -> l1 GGSW -> l1 GLWE -> l1 LWE -> l0 LWE
/// ```
///
/// where:
/// l1_params are high-noise and encrypt LWE ciphertexts.
/// l1_params contain a medium amount of noise and encrypt LWE, GLWE, and GGSW ciphertexts.
/// l2_params are low noise and are an implementation detail of circuit bootstrapping.
///
/// and each ciphertext encrypts a single 1 or 0 bit.
///
/// * l0 LWE -> l1 GGSW
/// The first step in the cycle is circuit bootstrapping, which simultaneously resets the noise in
/// the input l0 LWE ciphertext and emits a GGSW ciphertext. Internally, circuit bootstrapping
/// first bootstraps to l2 LWE multiple ciphertexts then applies private functional keyswitching
/// to generate the l1 GGSW ciphertext.
/// * l1 GGSW -> l1 GLWE
/// This step actually evaluates functions using trees of multiplexers (via the CMux
/// operation). The CMux operation accepts 2 GLWE ciphertexts, `a` and `b`, and a `GGSW`
/// ciphertext `sel`. The output is a GLWE ciphertext encrypting the same message as `a` when
/// `sel` is 0 and `b` when `sel` is 1.
///
/// To evaluate an N-bit function, we build a multiplexer tree using N layers.
/// At the first layer of the tree, we pass trivial one and zero encryptions as the a and b inputs
/// as the truth table requires as well as the first GGSW. We evaluate each subsequent `i-th`
/// mux layer, using outputs from the `(i-1)-th` layer as `a` and `b` inputs and the `i-th`
/// GGSW encrypted input as `sel`. The final result of this mux tree is an l1 GLWE ciphertext.
/// * l1 GLWE -> l1 LWE
/// We perform sample extraction to produce an LWE encryption of the 0th coefficient of the input
/// GLWE ciphertext's contained message (i.e. the encrypted bit).
/// * l1 LWE -> l0 LWE
/// LWE keyswitching changes the ciphertext's key so we can repeat this process and chain our
/// computation.
///
/// # Radix decomposition
/// Many operations decompose polynomials into the sum of polynomials with smaller coefficients, which
/// get recombobulated with gadget factors during the operation. This is a common technique that
/// reduces noise, but requires a tradeoff between performance and noise growth. Runtime scales
/// linearly with the radix count, so ideally this should be small. However, too small a radix count
/// causes computations to exceed the noise budget and results in wrong results when decrypted.
/// The standard 128-bit secure parameter set.
///
/// # Remarks
/// - This parameter set is compatible with RLWE public-key encryption.
/// - The noise exponent (2^x) at a given depth inside a CMUX tree can be
/// calculated using the following equation for the standard deviation
///
/// σ²_total(d) = σ₀² + d² * σₘ² + σₛ²(d), where σₛ(d) = f(x) = -1 / (a * (x + b)) + c"
/// where
/// - a = 0.029052727604361776
/// - b = 2525.7137265334895
/// - c = 0.02282344595365389
/// - d is the depth to look at (starting at 1).
///
/// This equation can be plugged into the gaussian tails error estimate to derive
/// the error at a given depth. For example, the `parasol_runtime` crate defines
/// the `probability_away_from_mean_gaussian_log` function to find the error
/// for a given plaintext modulus
///
/// ```rust, ignore
/// // We use 0.25 as the failure point in a binary scheme. In general for a
/// // plaintext modulus `p`, we use `1/(2p)` as the failure point.
/// probability_away_from_mean_gaussian_log(0.25, total_std_256).log_2();
/// ```
///
/// The error at a computational depth of 256 is about 2^(-300).
pub const DEFAULT_128: Params = Params ;
/// A balance of speed and keysize.
pub const FAST_BIG_128: Params = Params ;
/// Fastest parameters at the expense of significantly larger key size.
pub const TURBO_CHUNGUS_128: Params = Params ;