concrete_shortint/server_key/add.rs
1use super::ServerKey;
2use crate::engine::ShortintEngine;
3use crate::server_key::CheckError;
4use crate::server_key::CheckError::CarryFull;
5use crate::Ciphertext;
6
7impl ServerKey {
8 /// Computes homomorphically an addition between two ciphertexts encrypting integer values.
9 ///
10 /// The result is returned in a _new_ ciphertext.
11 ///
12 /// This function computes the addition without checking if it exceeds the capacity of the
13 /// ciphertext.
14 ///
15 /// # Example
16 ///
17 /// ```rust
18 /// use concrete_shortint::gen_keys;
19 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
20 ///
21 /// // Generate the client key and the server key:
22 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
23 ///
24 /// let msg1 = 1;
25 /// let msg2 = 2;
26 /// let ct1 = cks.encrypt(msg1);
27 /// let ct2 = cks.encrypt(msg2);
28 ///
29 /// // Compute homomorphically an addition:
30 /// let ct_res = sks.unchecked_add(&ct1, &ct2);
31 ///
32 /// // Decrypt:
33 /// let res = cks.decrypt(&ct_res);
34 /// assert_eq!(msg1 + msg2, res);
35 /// ```
36 pub fn unchecked_add(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
37 ShortintEngine::with_thread_local_mut(|engine| {
38 engine.unchecked_add(ct_left, ct_right).unwrap()
39 })
40 }
41
42 /// Computes homomorphically an addition between two ciphertexts encrypting integer values.
43 ///
44 /// The result is _stored_ in the `ct_left` ciphertext.
45 ///
46 /// This function computes the addition without checking if it exceeds the capacity of the
47 /// ciphertext.
48 ///
49 /// # Example
50 ///
51 /// ```rust
52 /// use concrete_shortint::gen_keys;
53 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
54 ///
55 /// // Generate the client key and the server key:
56 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
57 ///
58 /// let msg = 1;
59 ///
60 /// let mut ct_left = cks.encrypt(msg);
61 /// let ct_right = cks.encrypt(msg);
62 ///
63 /// // Compute homomorphically an addition:
64 /// sks.unchecked_add_assign(&mut ct_left, &ct_right);
65 ///
66 /// // Decrypt:
67 /// let two = cks.decrypt(&ct_left);
68 /// assert_eq!(msg + msg, two);
69 /// ```
70 pub fn unchecked_add_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
71 ShortintEngine::with_thread_local_mut(|engine| {
72 engine.unchecked_add_assign(ct_left, ct_right).unwrap()
73 })
74 }
75
76 /// Verifies if ct_left and ct_right can be added together.
77 ///
78 /// This checks that the sum of their degree is
79 /// smaller than the maximum degree.
80 ///
81 /// # Example
82 ///
83 ///```rust
84 /// use concrete_shortint::gen_keys;
85 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
86 ///
87 /// // Generate the client key and the server key:
88 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
89 ///
90 /// let msg = 2;
91 ///
92 /// // Encrypt two messages:
93 /// let ct_left = cks.encrypt(msg);
94 /// let ct_right = cks.encrypt(msg);
95 ///
96 /// // Check if we can perform an addition
97 /// let can_be_added = sks.is_add_possible(&ct_left, &ct_right);
98 ///
99 /// assert_eq!(can_be_added, true);
100 /// ```
101 pub fn is_add_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
102 let final_operation_count = ct_left.degree.0 + ct_right.degree.0;
103 final_operation_count <= self.max_degree.0
104 }
105
106 /// Computes homomorphically an addition between two ciphertexts encrypting integer values.
107 ///
108 /// If the operation can be performed, the result is returned a _new_ ciphertext.
109 /// Otherwise [CheckError::CarryFull] is returned.
110 ///
111 /// # Example
112 ///
113 /// ```rust
114 /// use concrete_shortint::gen_keys;
115 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
116 ///
117 /// // Generate the client key and the server key:
118 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
119 ///
120 /// let msg = 1;
121 ///
122 /// // Encrypt two messages:
123 /// let ct1 = cks.encrypt(msg);
124 /// let ct2 = cks.encrypt(msg);
125 ///
126 /// // Compute homomorphically an addition:
127 /// let ct_res = sks.checked_add(&ct1, &ct2);
128 ///
129 /// assert!(ct_res.is_ok());
130 ///
131 /// let ct_res = ct_res.unwrap();
132 /// let clear_res = cks.decrypt(&ct_res);
133 /// assert_eq!(clear_res, msg + msg);
134 /// ```
135 pub fn checked_add(
136 &self,
137 ct_left: &Ciphertext,
138 ct_right: &Ciphertext,
139 ) -> Result<Ciphertext, CheckError> {
140 if self.is_add_possible(ct_left, ct_right) {
141 let ct_result = self.unchecked_add(ct_left, ct_right);
142 Ok(ct_result)
143 } else {
144 Err(CarryFull)
145 }
146 }
147
148 /// Computes homomorphically an addition between two ciphertexts encrypting integer values.
149 ///
150 /// If the operation can be performed, the result is stored in the `ct_left` ciphertext.
151 /// Otherwise [CheckError::CarryFull] is returned, and `ct_left` is not modified.
152 ///
153 /// # Example
154 ///
155 /// ```rust
156 /// use concrete_shortint::gen_keys;
157 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
158 ///
159 /// // Generate the client key and the server key:
160 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
161 ///
162 /// let msg = 1;
163 ///
164 /// // Encrypt two messages:
165 /// let mut ct_left = cks.encrypt(msg);
166 /// let ct_right = cks.encrypt(msg);
167 ///
168 /// // Compute homomorphically an addition:
169 /// let res = sks.checked_add_assign(&mut ct_left, &ct_right);
170 ///
171 /// assert!(res.is_ok());
172 ///
173 /// let clear_res = cks.decrypt(&ct_left);
174 /// assert_eq!(clear_res, msg + msg);
175 /// ```
176 pub fn checked_add_assign(
177 &self,
178 ct_left: &mut Ciphertext,
179 ct_right: &Ciphertext,
180 ) -> Result<(), CheckError> {
181 if self.is_add_possible(ct_left, ct_right) {
182 self.unchecked_add_assign(ct_left, ct_right);
183 Ok(())
184 } else {
185 Err(CarryFull)
186 }
187 }
188
189 /// Computes homomorphically an addition between two ciphertexts encrypting integer values.
190 ///
191 /// This checks that the addition is possible. In the case where the carry buffers are full,
192 /// then it is automatically cleared to allow the operation.
193 /// # Example
194 ///
195 /// ```rust
196 /// use concrete_shortint::gen_keys;
197 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
198 ///
199 /// // Generate the client key and the server key:
200 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
201 ///
202 /// let msg = 1;
203 ///
204 /// // Encrypt two messages:
205 /// let mut ct1 = cks.encrypt(msg);
206 /// let mut ct2 = cks.encrypt(msg);
207 ///
208 /// // Compute homomorphically an addition:
209 /// let ct_res = sks.smart_add(&mut ct1, &mut ct2);
210 ///
211 /// // Decrypt:
212 /// let two = cks.decrypt(&ct_res);
213 /// assert_eq!(msg + msg, two);
214 /// ```
215 pub fn smart_add(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
216 ShortintEngine::with_thread_local_mut(|engine| {
217 engine.smart_add(self, ct_left, ct_right).unwrap()
218 })
219 }
220
221 /// Computes homomorphically an addition between two ciphertexts
222 ///
223 /// The result is stored in the `ct_left` cipher text.
224 ///
225 /// # Example
226 ///
227 /// ```rust
228 /// use concrete_shortint::gen_keys;
229 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
230 ///
231 /// // Generate the client key and the server key:
232 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
233 ///
234 /// // Encrypt two messages:
235 /// let msg1 = 15;
236 /// let msg2 = 3;
237 ///
238 /// let mut ct1 = cks.unchecked_encrypt(msg1);
239 /// let mut ct2 = cks.encrypt(msg2);
240 ///
241 /// // Compute homomorphically an addition:
242 /// sks.smart_add_assign(&mut ct1, &mut ct2);
243 ///
244 /// // Decrypt:
245 /// let two = cks.decrypt(&ct1);
246 ///
247 /// // 15 + 3 mod 4 -> 3 + 3 mod 4 -> 2 mod 4
248 /// let modulus = cks.parameters.message_modulus.0 as u64;
249 /// assert_eq!((msg2 + msg1) % modulus, two);
250 /// ```
251 pub fn smart_add_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
252 ShortintEngine::with_thread_local_mut(|engine| {
253 engine.smart_add_assign(self, ct_left, ct_right).unwrap()
254 })
255 }
256}