Skip to main content

tfhe/shortint/client_key/
mod.rs

1//! Module with the definition of the ClientKey.
2
3pub mod atomic_pattern;
4pub(crate) mod secret_encryption_key;
5use atomic_pattern::{
6    AtomicPatternClientKey, EncryptionAtomicPattern, StandardAtomicPatternClientKey,
7};
8use tfhe_versionable::Versionize;
9
10use super::parameters::ShortintKeySwitchingParameters;
11use super::server_key::UnsupportedOperation;
12use super::{AtomicPatternParameters, PaddingBit, ShortintEncoding};
13use crate::core_crypto::entities::*;
14use crate::core_crypto::prelude::decrypt_lwe_ciphertext;
15use crate::shortint::backward_compatibility::client_key::ClientKeyVersions;
16use crate::shortint::ciphertext::{Ciphertext, CompressedCiphertext};
17use crate::shortint::engine::ShortintEngine;
18use crate::shortint::parameters::{DynamicDistribution, MessageModulus, ShortintParameterSet};
19use crate::shortint::CarryModulus;
20use secret_encryption_key::SecretEncryptionKeyView;
21use serde::{Deserialize, Serialize};
22use std::fmt::{Debug, Display};
23
24/// A structure containing the client key, which must be kept secret.
25///
26/// In more details, it contains:
27/// * `lwe_secret_key` - an LWE secret key, used to encrypt the inputs and decrypt the outputs. This
28///   secret key is also used in the generation of bootstrapping and key switching keys.
29/// * `glwe_secret_key` - a GLWE secret key, used to generate the bootstrapping keys and key
30///   switching keys.
31/// * `parameters` - the cryptographic parameter set.
32#[derive(Copy, Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Versionize)]
33#[versionize(ClientKeyVersions)]
34pub struct GenericClientKey<AP> {
35    pub atomic_pattern: AP,
36}
37
38pub type ClientKey = GenericClientKey<AtomicPatternClientKey>;
39pub type StandardClientKey = GenericClientKey<StandardAtomicPatternClientKey>;
40pub type ClientKeyView<'key> = GenericClientKey<&'key AtomicPatternClientKey>;
41pub type StandardClientKeyView<'key> = GenericClientKey<&'key StandardAtomicPatternClientKey>;
42
43impl<'cks> From<&'cks ClientKey> for SecretEncryptionKeyView<'cks> {
44    fn from(value: &'cks ClientKey) -> Self {
45        Self {
46            lwe_secret_key: value.encryption_key(),
47            message_modulus: value.parameters().message_modulus(),
48            carry_modulus: value.parameters().carry_modulus(),
49        }
50    }
51}
52
53impl<'key> TryFrom<ClientKeyView<'key>> for StandardClientKeyView<'key> {
54    type Error = UnsupportedOperation;
55
56    fn try_from(value: ClientKeyView<'key>) -> Result<Self, Self::Error> {
57        let AtomicPatternClientKey::Standard(atomic_pattern) = value.atomic_pattern else {
58            return Err(UnsupportedOperation);
59        };
60
61        Ok(Self { atomic_pattern })
62    }
63}
64
65impl<AP> GenericClientKey<AP> {
66    pub fn as_view(&self) -> GenericClientKey<&AP> {
67        GenericClientKey {
68            atomic_pattern: &self.atomic_pattern,
69        }
70    }
71}
72
73impl ClientKey {
74    /// Generate a client key.
75    ///
76    /// # Example
77    ///
78    /// ```rust
79    /// use tfhe::shortint::client_key::ClientKey;
80    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
81    ///
82    /// // Generate the client key:
83    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
84    /// ```
85    pub fn new<P>(parameters: P) -> Self
86    where
87        P: TryInto<ShortintParameterSet>,
88        <P as TryInto<ShortintParameterSet>>::Error: Debug,
89    {
90        ShortintEngine::with_thread_local_mut(|engine| engine.new_client_key(parameters))
91    }
92
93    pub fn try_from_lwe_encryption_key<P>(
94        encryption_key: LweSecretKeyOwned<u64>,
95        parameters: P,
96    ) -> crate::Result<Self>
97    where
98        P: TryInto<AtomicPatternParameters>,
99        <P as TryInto<AtomicPatternParameters>>::Error: Display,
100    {
101        let parameters = parameters
102            .try_into()
103            .map_err(|err| crate::Error::new(format!("{err}")))?;
104
105        let atomic_pattern =
106            AtomicPatternClientKey::try_from_lwe_encryption_key(encryption_key, parameters)?;
107
108        Ok(Self { atomic_pattern })
109    }
110}
111
112impl<AP: EncryptionAtomicPattern> GenericClientKey<AP> {
113    pub fn parameters(&self) -> ShortintParameterSet {
114        self.atomic_pattern.parameters()
115    }
116
117    /// Returns a view of the key used for encryption
118    pub fn encryption_key(&self) -> LweSecretKeyView<'_, u64> {
119        self.atomic_pattern.encryption_key()
120    }
121
122    /// Returns a view to the encryption key and the corresponding noise distribution.
123    pub fn encryption_key_and_noise(
124        &self,
125    ) -> (LweSecretKeyView<'_, u64>, DynamicDistribution<u64>) {
126        self.atomic_pattern.encryption_key_and_noise()
127    }
128
129    #[cfg(test)]
130    pub fn create_trivial(&self, value: u64) -> Ciphertext {
131        let modular_value = value % self.parameters().message_modulus().0;
132        self.unchecked_create_trivial(modular_value)
133    }
134
135    #[cfg(test)]
136    pub fn unchecked_create_trivial(&self, value: u64) -> Ciphertext {
137        let params = self.parameters();
138
139        let lwe_size = params.encryption_lwe_dimension().to_lwe_size();
140
141        super::ciphertext::unchecked_create_trivial_with_lwe_size(
142            Cleartext(value),
143            lwe_size,
144            params.message_modulus(),
145            params.carry_modulus(),
146            params.atomic_pattern(),
147            params.ciphertext_modulus(),
148        )
149    }
150
151    /// Encrypt a small integer message using the client key.
152    ///
153    /// The input message is reduced to the encrypted message space modulus
154    ///
155    /// # Example
156    ///
157    /// ```rust
158    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
159    /// use tfhe::shortint::ClientKey;
160    ///
161    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
162    ///
163    /// // Encryption of one message that is within the encrypted message modulus:
164    /// let msg = 3;
165    /// let ct = cks.encrypt(msg);
166    ///
167    /// let dec = cks.decrypt(&ct);
168    /// assert_eq!(msg, dec);
169    ///
170    /// // Encryption of one message that is outside the encrypted message modulus:
171    /// let msg = 5;
172    /// let ct = cks.encrypt(msg);
173    ///
174    /// let dec = cks.decrypt(&ct);
175    /// let modulus = cks.parameters().message_modulus().0;
176    /// assert_eq!(msg % modulus, dec);
177    /// ```
178    pub fn encrypt(&self, message: u64) -> Ciphertext {
179        ShortintEngine::with_thread_local_mut(|engine| engine.encrypt(self, message))
180    }
181
182    /// Encrypt a integer message using the client key returning a compressed ciphertext.
183    ///
184    /// The input message is reduced to the encrypted message space modulus
185    ///
186    /// # Example
187    ///
188    /// ```rust
189    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
190    /// use tfhe::shortint::ClientKey;
191    ///
192    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
193    ///
194    /// // Encryption of one message that is within the encrypted message modulus:
195    /// let msg = 3;
196    /// let ct = cks.encrypt_compressed(msg);
197    ///
198    /// let ct = ct.decompress();
199    ///
200    /// let dec = cks.decrypt(&ct);
201    /// assert_eq!(msg, dec);
202    ///
203    /// // Encryption of one message that is outside the encrypted message modulus:
204    /// let msg = 5;
205    /// let ct = cks.encrypt_compressed(msg);
206    ///
207    /// let ct = ct.decompress();
208    ///
209    /// let dec = cks.decrypt(&ct);
210    /// let modulus = cks.parameters().message_modulus().0;
211    /// assert_eq!(msg % modulus, dec);
212    /// ```
213    pub fn encrypt_compressed(&self, message: u64) -> CompressedCiphertext {
214        ShortintEngine::with_thread_local_mut(|engine| engine.encrypt_compressed(self, message))
215    }
216
217    /// Encrypt a small integer message using the client key with a specific message modulus
218    ///
219    /// # Example
220    ///
221    /// ```rust
222    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
223    /// use tfhe::shortint::ClientKey;
224    ///
225    /// // Generate the client key
226    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
227    ///
228    /// let msg = 3;
229    ///
230    /// // Encryption of one message:
231    /// let ct = cks.encrypt_with_message_modulus(msg, MessageModulus(6));
232    ///
233    /// // Decryption:
234    /// let dec = cks.decrypt(&ct);
235    /// assert_eq!(msg, dec);
236    /// ```
237    pub fn encrypt_with_message_modulus(
238        &self,
239        message: u64,
240        message_modulus: MessageModulus,
241    ) -> Ciphertext {
242        ShortintEngine::with_thread_local_mut(|engine| {
243            engine.encrypt_with_message_modulus(self, message, message_modulus)
244        })
245    }
246
247    /// Encrypt a small integer message using the client key with a specific message and carry
248    /// moduli.
249    ///
250    /// # Warning
251    /// Defining specific message AND carry moduli might lead to incorrect homomorphic
252    /// computations.
253    ///
254    /// # Example
255    ///
256    /// ```rust
257    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2};
258    /// use tfhe::shortint::{CarryModulus, ClientKey};
259    ///
260    /// // Generate the client key
261    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2);
262    ///
263    /// let msg = 3;
264    ///
265    /// // Encryption of one message with MessageModulus = 2 and CarryModulus = 2
266    /// // so that 6*2 < 2^(2 + 2) from the parameter set
267    /// let ct = cks.encrypt_with_message_and_carry_modulus(msg, MessageModulus(6), CarryModulus(2));
268    ///
269    /// // Decryption:
270    /// let dec = cks.decrypt(&ct);
271    /// assert_eq!(msg, dec);
272    /// ```
273    pub fn encrypt_with_message_and_carry_modulus(
274        &self,
275        message: u64,
276        message_modulus: MessageModulus,
277        carry_modulus: CarryModulus,
278    ) -> Ciphertext {
279        ShortintEngine::with_thread_local_mut(|engine| {
280            engine.encrypt_with_message_and_carry_modulus(
281                self,
282                message,
283                message_modulus,
284                carry_modulus,
285            )
286        })
287    }
288
289    /// Encrypt a small integer message using the client key with a specific message modulus
290    /// returning a compressed ciphertext
291    ///
292    /// # Example
293    ///
294    /// ```rust
295    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
296    /// use tfhe::shortint::ClientKey;
297    ///
298    /// // Generate the client key
299    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
300    ///
301    /// let msg = 3;
302    ///
303    /// // Encryption of one message:
304    /// let ct = cks.encrypt_with_message_modulus_compressed(msg, MessageModulus(6));
305    ///
306    /// let ct = ct.decompress();
307    ///
308    /// // Decryption:
309    /// let dec = cks.decrypt(&ct);
310    /// assert_eq!(msg, dec);
311    /// ```
312    pub fn encrypt_with_message_modulus_compressed(
313        &self,
314        message: u64,
315        message_modulus: MessageModulus,
316    ) -> CompressedCiphertext {
317        ShortintEngine::with_thread_local_mut(|engine| {
318            engine.encrypt_with_message_modulus_compressed(self, message, message_modulus)
319        })
320    }
321
322    /// Encrypt an integer without reducing the input message modulus the message space
323    ///
324    /// # Example
325    ///
326    /// ```rust
327    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
328    /// use tfhe::shortint::ClientKey;
329    ///
330    /// // Generate the client key
331    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
332    ///
333    /// let msg = 7;
334    /// let ct = cks.unchecked_encrypt(msg);
335    /// // |       ct        |
336    /// // | carry | message |
337    /// // |-------|---------|
338    /// // |  0 1  |   1 1   |
339    ///
340    /// let dec = cks.decrypt_message_and_carry(&ct);
341    /// assert_eq!(msg, dec);
342    /// ```
343    pub fn unchecked_encrypt(&self, message: u64) -> Ciphertext {
344        ShortintEngine::with_thread_local_mut(|engine| engine.unchecked_encrypt(self, message))
345    }
346
347    /// Decrypt a ciphertext encrypting an integer message and carries using the client key.
348    ///
349    /// # Example
350    ///
351    /// ```rust
352    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
353    /// use tfhe::shortint::ClientKey;
354    ///
355    /// // Generate the client key
356    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
357    ///
358    /// let msg = 3;
359    ///
360    /// // Encryption of one message:
361    /// let ct = cks.encrypt(msg);
362    ///
363    /// // Decryption:
364    /// let dec = cks.decrypt_message_and_carry(&ct);
365    /// assert_eq!(msg, dec);
366    /// ```
367    pub fn decrypt_message_and_carry(&self, ct: &Ciphertext) -> u64 {
368        let decrypted_u64 = self.decrypt_no_decode(ct);
369
370        ShortintEncoding::from_parameters(self.parameters(), PaddingBit::Yes)
371            .decode(decrypted_u64)
372            .0
373    }
374
375    /// Decrypt a ciphertext encrypting a message using the client key.
376    ///
377    /// # Example
378    ///
379    /// ```rust
380    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
381    /// use tfhe::shortint::ClientKey;
382    ///
383    /// // Generate the client key
384    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
385    ///
386    /// let msg = 3;
387    ///
388    /// // Encryption of one message:
389    /// let ct = cks.encrypt(msg);
390    ///
391    /// // Decryption:
392    /// let dec = cks.decrypt(&ct);
393    /// assert_eq!(msg, dec);
394    /// ```
395    pub fn decrypt(&self, ct: &Ciphertext) -> u64 {
396        self.decrypt_message_and_carry(ct) % ct.message_modulus.0
397    }
398
399    /// Decrypt a ciphertext without decoding the message, using the client key.
400    ///
401    /// This can be used to extract noise values after doing some computations.
402    ///
403    /// # Example
404    ///
405    /// ```rust
406    /// use tfhe::shortint::gen_keys;
407    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
408    ///
409    /// // Generate the keys
410    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
411    ///
412    /// let msg = 3;
413    ///
414    /// // Encryption of two messages:
415    /// let ct1 = cks.encrypt(msg);
416    /// let ct2 = cks.encrypt(msg);
417    ///
418    /// // Compute homomorphically an addition to generate a carry
419    /// let ct_res = sks.unchecked_add(&ct1, &ct2);
420    ///
421    /// // Decrypt:
422    /// let res = cks.decrypt_no_decode(&ct_res);
423    /// let expected_res = 3 + 3;
424    /// // Delta for params 2_2 with a padding bit
425    /// let delta = (1u64 << (u64::BITS - 1 - 1)) / 16 * 2;
426    /// let noise = res.0.wrapping_sub(expected_res * delta);
427    ///
428    /// assert!((noise as i64).abs() < delta as i64 / 2);
429    /// ```
430    pub fn decrypt_no_decode(&self, ct: &Ciphertext) -> Plaintext<u64> {
431        let lwe_decryption_key = self.encryption_key();
432
433        decrypt_lwe_ciphertext(&lwe_decryption_key, &ct.ct)
434    }
435
436    /// Encrypt a small integer message using the client key without padding bit.
437    ///
438    /// The input message is reduced to the encrypted message space modulus
439    ///
440    /// # Example
441    ///
442    /// ```rust
443    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
444    /// use tfhe::shortint::ClientKey;
445    ///
446    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
447    ///
448    /// // Encryption of one message that is within the encrypted message modulus:
449    /// let msg = 6;
450    /// let ct = cks.encrypt_without_padding(msg);
451    ///
452    /// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
453    /// assert_eq!(msg, dec);
454    /// ```
455    pub fn encrypt_without_padding(&self, message: u64) -> Ciphertext {
456        ShortintEngine::with_thread_local_mut(|engine| {
457            engine.encrypt_without_padding(self, message)
458        })
459    }
460
461    /// Encrypt a small integer message using the client key without padding bit returning a
462    /// compressed message.
463    ///
464    /// The input message is reduced to the encrypted message space modulus
465    ///
466    /// # Example
467    ///
468    /// ```rust
469    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
470    /// use tfhe::shortint::ClientKey;
471    ///
472    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
473    ///
474    /// // Encryption of one message that is within the encrypted message modulus:
475    /// let msg = 6;
476    /// let ct = cks.encrypt_without_padding_compressed(msg);
477    ///
478    /// let ct = ct.decompress();
479    ///
480    /// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
481    /// assert_eq!(msg, dec);
482    /// ```
483    pub fn encrypt_without_padding_compressed(&self, message: u64) -> CompressedCiphertext {
484        ShortintEngine::with_thread_local_mut(|engine| {
485            engine.encrypt_without_padding_compressed(self, message)
486        })
487    }
488
489    /// Decrypt a ciphertext encrypting an integer message and carries using the client key,
490    /// where the ciphertext is assumed to not have any padding bit.
491    ///
492    /// # Example
493    ///
494    /// ```rust
495    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
496    /// use tfhe::shortint::ClientKey;
497    ///
498    /// // Generate the client key
499    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
500    ///
501    /// let msg = 3;
502    ///
503    /// // Encryption of one message:
504    /// let ct = cks.encrypt_without_padding(msg);
505    ///
506    /// // Decryption:
507    /// let dec = cks.decrypt_message_and_carry_without_padding(&ct);
508    /// assert_eq!(msg, dec);
509    /// ```
510    pub fn decrypt_message_and_carry_without_padding(&self, ct: &Ciphertext) -> u64 {
511        let decrypted_u64 = self.decrypt_no_decode(ct);
512
513        ShortintEncoding::from_parameters(self.parameters(), PaddingBit::No)
514            .decode(decrypted_u64)
515            .0
516    }
517
518    /// Decrypt a ciphertext encrypting an integer message using the client key,
519    /// where the ciphertext is assumed to not have any padding bit.
520    ///
521    /// # Example
522    ///
523    /// ```rust
524    /// use tfhe::shortint::parameters::PARAM_MESSAGE_2_CARRY_2_KS_PBS;
525    /// use tfhe::shortint::ClientKey;
526    ///
527    /// // Generate the client key
528    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
529    ///
530    /// let msg = 7;
531    /// let modulus = 4;
532    ///
533    /// // Encryption of one message:
534    /// let ct = cks.encrypt_without_padding(msg);
535    ///
536    /// // Decryption:
537    /// let dec = cks.decrypt_without_padding(&ct);
538    /// assert_eq!(msg % modulus, dec);
539    /// ```
540    pub fn decrypt_without_padding(&self, ct: &Ciphertext) -> u64 {
541        self.decrypt_message_and_carry_without_padding(ct) % ct.message_modulus.0
542    }
543
544    /// Encrypt a small integer message using the client key without padding bit with some modulus.
545    ///
546    /// The input message is reduced to the encrypted message space modulus
547    ///
548    /// # Example
549    ///
550    /// ```rust
551    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
552    /// use tfhe::shortint::ClientKey;
553    ///
554    /// // Generate the client key
555    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
556    ///
557    /// let msg = 2;
558    /// let modulus = MessageModulus(3);
559    ///
560    /// // Encryption of one message:
561    /// let ct = cks.encrypt_native_crt(msg, modulus);
562    ///
563    /// // Decryption:
564    /// let dec = cks.decrypt_message_native_crt(&ct, modulus);
565    /// assert_eq!(msg, dec % modulus.0);
566    /// ```
567    pub fn encrypt_native_crt(&self, message: u64, message_modulus: MessageModulus) -> Ciphertext {
568        ShortintEngine::with_thread_local_mut(|engine| {
569            engine.encrypt_native_crt(self, message, message_modulus)
570        })
571    }
572
573    /// Encrypt a small integer message using the client key without padding bit with some modulus
574    /// returning a compressed ciphertext.
575    ///
576    /// The input message is reduced to the encrypted message space modulus
577    ///
578    /// # Example
579    ///
580    /// ```rust
581    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
582    /// use tfhe::shortint::ClientKey;
583    ///
584    /// // Generate the client key
585    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
586    ///
587    /// let msg = 2;
588    /// let modulus = MessageModulus(3);
589    ///
590    /// // Encryption of one message:
591    /// let ct = cks.encrypt_native_crt_compressed(msg, modulus);
592    ///
593    /// let ct = ct.decompress();
594    ///
595    /// // Decryption:
596    /// let dec = cks.decrypt_message_native_crt(&ct, modulus);
597    /// assert_eq!(msg, dec % modulus.0);
598    /// ```
599    pub fn encrypt_native_crt_compressed(
600        &self,
601        message: u64,
602        message_modulus: MessageModulus,
603    ) -> CompressedCiphertext {
604        ShortintEngine::with_thread_local_mut(|engine| {
605            engine.encrypt_native_crt_compressed(self, message, message_modulus)
606        })
607    }
608
609    /// Decrypt a ciphertext encrypting an integer message using the client key,
610    /// where the ciphertext is assumed to not have any padding bit and is related to some modulus.
611    ///
612    /// # Example
613    ///
614    /// ```rust
615    /// use tfhe::shortint::parameters::{MessageModulus, PARAM_MESSAGE_2_CARRY_2_KS_PBS};
616    /// use tfhe::shortint::ClientKey;
617    ///
618    /// // Generate the client key
619    /// let cks = ClientKey::new(PARAM_MESSAGE_2_CARRY_2_KS_PBS);
620    ///
621    /// let msg = 1;
622    /// let modulus = MessageModulus(3);
623    ///
624    /// // Encryption of one message:
625    /// let ct = cks.encrypt_native_crt(msg, modulus);
626    ///
627    /// // Decryption:
628    /// let dec = cks.decrypt_message_native_crt(&ct, modulus);
629    /// assert_eq!(msg, dec % modulus.0);
630    /// ```
631    pub fn decrypt_message_native_crt(
632        &self,
633        ct: &Ciphertext,
634        message_modulus: MessageModulus,
635    ) -> u64 {
636        let basis = message_modulus.0;
637
638        let decrypted_u64: u64 = self.decrypt_no_decode(ct).0;
639
640        let mut result = decrypted_u64 as u128 * basis as u128;
641        result = result.wrapping_add((result & (1 << 63)) << 1) / (1 << 64);
642
643        result as u64 % basis
644    }
645}
646
647impl StandardClientKeyView<'_> {
648    /// Returns a view to the encryption key used for a keyswitch operation and the corresponding
649    /// noise distribution.
650    pub fn keyswitch_encryption_key_and_noise(
651        &self,
652        params: ShortintKeySwitchingParameters,
653    ) -> (LweSecretKeyView<'_, u64>, DynamicDistribution<u64>) {
654        self.atomic_pattern
655            .keyswitch_encryption_key_and_noise(params)
656    }
657}