tfhe/integer/server_key/crt/
sub_crt.rs

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