concrete_integer/server_key/crt/
scalar_mul_crt.rs

1use crate::server_key::CheckError;
2use crate::server_key::CheckError::CarryFull;
3use crate::{CrtCiphertext, ServerKey};
4
5impl ServerKey {
6    /// Computes homomorphically a multiplication between a scalar and a ciphertext.
7    ///
8    /// This function computes the operation without checking if it exceeds the capacity of the
9    /// ciphertext.
10    ///
11    /// The result is returned as a new ciphertext.
12    ///
13    /// # Example
14    ///
15    ///```rust
16    /// use concrete_integer::gen_keys;
17    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
18    ///
19    /// // Generate the client key and the server key:
20    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
21    ///
22    /// let clear_1 = 14;
23    /// let clear_2 = 2;
24    /// let basis = vec![2, 3, 5];
25    /// // Encrypt two messages
26    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
27    ///
28    /// sks.unchecked_crt_scalar_mul_assign(&mut ctxt_1, clear_2);
29    ///
30    /// // Decrypt
31    /// let res = cks.decrypt_crt(&ctxt_1);
32    /// assert_eq!((clear_1 * clear_2) % 30, res);
33    /// ```
34    pub fn unchecked_crt_scalar_mul(&self, ctxt: &CrtCiphertext, scalar: u64) -> CrtCiphertext {
35        let mut ct_result = ctxt.clone();
36        self.unchecked_crt_scalar_mul_assign(&mut ct_result, scalar);
37
38        ct_result
39    }
40
41    pub fn unchecked_crt_scalar_mul_assign(&self, ctxt: &mut CrtCiphertext, scalar: u64) {
42        for (ct_i, mod_i) in ctxt.blocks.iter_mut().zip(ctxt.moduli.iter()) {
43            self.key
44                .unchecked_scalar_mul_assign(ct_i, (scalar % mod_i) as u8);
45        }
46    }
47
48    ///Verifies if ct1 can be multiplied by scalar.
49    ///
50    /// # Example
51    ///
52    ///```rust
53    /// use concrete_integer::gen_keys;
54    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
55    ///
56    /// // Generate the client key and the server key:
57    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
58    ///
59    /// let clear_1 = 14;
60    /// let clear_2 = 2;
61    /// let basis = vec![2, 3, 5];
62    /// // Encrypt two messages
63    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
64    ///
65    /// let tmp = sks.is_crt_scalar_mul_possible(&mut ctxt_1, clear_2);
66    ///
67    /// assert_eq!(true, tmp);
68    /// ```
69    pub fn is_crt_scalar_mul_possible(&self, ctxt: &CrtCiphertext, scalar: u64) -> bool {
70        for (ct_i, mod_i) in ctxt.blocks.iter().zip(ctxt.moduli.iter()) {
71            if !self
72                .key
73                .is_scalar_mul_possible(ct_i, (scalar % mod_i) as u8)
74            {
75                return false;
76            }
77        }
78        true
79    }
80
81    /// Computes homomorphically a multiplication between a scalar and a ciphertext.
82    ///
83    /// If the operation can be performed, the result is returned in a new ciphertext.
84    /// Otherwise [CheckError::CarryFull] is returned.
85    ///
86    /// # Example
87    ///
88    /// ```rust
89    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
90    /// use concrete_integer::gen_keys;
91    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
92    ///
93    /// // Generate the client key and the server key:
94    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
95    ///
96    /// let clear_1 = 14;
97    /// let clear_2 = 2;
98    /// let basis = vec![2, 3, 5];
99    /// // Encrypt two messages
100    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
101    ///
102    /// sks.checked_crt_scalar_mul_assign(&mut ctxt_1, clear_2);
103    ///
104    /// // Decrypt
105    /// let res = cks.decrypt_crt(&ctxt_1);
106    /// assert_eq!((clear_1 * clear_2) % 30, res);
107    /// # Ok(())
108    /// # }
109    /// ```
110    pub fn checked_crt_scalar_mul(
111        &self,
112        ct: &CrtCiphertext,
113        scalar: u64,
114    ) -> Result<CrtCiphertext, CheckError> {
115        let mut ct_result = ct.clone();
116
117        // If the ciphertext cannot be multiplied without exceeding the capacity of a ciphertext
118        if self.is_crt_scalar_mul_possible(ct, scalar) {
119            ct_result = self.unchecked_crt_scalar_mul(&ct_result, scalar);
120
121            Ok(ct_result)
122        } else {
123            Err(CarryFull)
124        }
125    }
126
127    /// Computes homomorphically a multiplication between a scalar and a ciphertext.
128    ///
129    /// If the operation can be performed, the result is assigned to the ciphertext given
130    /// as parameter.
131    /// Otherwise [CheckError::CarryFull] is returned.
132    pub fn checked_crt_scalar_mul_assign(
133        &self,
134        ct: &mut CrtCiphertext,
135        scalar: u64,
136    ) -> Result<(), CheckError> {
137        // If the ciphertext cannot be multiplied without exceeding the capacity of a ciphertext
138        if self.is_crt_scalar_mul_possible(ct, scalar) {
139            self.unchecked_crt_scalar_mul_assign(ct, scalar);
140            Ok(())
141        } else {
142            Err(CarryFull)
143        }
144    }
145
146    /// Computes homomorphically a multiplication between a scalar and a ciphertext.
147    ///
148    /// `small` means the scalar value shall fit in a __shortint block__.
149    /// For example, if the parameters are PARAM_MESSAGE_2_CARRY_2,
150    /// the scalar should fit in 2 bits.
151    ///
152    /// The result is returned as a new ciphertext.
153    ///
154    /// # Example
155    ///
156    ///```rust
157    /// use concrete_integer::gen_keys;
158    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
159    ///
160    /// // Generate the client key and the server key:
161    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
162    ///
163    /// let clear_1 = 14;
164    /// let clear_2 = 14;
165    /// let basis = vec![2, 3, 5];
166    /// // Encrypt two messages
167    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
168    ///
169    /// let ctxt = sks.smart_crt_scalar_mul(&mut ctxt_1, clear_2);
170    ///
171    /// // Decrypt
172    /// let res = cks.decrypt_crt(&ctxt);
173    /// assert_eq!((clear_1 * clear_2) % 30, res);
174    /// ```
175    pub fn smart_crt_scalar_mul(&self, ctxt: &mut CrtCiphertext, scalar: u64) -> CrtCiphertext {
176        if !self.is_crt_scalar_mul_possible(ctxt, scalar) {
177            self.full_extract(ctxt);
178        }
179        self.unchecked_crt_scalar_mul(ctxt, scalar)
180    }
181
182    /// Computes homomorphically a multiplication between a scalar and a ciphertext.
183    ///
184    /// `small` means the scalar shall value fit in a __shortint block__.
185    /// For example, if the parameters are PARAM_MESSAGE_2_CARRY_2,
186    /// the scalar should fit in 2 bits.
187    ///
188    /// The result is assigned to the input ciphertext
189    ///
190    /// # Example
191    ///
192    ///```rust
193    /// use concrete_integer::gen_keys;
194    /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
195    ///
196    /// // Generate the client key and the server key:
197    /// let (cks, sks) = gen_keys(&PARAM_MESSAGE_2_CARRY_2);
198    ///
199    /// let clear_1 = 14;
200    /// let clear_2 = 14;
201    /// let basis = vec![2, 3, 5];
202    /// // Encrypt two messages
203    /// let mut ctxt_1 = cks.encrypt_crt(clear_1, basis.clone());
204    ///
205    /// sks.smart_crt_scalar_mul_assign(&mut ctxt_1, clear_2);
206    ///
207    /// // Decrypt
208    /// let res = cks.decrypt_crt(&ctxt_1);
209    /// assert_eq!((clear_1 * clear_2) % 30, res);
210    /// ```
211    pub fn smart_crt_scalar_mul_assign(&self, ctxt: &mut CrtCiphertext, scalar: u64) {
212        if !self.is_crt_small_scalar_mul_possible(ctxt, scalar) {
213            self.full_extract(ctxt);
214        }
215        self.unchecked_crt_scalar_mul_assign(ctxt, scalar);
216    }
217
218    pub fn is_crt_small_scalar_mul_possible(&self, ctxt: &CrtCiphertext, scalar: u64) -> bool {
219        for ct_i in ctxt.blocks.iter() {
220            if !self.key.is_scalar_mul_possible(ct_i, scalar as u8) {
221                return false;
222            }
223        }
224        true
225    }
226}