concrete_integer/server_key/crt_parallel/
mul_crt.rs

1use crate::ciphertext::CrtCiphertext;
2use crate::ServerKey;
3use rayon::prelude::*;
4
5impl ServerKey {
6    /// Computes homomorphically a multiplication between two ciphertexts encrypting integer
7    /// values in the CRT decomposition.
8    ///
9    /// # Example
10    ///
11    /// ```rust
12    /// use concrete_integer::gen_keys_crt;
13    /// use concrete_shortint::parameters::PARAM_MESSAGE_3_CARRY_3;
14    /// let size = 3;
15    ///
16    /// // Generate the client key and the server key:
17    /// let basis = vec![2, 3, 5];
18    /// let (cks, sks) = gen_keys_crt(&PARAM_MESSAGE_3_CARRY_3, basis);
19    ///
20    /// let clear_1 = 29;
21    /// let clear_2 = 23;
22    ///
23    /// // Encrypt two messages
24    /// let mut ctxt_1 = cks.encrypt(clear_1);
25    /// let ctxt_2 = cks.encrypt(clear_2);
26    ///
27    /// // Compute homomorphically a multiplication
28    /// sks.unchecked_crt_mul_assign_parallelized(&mut ctxt_1, &ctxt_2);
29    /// // Decrypt
30    /// let res = cks.decrypt(&ctxt_1);
31    /// assert_eq!((clear_1 * clear_2) % 30, res);
32    /// ```
33    pub fn unchecked_crt_mul_assign_parallelized(
34        &self,
35        ct_left: &mut CrtCiphertext,
36        ct_right: &CrtCiphertext,
37    ) {
38        ct_left
39            .blocks
40            .par_iter_mut()
41            .zip(&ct_right.blocks)
42            .for_each(|(ct_left, ct_right)| {
43                self.key.unchecked_mul_lsb_assign(ct_left, ct_right);
44            });
45    }
46
47    pub fn unchecked_crt_mul_parallelized(
48        &self,
49        ct_left: &CrtCiphertext,
50        ct_right: &CrtCiphertext,
51    ) -> CrtCiphertext {
52        let mut ct_res = ct_left.clone();
53        self.unchecked_crt_mul_assign_parallelized(&mut ct_res, ct_right);
54        ct_res
55    }
56
57    /// Computes homomorphically a multiplication between two ciphertexts encrypting integer
58    /// values in the CRT decomposition.
59    ///
60    /// This checks that the addition is possible. In the case where the carry buffers are full,
61    /// then it is automatically cleared to allow the operation.
62    ///
63    /// # Example
64    ///
65    /// ```rust
66    /// use concrete_integer::gen_keys_crt;
67    /// use concrete_shortint::parameters::PARAM_MESSAGE_3_CARRY_3;
68    ///
69    /// let basis = vec![2, 3, 5];
70    /// let (cks, sks) = gen_keys_crt(&PARAM_MESSAGE_3_CARRY_3, basis);
71    ///
72    /// let clear_1 = 29;
73    /// let clear_2 = 29;
74    ///
75    /// // Encrypt two messages
76    /// let mut ctxt_1 = cks.encrypt(clear_1);
77    /// let mut ctxt_2 = cks.encrypt(clear_2);
78    ///
79    /// // Compute homomorphically a multiplication
80    /// sks.smart_crt_mul_assign_parallelized(&mut ctxt_1, &mut ctxt_2);
81    ///
82    /// // Decrypt
83    /// let res = cks.decrypt(&ctxt_1);
84    /// assert_eq!((clear_1 * clear_2) % 30, res);
85    /// ```
86    pub fn smart_crt_mul_assign_parallelized(
87        &self,
88        ct_left: &mut CrtCiphertext,
89        ct_right: &mut CrtCiphertext,
90    ) {
91        ct_left
92            .blocks
93            .par_iter_mut()
94            .zip(&mut ct_right.blocks)
95            .for_each(|(block_left, block_right)| {
96                self.key.smart_mul_lsb_assign(block_left, block_right);
97            });
98    }
99    pub fn smart_crt_mul_parallelized(
100        &self,
101        ct_left: &mut CrtCiphertext,
102        ct_right: &mut CrtCiphertext,
103    ) -> CrtCiphertext {
104        let mut ct_res = ct_left.clone();
105        self.smart_crt_mul_assign_parallelized(&mut ct_res, ct_right);
106        ct_res
107    }
108}