concrete_integer/server_key/crt_parallel/scalar_add_crt.rs
1use crate::server_key::CheckError;
2use crate::server_key::CheckError::CarryFull;
3use crate::{CrtCiphertext, ServerKey};
4use rayon::prelude::*;
5
6impl ServerKey {
7 /// Computes homomorphically an addition between a scalar and a ciphertext.
8 ///
9 /// This function computes the operation without checking if it exceeds the capacity of the
10 /// ciphertext.
11 ///
12 /// The result is returned as a new ciphertext.
13 ///
14 /// # Example
15 ///
16 ///```rust
17 /// use concrete_integer::gen_keys;
18 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
19 ///
20 /// // Generate the client key and the server key:
21 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
22 ///
23 /// let clear_1 = 14;
24 /// let clear_2 = 14;
25 /// let basis = vec![2, 3, 5];
26 /// // Encrypt two messages
27 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
28 ///
29 /// sks.unchecked_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
30 ///
31 /// // Decrypt
32 /// let res = cks.decrypt_crt(&ctxt_1);
33 /// assert_eq!((clear_1 + clear_2) % 30, res);
34 /// ```
35 pub fn unchecked_crt_scalar_add_parallelized(
36 &self,
37 ct: &CrtCiphertext,
38 scalar: u64,
39 ) -> CrtCiphertext {
40 let mut result = ct.clone();
41 self.unchecked_crt_scalar_add_assign_parallelized(&mut result, scalar);
42 result
43 }
44
45 /// Computes homomorphically an addition between a scalar and a ciphertext.
46 ///
47 /// This function computes the operation without checking if it exceeds the capacity of the
48 /// ciphertext.
49 ///
50 /// The result is assigned to the `ct_left` ciphertext.
51 pub fn unchecked_crt_scalar_add_assign_parallelized(
52 &self,
53 ct: &mut CrtCiphertext,
54 scalar: u64,
55 ) {
56 //Add the crt representation of the scalar to the ciphertext
57 ct.blocks
58 .par_iter_mut()
59 .zip(ct.moduli.par_iter())
60 .for_each(|(ct_i, mod_i)| {
61 let scalar_i = scalar % mod_i;
62 self.key.unchecked_scalar_add_assign(ct_i, scalar_i as u8);
63 });
64 }
65
66 /// Computes homomorphically an addition between a scalar and a ciphertext.
67 ///
68 /// If the operation can be performed, the result is returned in a new ciphertext.
69 /// Otherwise [CheckError::CarryFull] is returned.
70 ///
71 /// # Example
72 ///
73 /// ```rust
74 /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
75 /// use concrete_integer::gen_keys;
76 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
77 ///
78 /// // Generate the client key and the server key:
79 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
80 ///
81 /// let clear_1 = 14;
82 /// let clear_2 = 14;
83 /// let basis = vec![2, 3, 5];
84 /// // Encrypt two messages
85 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
86 ///
87 /// sks.checked_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
88 ///
89 /// // Decrypt
90 /// let res = cks.decrypt_crt(&ctxt_1);
91 /// assert_eq!((clear_1 + clear_2) % 30, res);
92 /// # Ok(())
93 /// # }
94 /// ```
95 pub fn checked_crt_scalar_add_parallelized(
96 &self,
97 ct: &CrtCiphertext,
98 scalar: u64,
99 ) -> Result<CrtCiphertext, CheckError> {
100 if self.is_crt_scalar_add_possible(ct, scalar) {
101 Ok(self.unchecked_crt_scalar_add_parallelized(ct, scalar))
102 } else {
103 Err(CarryFull)
104 }
105 }
106
107 /// Computes homomorphically an addition between a scalar and a ciphertext.
108 ///
109 /// If the operation can be performed, the result is stored in the `ct_left` ciphertext.
110 /// Otherwise [CheckError::CarryFull] is returned, and `ct_left` is not modified.
111 pub fn checked_crt_scalar_add_assign_parallelized(
112 &self,
113 ct: &mut CrtCiphertext,
114 scalar: u64,
115 ) -> Result<(), CheckError> {
116 if self.is_crt_scalar_add_possible(ct, scalar) {
117 self.unchecked_crt_scalar_add_assign_parallelized(ct, scalar);
118 Ok(())
119 } else {
120 Err(CarryFull)
121 }
122 }
123
124 /// Computes homomorphically the addition of ciphertext with a scalar.
125 ///
126 /// The result is returned in a new ciphertext.
127 ///
128 /// # Example
129 ///
130 ///```rust
131 /// use concrete_integer::gen_keys;
132 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
133 ///
134 /// // Generate the client key and the server key:
135 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
136 ///
137 /// let clear_1 = 14;
138 /// let clear_2 = 14;
139 /// let basis = vec![2, 3, 5];
140 /// // Encrypt two messages
141 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
142 ///
143 /// let ctxt = sks.smart_crt_scalar_add_parallelized(&mut ctxt_1, clear_2);
144 ///
145 /// // Decrypt
146 /// let res = cks.decrypt_crt(&ctxt);
147 /// assert_eq!((clear_1 + clear_2) % 30, res);
148 /// ```
149 pub fn smart_crt_scalar_add_parallelized(
150 &self,
151 ct: &mut CrtCiphertext,
152 scalar: u64,
153 ) -> CrtCiphertext {
154 if !self.is_crt_scalar_add_possible(ct, scalar) {
155 self.full_extract_parallelized(ct);
156 }
157
158 let mut ct = ct.clone();
159 self.unchecked_crt_scalar_add_assign_parallelized(&mut ct, scalar);
160 ct
161 }
162
163 /// Computes homomorphically the addition of ciphertext with a scalar.
164 ///
165 /// The result is assigned to the `ct_left` ciphertext.
166 ///
167 /// # Example
168 ///
169 ///```rust
170 /// use concrete_integer::gen_keys;
171 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
172 ///
173 /// // Generate the client key and the server key:
174 /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
175 ///
176 /// let clear_1 = 14;
177 /// let clear_2 = 14;
178 /// let basis = vec![2, 3, 5];
179 /// // Encrypt two messages
180 /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
181 ///
182 /// sks.smart_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
183 ///
184 /// // Decrypt
185 /// let res = cks.decrypt_crt(&ctxt_1);
186 /// assert_eq!((clear_1 + clear_2) % 30, res);
187 /// ```
188 pub fn smart_crt_scalar_add_assign_parallelized(&self, ct: &mut CrtCiphertext, scalar: u64) {
189 if !self.is_crt_scalar_add_possible(ct, scalar) {
190 self.full_extract_parallelized(ct);
191 }
192 self.unchecked_crt_scalar_add_assign_parallelized(ct, scalar);
193 }
194}