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}