concrete_shortint/server_key/neg.rs
1use super::ServerKey;
2use crate::engine::ShortintEngine;
3use crate::server_key::CheckError;
4use crate::server_key::CheckError::CarryFull;
5use crate::Ciphertext;
6
7impl ServerKey {
8 /// Homomorphically negates a message without checks.
9 ///
10 /// Negation here means the opposite value in the modulo set.
11 ///
12 /// This function computes the opposite of a message without checking if it exceeds the
13 /// capacity of the ciphertext.
14 ///
15 /// # Example
16 ///
17 /// ```rust
18 /// use concrete_shortint::{gen_keys, Parameters};
19 ///
20 /// // Generate the client key and the server key:
21 /// let (mut cks, mut sks) = gen_keys(Parameters::default());
22 ///
23 /// let msg = 1;
24 ///
25 /// // Encrypt a message
26 /// let ct = cks.encrypt(msg);
27 ///
28 /// // Compute homomorphically a negation
29 /// let mut ct_res = sks.unchecked_neg(&ct);
30 ///
31 /// // Decrypt
32 /// let three = cks.decrypt(&ct_res);
33 /// let modulus = cks.parameters.message_modulus.0 as u64;
34 /// assert_eq!(modulus - msg, three);
35 /// ```
36 pub fn unchecked_neg(&self, ct: &Ciphertext) -> Ciphertext {
37 ShortintEngine::with_thread_local_mut(|engine| engine.unchecked_neg(self, ct).unwrap())
38 }
39
40 pub fn unchecked_neg_with_z(&self, ct: &Ciphertext) -> (Ciphertext, u64) {
41 ShortintEngine::with_thread_local_mut(|engine| {
42 engine.unchecked_neg_with_z(self, ct).unwrap()
43 })
44 }
45
46 /// Homomorphically negates a message inplace without checks.
47 ///
48 /// Negation here means the opposite value in the modulo set.
49 ///
50 /// # Example
51 ///
52 /// ```rust
53 /// use concrete_shortint::{gen_keys, Parameters};
54 ///
55 /// // Generate the client key and the server key:
56 /// let (cks, sks) = gen_keys(Parameters::default());
57 ///
58 /// // Encrypt a message
59 /// let msg = 3;
60 /// let mut ct = cks.encrypt(msg);
61 ///
62 /// // Compute homomorphically a negation
63 /// sks.unchecked_neg_assign(&mut ct);
64 ///
65 /// // Decrypt
66 /// let modulus = cks.parameters.message_modulus.0 as u64;
67 /// assert_eq!(modulus - msg, cks.decrypt(&ct));
68 /// ```
69 pub fn unchecked_neg_assign(&self, ct: &mut Ciphertext) {
70 ShortintEngine::with_thread_local_mut(|engine| {
71 engine.unchecked_neg_assign(self, ct).unwrap()
72 })
73 }
74
75 pub fn unchecked_neg_assign_with_z(&self, ct: &mut Ciphertext) -> u64 {
76 ShortintEngine::with_thread_local_mut(|engine| {
77 engine.unchecked_neg_assign_with_z(self, ct).unwrap()
78 })
79 }
80
81 /// Verifies if a ciphertext can be negated.
82 ///
83 /// # Example
84 ///
85 ///```rust
86 /// use concrete_shortint::{gen_keys, Parameters};
87 ///
88 /// // Generate the client key and the server key:
89 /// let (cks, sks) = gen_keys(Parameters::default());
90 ///
91 /// // Encrypt a message
92 /// let msg = 2;
93 /// let ct = cks.encrypt(msg);
94 ///
95 /// // Check if we can perform a negation
96 /// let can_be_negated = sks.is_neg_possible(&ct);
97 ///
98 /// assert_eq!(can_be_negated, true);
99 /// ```
100 pub fn is_neg_possible(&self, ct: &Ciphertext) -> bool {
101 // z = ceil( degree / 2^p ) x 2^p
102 let msg_mod = self.message_modulus.0;
103 let mut z = (ct.degree.0 + msg_mod - 1) / msg_mod;
104 z = z.wrapping_mul(msg_mod);
105
106 // counter = z / (2^p-1)
107 let counter = z / (self.message_modulus.0 - 1);
108
109 counter <= self.max_degree.0
110 }
111
112 /// Computes homomorphically a negation of a ciphertext.
113 ///
114 /// If the operation can be performed, the result is returned a _new_ ciphertext.
115 /// Otherwise [CheckError::CarryFull] is returned.
116 ///
117 /// # Example
118 ///
119 /// ```rust
120 /// use concrete_shortint::{gen_keys, Parameters};
121 ///
122 /// // Generate the client key and the server key:
123 /// let (cks, sks) = gen_keys(Parameters::default());
124 ///
125 /// // Encrypt a message
126 /// let msg = 1;
127 /// let ct = cks.encrypt(msg);
128 ///
129 /// // Compute homomorphically a negation:
130 /// let ct_res = sks.checked_neg(&ct);
131 ///
132 /// assert!(ct_res.is_ok());
133 ///
134 /// let clear_res = cks.decrypt(&ct_res.unwrap());
135 /// let modulus = cks.parameters.message_modulus.0 as u64;
136 /// assert_eq!(clear_res, modulus - msg);
137 /// ```
138 pub fn checked_neg(&self, ct: &Ciphertext) -> Result<Ciphertext, CheckError> {
139 // If the ciphertext cannot be negated without exceeding the capacity of a ciphertext
140 if self.is_neg_possible(ct) {
141 let ct_result = self.unchecked_neg(ct);
142 Ok(ct_result)
143 } else {
144 Err(CarryFull)
145 }
146 }
147
148 /// Computes homomorphically a negation of a ciphertext.
149 ///
150 /// If the operation is possible, the result is stored _in_ the input ciphertext.
151 /// Otherwise [CheckError::CarryFull] is returned and the ciphertext is not .
152 ///
153 ///
154 ///
155 /// # Example
156 ///
157 /// ```rust
158 /// use concrete_shortint::{gen_keys, Parameters};
159 ///
160 /// // Generate the client key and the server key:
161 /// let (cks, sks) = gen_keys(Parameters::default());
162 ///
163 /// // Encrypt a message:
164 /// let msg = 1;
165 /// let mut ct = cks.encrypt(msg);
166 ///
167 /// // Compute homomorphically the negation:
168 /// let res = sks.checked_neg_assign(&mut ct);
169 ///
170 /// assert!(res.is_ok());
171 ///
172 /// let clear_res = cks.decrypt(&ct);
173 /// let modulus = cks.parameters.message_modulus.0 as u64;
174 /// assert_eq!(clear_res, modulus - msg);
175 /// ```
176 pub fn checked_neg_assign(&self, ct: &mut Ciphertext) -> Result<(), CheckError> {
177 if self.is_neg_possible(ct) {
178 self.unchecked_neg_assign(ct);
179 Ok(())
180 } else {
181 Err(CarryFull)
182 }
183 }
184
185 /// Computes homomorphically a negation of a ciphertext.
186 ///
187 /// This checks that the negation is possible. In the case where the carry buffers are full,
188 /// then it is automatically cleared to allow the operation.
189 ///
190 /// # Example
191 ///
192 /// ```rust
193 /// use concrete_shortint::{gen_keys, Parameters};
194 ///
195 /// // Generate the client key and the server key:
196 /// let (cks, sks) = gen_keys(Parameters::default());
197 ///
198 /// // Encrypt two messages:
199 /// let msg = 3;
200 /// let mut ct = cks.encrypt(msg);
201 ///
202 /// // Compute homomorphically a negation
203 /// let ct_res = sks.smart_neg(&mut ct);
204 ///
205 /// // Decrypt
206 /// let clear_res = cks.decrypt(&ct_res);
207 /// let modulus = cks.parameters.message_modulus.0 as u64;
208 /// assert_eq!(clear_res, modulus - msg);
209 /// ```
210 pub fn smart_neg(&self, ct: &mut Ciphertext) -> Ciphertext {
211 ShortintEngine::with_thread_local_mut(|engine| engine.smart_neg(self, ct).unwrap())
212 }
213
214 /// Computes homomorphically a negation of a ciphertext.
215 ///
216 /// This checks that the addition is possible. In the case where the carry buffers are full,
217 /// then it is automatically cleared to allow the operation.
218 /// # Example
219 ///
220 /// ```rust
221 /// use concrete_shortint::{gen_keys, Parameters};
222 ///
223 /// // Generate the client key and the server key:
224 /// let (cks, sks) = gen_keys(Parameters::default());
225 ///
226 /// // Encrypt two messages:
227 /// let msg = 3;
228 /// let mut ct = cks.encrypt(msg);
229 ///
230 /// // Compute homomorphically a negation
231 /// sks.smart_neg_assign(&mut ct);
232 ///
233 /// // Decrypt
234 /// let clear_res = cks.decrypt(&ct);
235 /// let modulus = cks.parameters.message_modulus.0 as u64;
236 /// assert_eq!(clear_res, modulus - msg);
237 /// ```
238 pub fn smart_neg_assign(&self, ct: &mut Ciphertext) {
239 ShortintEngine::with_thread_local_mut(|engine| engine.smart_neg_assign(self, ct).unwrap())
240 }
241}