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}