@@ -264,39 +264,72 @@ namespace seal
264
264
// Make sure we have enough secret key powers computed
265
265
compute_secret_key_array (encrypted_size - 1 );
266
266
267
- // put < (c_1 , c_2, ... , c_{count-1}) , (s,s^2,...,s^{count-1}) > mod q in destination
268
- // Now do the dot product of encrypted_copy and the secret key array using NTT.
269
- // The secret key powers are already NTT transformed.
270
-
271
- SEAL_ALLOCATE_GET_POLY_ITER (encrypted_copy, encrypted_size - 1 , coeff_count, coeff_modulus_size, pool);
272
- set_poly_array (encrypted.data (1 ), encrypted_size - 1 , coeff_count, coeff_modulus_size, encrypted_copy);
273
-
274
- // Transform c_1, c_2, ... to NTT form unless they already are
275
- if (!is_ntt_form)
267
+ if (encrypted_size == 2 )
276
268
{
277
- ntt_negacyclic_harvey_lazy (encrypted_copy, encrypted_size - 1 , ntt_tables);
269
+ ConstRNSIter secret_key_array (secret_key_array_.get (), coeff_count);
270
+ ConstRNSIter c0 (encrypted.data (0 ), coeff_count);
271
+ ConstRNSIter c1 (encrypted.data (1 ), coeff_count);
272
+ if (is_ntt_form)
273
+ {
274
+ SEAL_ITERATE (
275
+ iter (c0, c1, secret_key_array, coeff_modulus, destination), coeff_modulus_size, [&](auto I) {
276
+ // put < c_1 * s > mod q in destination
277
+ dyadic_product_coeffmod (get<1 >(I), get<2 >(I), coeff_count, get<3 >(I), get<4 >(I));
278
+ // add c_0 to the result; note that destination should be in the same (NTT) form as encrypted
279
+ add_poly_coeffmod (get<4 >(I), get<0 >(I), coeff_count, get<3 >(I), get<4 >(I));
280
+ });
281
+ }
282
+ else
283
+ {
284
+ SEAL_ITERATE (
285
+ iter (c0, c1, secret_key_array, coeff_modulus, ntt_tables, destination), coeff_modulus_size,
286
+ [&](auto I) {
287
+ set_uint (get<1 >(I), coeff_count, get<5 >(I));
288
+ // Transform c_1 to NTT form
289
+ ntt_negacyclic_harvey_lazy (get<5 >(I), get<4 >(I));
290
+ // put < c_1 * s > mod q in destination
291
+ dyadic_product_coeffmod (get<5 >(I), get<2 >(I), coeff_count, get<3 >(I), get<5 >(I));
292
+ // Transform back
293
+ inverse_ntt_negacyclic_harvey (get<5 >(I), get<4 >(I));
294
+ // add c_0 to the result; note that destination should be in the same (NTT) form as encrypted
295
+ add_poly_coeffmod (get<5 >(I), get<0 >(I), coeff_count, get<3 >(I), get<5 >(I));
296
+ });
297
+ }
278
298
}
299
+ else
300
+ {
301
+ // put < (c_1 , c_2, ... , c_{count-1}) , (s,s^2,...,s^{count-1}) > mod q in destination
302
+ // Now do the dot product of encrypted_copy and the secret key array using NTT.
303
+ // The secret key powers are already NTT transformed.
304
+ SEAL_ALLOCATE_GET_POLY_ITER (encrypted_copy, encrypted_size - 1 , coeff_count, coeff_modulus_size, pool);
305
+ set_poly_array (encrypted.data (1 ), encrypted_size - 1 , coeff_count, coeff_modulus_size, encrypted_copy);
306
+
307
+ // Transform c_1, c_2, ... to NTT form unless they already are
308
+ if (!is_ntt_form)
309
+ {
310
+ ntt_negacyclic_harvey_lazy (encrypted_copy, encrypted_size - 1 , ntt_tables);
311
+ }
312
+
313
+ // Compute dyadic product with secret power array
314
+ auto secret_key_array = PolyIter (secret_key_array_.get (), coeff_count, key_coeff_modulus_size);
315
+ SEAL_ITERATE (iter (encrypted_copy, secret_key_array), encrypted_size - 1 , [&](auto I) {
316
+ dyadic_product_coeffmod (get<0 >(I), get<1 >(I), coeff_modulus_size, coeff_modulus, get<0 >(I));
317
+ });
318
+ // Aggregate all polynomials together to complete the dot product
319
+ set_zero_poly (coeff_count, coeff_modulus_size, destination);
320
+ SEAL_ITERATE (encrypted_copy, encrypted_size - 1 , [&](auto I) {
321
+ add_poly_coeffmod (destination, I, coeff_modulus_size, coeff_modulus, destination);
322
+ });
279
323
280
- // Compute dyadic product with secret power array
281
- auto secret_key_array = PolyIter (secret_key_array_.get (), coeff_count, key_coeff_modulus_size);
282
- SEAL_ITERATE (iter (encrypted_copy, secret_key_array), encrypted_size - 1 , [&](auto I) {
283
- dyadic_product_coeffmod (get<0 >(I), get<1 >(I), coeff_modulus_size, coeff_modulus, get<0 >(I));
284
- });
285
-
286
- // Aggregate all polynomials together to complete the dot product
287
- set_zero_poly (coeff_count, coeff_modulus_size, destination);
288
- SEAL_ITERATE (encrypted_copy, encrypted_size - 1 , [&](auto I) {
289
- add_poly_coeffmod (destination, I, coeff_modulus_size, coeff_modulus, destination);
290
- });
324
+ if (!is_ntt_form)
325
+ {
326
+ // If the input was not in NTT form, need to transform back
327
+ inverse_ntt_negacyclic_harvey (destination, coeff_modulus_size, ntt_tables);
328
+ }
291
329
292
- if (!is_ntt_form)
293
- {
294
- // If the input was not in NTT form, need to transform back
295
- inverse_ntt_negacyclic_harvey (destination, coeff_modulus_size, ntt_tables);
330
+ // Finally add c_0 to the result; note that destination should be in the same (NTT) form as encrypted
331
+ add_poly_coeffmod (destination, *iter (encrypted), coeff_modulus_size, coeff_modulus, destination);
296
332
}
297
-
298
- // Finally add c_0 to the result; note that destination should be in the same (NTT) form as encrypted
299
- add_poly_coeffmod (destination, *iter (encrypted), coeff_modulus_size, coeff_modulus, destination);
300
333
}
301
334
302
335
int Decryptor::invariant_noise_budget (const Ciphertext &encrypted)
0 commit comments