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}