concrete_integer/server_key/radix/
sub.rs

1use crate::ciphertext::RadixCiphertext;
2use crate::server_key::CheckError;
3use crate::server_key::CheckError::CarryFull;
4use crate::ServerKey;
5
6impl ServerKey {
7    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
8    ///
9    /// This function computes the subtraction 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_radix;
18    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
19    ///
20    /// let num_blocks = 4;
21    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
22    ///
23    /// let msg_1 = 12;
24    /// let msg_2 = 10;
25    ///
26    /// // Encrypt two messages:
27    /// let ctxt_1 = cks.encrypt(msg_1);
28    /// let ctxt_2 = cks.encrypt(msg_2);
29    ///
30    /// // Compute homomorphically a subtraction:
31    /// let ct_res = sks.unchecked_sub(&ctxt_1, &ctxt_2);
32    ///
33    /// // Decrypt:
34    /// let dec_result = cks.decrypt(&ct_res);
35    /// assert_eq!(dec_result, msg_1 - msg_2);
36    /// ```
37    pub fn unchecked_sub(
38        &self,
39        ctxt_left: &RadixCiphertext,
40        ctxt_right: &RadixCiphertext,
41    ) -> RadixCiphertext {
42        let mut result = ctxt_left.clone();
43        self.unchecked_sub_assign(&mut result, ctxt_right);
44        result
45    }
46
47    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
48    ///
49    /// This function computes the subtraction without checking if it exceeds the capacity of the
50    /// ciphertext.
51    ///
52    /// The result is assigned to the `ct_left` ciphertext.
53    ///
54    /// # Example
55    ///
56    /// ```rust
57    /// use concrete_integer::gen_keys_radix;
58    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
59    ///
60    /// // We have 4 * 2 = 8 bits of message
61    /// let num_blocks = 4;
62    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
63    ///
64    /// let msg_1 = 128;
65    /// let msg_2 = 99;
66    ///
67    /// // Encrypt two messages:
68    /// let mut ctxt_1 = cks.encrypt(msg_1);
69    /// let ctxt_2 = cks.encrypt(msg_2);
70    ///
71    /// // Compute homomorphically a subtraction:
72    /// sks.unchecked_sub_assign(&mut ctxt_1, &ctxt_2);
73    ///
74    /// // Decrypt:
75    /// let dec_result = cks.decrypt(&ctxt_1);
76    /// assert_eq!(dec_result, msg_1 - msg_2);
77    /// ```
78    pub fn unchecked_sub_assign(
79        &self,
80        ctxt_left: &mut RadixCiphertext,
81        ctxt_right: &RadixCiphertext,
82    ) {
83        let neg = self.unchecked_neg(ctxt_right);
84        self.unchecked_add_assign(ctxt_left, &neg);
85    }
86
87    /// Verifies if ct_right can be subtracted to ct_left.
88    ///
89    /// # Example
90    ///
91    ///```rust
92    /// use concrete_integer::gen_keys_radix;
93    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
94    ///
95    /// // We have 4 * 2 = 8 bits of message
96    /// let num_blocks = 4;
97    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
98    ///
99    /// let msg_1 = 182;
100    /// let msg_2 = 120;
101    ///
102    /// // Encrypt two messages:
103    /// let ctxt_1 = cks.encrypt(msg_1);
104    /// let ctxt_2 = cks.encrypt(msg_2);
105    ///
106    /// // Check if we can perform a subtraction
107    /// let res = sks.is_sub_possible(&ctxt_1, &ctxt_2);
108    ///
109    /// assert_eq!(true, res);
110    /// ```
111    pub fn is_sub_possible(
112        &self,
113        ctxt_left: &RadixCiphertext,
114        ctxt_right: &RadixCiphertext,
115    ) -> bool {
116        for (ct_left_i, ct_right_i) in ctxt_left.blocks.iter().zip(ctxt_right.blocks.iter()) {
117            if !self.key.is_sub_possible(ct_left_i, ct_right_i) {
118                return false;
119            }
120        }
121        true
122    }
123
124    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
125    ///
126    /// If the operation can be performed, the result is returned in a new ciphertext.
127    /// Otherwise [CheckError::CarryFull] is returned.
128    ///
129    /// The result is returned as a new ciphertext.
130    ///
131    /// # Example
132    ///
133    /// ```rust
134    /// use concrete_integer::gen_keys_radix;
135    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
136    ///
137    /// // We have 4 * 2 = 8 bits of message
138    /// let num_blocks = 4;
139    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
140    ///
141    /// let msg = 1;
142    ///
143    /// // Encrypt two messages:
144    /// let ctxt_1 = cks.encrypt(msg);
145    /// let ctxt_2 = cks.encrypt(msg);
146    ///
147    /// // Compute homomorphically a subtraction:
148    /// let ct_res = sks.checked_sub(&ctxt_1, &ctxt_2);
149    ///
150    /// match ct_res {
151    ///     Err(x) => panic!("{:?}", x),
152    ///     Ok(y) => {
153    ///         let clear = cks.decrypt(&y);
154    ///         assert_eq!(0, clear);
155    ///     }
156    /// }
157    /// ```
158    pub fn checked_sub(
159        &self,
160        ctxt_left: &RadixCiphertext,
161        ctxt_right: &RadixCiphertext,
162    ) -> Result<RadixCiphertext, CheckError> {
163        if self.is_sub_possible(ctxt_left, ctxt_right) {
164            Ok(self.unchecked_sub(ctxt_left, ctxt_right))
165        } else {
166            Err(CarryFull)
167        }
168    }
169
170    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
171    ///
172    /// If the operation can be performed, the result is returned in a new ciphertext.
173    /// Otherwise [CheckError::CarryFull] is returned.
174    ///
175    /// The result is assigned to the `ct_left` ciphertext.
176    ///
177    /// # Example
178    ///
179    /// ```rust
180    /// use concrete_integer::gen_keys_radix;
181    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
182    ///
183    /// let num_blocks = 4;
184    ///
185    /// // Generate the client key and the server key:
186    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
187    ///
188    /// let msg1 = 41u8;
189    /// let msg2 = 101u8;
190    ///
191    /// let mut ct1 = cks.encrypt(msg1 as u64);
192    /// let ct2 = cks.encrypt(msg2 as u64);
193    ///
194    /// // Compute homomorphically an addition:
195    /// let res = sks.checked_sub_assign(&mut ct1, &ct2);
196    ///
197    /// assert!(res.is_ok());
198    ///
199    /// let clear = cks.decrypt(&ct1);
200    /// assert_eq!(msg1.wrapping_sub(msg2) as u64, clear);
201    /// ```
202    pub fn checked_sub_assign(
203        &self,
204        ct_left: &mut RadixCiphertext,
205        ct_right: &RadixCiphertext,
206    ) -> Result<(), CheckError> {
207        if self.is_sub_possible(ct_left, ct_right) {
208            self.unchecked_sub_assign(ct_left, ct_right);
209            Ok(())
210        } else {
211            Err(CarryFull)
212        }
213    }
214
215    /// Computes homomorphically the subtraction between ct_left and ct_right.
216    ///
217    /// # Example
218    ///
219    /// ```rust
220    /// use concrete_integer::gen_keys_radix;
221    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
222    ///
223    /// // We have 4 * 2 = 8 bits of message
224    /// let num_blocks = 4;
225    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
226    ///
227    /// let msg_1 = 120u8;
228    /// let msg_2 = 181u8;
229    ///
230    /// // Encrypt two messages:
231    /// let mut ctxt_1 = cks.encrypt(msg_1 as u64);
232    /// let mut ctxt_2 = cks.encrypt(msg_2 as u64);
233    ///
234    /// // Compute homomorphically a subtraction
235    /// let ct_res = sks.smart_sub(&mut ctxt_1, &mut ctxt_2);
236    ///
237    /// // Decrypt:
238    /// let res = cks.decrypt(&ct_res);
239    /// assert_eq!(msg_1.wrapping_sub(msg_2) as u64, res);
240    /// ```
241    pub fn smart_sub(
242        &self,
243        ctxt_left: &mut RadixCiphertext,
244        ctxt_right: &mut RadixCiphertext,
245    ) -> RadixCiphertext {
246        // If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
247        if !self.is_neg_possible(ctxt_right) {
248            self.full_propagate(ctxt_right);
249        }
250
251        // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
252        if !self.is_sub_possible(ctxt_left, ctxt_right) {
253            self.full_propagate(ctxt_left);
254            self.full_propagate(ctxt_right);
255        }
256
257        let mut result = ctxt_left.clone();
258        self.unchecked_sub_assign(&mut result, ctxt_right);
259
260        result
261    }
262
263    /// Computes homomorphically the subtraction between ct_left and ct_right.
264    ///
265    /// # Example
266    ///
267    /// ```rust
268    /// use concrete_integer::gen_keys_radix;
269    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
270    ///
271    /// // We have 4 * 2 = 8 bits of message
272    /// let num_blocks = 4;
273    /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, num_blocks);
274    ///
275    /// let msg_1 = 120u8;
276    /// let msg_2 = 181u8;
277    ///
278    /// // Encrypt two messages:
279    /// let mut ctxt_1 = cks.encrypt(msg_1 as u64);
280    /// let mut ctxt_2 = cks.encrypt(msg_2 as u64);
281    ///
282    /// // Compute homomorphically a subtraction
283    /// sks.smart_sub_assign(&mut ctxt_1, &mut ctxt_2);
284    ///
285    /// // Decrypt:
286    /// let res = cks.decrypt(&ctxt_1);
287    /// assert_eq!(msg_1.wrapping_sub(msg_2) as u64, res);
288    /// ```
289    pub fn smart_sub_assign(
290        &self,
291        ctxt_left: &mut RadixCiphertext,
292        ctxt_right: &mut RadixCiphertext,
293    ) {
294        // If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
295        if !self.is_neg_possible(ctxt_right) {
296            self.full_propagate(ctxt_right);
297        }
298
299        // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
300        if !self.is_sub_possible(ctxt_left, ctxt_right) {
301            self.full_propagate(ctxt_left);
302            self.full_propagate(ctxt_right);
303        }
304
305        self.unchecked_sub_assign(ctxt_left, ctxt_right);
306    }
307}