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}