concrete_shortint/server_key/sub.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 /// Homomorphically subtracts ct_right to ct_left.
9 ///
10 /// The result is returned in a _new_ ciphertext.
11 ///
12 /// This function computes the subtraction without checking
13 /// if it exceeds the capacity of the 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 /// // Encrypt two messages:
25 /// let ct_1 = cks.encrypt(2);
26 /// let ct_2 = cks.encrypt(1);
27 ///
28 /// // Compute homomorphically a subtraction:
29 /// let ct_res = sks.unchecked_sub(&ct_1, &ct_2);
30 ///
31 /// // Decrypt:
32 /// let modulus = cks.parameters.message_modulus.0 as u64;
33 /// assert_eq!(cks.decrypt(&ct_res), 2 - 1);
34 /// ```
35 pub fn unchecked_sub(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> Ciphertext {
36 ShortintEngine::with_thread_local_mut(|engine| {
37 engine.unchecked_sub(self, ct_left, ct_right).unwrap()
38 })
39 }
40
41 /// Homomorphically subtracts ct_right to ct_left.
42 ///
43 /// The result is assigned in the `ct_left` ciphertext.
44 ///
45 /// This function computes the subtraction without checking
46 /// if it exceeds the capacity of the ciphertext.
47 ///
48 /// # Example
49 ///
50 /// ```rust
51 /// use concrete_shortint::gen_keys;
52 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
53 ///
54 /// // Generate the client key and the server key:
55 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
56 ///
57 /// // Encrypt two messages:
58 /// let mut ct_1 = cks.encrypt(2);
59 /// let ct_2 = cks.encrypt(1);
60 ///
61 /// // Compute homomorphically a subtraction:
62 /// sks.unchecked_sub_assign(&mut ct_1, &ct_2);
63 ///
64 /// // Decrypt:
65 /// let modulus = cks.parameters.message_modulus.0 as u64;
66 /// assert_eq!(cks.decrypt(&ct_1) % modulus, 1);
67 /// ```
68 pub fn unchecked_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &Ciphertext) {
69 ShortintEngine::with_thread_local_mut(|engine| {
70 engine
71 .unchecked_sub_assign(self, ct_left, ct_right)
72 .unwrap()
73 })
74 }
75
76 /// Verifies if ct_right can be subtracted to ct_left.
77 ///
78 /// # Example
79 ///
80 ///```rust
81 /// use concrete_shortint::gen_keys;
82 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
83 ///
84 /// // Generate the client key and the server key:
85 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
86 ///
87 /// let msg = 2;
88 ///
89 /// // Encrypt two messages:
90 /// let ct_1 = cks.encrypt(msg);
91 /// let ct_2 = cks.encrypt(msg);
92 ///
93 /// // Check if we can perform an subtraction
94 /// let can_be_subtracted = sks.is_sub_possible(&ct_1, &ct_2);
95 ///
96 /// assert_eq!(true, can_be_subtracted);
97 /// ```
98 pub fn is_sub_possible(&self, ct_left: &Ciphertext, ct_right: &Ciphertext) -> bool {
99 // z = ceil( degree / 2^p ) x 2^p
100 let msg_mod = self.message_modulus.0;
101 let mut z = (ct_right.degree.0 + msg_mod - 1) / msg_mod;
102 z = z.wrapping_mul(msg_mod);
103
104 let final_operation_count = ct_left.degree.0 + z;
105
106 final_operation_count <= self.max_degree.0
107 }
108
109 /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
110 ///
111 /// If the operation can be performed, the result is returned a _new_ ciphertext.
112 /// Otherwise [CheckError::CarryFull] is returned.
113 ///
114 /// # Example
115 ///
116 /// ```rust
117 /// use concrete_shortint::gen_keys;
118 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
119 ///
120 /// // Generate the client key and the server key:
121 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
122 ///
123 /// // Encrypt two messages:
124 /// let ct_1 = cks.encrypt(3);
125 /// let ct_2 = cks.encrypt(1);
126 ///
127 /// // Compute homomorphically a subtraction:
128 /// let ct_res = sks.checked_sub(&ct_1, &ct_2);
129 ///
130 /// assert!(ct_res.is_ok());
131 /// let modulus = cks.parameters.message_modulus.0 as u64;
132 /// let clear_res = cks.decrypt(&ct_res.unwrap());
133 /// assert_eq!(clear_res % modulus, 2);
134 /// ```
135 pub fn checked_sub(
136 &self,
137 ct_left: &Ciphertext,
138 ct_right: &Ciphertext,
139 ) -> Result<Ciphertext, CheckError> {
140 // If the ciphertexts cannot be subtracted without exceeding the degree max
141 if self.is_sub_possible(ct_left, ct_right) {
142 let ct_result = self.unchecked_sub(ct_left, ct_right);
143 Ok(ct_result)
144 } else {
145 Err(CarryFull)
146 }
147 }
148
149 /// Computes homomorphically a subtraction between two ciphertexts.
150 ///
151 /// If the operation can be performed, the result is stored in the `ct_left` ciphertext.
152 /// Otherwise [CheckError::CarryFull] is returned, and `ct_left` is not modified.
153 ///
154 /// # Example
155 ///
156 /// ```rust
157 /// use concrete_shortint::gen_keys;
158 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
159 ///
160 /// // Generate the client key and the server key:
161 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
162 ///
163 /// // Encrypt two messages:
164 /// let mut ct_1 = cks.encrypt(3);
165 /// let ct_2 = cks.encrypt(1);
166 ///
167 /// // Compute homomorphically a subtraction:
168 /// let res = sks.checked_sub_assign(&mut ct_1, &ct_2);
169 ///
170 /// assert!(res.is_ok());
171 /// let modulus = cks.parameters.message_modulus.0 as u64;
172 /// let clear_res = cks.decrypt(&ct_1);
173 /// assert_eq!(clear_res % modulus, 2);
174 /// ```
175 pub fn checked_sub_assign(
176 &self,
177 ct_left: &mut Ciphertext,
178 ct_right: &Ciphertext,
179 ) -> Result<(), CheckError> {
180 // If the ciphertexts cannot be subtracted without exceeding the degree max
181 if self.is_sub_possible(ct_left, ct_right) {
182 self.unchecked_sub_assign(ct_left, ct_right);
183 Ok(())
184 } else {
185 Err(CarryFull)
186 }
187 }
188
189 /// Computes homomorphically a subtraction between two ciphertexts.
190 ///
191 /// This checks that the subtraction is possible. In the case where the carry buffers are
192 /// full, then it is automatically cleared to allow the operation.
193 ///
194 /// # Example
195 ///
196 /// ```rust
197 /// use concrete_shortint::gen_keys;
198 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
199 ///
200 /// // Generate the client key and the server key:
201 /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
202 ///
203 /// // Encrypt two messages:
204 /// let mut ct_1 = cks.encrypt(3);
205 /// let mut ct_2 = cks.encrypt(1);
206 ///
207 /// // Compute homomorphically a subtraction:
208 /// let ct_res = sks.smart_sub(&mut ct_1, &mut ct_2);
209 ///
210 /// let clear_res = cks.decrypt(&ct_res);
211 /// let modulus = cks.parameters.message_modulus.0 as u64;
212 /// assert_eq!(clear_res % modulus, 2);
213 /// ```
214 pub fn smart_sub(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) -> Ciphertext {
215 ShortintEngine::with_thread_local_mut(|engine| {
216 engine.smart_sub(self, ct_left, ct_right).unwrap()
217 })
218 }
219
220 /// Computes homomorphically a subtraction between two ciphertexts.
221 ///
222 /// This checks that the subtraction is possible. In the case where the carry buffers are
223 /// full, then it is automatically cleared to allow the operation.
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 mut ct_1 = cks.encrypt(3);
236 /// let mut ct_2 = cks.encrypt(1);
237 ///
238 /// // Compute homomorphically a subtraction:
239 /// sks.smart_sub_assign(&mut ct_1, &mut ct_2);
240 /// let modulus = cks.parameters.message_modulus.0 as u64;
241 /// assert_eq!(cks.decrypt(&ct_1) % modulus, 2);
242 /// ```
243 pub fn smart_sub_assign(&self, ct_left: &mut Ciphertext, ct_right: &mut Ciphertext) {
244 ShortintEngine::with_thread_local_mut(|engine| {
245 engine.smart_sub_assign(self, ct_left, ct_right).unwrap()
246 })
247 }
248
249 /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
250 /// a correcting term.
251 ///
252 /// This checks that the subtraction is possible. In the case where the carry buffers are
253 /// full, then it is automatically cleared to allow the operation.
254 ///
255 /// # Warning
256 ///
257 /// This is an advanced functionality, needed for internal requirements.
258 pub fn unchecked_sub_with_correcting_term(
259 &self,
260 ct_left: &Ciphertext,
261 ct_right: &Ciphertext,
262 ) -> (Ciphertext, u64) {
263 ShortintEngine::with_thread_local_mut(|engine| {
264 engine
265 .unchecked_sub_with_z(self, ct_left, ct_right)
266 .unwrap()
267 })
268 }
269
270 /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
271 /// a correcting term.
272 ///
273 /// # Warning
274 ///
275 /// This is an advanced functionality, needed for internal requirements.
276 pub fn unchecked_sub_with_correcting_term_assign(
277 &self,
278 ct_left: &mut Ciphertext,
279 ct_right: &Ciphertext,
280 ) -> u64 {
281 ShortintEngine::with_thread_local_mut(|engine| {
282 engine
283 .unchecked_sub_assign_with_z(self, ct_left, ct_right)
284 .unwrap()
285 })
286 }
287
288 /// Computes homomorphically a subtraction between two ciphertexts without checks, and returns
289 /// a correcting term.
290 ///
291 /// # Warning
292 ///
293 /// This is an advanced functionality, needed for internal requirements.
294 pub fn smart_sub_with_correcting_term(
295 &self,
296 ct_left: &mut Ciphertext,
297 ct_right: &mut Ciphertext,
298 ) -> (Ciphertext, u64) {
299 ShortintEngine::with_thread_local_mut(|engine| {
300 engine.smart_sub_with_z(self, ct_left, ct_right).unwrap()
301 })
302 }
303}