concrete_shortint/server_key/
scalar_sub.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    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
9    ///
10    /// The result is returned in a _new_ ciphertext.
11    ///
12    /// This function does _not_ check whether the capacity of the ciphertext is exceeded.
13    ///
14    /// # Example
15    ///
16    /// ```rust
17    /// use concrete_shortint::gen_keys;
18    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
19    ///
20    /// // Generate the client key and the server key:
21    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
22    ///
23    /// let ct = cks.encrypt(5);
24    ///
25    /// // Compute homomorphically a scalar subtraction:
26    /// let ct_res = sks.unchecked_scalar_sub(&ct, 6);
27    ///
28    /// // 5 - 6 mod 4 = 3 mod 4
29    /// let clear = cks.decrypt(&ct_res);
30    /// assert_eq!(3, clear);
31    /// ```
32    pub fn unchecked_scalar_sub(&self, ct: &Ciphertext, scalar: u8) -> Ciphertext {
33        ShortintEngine::with_thread_local_mut(|engine| {
34            engine.unchecked_scalar_sub(ct, scalar).unwrap()
35        })
36    }
37
38    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
39    ///
40    /// The result it stored in the given ciphertext.
41    ///
42    /// This function does not check whether the capacity of the ciphertext is exceeded.
43    ///
44    /// # Example
45    ///
46    /// ```rust
47    /// use concrete_shortint::gen_keys;
48    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
49    ///
50    /// // Generate the client key and the server key:
51    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
52    ///
53    /// let mut ct = cks.encrypt(5);
54    ///
55    /// // Compute homomorphically a scalar subtraction:
56    /// sks.unchecked_scalar_sub_assign(&mut ct, 2);
57    ///
58    /// let clear = cks.decrypt(&ct);
59    /// assert_eq!(3, clear);
60    /// ```
61    pub fn unchecked_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8) {
62        ShortintEngine::with_thread_local_mut(|engine| {
63            engine.unchecked_scalar_sub_assign(ct, scalar).unwrap()
64        })
65    }
66
67    /// Verifies if a scalar can be subtracted to the ciphertext.
68    ///
69    /// # Example
70    ///
71    ///```rust
72    /// use concrete_shortint::gen_keys;
73    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
74    ///
75    /// // Generate the client key and the server key:
76    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
77    ///
78    /// let ct = cks.encrypt(5);
79    ///
80    /// // Verification if the scalar subtraction can be computed:
81    /// let can_be_computed = sks.is_scalar_sub_possible(&ct, 3);
82    ///
83    /// assert_eq!(can_be_computed, true);
84    /// ```
85    pub fn is_scalar_sub_possible(&self, ct: &Ciphertext, scalar: u8) -> bool {
86        let neg_scalar = u64::from(scalar.wrapping_neg()) % self.message_modulus.0 as u64;
87        let final_degree = neg_scalar as usize + ct.degree.0;
88        final_degree <= self.max_degree.0
89    }
90
91    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
92    ///
93    /// If the operation is possible, the result is returned in a _new_ ciphertext.
94    /// Otherwise [CheckError::CarryFull] is returned.
95    ///
96    /// # Example
97    ///
98    /// ```rust
99    /// use concrete_shortint::gen_keys;
100    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
101    ///
102    /// // Generate the client key and the server key:
103    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
104    ///
105    /// // Encrypt a message:
106    /// let ct = cks.encrypt(5);
107    ///
108    /// // Compute homomorphically a subtraction multiplication:
109    /// let ct_res = sks.checked_scalar_sub(&ct, 2);
110    ///
111    /// assert!(ct_res.is_ok());
112    ///
113    /// let ct_res = ct_res.unwrap();
114    /// let clear_res = cks.decrypt(&ct_res);
115    /// assert_eq!(clear_res, 3);
116    /// ```
117    pub fn checked_scalar_sub(
118        &self,
119        ct: &Ciphertext,
120        scalar: u8,
121    ) -> Result<Ciphertext, CheckError> {
122        //If the scalar subtraction cannot be done without exceeding the max degree
123        if self.is_scalar_sub_possible(ct, scalar) {
124            let ct_result = self.unchecked_scalar_sub(ct, scalar);
125            Ok(ct_result)
126        } else {
127            Err(CarryFull)
128        }
129    }
130
131    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
132    ///
133    /// If the operation is possible, the result is stored _in_ the input ciphertext.
134    /// Otherwise [CheckError::CarryFull] is returned and the ciphertext is not modified.
135    ///
136    /// # Example
137    ///
138    /// ```rust
139    /// use concrete_shortint::gen_keys;
140    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
141    ///
142    /// // Generate the client key and the server key:
143    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
144    ///
145    /// // Encrypt a message:
146    /// let mut ct = cks.encrypt(5);
147    ///
148    /// // Compute homomorphically a scalar subtraction:
149    /// let res = sks.checked_scalar_sub_assign(&mut ct, 2);
150    ///
151    /// assert!(res.is_ok());
152    ///
153    /// let clear_res = cks.decrypt(&ct);
154    /// assert_eq!(clear_res, 3);
155    /// ```
156    pub fn checked_scalar_sub_assign(
157        &self,
158        ct: &mut Ciphertext,
159        scalar: u8,
160    ) -> Result<(), CheckError> {
161        if self.is_scalar_sub_possible(ct, scalar) {
162            self.unchecked_scalar_sub_assign(ct, scalar);
163            Ok(())
164        } else {
165            Err(CarryFull)
166        }
167    }
168
169    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
170    ///
171    /// The result is returned in a _new_ ciphertext.
172    ///
173    /// This checks that the scalar subtraction is possible. In the case where the carry buffers are
174    /// full, then it is automatically cleared to allow the operation.
175    /// # Example
176    ///
177    /// ```rust
178    /// use concrete_shortint::gen_keys;
179    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
180    ///
181    /// // Generate the client key and the server key:
182    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
183    ///
184    /// let msg = 3;
185    /// let scalar = 3;
186    ///
187    /// let mut ct = cks.encrypt(msg);
188    ///
189    /// // Compute homomorphically a scalar multiplication:
190    /// let ct_res = sks.smart_scalar_sub(&mut ct, scalar);
191    ///
192    /// // The input ciphertext content is not changed
193    /// assert_eq!(cks.decrypt(&ct), msg);
194    ///
195    /// // Our result is what we expect
196    /// let clear = cks.decrypt(&ct_res);
197    ///
198    /// assert_eq!(msg - scalar as u64, clear);
199    /// ```
200    pub fn smart_scalar_sub(&self, ct: &mut Ciphertext, scalar: u8) -> Ciphertext {
201        ShortintEngine::with_thread_local_mut(|engine| {
202            engine.smart_scalar_sub(self, ct, scalar).unwrap()
203        })
204    }
205
206    /// Computes homomorphically a subtraction of a ciphertext by a scalar.
207    ///
208    /// The result is _stored_ in the `ct` ciphertext.
209    ///
210    /// This checks that the scalar subtraction is possible. In the case where the carry buffers are
211    /// full, then it is automatically cleared to allow the operation.
212    ///
213    /// # Example
214    ///
215    /// ```rust
216    /// use concrete_shortint::gen_keys;
217    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
218    ///
219    /// // Generate the client key and the server key:
220    /// let (cks, sks) = gen_keys(PARAM_MESSAGE_2_CARRY_2);
221    ///
222    /// let msg = 5;
223    /// let scalar = 3;
224    ///
225    /// let mut ct = cks.encrypt(msg);
226    ///
227    /// // Compute homomorphically a scalar multiplication:
228    /// sks.smart_scalar_sub_assign(&mut ct, scalar);
229    ///
230    /// // Our result is what we expect
231    /// let clear = cks.decrypt(&ct);
232    /// assert_eq!(msg - scalar as u64, clear);
233    /// ```
234    pub fn smart_scalar_sub_assign(&self, ct: &mut Ciphertext, scalar: u8) {
235        ShortintEngine::with_thread_local_mut(|engine| {
236            engine.smart_scalar_sub_assign(self, ct, scalar).unwrap()
237        })
238    }
239}