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