concrete_integer/server_key/multi_crt/
mod.rs

1#[cfg(test)]
2mod test;
3
4use crate::ciphertext::KeyId;
5use crate::{CrtMultiCiphertext, CrtMultiClientKey};
6use concrete_shortint::server_key::MaxDegree;
7use rayon::prelude::*;
8use serde::{Deserialize, Serialize};
9
10#[derive(Serialize, Deserialize, Debug, Clone)]
11pub struct CrtMultiServerKey {
12    pub(crate) keys: Vec<concrete_shortint::server_key::ServerKey>,
13    pub(crate) key_ids: Vec<KeyId>,
14}
15
16impl From<Vec<concrete_shortint::ServerKey>> for CrtMultiServerKey {
17    fn from(keys: Vec<concrete_shortint::ServerKey>) -> Self {
18        let key_ids = (0..keys.len()).map(KeyId).collect();
19
20        Self { keys, key_ids }
21    }
22}
23
24impl CrtMultiServerKey {
25    /// Allocates and generates a server key.
26    ///
27    /// # Example
28    ///
29    /// ```rust
30    /// use concrete_integer::{CrtMultiClientKey, CrtMultiServerKey};
31    /// use concrete_shortint::parameters::{PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2};
32    ///
33    /// // Generate the client key:
34    /// let cks = CrtMultiClientKey::new_many_keys(&[PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2]);
35    /// let sks = CrtMultiServerKey::new_many_keys(&cks);
36    /// ```
37    pub fn new_many_keys(cks: &CrtMultiClientKey) -> CrtMultiServerKey {
38        let mut vec_sks = Vec::with_capacity(cks.keys.len());
39        let mut vec_id = Vec::with_capacity(cks.keys.len());
40
41        for (key, id) in cks.keys.iter().zip(cks.key_ids.iter()) {
42            let max = (key.parameters.message_modulus.0 - 1) * key.parameters.carry_modulus.0 - 1;
43
44            let sks = concrete_shortint::ServerKey::new_with_max_degree(key, MaxDegree(max));
45            vec_sks.push(sks);
46            vec_id.push(*id);
47        }
48        CrtMultiServerKey {
49            keys: vec_sks,
50            key_ids: vec_id,
51        }
52    }
53
54    /// Computes an homomorphic addition.
55    ///
56    /// # Example
57    ///
58    ///```rust
59    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
60    /// use concrete_shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_1};
61    ///
62    /// // Generate the client key and the server key:
63    /// let (cks, sks) = gen_keys_multi_crt(&[PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_1]);
64    ///
65    /// let clear_1 = 14;
66    /// let clear_2 = 11;
67    ///
68    /// let basis = vec![2, 3, 7];
69    /// let keys_id = gen_key_id(&[0, 0, 1]);
70    ///
71    /// // Encrypt two messages
72    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
73    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
74    ///
75    /// sks.unchecked_add_crt_many_keys_assign(&mut ctxt_1, &mut ctxt_2);
76    ///
77    /// // Decrypt
78    /// let res = cks.decrypt(&ctxt_1);
79    /// assert_eq!((clear_1 + clear_2) % 30, res);
80    /// ```
81    pub fn unchecked_add_crt_many_keys_assign(
82        &self,
83        ct_left: &mut CrtMultiCiphertext,
84        ct_right: &mut CrtMultiCiphertext,
85    ) {
86        for ((ct_left, ct_right), key_id) in ct_left
87            .blocks
88            .iter_mut()
89            .zip(ct_right.blocks.iter_mut())
90            .zip(ct_left.key_ids.iter())
91        {
92            self.keys[key_id.0].unchecked_add_assign(ct_left, ct_right);
93        }
94    }
95
96    /// Computes an homomorphic addition.
97    ///
98    /// # Warning
99    ///
100    /// Multithreaded
101    ///
102    /// # Example
103    ///
104    ///```rust
105    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
106    /// use concrete_shortint::parameters::{PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_1};
107    ///
108    /// // Generate the client key and the server key:
109    /// let (cks, sks) = gen_keys_multi_crt(&[PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_1]);
110    ///
111    /// let clear_1 = 14;
112    /// let clear_2 = 11;
113    ///
114    /// let basis = vec![2, 3, 7];
115    /// let keys_id = gen_key_id(&[0, 0, 1]);
116    ///
117    /// // Encrypt two messages
118    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
119    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
120    ///
121    /// sks.unchecked_add_crt_many_keys_assign_parallelized(&mut ctxt_1, &mut ctxt_2);
122    ///
123    /// // Decrypt
124    /// let res = cks.decrypt(&ctxt_1);
125    /// assert_eq!((clear_1 + clear_2) % 30, res);
126    /// ```
127    pub fn unchecked_add_crt_many_keys_assign_parallelized(
128        &self,
129        ct_left: &mut CrtMultiCiphertext,
130        ct_right: &mut CrtMultiCiphertext,
131    ) {
132        ct_left
133            .blocks
134            .par_iter_mut()
135            .zip(ct_right.blocks.par_iter_mut())
136            .zip(ct_left.key_ids.par_iter())
137            .for_each(|((block_left, block_right), key_id)| {
138                let key = &self.keys[key_id.0];
139                key.unchecked_add_assign(block_left, block_right);
140            });
141    }
142
143    /// Computes an homomorphic multiplication.
144    ///
145    /// # Example
146    ///
147    ///```rust
148    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
149    /// use concrete_shortint::parameters::{
150    ///     PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_3,
151    /// };
152    ///
153    /// // Generate the client key and the server key:
154    /// let (cks, sks) = gen_keys_multi_crt(&vec![
155    ///     PARAM_MESSAGE_1_CARRY_1,
156    ///     PARAM_MESSAGE_2_CARRY_2,
157    ///     PARAM_MESSAGE_3_CARRY_3,
158    /// ]);
159    ///
160    /// let clear_1 = 13;
161    /// let clear_2 = 11;
162    ///
163    /// let basis = vec![2, 3, 5];
164    /// let keys_id = gen_key_id(&[0, 1, 2]);
165    ///
166    /// // Encrypt two messages
167    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
168    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
169    ///
170    /// sks.unchecked_mul_crt_many_keys_assign(&mut ctxt_1, &mut ctxt_2);
171    ///
172    /// // Decrypt
173    /// let res = cks.decrypt(&ctxt_1);
174    /// assert_eq!((clear_1 * clear_2) % 30, res);
175    /// ```
176    pub fn unchecked_mul_crt_many_keys_assign(
177        &self,
178        ct_left: &mut CrtMultiCiphertext,
179        ct_right: &mut CrtMultiCiphertext,
180    ) {
181        for ((block_left, block_right), id) in ct_left
182            .blocks
183            .iter_mut()
184            .zip(ct_right.blocks.iter_mut())
185            .zip(ct_left.key_ids.iter())
186        {
187            self.keys[id.0].unchecked_mul_lsb_assign(block_left, block_right);
188        }
189    }
190
191    /// Computes an homomorphic multiplication.
192    ///
193    /// # Warning
194    ///
195    /// Multithreaded
196    ///
197    /// # Example
198    ///
199    ///```rust
200    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
201    /// use concrete_shortint::parameters::{
202    ///     PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_3,
203    /// };
204    ///
205    /// // Generate the client key and the server key:
206    /// let (cks, sks) = gen_keys_multi_crt(&vec![
207    ///     PARAM_MESSAGE_1_CARRY_1,
208    ///     PARAM_MESSAGE_2_CARRY_2,
209    ///     PARAM_MESSAGE_3_CARRY_3,
210    /// ]);
211    ///
212    /// let clear_1 = 13;
213    /// let clear_2 = 11;
214    ///
215    /// let basis = vec![2, 3, 5];
216    /// let keys_id = gen_key_id(&[0, 1, 2]);
217    ///
218    /// // Encrypt two messages
219    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
220    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
221    ///
222    /// sks.unchecked_mul_crt_many_keys_assign_parallelized(&mut ctxt_1, &mut ctxt_2);
223    ///
224    /// // Decrypt
225    /// let res = cks.decrypt(&ctxt_1);
226    /// assert_eq!((clear_1 * clear_2) % 30, res);
227    /// ```
228    pub fn unchecked_mul_crt_many_keys_assign_parallelized(
229        &self,
230        ct_left: &mut CrtMultiCiphertext,
231        ct_right: &mut CrtMultiCiphertext,
232    ) {
233        ct_left
234            .blocks
235            .par_iter_mut()
236            .zip(ct_right.blocks.par_iter_mut())
237            .zip(ct_left.key_ids.par_iter())
238            .for_each(|((block_left, block_right), id)| {
239                self.keys[id.0].unchecked_mul_lsb_assign(block_left, block_right);
240            });
241    }
242
243    /// Computes an homomorphic evaluation of an CRT-compliant univariate function.
244    ///
245    /// # Warning The function has to be CRT-compliant.
246    ///
247    /// # Example
248    ///
249    ///```rust
250    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
251    /// use concrete_shortint::parameters::{
252    ///     PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_3,
253    /// };
254    ///
255    /// // Generate the client key and the server key:
256    /// let (cks, sks) = gen_keys_multi_crt(&vec![
257    ///     PARAM_MESSAGE_1_CARRY_1,
258    ///     PARAM_MESSAGE_2_CARRY_2,
259    ///     PARAM_MESSAGE_3_CARRY_3,
260    /// ]);
261    ///
262    /// let clear_1 = 14;
263    /// let clear_2 = 11;
264    ///
265    /// let basis = vec![2, 3, 5];
266    /// let keys_id = gen_key_id(&[0, 1, 2]);
267    ///
268    /// // Encrypt two messages
269    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
270    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
271    ///
272    /// sks.arithmetic_function_crt_many_keys_assign(&mut ctxt_1, |x| x * x);
273    ///
274    /// // Decrypt
275    /// let res = cks.decrypt(&ctxt_1);
276    /// assert_eq!((clear_1 * clear_1) % 30, res);
277    /// ```
278    pub fn arithmetic_function_crt_many_keys_assign<F>(&self, ct: &mut CrtMultiCiphertext, f: F)
279    where
280        F: Fn(u64) -> u64,
281    {
282        let basis = &ct.moduli;
283        let keys_id = &ct.key_ids;
284        for ((block, key_id), basis) in ct.blocks.iter_mut().zip(keys_id.iter()).zip(basis.iter()) {
285            let acc = self.keys[key_id.0].generate_accumulator(|x| f(x) % basis);
286            self.keys[key_id.0].keyswitch_programmable_bootstrap_assign(block, &acc);
287        }
288    }
289
290    /// Computes an homomorphic evaluation of an CRT-compliant univariate function.
291    ///
292    /// # Warning
293    ///
294    /// - Multithreaded
295    /// - The function has to be CRT-compliant.
296    ///
297    /// # Example
298    ///
299    ///```rust
300    /// use concrete_integer::{gen_key_id, gen_keys_multi_crt};
301    /// use concrete_shortint::parameters::{
302    ///     PARAM_MESSAGE_1_CARRY_1, PARAM_MESSAGE_2_CARRY_2, PARAM_MESSAGE_3_CARRY_3,
303    /// };
304    ///
305    /// // Generate the client key and the server key:
306    /// let (cks, sks) = gen_keys_multi_crt(&vec![
307    ///     PARAM_MESSAGE_1_CARRY_1,
308    ///     PARAM_MESSAGE_2_CARRY_2,
309    ///     PARAM_MESSAGE_3_CARRY_3,
310    /// ]);
311    ///
312    /// let clear_1 = 14;
313    /// let clear_2 = 11;
314    ///
315    /// let basis = vec![2, 3, 5];
316    /// let keys_id = gen_key_id(&[0, 1, 2]);
317    ///
318    /// // Encrypt two messages
319    /// let mut ctxt_1 = cks.encrypt(&clear_1, &basis, &keys_id);
320    /// let mut ctxt_2 = cks.encrypt(&clear_2, &basis, &keys_id);
321    ///
322    /// sks.arithmetic_function_crt_many_keys_assign_parallelized(&mut ctxt_1, |x| x * x);
323    ///
324    /// // Decrypt
325    /// let res = cks.decrypt(&ctxt_1);
326    /// assert_eq!((clear_1 * clear_1) % 30, res);
327    /// ```
328    pub fn arithmetic_function_crt_many_keys_assign_parallelized<F>(
329        &self,
330        ct: &mut CrtMultiCiphertext,
331        f: F,
332    ) where
333        F: Fn(u64) -> u64,
334    {
335        let basis = &ct.moduli;
336        let keys_id = &ct.key_ids;
337
338        let accumulators = keys_id
339            .iter()
340            .zip(basis.iter())
341            .map(|(key_id, basis)| self.keys[key_id.0].generate_accumulator(|x| f(x) % basis))
342            .collect::<Vec<_>>();
343
344        ct.blocks
345            .par_iter_mut()
346            .zip(keys_id)
347            .zip(&accumulators)
348            .for_each(|((block, key_id), acc)| {
349                self.keys[key_id.0].keyswitch_programmable_bootstrap_assign(block, acc);
350            });
351    }
352}