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}