void Evaluator::relinearize(const uint64_t *encrypted, uint64_t *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); // Clear destatintion. set_zero_poly(coeff_count, coeff_uint64_count, destination); // Create polynomial to store decomposed polynomial (one at a time). Pointer decomp_poly(allocate_poly(coeff_count, coeff_uint64_count, pool_)); Pointer decomp_eval_poly(allocate_poly(coeff_count, coeff_uint64_count, pool_)); int shift = 0; for (int decomp_index = 0; decomp_index < evaluation_keys_.count(); ++decomp_index) { // Isolate decomposition_bit_count_ bits for each coefficient. for (int coeff_index = 0; coeff_index < coeff_count; ++coeff_index) { const uint64_t *productmoded_coeff = get_poly_coeff(encrypted, coeff_index, coeff_uint64_count); uint64_t *decomp_coeff = get_poly_coeff(decomp_poly.get(), coeff_index, coeff_uint64_count); right_shift_uint(productmoded_coeff, shift, coeff_uint64_count, decomp_coeff); filter_highbits_uint(decomp_coeff, coeff_uint64_count, decomposition_bit_count_); } // Multiply decomposed poly by evaluation key and accumulate to result. const BigPoly &evaluation_key = evaluation_keys_[decomp_index]; multiply_poly_poly_polymod_coeffmod(decomp_poly.get(), evaluation_key.pointer(), polymod_, mod_, decomp_eval_poly.get(), pool_); add_poly_poly_coeffmod(decomp_eval_poly.get(), destination, coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, destination); // Increase shift by decomposition_bit_count_ for next iteration. shift += decomposition_bit_count_; } }
void Evaluator::add_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_); add_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()); // Add encrypted polynomial and encrypted-version of plain2. add_poly_poly_coeffmod(encrypted1.pointer(), destination.pointer(), coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, destination.pointer()); }
void Evaluator::add(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) { add_poly_poly_coeffmod(encrypted1.pointer(), encrypted2.pointer(), coeff_count, plain_modulus_.pointer(), coeff_uint64_count, destination.pointer()); return; } // Add polynomials. add_poly_poly_coeffmod(encrypted1.pointer(), encrypted2.pointer(), coeff_count, coeff_modulus_.pointer(), coeff_uint64_count, destination.pointer()); }
void KeyGenerator::generate() { // 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); // Loop until find a valid secret key. uint64_t *secret_key = secret_key_.pointer(); set_zero_poly(coeff_count, coeff_uint64_count, secret_key); Pointer secret_key_inv(allocate_poly(coeff_count, coeff_uint64_count, pool_)); while (true) { // Create noise with random [-1, 1] coefficients. set_poly_coeffs_zero_one_negone(secret_key); // Calculate secret_key * plaintext_modulus + 1. multiply_poly_scalar_coeffmod(secret_key, coeff_count, plain_modulus_.pointer(), mod_, secret_key, pool_); uint64_t *constant_coeff = get_poly_coeff(secret_key, 0, coeff_uint64_count); increment_uint_mod(constant_coeff, coeff_modulus_.pointer(), coeff_uint64_count, constant_coeff); // Attempt to invert secret_key. if (try_invert_poly_coeffmod(secret_key, poly_modulus_.pointer(), coeff_count, mod_, secret_key_inv.get(), pool_)) { // Secret_key is invertible, so is valid break; } } // 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, 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()); } }
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()); } }