concrete_integer/server_key/crt_parallel/
add_crt.rs

1use crate::ciphertext::CrtCiphertext;
2use crate::ServerKey;
3use rayon::prelude::*;
4
5impl ServerKey {
6    /// Computes homomorphically an addition 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_2_CARRY_2;
14    ///
15    /// // Generate the client key and the server key:
16    /// let basis = vec![2, 3, 5];
17    /// let (cks, sks) = gen_keys_crt(&PARAM_MESSAGE_2_CARRY_2, basis);
18    ///
19    /// let clear_1 = 14;
20    /// let clear_2 = 14;
21    ///
22    /// // Encrypt two messages
23    /// let mut ctxt_1 = cks.encrypt(clear_1);
24    /// let ctxt_2 = cks.encrypt(clear_2);
25    ///
26    /// // Compute homomorphically a multiplication
27    /// sks.unchecked_crt_add_assign_parallelized(&mut ctxt_1, &ctxt_2);
28    ///
29    /// // Decrypt
30    /// let res = cks.decrypt(&ctxt_1);
31    /// assert_eq!((clear_1 + clear_2) % 30, res);
32    /// ```
33    pub fn unchecked_crt_add_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_add_assign(ct_left, ct_right);
44            });
45    }
46
47    pub fn unchecked_crt_add_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_add_assign_parallelized(&mut ct_res, ct_right);
54        ct_res
55    }
56
57    /// Computes homomorphically an addition between two ciphertexts encrypting integer values in
58    /// 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_2_CARRY_2;
68    /// let size = 4;
69    ///
70    /// // Generate the client key and the server key:
71    /// let basis = vec![2, 3, 5];
72    /// let (cks, sks) = gen_keys_crt(&PARAM_MESSAGE_2_CARRY_2, basis);
73    ///
74    /// let clear_1 = 29;
75    /// let clear_2 = 29;
76    ///
77    /// // Encrypt two messages
78    /// let mut ctxt_1 = cks.encrypt(clear_1);
79    /// let mut ctxt_2 = cks.encrypt(clear_2);
80    ///
81    /// // Compute homomorphically a multiplication
82    /// sks.smart_crt_add_assign_parallelized(&mut ctxt_1, &mut ctxt_2);
83    ///
84    /// // Decrypt
85    /// let res = cks.decrypt(&ctxt_1);
86    /// assert_eq!((clear_1 + clear_2) % 30, res);
87    /// ```
88    pub fn smart_crt_add_assign_parallelized(
89        &self,
90        ct_left: &mut CrtCiphertext,
91        ct_right: &mut CrtCiphertext,
92    ) {
93        if !self.is_crt_add_possible(ct_left, ct_right) {
94            rayon::join(
95                || self.full_extract(ct_left),
96                || self.full_extract(ct_right),
97            );
98        }
99        self.unchecked_crt_add_assign_parallelized(ct_left, ct_right);
100    }
101
102    pub fn smart_crt_add_parallelized(
103        &self,
104        ct_left: &mut CrtCiphertext,
105        ct_right: &mut CrtCiphertext,
106    ) -> CrtCiphertext {
107        if !self.is_crt_add_possible(ct_left, ct_right) {
108            rayon::join(
109                || self.full_extract(ct_left),
110                || self.full_extract(ct_right),
111            );
112        }
113        self.unchecked_crt_add_parallelized(ct_left, ct_right)
114    }
115}