concrete_integer/server_key/crt_parallel/
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_parallelized(&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_parallelized(
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_parallelized(&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_parallelized(&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_parallelized(
71        &self,
72        ctxt_left: &mut CrtCiphertext,
73        ctxt_right: &CrtCiphertext,
74    ) {
75        let neg = self.unchecked_crt_neg_parallelized(ctxt_right);
76        self.unchecked_crt_add_assign_parallelized(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_parallelized(&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_parallelized(
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            rayon::join(
111                || self.full_extract_parallelized(ctxt_left),
112                || self.full_extract_parallelized(ctxt_right),
113            );
114        }
115
116        self.unchecked_crt_sub_parallelized(ctxt_left, ctxt_right)
117    }
118
119    /// Computes homomorphically the subtraction between ct_left and ct_right.
120    ///
121    /// # Example
122    ///
123    ///```rust
124    /// use concrete_integer::gen_keys;
125    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
126    ///
127    /// // Generate the client key and the server key:
128    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
129    ///
130    /// let clear_1 = 14;
131    /// let clear_2 = 5;
132    /// let basis = vec![2, 3, 5];
133    /// // Encrypt two messages
134    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
135    /// let mut ctxt_2 = cks.encrypt_crt(clear_2, basis.clone());
136    ///
137    /// sks.smart_crt_sub_assign_parallelized(&mut ctxt_1, &mut ctxt_2);
138    ///
139    /// // Decrypt
140    /// let res = cks.decrypt_crt(&ctxt_1);
141    /// assert_eq!((clear_1 - clear_2) % 30, res);
142    /// ```
143    pub fn smart_crt_sub_assign_parallelized(
144        &self,
145        ctxt_left: &mut CrtCiphertext,
146        ctxt_right: &mut CrtCiphertext,
147    ) {
148        // If the ciphertext cannot be added together without exceeding the capacity of a ciphertext
149        if !self.is_crt_sub_possible(ctxt_left, ctxt_right) {
150            rayon::join(
151                || self.full_extract_parallelized(ctxt_left),
152                || self.full_extract_parallelized(ctxt_right),
153            );
154        }
155
156        self.unchecked_crt_sub_assign_parallelized(ctxt_left, ctxt_right);
157    }
158}