concrete_integer/server_key/crt/
sub_crt.rs

1use crate::{CrtCiphertext, ServerKey};
2
3impl ServerKey {
4    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
5    ///
6    /// This function computes the subtraction without checking if it exceeds the capacity of the
7    /// ciphertext.
8    ///
9    /// The result is returned as a new ciphertext.
10    /// # Example
11    ///
12    ///```rust
13    /// use concrete_integer::gen_keys;
14    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
15    ///
16    /// // Generate the client key and the server key:
17    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
18    ///
19    /// let clear_1 = 14;
20    /// let clear_2 = 5;
21    /// let basis = vec![2, 3, 5];
22    /// // Encrypt two messages
23    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
24    /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
25    ///
26    /// let ctxt = sks.unchecked_crt_sub(&mut ctxt_1, &mut ctxt_2);
27    ///
28    /// // Decrypt
29    /// let res = cks.decrypt_crt(&ctxt);
30    /// assert_eq!((clear_1 - clear_2) % 30, res);
31    /// ```
32    pub fn unchecked_crt_sub(
33        &self,
34        ctxt_left: &CrtCiphertext,
35        ctxt_right: &CrtCiphertext,
36    ) -> CrtCiphertext {
37        let mut result = ctxt_left.clone();
38        self.unchecked_crt_sub_assign(&mut result, ctxt_right);
39        result
40    }
41
42    /// Computes homomorphically a subtraction between two ciphertexts encrypting integer values.
43    ///
44    /// This function computes the subtraction without checking if it exceeds the capacity of the
45    /// ciphertext.
46    ///
47    /// The result is assigned to the `ct_left` ciphertext.
48    /// # Example
49    ///
50    ///```rust
51    /// use concrete_integer::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    /// let clear_1 = 14;
58    /// let clear_2 = 5;
59    /// let basis = vec![2, 3, 5];
60    /// // Encrypt two messages
61    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
62    /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
63    ///
64    /// let ctxt = sks.unchecked_crt_sub(&mut ctxt_1, &mut ctxt_2);
65    ///
66    /// // Decrypt
67    /// let res = cks.decrypt_crt(&ctxt);
68    /// assert_eq!((clear_1 - clear_2) % 30, res);
69    /// ```
70    pub fn unchecked_crt_sub_assign(
71        &self,
72        ctxt_left: &mut CrtCiphertext,
73        ctxt_right: &CrtCiphertext,
74    ) {
75        let neg = self.unchecked_crt_neg(ctxt_right);
76        self.unchecked_crt_add_assign(ctxt_left, &neg);
77    }
78
79    /// Computes homomorphically the subtraction between ct_left and ct_right.
80    ///
81    /// # Example
82    ///
83    ///```rust
84    /// use concrete_integer::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 clear_1 = 14;
91    /// let clear_2 = 5;
92    /// let basis = vec![2, 3, 5];
93    /// // Encrypt two messages
94    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
95    /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
96    ///
97    /// let ctxt = sks.smart_crt_sub(&mut ctxt_1, &mut ctxt_2);
98    ///
99    /// // Decrypt
100    /// let res = cks.decrypt_crt(&ctxt);
101    /// assert_eq!((clear_1 - clear_2) % 30, res);
102    /// ```
103    pub fn smart_crt_sub(
104        &self,
105        ctxt_left: &mut CrtCiphertext,
106        ctxt_right: &mut CrtCiphertext,
107    ) -> CrtCiphertext {
108        // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
109        if !self.is_crt_sub_possible(ctxt_left, ctxt_right) {
110            self.full_extract(ctxt_left);
111            self.full_extract(ctxt_right);
112        }
113
114        let mut result = ctxt_left.clone();
115        self.unchecked_crt_sub_assign(&mut result, ctxt_right);
116
117        result
118    }
119
120    /// Computes homomorphically the subtraction between ct_left and ct_right.
121    ///
122    /// # Example
123    ///
124    ///```rust
125    /// use concrete_integer::gen_keys;
126    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
127    ///
128    /// // Generate the client key and the server key:
129    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
130    ///
131    /// let clear_1 = 14;
132    /// let clear_2 = 5;
133    /// let basis = vec![2, 3, 5];
134    /// // Encrypt two messages
135    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
136    /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
137    ///
138    /// sks.smart_crt_sub_assign(&mut ctxt_1, &mut ctxt_2);
139    ///
140    /// // Decrypt
141    /// let res = cks.decrypt_crt(&ctxt_1);
142    /// assert_eq!((clear_1 - clear_2) % 30, res);
143    /// ```
144    pub fn smart_crt_sub_assign(
145        &self,
146        ctxt_left: &mut CrtCiphertext,
147        ctxt_right: &mut CrtCiphertext,
148    ) {
149        // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
150        if !self.is_crt_sub_possible(ctxt_left, ctxt_right) {
151            self.full_extract(ctxt_left);
152            self.full_extract(ctxt_right);
153        }
154
155        self.unchecked_crt_sub_assign(ctxt_left, ctxt_right);
156    }
157
158    pub fn is_crt_sub_possible(
159        &self,
160        ctxt_left: &CrtCiphertext,
161        ctxt_right: &CrtCiphertext,
162    ) -> bool {
163        for (ct_left_i, ct_right_i) in ctxt_left.blocks.iter().zip(ctxt_right.blocks.iter()) {
164            if !self.key.is_sub_possible(ct_left_i, ct_right_i) {
165                return false;
166            }
167        }
168        true
169    }
170}