From e4462eba80e8e760c5f28f6b64a6355bb10542e7 Mon Sep 17 00:00:00 2001 From: Wei Dai Date: Thu, 17 Mar 2022 01:26:05 -0700 Subject: [PATCH] Fixed an issue related to correction factors. --- README.md | 6 ++--- native/src/seal/evaluator.cpp | 51 ++++++++++++++++++----------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 12b5a31ba..019587ab3 100644 --- a/README.md +++ b/README.md @@ -103,10 +103,10 @@ Microsoft SEAL itself has a steep learning curve and requires the user to unders Even if a user is able to program and run a specific computation using Microsoft SEAL, the difference between efficient and inefficient implementations can be several orders of magnitude, and it can be hard for new users to know how to improve the performance of their computation. Microsoft SEAL comes with two different homomorphic encryption schemes with very different properties. -The BFV scheme allows modular arithmetic to be performed on encrypted integers. +The BFV and BGV schemes allow modular arithmetic to be performed on encrypted integers. The CKKS scheme allows additions and multiplications on encrypted real or complex numbers, but yields only approximate results. In applications such as summing up encrypted real numbers, evaluating machine learning models on encrypted data, or computing distances of encrypted locations CKKS is going to be by far the best choice. -For applications where exact values are necessary, the BFV scheme is the only choice. +For applications where exact values are necessary, the BFV and BGV schemes are more suitable. ## Getting Started @@ -216,7 +216,7 @@ EVA allows programmers to express desired encrypted computations in Python. It o EVA is available at [GitHub.com/Microsoft/EVA](https://GitHub.com/Microsoft/EVA). Try it out, and let us know what you think! -**Note:** EVA only supports the CKKS scheme. There are no immediate plans to support the BFV scheme. +**Note:** EVA only supports the CKKS scheme. There are no immediate plans to support the BFV or BGV scheme. ## Building Microsoft SEAL Manually diff --git a/native/src/seal/evaluator.cpp b/native/src/seal/evaluator.cpp index f26b556b8..93768bee3 100644 --- a/native/src/seal/evaluator.cpp +++ b/native/src/seal/evaluator.cpp @@ -194,18 +194,15 @@ namespace seal throw logic_error("invalid parameters"); } - // Prepare destination - encrypted1.resize(context_, context_data.parms_id(), max_count); - if (encrypted1.correction_factor() != encrypted2.correction_factor()) { // Balance correction factors and multiply by scalars before addition in BGV auto factors = balance_correction_factors( encrypted1.correction_factor(), encrypted2.correction_factor(), plain_modulus); - multiply_poly_scalar_coeffmod( ConstPolyIter(encrypted1.data(), coeff_count, coeff_modulus_size), encrypted1.size(), get<1>(factors), coeff_modulus, PolyIter(encrypted1.data(), coeff_count, coeff_modulus_size)); + Ciphertext encrypted2_copy = encrypted2; multiply_poly_scalar_coeffmod( ConstPolyIter(encrypted2.data(), coeff_count, coeff_modulus_size), encrypted2.size(), get<2>(factors), @@ -213,23 +210,26 @@ namespace seal // Set new correction factor encrypted1.correction_factor() = get<0>(factors); + encrypted2_copy.correction_factor() = get<0>(factors); - // Add ciphertexts - add_poly_coeffmod(encrypted1, encrypted2_copy, min_count, coeff_modulus, encrypted1); + add_inplace(encrypted1, encrypted2_copy); } else { + // Prepare destination + encrypted1.resize(context_, context_data.parms_id(), max_count); // Add ciphertexts add_poly_coeffmod(encrypted1, encrypted2, min_count, coeff_modulus, encrypted1); - } - // Copy the remainding polys of the array with larger count into encrypted1 - if (encrypted1_size < encrypted2_size) - { - set_poly_array( - encrypted2.data(min_count), encrypted2_size - encrypted1_size, coeff_count, coeff_modulus_size, - encrypted1.data(encrypted1_size)); + // Copy the remainding polys of the array with larger count into encrypted1 + if (encrypted1_size < encrypted2_size) + { + set_poly_array( + encrypted2.data(min_count), encrypted2_size - encrypted1_size, coeff_count, coeff_modulus_size, + encrypted1.data(encrypted1_size)); + } } + #ifdef SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT // Transparent ciphertext output is not allowed. if (encrypted1.is_transparent()) @@ -302,9 +302,6 @@ namespace seal throw logic_error("invalid parameters"); } - // Prepare destination - encrypted1.resize(context_, context_data.parms_id(), max_count); - if (encrypted1.correction_factor() != encrypted2.correction_factor()) { // Balance correction factors and multiply by scalars before subtraction in BGV @@ -314,6 +311,7 @@ namespace seal multiply_poly_scalar_coeffmod( ConstPolyIter(encrypted1.data(), coeff_count, coeff_modulus_size), encrypted1.size(), get<1>(factors), coeff_modulus, PolyIter(encrypted1.data(), coeff_count, coeff_modulus_size)); + Ciphertext encrypted2_copy = encrypted2; multiply_poly_scalar_coeffmod( ConstPolyIter(encrypted2.data(), coeff_count, coeff_modulus_size), encrypted2.size(), get<2>(factors), @@ -321,22 +319,27 @@ namespace seal // Set new correction factor encrypted1.correction_factor() = get<0>(factors); + encrypted2_copy.correction_factor() = get<0>(factors); - // Subtract ciphertexts - sub_poly_coeffmod(encrypted1, encrypted2_copy, min_count, coeff_modulus, encrypted1); + sub_inplace(encrypted1, encrypted2_copy); } else { + // Prepare destination + encrypted1.resize(context_, context_data.parms_id(), max_count); + // Subtract ciphertexts sub_poly_coeffmod(encrypted1, encrypted2, min_count, coeff_modulus, encrypted1); - } - // If encrypted2 has larger count, negate remaining entries - if (encrypted1_size < encrypted2_size) - { - negate_poly_coeffmod( - iter(encrypted2) + min_count, encrypted2_size - min_count, coeff_modulus, iter(encrypted1) + min_count); + // If encrypted2 has larger count, negate remaining entries + if (encrypted1_size < encrypted2_size) + { + negate_poly_coeffmod( + iter(encrypted2) + min_count, encrypted2_size - min_count, coeff_modulus, + iter(encrypted1) + min_count); + } } + #ifdef SEAL_THROW_ON_TRANSPARENT_CIPHERTEXT // Transparent ciphertext output is not allowed. if (encrypted1.is_transparent())