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}