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}