1use super::ShortintEngine;
4use crate::core_crypto::algorithms::*;
5use crate::core_crypto::commons::math::random::{Distribution, RandomGenerable};
6use crate::core_crypto::entities::*;
7use crate::shortint::ciphertext::{Degree, NoiseLevel};
8use crate::shortint::client_key::atomic_pattern::{
9 AtomicPatternClientKey, EncryptionAtomicPattern, StandardAtomicPatternClientKey,
10};
11use crate::shortint::client_key::GenericClientKey;
12use crate::shortint::parameters::{CarryModulus, MessageModulus, ModulusSwitchType};
13use crate::shortint::{
14 Ciphertext, ClassicPBSParameters, ClientKey, CompressedCiphertext, MaxNoiseLevel, PaddingBit,
15 ShortintEncoding, ShortintParameterSet,
16};
17
18impl ShortintEngine {
19 pub fn new_client_key<P>(&mut self, parameters: P) -> ClientKey
20 where
21 P: TryInto<ShortintParameterSet>,
22 <P as TryInto<ShortintParameterSet>>::Error: std::fmt::Debug,
23 {
24 let shortint_params: ShortintParameterSet = parameters.try_into().unwrap();
25
26 let atomic_pattern = if let Some(wopbs_params) = shortint_params.wopbs_parameters() {
27 let pbs_params = shortint_params.pbs_parameters().unwrap_or_else(|| {
32 ClassicPBSParameters {
33 lwe_dimension: wopbs_params.lwe_dimension,
34 glwe_dimension: wopbs_params.glwe_dimension,
35 polynomial_size: wopbs_params.polynomial_size,
36 lwe_noise_distribution: wopbs_params.lwe_noise_distribution,
37 glwe_noise_distribution: wopbs_params.glwe_noise_distribution,
38 pbs_base_log: wopbs_params.pbs_base_log,
39 pbs_level: wopbs_params.pbs_level,
40 ks_base_log: wopbs_params.ks_base_log,
41 ks_level: wopbs_params.ks_level,
42 message_modulus: wopbs_params.message_modulus,
43 carry_modulus: wopbs_params.carry_modulus,
44 max_noise_level: MaxNoiseLevel::from_msg_carry_modulus(
45 wopbs_params.message_modulus,
46 wopbs_params.carry_modulus,
47 ),
48 log2_p_fail: 1.0,
49 ciphertext_modulus: wopbs_params.ciphertext_modulus,
50 encryption_key_choice: wopbs_params.encryption_key_choice,
51 modulus_switch_noise_reduction_params: ModulusSwitchType::Standard,
52 }
53 .into()
54 });
55
56 let std_ck = StandardAtomicPatternClientKey::new_with_engine(
57 pbs_params,
58 Some(wopbs_params),
59 self,
60 );
61 AtomicPatternClientKey::Standard(std_ck)
62 } else if let Some(ap_params) = shortint_params.ap_parameters() {
63 AtomicPatternClientKey::new_with_engine(ap_params, self)
64 } else {
65 panic!("Invalid parameters, missing Atomic Pattern or WOPBS params")
66 };
67
68 ClientKey { atomic_pattern }
69 }
70
71 pub fn encrypt<AP: EncryptionAtomicPattern>(
72 &mut self,
73 client_key: &GenericClientKey<AP>,
74 message: u64,
75 ) -> Ciphertext {
76 self.encrypt_with_message_modulus(
77 client_key,
78 message,
79 client_key.parameters().message_modulus(),
80 )
81 }
82
83 pub fn encrypt_compressed<AP: EncryptionAtomicPattern>(
84 &mut self,
85 client_key: &GenericClientKey<AP>,
86 message: u64,
87 ) -> CompressedCiphertext {
88 self.encrypt_with_message_modulus_compressed(
89 client_key,
90 message,
91 client_key.parameters().message_modulus(),
92 )
93 }
94
95 fn encrypt_inner_ct<KeyCont, NoiseDistribution>(
96 &mut self,
97 client_key_parameters: &ShortintParameterSet,
98 client_lwe_sk: &LweSecretKey<KeyCont>,
99 noise_distribution: NoiseDistribution,
100 message: u64,
101 message_modulus: MessageModulus,
102 ) -> LweCiphertextOwned<u64>
103 where
104 NoiseDistribution: Distribution,
105 u64: RandomGenerable<NoiseDistribution, CustomModulus = u64>,
106 KeyCont: crate::core_crypto::commons::traits::Container<Element = u64>,
107 {
108 let m = Cleartext(message % message_modulus.0);
109
110 let encoded =
111 ShortintEncoding::from_parameters(*client_key_parameters, PaddingBit::Yes).encode(m);
112
113 allocate_and_encrypt_new_lwe_ciphertext(
114 client_lwe_sk,
115 encoded,
116 noise_distribution,
117 client_key_parameters.ciphertext_modulus(),
118 &mut self.encryption_generator,
119 )
120 }
121
122 pub(crate) fn encrypt_with_message_modulus<AP: EncryptionAtomicPattern>(
123 &mut self,
124 client_key: &GenericClientKey<AP>,
125 message: u64,
126 message_modulus: MessageModulus,
127 ) -> Ciphertext {
128 let params_atomic_pattern = client_key.parameters().atomic_pattern();
129
130 let (encryption_lwe_sk, encryption_noise_distribution) =
131 client_key.encryption_key_and_noise();
132
133 let ct = self.encrypt_inner_ct(
134 &client_key.parameters(),
135 &encryption_lwe_sk,
136 encryption_noise_distribution,
137 message,
138 message_modulus,
139 );
140
141 let carry_modulus = (client_key.parameters().message_modulus().0
144 * client_key.parameters().carry_modulus().0)
145 / message_modulus.0;
146
147 Ciphertext::new(
148 ct,
149 Degree::new(message_modulus.0 - 1),
150 NoiseLevel::NOMINAL,
151 message_modulus,
152 CarryModulus(carry_modulus),
153 params_atomic_pattern,
154 )
155 }
156
157 pub(crate) fn encrypt_with_message_and_carry_modulus<AP: EncryptionAtomicPattern>(
158 &mut self,
159 client_key: &GenericClientKey<AP>,
160 message: u64,
161 message_modulus: MessageModulus,
162 carry_modulus: CarryModulus,
163 ) -> Ciphertext {
164 assert!(
165 message_modulus.0 * carry_modulus.0
166 <= client_key.parameters().message_modulus().0
167 * client_key.parameters().carry_modulus().0,
168 "MessageModulus * CarryModulus should be \
169 smaller or equal to the max given by the parameter set."
170 );
171
172 let atomic_pattern = client_key.parameters().atomic_pattern();
173
174 let (encryption_lwe_sk, encryption_noise_distribution) =
175 client_key.encryption_key_and_noise();
176
177 let ct = self.encrypt_inner_ct(
178 &client_key.parameters(),
179 &encryption_lwe_sk,
180 encryption_noise_distribution,
181 message,
182 message_modulus,
183 );
184
185 Ciphertext::new(
186 ct,
187 Degree::new(message_modulus.0 - 1),
188 NoiseLevel::NOMINAL,
189 message_modulus,
190 carry_modulus,
191 atomic_pattern,
192 )
193 }
194
195 pub(crate) fn encrypt_with_message_modulus_compressed<AP: EncryptionAtomicPattern>(
196 &mut self,
197 client_key: &GenericClientKey<AP>,
198 message: u64,
199 message_modulus: MessageModulus,
200 ) -> CompressedCiphertext {
201 let carry_modulus = (client_key.parameters().message_modulus().0
204 * client_key.parameters().carry_modulus().0)
205 / message_modulus.0;
206
207 let m = Cleartext(message % message_modulus.0);
208
209 let encoded =
210 ShortintEncoding::from_parameters(client_key.parameters(), PaddingBit::Yes).encode(m);
211
212 let atomic_pattern = client_key.parameters().atomic_pattern();
213
214 let (encryption_lwe_sk, encryption_noise_distribution) =
215 client_key.encryption_key_and_noise();
216
217 let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
218 &encryption_lwe_sk,
219 encoded,
220 encryption_noise_distribution,
221 client_key.parameters().ciphertext_modulus(),
222 &mut self.seeder,
223 );
224
225 CompressedCiphertext {
226 ct,
227 degree: Degree::new(message_modulus.0 - 1),
228 message_modulus,
229 carry_modulus: CarryModulus(carry_modulus),
230 atomic_pattern,
231 noise_level: NoiseLevel::NOMINAL,
232 }
233 }
234
235 pub(crate) fn unchecked_encrypt<AP: EncryptionAtomicPattern>(
236 &mut self,
237 client_key: &GenericClientKey<AP>,
238 message: u64,
239 ) -> Ciphertext {
240 let atomic_pattern = client_key.parameters().atomic_pattern();
241
242 let (encryption_lwe_sk, encryption_noise_distribution) =
243 client_key.encryption_key_and_noise();
244
245 let encoded = ShortintEncoding::from_parameters(client_key.parameters(), PaddingBit::Yes)
246 .encode(Cleartext(message));
247
248 let ct = allocate_and_encrypt_new_lwe_ciphertext(
249 &encryption_lwe_sk,
250 encoded,
251 encryption_noise_distribution,
252 client_key.parameters().ciphertext_modulus(),
253 &mut self.encryption_generator,
254 );
255
256 Ciphertext::new(
257 ct,
258 Degree::new(
259 client_key.parameters().message_modulus().0
260 * client_key.parameters().carry_modulus().0
261 - 1,
262 ),
263 NoiseLevel::NOMINAL,
264 client_key.parameters().message_modulus(),
265 client_key.parameters().carry_modulus(),
266 atomic_pattern,
267 )
268 }
269
270 pub(crate) fn encrypt_without_padding<AP: EncryptionAtomicPattern>(
271 &mut self,
272 client_key: &GenericClientKey<AP>,
273 message: u64,
274 ) -> Ciphertext {
275 let encoded = ShortintEncoding::from_parameters(client_key.parameters(), PaddingBit::No)
276 .encode(Cleartext(message));
277
278 let atomic_pattern = client_key.parameters().atomic_pattern();
279
280 let (encryption_lwe_sk, encryption_noise_distribution) =
281 client_key.encryption_key_and_noise();
282
283 let ct = allocate_and_encrypt_new_lwe_ciphertext(
284 &encryption_lwe_sk,
285 encoded,
286 encryption_noise_distribution,
287 client_key.parameters().ciphertext_modulus(),
288 &mut self.encryption_generator,
289 );
290
291 Ciphertext::new(
292 ct,
293 Degree::new(client_key.parameters().message_modulus().0 - 1),
294 NoiseLevel::NOMINAL,
295 client_key.parameters().message_modulus(),
296 client_key.parameters().carry_modulus(),
297 atomic_pattern,
298 )
299 }
300
301 pub(crate) fn encrypt_without_padding_compressed<AP: EncryptionAtomicPattern>(
302 &mut self,
303 client_key: &GenericClientKey<AP>,
304 message: u64,
305 ) -> CompressedCiphertext {
306 let encoded = ShortintEncoding::from_parameters(client_key.parameters(), PaddingBit::No)
307 .encode(Cleartext(message));
308
309 let atomic_pattern = client_key.parameters().atomic_pattern();
310
311 let (encryption_lwe_sk, encryption_noise_distribution) =
312 client_key.encryption_key_and_noise();
313
314 let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
315 &encryption_lwe_sk,
316 encoded,
317 encryption_noise_distribution,
318 client_key.parameters().ciphertext_modulus(),
319 &mut self.seeder,
320 );
321
322 CompressedCiphertext {
323 ct,
324 degree: Degree::new(client_key.parameters().message_modulus().0 - 1),
325 message_modulus: client_key.parameters().message_modulus(),
326 carry_modulus: client_key.parameters().carry_modulus(),
327 atomic_pattern,
328 noise_level: NoiseLevel::NOMINAL,
329 }
330 }
331
332 pub(crate) fn encrypt_native_crt<AP: EncryptionAtomicPattern>(
333 &mut self,
334 client_key: &GenericClientKey<AP>,
335 message: u64,
336 message_modulus: MessageModulus,
337 ) -> Ciphertext {
338 let carry_modulus = CarryModulus(1);
339 let m = (message % message_modulus.0) as u128;
340 let shifted_message = (m * (1 << 64) / message_modulus.0 as u128) as u64;
341
342 let encoded = Plaintext(shifted_message);
343
344 let atomic_pattern = client_key.parameters().atomic_pattern();
345
346 let (encryption_lwe_sk, encryption_noise_distribution) =
347 client_key.encryption_key_and_noise();
348
349 let ct = allocate_and_encrypt_new_lwe_ciphertext(
350 &encryption_lwe_sk,
351 encoded,
352 encryption_noise_distribution,
353 client_key.parameters().ciphertext_modulus(),
354 &mut self.encryption_generator,
355 );
356
357 Ciphertext::new(
358 ct,
359 Degree::new(message_modulus.0 - 1),
360 NoiseLevel::NOMINAL,
361 message_modulus,
362 carry_modulus,
363 atomic_pattern,
364 )
365 }
366
367 pub(crate) fn encrypt_native_crt_compressed<AP: EncryptionAtomicPattern>(
368 &mut self,
369 client_key: &GenericClientKey<AP>,
370 message: u64,
371 message_modulus: MessageModulus,
372 ) -> CompressedCiphertext {
373 let carry_modulus = CarryModulus(1);
374 let m = (message % message_modulus.0) as u128;
375 let shifted_message = (m * (1 << 64) / message_modulus.0 as u128) as u64;
376
377 let encoded = Plaintext(shifted_message);
378
379 let atomic_pattern = client_key.parameters().atomic_pattern();
380
381 let (encryption_lwe_sk, encryption_noise_distribution) =
382 client_key.encryption_key_and_noise();
383
384 let ct = allocate_and_encrypt_new_seeded_lwe_ciphertext(
385 &encryption_lwe_sk,
386 encoded,
387 encryption_noise_distribution,
388 client_key.parameters().ciphertext_modulus(),
389 &mut self.seeder,
390 );
391
392 CompressedCiphertext {
393 ct,
394 degree: Degree::new(message_modulus.0 - 1),
395 message_modulus,
396 carry_modulus,
397 atomic_pattern,
398 noise_level: NoiseLevel::NOMINAL,
399 }
400 }
401}