concrete_integer/server_key/radix/mul.rs
1use crate::ciphertext::RadixCiphertext;
2use crate::ServerKey;
3
4impl ServerKey {
5 /// Computes homomorphically a multiplication between a ciphertext encrypting an integer value
6 /// and another encrypting a shortint value.
7 ///
8 /// This function computes the operation without checking if it exceeds the capacity of the
9 /// ciphertext.
10 ///
11 /// The result is assigned to the `ct_left` ciphertext.
12 ///
13 /// # Example
14 ///
15 ///```rust
16 /// use concrete_integer::gen_keys_radix;
17 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
18 /// let size = 4;
19 ///
20 /// // Generate the client key and the server key:
21 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
22 ///
23 /// let clear_1 = 170;
24 /// let clear_2 = 3;
25 ///
26 /// // Encrypt two messages
27 /// let mut ct_left = cks.encrypt(clear_1);
28 /// let ct_right = cks.encrypt_one_block(clear_2);
29 ///
30 /// // Compute homomorphically a multiplication
31 /// sks.unchecked_block_mul_assign(&mut ct_left, &ct_right, 0);
32 ///
33 /// // Decrypt
34 /// let res = cks.decrypt(&ct_left);
35 /// assert_eq!((clear_1 * clear_2) % 256, res);
36 /// ```
37 pub fn unchecked_block_mul_assign(
38 &self,
39 ct_left: &mut RadixCiphertext,
40 ct_right: &concrete_shortint::Ciphertext,
41 index: usize,
42 ) {
43 *ct_left = self.unchecked_block_mul(ct_left, ct_right, index);
44 }
45
46 /// Computes homomorphically a multiplication between a ciphertexts encrypting an integer
47 /// value and another encrypting a shortint value.
48 ///
49 /// This function computes the operation without checking if it exceeds the capacity of the
50 /// ciphertext.
51 ///
52 /// The result is returned as a new ciphertext.
53 ///
54 /// # Example
55 ///
56 ///```rust
57 /// use concrete_integer::gen_keys_radix;
58 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
59 /// let size = 4;
60 ///
61 /// // Generate the client key and the server key:
62 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
63 ///
64 /// let clear_1 = 55;
65 /// let clear_2 = 3;
66 ///
67 /// // Encrypt two messages
68 /// let ct_left = cks.encrypt(clear_1);
69 /// let ct_right = cks.encrypt_one_block(clear_2);
70 ///
71 /// // Compute homomorphically a multiplication
72 /// let ct_res = sks.unchecked_block_mul(&ct_left, &ct_right, 0);
73 ///
74 /// // Decrypt
75 /// let res = cks.decrypt(&ct_res);
76 /// assert_eq!((clear_1 * clear_2) % 256, res);
77 /// ```
78 pub fn unchecked_block_mul(
79 &self,
80 ct1: &RadixCiphertext,
81 ct2: &concrete_shortint::Ciphertext,
82 index: usize,
83 ) -> RadixCiphertext {
84 let shifted_ct = self.blockshift(ct1, index);
85
86 let mut result_lsb = shifted_ct.clone();
87 let mut result_msb = shifted_ct;
88
89 for res_lsb_i in result_lsb.blocks[index..].iter_mut() {
90 self.key.unchecked_mul_lsb_assign(res_lsb_i, ct2);
91 }
92
93 let len = result_msb.blocks.len() - 1;
94 for res_msb_i in result_msb.blocks[index..len].iter_mut() {
95 self.key.unchecked_mul_msb_assign(res_msb_i, ct2);
96 }
97
98 result_msb = self.blockshift(&result_msb, 1);
99
100 self.unchecked_add(&result_lsb, &result_msb)
101 }
102
103 /// Computes homomorphically a multiplication between a ciphertext encrypting integer value
104 /// and another encrypting a shortint value.
105 ///
106 /// The result is returned as a new ciphertext.
107 ///
108 /// # Example
109 ///
110 ///```rust
111 /// use concrete_integer::gen_keys_radix;
112 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
113 /// let size = 4;
114 ///
115 /// // Generate the client key and the server key:
116 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
117 ///
118 /// let clear_1 = 170;
119 /// let clear_2 = 3;
120 ///
121 /// // Encrypt two messages
122 /// let mut ctxt_1 = cks.encrypt(clear_1);
123 /// let ctxt_2 = cks.encrypt_one_block(clear_2);
124 ///
125 /// // Compute homomorphically a multiplication
126 /// let ct_res = sks.smart_block_mul(&mut ctxt_1, &ctxt_2, 0);
127 ///
128 /// // Decrypt
129 /// let res = cks.decrypt(&ct_res);
130 /// assert_eq!((clear_1 * clear_2) % 256, res);
131 /// ```
132 pub fn smart_block_mul(
133 &self,
134 ct1: &mut RadixCiphertext,
135 ct2: &concrete_shortint::Ciphertext,
136 index: usize,
137 ) -> RadixCiphertext {
138 //Makes sure we can do the multiplications
139 self.full_propagate(ct1);
140
141 let shifted_ct = self.blockshift(ct1, index);
142
143 let mut result_lsb = shifted_ct.clone();
144 let mut result_msb = shifted_ct;
145
146 for res_lsb_i in result_lsb.blocks[index..].iter_mut() {
147 self.key.unchecked_mul_lsb_assign(res_lsb_i, ct2);
148 }
149
150 let len = result_msb.blocks.len() - 1;
151 for res_msb_i in result_msb.blocks[index..len].iter_mut() {
152 self.key.unchecked_mul_msb_assign(res_msb_i, ct2);
153 }
154
155 result_msb = self.blockshift(&result_msb, 1);
156
157 self.smart_add(&mut result_lsb, &mut result_msb)
158 }
159
160 pub fn smart_block_mul_assign(
161 &self,
162 ct1: &mut RadixCiphertext,
163 ct2: &concrete_shortint::Ciphertext,
164 index: usize,
165 ) {
166 *ct1 = self.smart_block_mul(ct1, ct2, index);
167 }
168
169 /// Computes homomorphically a multiplication between two ciphertexts encrypting integer values.
170 ///
171 /// This function computes the operation without checking if it exceeds the capacity of the
172 /// ciphertext.
173 ///
174 /// The result is assigned to the `ct_left` ciphertext.
175 /// # Example
176 ///
177 /// ```rust
178 /// use concrete_integer::gen_keys_radix;
179 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
180 /// let size = 4;
181 ///
182 /// // Generate the client key and the server key:
183 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
184 ///
185 /// let clear_1 = 255;
186 /// let clear_2 = 143;
187 ///
188 /// // Encrypt two messages
189 /// let mut ctxt_1 = cks.encrypt(clear_1);
190 /// let ctxt_2 = cks.encrypt(clear_2);
191 ///
192 /// // Compute homomorphically a multiplication
193 /// let ct_res = sks.unchecked_mul(&mut ctxt_1, &ctxt_2);
194 ///
195 /// // Decrypt
196 /// let res = cks.decrypt(&ct_res);
197 /// assert_eq!((clear_1 * clear_2) % 256, res);
198 /// ```
199 pub fn unchecked_mul_assign(&self, ct1: &mut RadixCiphertext, ct2: &RadixCiphertext) {
200 *ct1 = self.unchecked_mul(ct1, ct2);
201 }
202
203 /// Computes homomorphically a multiplication between two ciphertexts encrypting integer values.
204 ///
205 /// This function computes the operation without checking if it exceeds the capacity of the
206 /// ciphertext.
207 ///
208 /// The result is returned as a new ciphertext.
209 pub fn unchecked_mul(
210 &self,
211 ct1: &mut RadixCiphertext,
212 ct2: &RadixCiphertext,
213 ) -> RadixCiphertext {
214 let copy = ct1.clone();
215 let mut result = self.create_trivial_zero_radix(ct1.blocks.len());
216
217 for (i, ct2_i) in ct2.blocks.iter().enumerate() {
218 let tmp = self.unchecked_block_mul(©, ct2_i, i);
219
220 self.unchecked_add_assign(&mut result, &tmp);
221 }
222
223 result
224 }
225
226 /// Computes homomorphically a multiplication between two ciphertexts encrypting integer values.
227 ///
228 /// The result is assigned to the `ct_left` ciphertext.
229 ///
230 /// # Example
231 ///
232 /// ```rust
233 /// use concrete_integer::gen_keys_radix;
234 /// use concrete_shortint::parameters::PARAM_MESSAGE_2_CARRY_2;
235 /// let size = 4;
236 ///
237 /// // Generate the client key and the server key:
238 /// let (cks, sks) = gen_keys_radix(&PARAM_MESSAGE_2_CARRY_2, size);
239 ///
240 /// let clear_1 = 170;
241 /// let clear_2 = 6;
242 ///
243 /// // Encrypt two messages
244 /// let mut ctxt_1 = cks.encrypt(clear_1);
245 /// let mut ctxt_2 = cks.encrypt(clear_2);
246 ///
247 /// // Compute homomorphically a multiplication
248 /// let ct_res = sks.smart_mul(&mut ctxt_1, &mut ctxt_2);
249 /// // Decrypt
250 /// let res = cks.decrypt(&ct_res);
251 /// assert_eq!((clear_1 * clear_2) % 256, res);
252 /// ```
253 pub fn smart_mul_assign(&self, ct1: &mut RadixCiphertext, ct2: &mut RadixCiphertext) {
254 *ct1 = self.smart_mul(ct1, ct2);
255 }
256
257 /// Computes homomorphically a multiplication between two ciphertexts encrypting integer values.
258 ///
259 /// The result is returned as a new ciphertext.
260 pub fn smart_mul(
261 &self,
262 ct1: &mut RadixCiphertext,
263 ct2: &mut RadixCiphertext,
264 ) -> RadixCiphertext {
265 self.full_propagate(ct1);
266 self.full_propagate(ct2);
267
268 let copy = ct1.clone();
269 let mut result = self.create_trivial_zero_radix(ct1.blocks.len());
270
271 for (i, ct2_i) in ct2.blocks.iter().enumerate() {
272 let mut tmp = self.unchecked_block_mul(©, ct2_i, i);
273 self.smart_add_assign(&mut result, &mut tmp);
274 }
275
276 result
277 }
278}