concrete_integer/server_key/crt_parallel/
scalar_add_crt.rs

1use crate::server_key::CheckError;
2use crate::server_key::CheckError::CarryFull;
3use crate::{CrtCiphertext, ServerKey};
4use rayon::prelude::*;
5
6impl ServerKey {
7    /// Computes homomorphically an addition between a scalar and a ciphertext.
8    ///
9    /// This function computes the operation without checking if it exceeds the capacity of the
10    /// ciphertext.
11    ///
12    /// The result is returned as a new ciphertext.
13    ///
14    /// # Example
15    ///
16    ///```rust
17    /// use concrete_integer::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 clear_1 = 14;
24    /// let clear_2 = 14;
25    /// let basis = vec![2, 3, 5];
26    /// // Encrypt two messages
27    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
28    ///
29    /// sks.unchecked_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
30    ///
31    /// // Decrypt
32    /// let res = cks.decrypt_crt(&ctxt_1);
33    /// assert_eq!((clear_1 + clear_2) % 30, res);
34    /// ```
35    pub fn unchecked_crt_scalar_add_parallelized(
36        &self,
37        ct: &CrtCiphertext,
38        scalar: u64,
39    ) -> CrtCiphertext {
40        let mut result = ct.clone();
41        self.unchecked_crt_scalar_add_assign_parallelized(&mut result, scalar);
42        result
43    }
44
45    /// Computes homomorphically an addition between a scalar and a ciphertext.
46    ///
47    /// This function computes the operation without checking if it exceeds the capacity of the
48    /// ciphertext.
49    ///
50    /// The result is assigned to the `ct_left` ciphertext.
51    pub fn unchecked_crt_scalar_add_assign_parallelized(
52        &self,
53        ct: &mut CrtCiphertext,
54        scalar: u64,
55    ) {
56        //Add the crt representation of the scalar to the ciphertext
57        ct.blocks
58            .par_iter_mut()
59            .zip(ct.moduli.par_iter())
60            .for_each(|(ct_i, mod_i)| {
61                let scalar_i = scalar % mod_i;
62                self.key.unchecked_scalar_add_assign(ct_i, scalar_i as u8);
63            });
64    }
65
66    /// Computes homomorphically an addition between a scalar and a ciphertext.
67    ///
68    /// If the operation can be performed, the result is returned in a new ciphertext.
69    /// Otherwise [CheckError::CarryFull] is returned.
70    ///
71    /// # Example
72    ///
73    /// ```rust
74    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
75    /// use concrete_integer::gen_keys;
76    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
77    ///
78    /// // Generate the client key and the server key:
79    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
80    ///
81    /// let clear_1 = 14;
82    /// let clear_2 = 14;
83    /// let basis = vec![2, 3, 5];
84    /// // Encrypt two messages
85    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
86    ///
87    /// sks.checked_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
88    ///
89    /// // Decrypt
90    /// let res = cks.decrypt_crt(&ctxt_1);
91    /// assert_eq!((clear_1 + clear_2) % 30, res);
92    /// # Ok(())
93    /// # }
94    /// ```
95    pub fn checked_crt_scalar_add_parallelized(
96        &self,
97        ct: &CrtCiphertext,
98        scalar: u64,
99    ) -> Result<CrtCiphertext, CheckError> {
100        if self.is_crt_scalar_add_possible(ct, scalar) {
101            Ok(self.unchecked_crt_scalar_add_parallelized(ct, scalar))
102        } else {
103            Err(CarryFull)
104        }
105    }
106
107    /// Computes homomorphically an addition between a scalar and a ciphertext.
108    ///
109    /// If the operation can be performed, the result is stored in the `ct_left` ciphertext.
110    /// Otherwise [CheckError::CarryFull] is returned, and `ct_left` is not modified.
111    pub fn checked_crt_scalar_add_assign_parallelized(
112        &self,
113        ct: &mut CrtCiphertext,
114        scalar: u64,
115    ) -> Result<(), CheckError> {
116        if self.is_crt_scalar_add_possible(ct, scalar) {
117            self.unchecked_crt_scalar_add_assign_parallelized(ct, scalar);
118            Ok(())
119        } else {
120            Err(CarryFull)
121        }
122    }
123
124    /// Computes homomorphically the addition of ciphertext with a scalar.
125    ///
126    /// The result is returned in a new ciphertext.
127    ///
128    /// # Example
129    ///
130    ///```rust
131    /// use concrete_integer::gen_keys;
132    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
133    ///
134    /// // Generate the client key and the server key:
135    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
136    ///
137    /// let clear_1 = 14;
138    /// let clear_2 = 14;
139    /// let basis = vec![2, 3, 5];
140    /// // Encrypt two messages
141    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
142    ///
143    /// let ctxt = sks.smart_crt_scalar_add_parallelized(&mut ctxt_1, clear_2);
144    ///
145    /// // Decrypt
146    /// let res = cks.decrypt_crt(&ctxt);
147    /// assert_eq!((clear_1 + clear_2) % 30, res);
148    /// ```
149    pub fn smart_crt_scalar_add_parallelized(
150        &self,
151        ct: &mut CrtCiphertext,
152        scalar: u64,
153    ) -> CrtCiphertext {
154        if !self.is_crt_scalar_add_possible(ct, scalar) {
155            self.full_extract_parallelized(ct);
156        }
157
158        let mut ct = ct.clone();
159        self.unchecked_crt_scalar_add_assign_parallelized(&mut ct, scalar);
160        ct
161    }
162
163    /// Computes homomorphically the addition of ciphertext with a scalar.
164    ///
165    /// The result is assigned to the `ct_left` ciphertext.
166    ///
167    /// # Example
168    ///
169    ///```rust
170    /// use concrete_integer::gen_keys;
171    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
172    ///
173    /// // Generate the client key and the server key:
174    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
175    ///
176    /// let clear_1 = 14;
177    /// let clear_2 = 14;
178    /// let basis = vec![2, 3, 5];
179    /// // Encrypt two messages
180    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
181    ///
182    /// sks.smart_crt_scalar_add_assign_parallelized(&mut ctxt_1, clear_2);
183    ///
184    /// // Decrypt
185    /// let res = cks.decrypt_crt(&ctxt_1);
186    /// assert_eq!((clear_1 + clear_2) % 30, res);
187    /// ```
188    pub fn smart_crt_scalar_add_assign_parallelized(&self, ct: &mut CrtCiphertext, scalar: u64) {
189        if !self.is_crt_scalar_add_possible(ct, scalar) {
190            self.full_extract_parallelized(ct);
191        }
192        self.unchecked_crt_scalar_add_assign_parallelized(ct, scalar);
193    }
194}