void Evaluator::negate(const BigPoly &encrypted, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted.coeff_count() != coeff_count || encrypted.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted, coeff_modulus_)) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #endif if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } // Handle test-mode case. if (mode_ == TEST_MODE) { negate_poly_coeffmod(encrypted.pointer(), coeff_count, plain_modulus_.pointer(), coeff_uint64_count, destination.pointer()); return; } // Negate polynomial. negate_poly_coeffmod(encrypted.pointer(), coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, destination.pointer()); }
void Evaluator::multiply(const BigPoly &encrypted1, const BigPoly &encrypted2, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted1.coeff_count() != coeff_count || encrypted1.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } if (encrypted2.coeff_count() != coeff_count || encrypted2.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted2 is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted1.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted1, coeff_modulus_)) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } if (encrypted2.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted2, coeff_modulus_)) { throw invalid_argument("encrypted2 is not valid for encryption parameters"); } #endif if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } // Handle test-mode case. if (mode_ == TEST_MODE) { // Get pointer to inputs (duplicated if needed). ConstPointer encrypted1ptr = duplicate_poly_if_needed(encrypted1, encrypted1.pointer() == destination.pointer(), pool_); ConstPointer encrypted2ptr = duplicate_poly_if_needed(encrypted2, encrypted2.pointer() == destination.pointer(), pool_); multiply_poly_poly_polymod_coeffmod(encrypted1ptr.get(), encrypted2ptr.get(), polymod_, mod_, destination.pointer(), pool_); return; } // Multiply encrypted polynomials and perform key switching. Pointer product(allocate_poly(coeff_count, coeff_uint64_count, pool_)); multiply(encrypted1.pointer(), encrypted2.pointer(), product.get()); relinearize(product.get(), destination.pointer()); }
void Evaluator::sub_plain(const BigPoly &encrypted1, const BigPoly &plain2, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted1.coeff_count() != coeff_count || encrypted1.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted1.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted1, coeff_modulus_)) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } if (plain2.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain2, plain_modulus_)) { throw invalid_argument("plain2 is too large to be represented by encryption parameters"); } #endif if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } int plain2_coeff_uint64_count = divide_round_up(plain2.coeff_bit_count(), bits_per_uint64); if (mode_ == TEST_MODE) { // Handle test-mode case. set_poly_poly(plain2.pointer(), plain2.coeff_count(), plain2_coeff_uint64_count, coeff_count, coeff_uint64_count, destination.pointer()); modulo_poly_coeffs(destination.pointer(), coeff_count, mod_, pool_); sub_poly_poly_coeffmod(encrypted1.pointer(), destination.pointer(), coeff_count, plain_modulus_.pointer(), coeff_uint64_count, destination.pointer()); return; } // Multiply plain by scalar coeff_div_plaintext and reposition if in upper-half. preencrypt(plain2.pointer(), plain2.coeff_count(), plain2_coeff_uint64_count, destination.pointer()); // Subtract encrypted polynomial and encrypted-version of plain2. sub_poly_poly_coeffmod(encrypted1.pointer(), destination.pointer(), coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, destination.pointer()); }
void Evaluator::exponentiate_norelin(const BigPoly &encrypted, int exponent, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted.coeff_count() != coeff_count || encrypted.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted, coeff_modulus_)) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #endif if (exponent < 0) { throw invalid_argument("exponent must be non-negative"); } if (exponent == 0) { if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } set_uint_uint(coeff_div_plain_modulus_.pointer(), coeff_uint64_count, destination.pointer()); return; } if (exponent == 1) { encrypted.duplicate_to(destination); return; } vector<BigPoly> exp_vector(exponent, encrypted); multiply_norelin_many(exp_vector, destination); // Binary exponentiation /* if (exponent % 2 == 0) { exponentiate_norelin(multiply_norelin(encrypted, encrypted), exponent >> 1, destination); return; } multiply_norelin(exponentiate_norelin(multiply_norelin(encrypted, encrypted), (exponent - 1) >> 1), encrypted, destination); */ }
BigPoly Evaluator::multiply_norelin_many(vector<BigPoly> encrypteds) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); vector<BigPoly>::size_type original_size = encrypteds.size(); // Verify parameters. if (original_size == 0) { throw invalid_argument("encrypteds vector must not be empty"); } for (vector<BigPoly>::size_type i = 0; i < original_size; ++i) { if (encrypteds[i].coeff_count() != coeff_count || encrypteds[i].coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypteds is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypteds[i].significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypteds[i], coeff_modulus_)) { throw invalid_argument("encrypteds is not valid for encryption parameters"); } #endif } if (original_size == 1) { return encrypteds[0]; } // Repeatedly multiply and add to the back of the vector until the end is reached for (vector<BigPoly>::size_type i = 0; i < encrypteds.size() - 1; i += 2) { encrypteds.push_back(multiply_norelin(encrypteds[i], encrypteds[i + 1])); } return encrypteds[encrypteds.size() - 1]; }
void Evaluator::relinearize(const BigPoly &encrypted, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted.coeff_count() != coeff_count || encrypted.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted, coeff_modulus_)) { throw invalid_argument("encrypted is not valid for encryption parameters"); } #endif if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } // Handle test-mode case. if (mode_ == TEST_MODE) { set_poly_poly(encrypted.pointer(), coeff_count, coeff_uint64_count, destination.pointer()); return; } // Get pointer to inputs (duplicated if needed). ConstPointer encryptedptr = duplicate_poly_if_needed(encrypted, encrypted.pointer() == destination.pointer(), pool_); // Relinearize polynomial. relinearize(encryptedptr.get(), destination.pointer()); }
KeyGenerator::KeyGenerator(const EncryptionParameters &parms) : poly_modulus_(parms.poly_modulus()), coeff_modulus_(parms.coeff_modulus()), plain_modulus_(parms.plain_modulus()), noise_standard_deviation_(parms.noise_standard_deviation()), noise_max_deviation_(parms.noise_max_deviation()), decomposition_bit_count_(parms.decomposition_bit_count()), mode_(parms.mode()), random_generator_(parms.random_generator() != nullptr ? parms.random_generator()->create() : UniformRandomGeneratorFactory::default_factory()->create()) { // Verify required parameters are non-zero and non-nullptr. if (poly_modulus_.is_zero()) { throw invalid_argument("poly_modulus cannot be zero"); } if (coeff_modulus_.is_zero()) { throw invalid_argument("coeff_modulus cannot be zero"); } if (plain_modulus_.is_zero()) { throw invalid_argument("plain_modulus cannot be zero"); } if (noise_standard_deviation_ < 0) { throw invalid_argument("noise_standard_deviation must be non-negative"); } if (noise_max_deviation_ < 0) { throw invalid_argument("noise_max_deviation must be non-negative"); } if (decomposition_bit_count_ <= 0) { throw invalid_argument("decomposition_bit_count must be positive"); } // Verify parameters. if (plain_modulus_ >= coeff_modulus_) { throw invalid_argument("plain_modulus must be smaller than coeff_modulus"); } if (!are_poly_coefficients_less_than(poly_modulus_, coeff_modulus_)) { throw invalid_argument("poly_modulus cannot have coefficients larger than coeff_modulus"); } // Resize encryption parameters to consistent size. int coeff_count = poly_modulus_.significant_coeff_count(); int coeff_bit_count = coeff_modulus_.significant_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); if (poly_modulus_.coeff_count() != coeff_count || poly_modulus_.coeff_bit_count() != coeff_bit_count) { poly_modulus_.resize(coeff_count, coeff_bit_count); } if (coeff_modulus_.bit_count() != coeff_bit_count) { coeff_modulus_.resize(coeff_bit_count); } if (plain_modulus_.bit_count() != coeff_bit_count) { plain_modulus_.resize(coeff_bit_count); } if (decomposition_bit_count_ > coeff_bit_count) { decomposition_bit_count_ = coeff_bit_count; } // Calculate -1 (mod coeff_modulus). coeff_modulus_minus_one_.resize(coeff_bit_count); decrement_uint(coeff_modulus_.pointer(), coeff_uint64_count, coeff_modulus_minus_one_.pointer()); // Initialize public and secret key. public_key_.resize(coeff_count, coeff_bit_count); secret_key_.resize(coeff_count, coeff_bit_count); // Initialize evaluation keys. int evaluation_key_count = 0; Pointer evaluation_factor(allocate_uint(coeff_uint64_count, pool_)); set_uint(1, coeff_uint64_count, evaluation_factor.get()); while (!is_zero_uint(evaluation_factor.get(), coeff_uint64_count) && is_less_than_uint_uint(evaluation_factor.get(), coeff_modulus_.pointer(), coeff_uint64_count)) { left_shift_uint(evaluation_factor.get(), decomposition_bit_count_, coeff_uint64_count, evaluation_factor.get()); evaluation_key_count++; } evaluation_keys_.resize(evaluation_key_count); for (int i = 0; i < evaluation_key_count; ++i) { evaluation_keys_[i].resize(coeff_count, coeff_bit_count); } // Initialize moduli. polymod_ = PolyModulus(poly_modulus_.pointer(), coeff_count, coeff_uint64_count); mod_ = Modulus(coeff_modulus_.pointer(), coeff_uint64_count, pool_); }
void KeyGenerator::generate(const BigPoly &secret_key, uint64_t power) { // Validate arguments. if (secret_key.is_zero()) { throw invalid_argument("secret_key cannot be zero"); } if (power == 0) { throw invalid_argument("power cannot be zero"); } // Handle test-mode case. if (mode_ == TEST_MODE) { public_key_.set_zero(); public_key_[0] = 1; secret_key_.set_zero(); secret_key_[0] = 1; for (int i = 0; i < evaluation_keys_.count(); ++i) { evaluation_keys_[i].set_zero(); evaluation_keys_[i][0] = 1; } return; } // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify secret key looks valid. secret_key_ = secret_key; if (secret_key_.coeff_count() != coeff_count || secret_key_.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("secret_key is not valid for encryption parameters"); } #ifdef _DEBUG if (secret_key_.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(secret_key_, coeff_modulus_)) { throw invalid_argument("secret_key is not valid for encryption parameters"); } #endif // Raise level of secret key. if (power > 1) { exponentiate_poly_polymod_coeffmod(secret_key_.pointer(), &power, 1, polymod_, mod_, secret_key_.pointer(), pool_); } // Attempt to invert secret_key. Pointer secret_key_inv(allocate_poly(coeff_count, coeff_uint64_count, pool_)); if (!try_invert_poly_coeffmod(secret_key_.pointer(), poly_modulus_.pointer(), coeff_count, mod_, secret_key_inv.get(), pool_)) { // Secret_key is not invertible, so not valid. throw invalid_argument("secret_key is not valid for encryption parameters"); } // Calculate plaintext_modulus * noise * secret_key_inv. Pointer noise(allocate_poly(coeff_count, coeff_uint64_count, pool_)); set_poly_coeffs_zero_one_negone(noise.get()); uint64_t *public_key = public_key_.pointer(); multiply_poly_poly_polymod_coeffmod(noise.get(), secret_key_inv.get(), polymod_, mod_, noise.get(), pool_); multiply_poly_scalar_coeffmod(noise.get(), coeff_count, plain_modulus_.pointer(), mod_, public_key, pool_); // Create evaluation keys. Pointer evaluation_factor(allocate_uint(coeff_uint64_count, pool_)); set_uint(1, coeff_uint64_count, evaluation_factor.get()); for (int i = 0; i < evaluation_keys_.count(); ++i) { // Multiply secret_key by evaluation_factor (mod coeff modulus). uint64_t *evaluation_key = evaluation_keys_[i].pointer(); multiply_poly_scalar_coeffmod(secret_key_.pointer(), coeff_count, evaluation_factor.get(), mod_, evaluation_key, pool_); // Multiply public_key*normal noise and add into evaluation_key. set_poly_coeffs_normal(noise.get()); multiply_poly_poly_polymod_coeffmod(noise.get(), public_key, polymod_, mod_, noise.get(), pool_); add_poly_poly_coeffmod(noise.get(), evaluation_key, coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, evaluation_key); // Add-in more normal noise to evaluation_key. set_poly_coeffs_normal(noise.get()); add_poly_poly_coeffmod(noise.get(), evaluation_key, coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, evaluation_key); // Left shift evaluation factor. left_shift_uint(evaluation_factor.get(), decomposition_bit_count_, coeff_uint64_count, evaluation_factor.get()); } }
HkeyGen::HkeyGen(const EncryptionParameters &parms, const BigPoly &secret_key) : poly_modulus_(parms.poly_modulus()), coeff_modulus_(parms.coeff_modulus()), plain_modulus_(parms.plain_modulus()), secret_key_(secret_key), orig_plain_modulus_bit_count_(parms.plain_modulus().significant_bit_count()) { // Verify required parameters are non-zero and non-nullptr. if (poly_modulus_.is_zero()) { throw invalid_argument("poly_modulus cannot be zero"); } if (coeff_modulus_.is_zero()) { throw invalid_argument("coeff_modulus cannot be zero"); } if (plain_modulus_.is_zero()) { throw invalid_argument("plain_modulus cannot be zero"); } if (secret_key_.is_zero()) { throw invalid_argument("secret_key cannot be zero"); } // Verify parameters. if (plain_modulus_ >= coeff_modulus_) { throw invalid_argument("plain_modulus must be smaller than coeff_modulus"); } if (!are_poly_coefficients_less_than(poly_modulus_, coeff_modulus_)) { throw invalid_argument("poly_modulus cannot have coefficients larger than coeff_modulus"); } // Resize encryption parameters to consistent size. int coeff_count = poly_modulus_.significant_coeff_count(); int coeff_bit_count = coeff_modulus_.significant_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); if (poly_modulus_.coeff_count() != coeff_count || poly_modulus_.coeff_bit_count() != coeff_bit_count) { poly_modulus_.resize(coeff_count, coeff_bit_count); } if (coeff_modulus_.bit_count() != coeff_bit_count) { coeff_modulus_.resize(coeff_bit_count); } if (plain_modulus_.bit_count() != coeff_bit_count) { plain_modulus_.resize(coeff_bit_count); } if (secret_key_.coeff_count() != coeff_count || secret_key_.coeff_bit_count() != coeff_bit_count || secret_key_.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(secret_key_, coeff_modulus_)) { throw invalid_argument("secret_key is not valid for encryption parameters"); } // Set the secret_key_array to have size 1 (first power of secret) secret_key_array_.resize(1, coeff_count, coeff_bit_count); set_poly_poly(secret_key_.pointer(), coeff_count, coeff_uint64_count, secret_key_array_.pointer(0)); MemoryPool &pool = *MemoryPool::default_pool(); // Calculate coeff_modulus / plain_modulus. coeff_div_plain_modulus_.resize(coeff_bit_count); Pointer temp(allocate_uint(coeff_uint64_count, pool)); divide_uint_uint(coeff_modulus_.pointer(), plain_modulus_.pointer(), coeff_uint64_count, coeff_div_plain_modulus_.pointer(), temp.get(), pool); // Calculate coeff_modulus / plain_modulus / 2. coeff_div_plain_modulus_div_two_.resize(coeff_bit_count); right_shift_uint(coeff_div_plain_modulus_.pointer(), 1, coeff_uint64_count, coeff_div_plain_modulus_div_two_.pointer()); // Calculate coeff_modulus / 2. upper_half_threshold_.resize(coeff_bit_count); half_round_up_uint(coeff_modulus_.pointer(), coeff_uint64_count, upper_half_threshold_.pointer()); // Calculate upper_half_increment. upper_half_increment_.resize(coeff_bit_count); multiply_truncate_uint_uint(plain_modulus_.pointer(), coeff_div_plain_modulus_.pointer(), coeff_uint64_count, upper_half_increment_.pointer()); sub_uint_uint(coeff_modulus_.pointer(), upper_half_increment_.pointer(), coeff_uint64_count, upper_half_increment_.pointer()); // Initialize moduli. polymod_ = PolyModulus(poly_modulus_.pointer(), coeff_count, coeff_uint64_count); mod_ = Modulus(coeff_modulus_.pointer(), coeff_uint64_count, pool); }
Evaluator::Evaluator(const EncryptionParameters &parms, const EvaluationKeys &evaluation_keys) : poly_modulus_(parms.poly_modulus()), coeff_modulus_(parms.coeff_modulus()), plain_modulus_(parms.plain_modulus()), decomposition_bit_count_(parms.decomposition_bit_count()), evaluation_keys_(evaluation_keys), mode_(parms.mode()) { // Verify required parameters are non-zero and non-nullptr. if (poly_modulus_.is_zero()) { throw invalid_argument("poly_modulus cannot be zero"); } if (coeff_modulus_.is_zero()) { throw invalid_argument("coeff_modulus cannot be zero"); } if (plain_modulus_.is_zero()) { throw invalid_argument("plain_modulus cannot be zero"); } if (decomposition_bit_count_ <= 0) { throw invalid_argument("decomposition_bit_count must be positive"); } if (evaluation_keys_.count() == 0) { throw invalid_argument("evaluation_keys cannot be empty"); } // Verify parameters. if (plain_modulus_ >= coeff_modulus_) { throw invalid_argument("plain_modulus must be smaller than coeff_modulus"); } if (!are_poly_coefficients_less_than(poly_modulus_, coeff_modulus_)) { throw invalid_argument("poly_modulus cannot have coefficients larger than coeff_modulus"); } // Resize encryption parameters to consistent size. int coeff_count = poly_modulus_.significant_coeff_count(); int coeff_bit_count = coeff_modulus_.significant_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); if (poly_modulus_.coeff_count() != coeff_count || poly_modulus_.coeff_bit_count() != coeff_bit_count) { poly_modulus_.resize(coeff_count, coeff_bit_count); } if (coeff_modulus_.bit_count() != coeff_bit_count) { coeff_modulus_.resize(coeff_bit_count); } if (plain_modulus_.bit_count() != coeff_bit_count) { plain_modulus_.resize(coeff_bit_count); } if (decomposition_bit_count_ > coeff_bit_count) { decomposition_bit_count_ = coeff_bit_count; } // Determine correct number of evaluation keys. int evaluation_key_count = 0; Pointer evaluation_factor(allocate_uint(coeff_uint64_count, pool_)); set_uint(1, coeff_uint64_count, evaluation_factor.get()); while (!is_zero_uint(evaluation_factor.get(), coeff_uint64_count) && is_less_than_uint_uint(evaluation_factor.get(), coeff_modulus_.pointer(), coeff_uint64_count)) { left_shift_uint(evaluation_factor.get(), decomposition_bit_count_, coeff_uint64_count, evaluation_factor.get()); evaluation_key_count++; } // Verify evaluation keys. if (evaluation_keys_.count() != evaluation_key_count) { throw invalid_argument("evaluation_keys is not valid for encryption parameters"); } for (int i = 0; i < evaluation_keys_.count(); ++i) { BigPoly &evaluation_key = evaluation_keys_[i]; if (evaluation_key.coeff_count() != coeff_count || evaluation_key.coeff_bit_count() != coeff_bit_count || evaluation_key.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(evaluation_key, coeff_modulus_)) { throw invalid_argument("evaluation_keys is not valid for encryption parameters"); } } // Calculate coeff_modulus / plain_modulus. coeff_div_plain_modulus_.resize(coeff_bit_count); Pointer temp(allocate_uint(coeff_uint64_count, pool_)); divide_uint_uint(coeff_modulus_.pointer(), plain_modulus_.pointer(), coeff_uint64_count, coeff_div_plain_modulus_.pointer(), temp.get(), pool_); // Calculate (plain_modulus + 1) / 2. plain_upper_half_threshold_.resize(coeff_bit_count); half_round_up_uint(plain_modulus_.pointer(), coeff_uint64_count, plain_upper_half_threshold_.pointer()); // Calculate coeff_modulus - plain_modulus. plain_upper_half_increment_.resize(coeff_bit_count); sub_uint_uint(coeff_modulus_.pointer(), plain_modulus_.pointer(), coeff_uint64_count, plain_upper_half_increment_.pointer()); // Calculate (plain_modulus + 1) / 2 * coeff_div_plain_modulus. upper_half_threshold_.resize(coeff_bit_count); multiply_truncate_uint_uint(plain_upper_half_threshold_.pointer(), coeff_div_plain_modulus_.pointer(), coeff_uint64_count, upper_half_threshold_.pointer()); // Calculate upper_half_increment. upper_half_increment_.resize(coeff_bit_count); multiply_truncate_uint_uint(plain_modulus_.pointer(), coeff_div_plain_modulus_.pointer(), coeff_uint64_count, upper_half_increment_.pointer()); sub_uint_uint(coeff_modulus_.pointer(), upper_half_increment_.pointer(), coeff_uint64_count, upper_half_increment_.pointer()); // Widen coeff modulus. int product_coeff_bit_count = coeff_bit_count + coeff_bit_count + get_significant_bit_count(static_cast<uint64_t>(coeff_count)); int plain_modulus_bit_count = plain_modulus_.significant_bit_count(); int wide_bit_count = product_coeff_bit_count + plain_modulus_bit_count; int wide_uint64_count = divide_round_up(wide_bit_count, bits_per_uint64); wide_coeff_modulus_.resize(wide_bit_count); wide_coeff_modulus_ = coeff_modulus_; // Calculate wide_coeff_modulus_ / 2. wide_coeff_modulus_div_two_.resize(wide_bit_count); right_shift_uint(wide_coeff_modulus_.pointer(), 1, wide_uint64_count, wide_coeff_modulus_div_two_.pointer()); // Initialize moduli. polymod_ = PolyModulus(poly_modulus_.pointer(), coeff_count, coeff_uint64_count); if (mode_ == TEST_MODE) { mod_ = Modulus(plain_modulus_.pointer(), coeff_uint64_count, pool_); } else { mod_ = Modulus(coeff_modulus_.pointer(), coeff_uint64_count, pool_); } }
void Evaluator::multiply_plain(const BigPoly &encrypted1, const BigPoly &plain2, BigPoly &destination) { // Extract encryption parameters. int coeff_count = poly_modulus_.coeff_count(); int coeff_bit_count = poly_modulus_.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); // Verify parameters. if (encrypted1.coeff_count() != coeff_count || encrypted1.coeff_bit_count() != coeff_bit_count) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } #ifdef _DEBUG if (encrypted1.significant_coeff_count() == coeff_count || !are_poly_coefficients_less_than(encrypted1, coeff_modulus_)) { throw invalid_argument("encrypted1 is not valid for encryption parameters"); } if (plain2.significant_coeff_count() >= coeff_count || !are_poly_coefficients_less_than(plain2, plain_modulus_)) { throw invalid_argument("plain2 is too large to be represented by encryption parameters"); } #endif if (destination.coeff_count() != coeff_count || destination.coeff_bit_count() != coeff_bit_count) { destination.resize(coeff_count, coeff_bit_count); } // Get pointer to inputs (duplicated if needed). ConstPointer encrypted1ptr = duplicate_poly_if_needed(encrypted1, encrypted1.pointer() == destination.pointer(), pool_); // Handle test-mode case. if (mode_ == TEST_MODE) { // Get pointer to inputs (duplicated and resized if needed). ConstPointer plain2ptr = duplicate_poly_if_needed(plain2, coeff_count, coeff_uint64_count, plain2.pointer() == destination.pointer(), pool_); // Resize second operand if needed. multiply_poly_poly_polymod_coeffmod(encrypted1ptr.get(), plain2ptr.get(), polymod_, mod_, destination.pointer(), pool_); return; } // Reposition coefficients. Pointer moved2ptr(allocate_poly(coeff_count, coeff_uint64_count, pool_)); int plain_coeff_count = min(plain2.significant_coeff_count(), coeff_count); int plain2_coeff_uint64_count = plain2.coeff_uint64_count(); const uint64_t *plain2_coeff = plain2.pointer(); uint64_t *moved2_coeff = moved2ptr.get(); for (int i = 0; i < plain_coeff_count; ++i) { set_uint_uint(plain2_coeff, plain2_coeff_uint64_count, coeff_uint64_count, moved2_coeff); bool is_upper_half = is_greater_than_or_equal_uint_uint(moved2_coeff, plain_upper_half_threshold_.pointer(), coeff_uint64_count); if (is_upper_half) { add_uint_uint(moved2_coeff, plain_upper_half_increment_.pointer(), coeff_uint64_count, moved2_coeff); } moved2_coeff += coeff_uint64_count; plain2_coeff += plain2_coeff_uint64_count; } for (int i = plain_coeff_count; i < coeff_count; ++i) { set_zero_uint(coeff_uint64_count, moved2_coeff); moved2_coeff += coeff_uint64_count; } // Use normal polynomial multiplication. multiply_poly_poly_polymod_coeffmod(encrypted1ptr.get(), moved2ptr.get(), polymod_, mod_, destination.pointer(), pool_); }