void poly_eval_poly(const BigPoly &poly_to_evaluate, const BigPoly &poly_to_evaluate_at, BigPoly &destination, const MemoryPoolHandle &pool) { if (!pool) { throw invalid_argument("pool is uninitialized"); } int poly_to_eval_coeff_uint64_count = divide_round_up(poly_to_evaluate.coeff_bit_count(), bits_per_uint64); int value_coeff_uint64_count = divide_round_up(poly_to_evaluate_at.coeff_bit_count(), bits_per_uint64); if (poly_to_evaluate.is_zero()) { destination.set_zero(); return; } if (poly_to_evaluate_at.is_zero()) { destination.resize(1, poly_to_evaluate.coeff_bit_count()); set_uint_uint(poly_to_evaluate.data(), poly_to_eval_coeff_uint64_count, destination.data()); return; } int result_coeff_count = (poly_to_evaluate.significant_coeff_count() - 1) * (poly_to_evaluate_at.significant_coeff_count() - 1) + 1; int result_coeff_bit_count = poly_to_evaluate.coeff_bit_count() + (poly_to_evaluate.coeff_count() - 1) * poly_to_evaluate_at.coeff_bit_count(); int result_coeff_uint64_count = divide_round_up(result_coeff_bit_count, bits_per_uint64); destination.resize(result_coeff_count, result_coeff_bit_count); util::poly_eval_poly(poly_to_evaluate.data(), poly_to_evaluate.coeff_count(), poly_to_eval_coeff_uint64_count, poly_to_evaluate_at.data(), poly_to_evaluate_at.coeff_count(), value_coeff_uint64_count, result_coeff_count, result_coeff_uint64_count, destination.data(), pool); }
BigUInt poly_infty_norm_coeffmod(const BigPoly &poly, const BigUInt &modulus, const MemoryPoolHandle &pool) { if (modulus.is_zero()) { throw invalid_argument("modulus cannot be zero"); } if (!pool) { throw invalid_argument("pool is uninitialized"); } if (poly.is_zero()) { return BigUInt(); } int poly_coeff_count = poly.coeff_count(); int poly_coeff_bit_count = poly.coeff_bit_count(); int poly_coeff_uint64_count = divide_round_up(poly_coeff_bit_count, bits_per_uint64); Modulus mod(modulus.data(), modulus.uint64_count(), pool); BigUInt result(modulus.significant_bit_count()); util::poly_infty_norm_coeffmod(poly.data(), poly_coeff_count, poly_coeff_uint64_count, mod, result.data(), pool); return result; }
void poly_eval_poly_polymod_coeffmod(const BigPoly &poly_to_evaluate, const BigPoly &poly_to_evaluate_at, const BigPoly &poly_modulus, const BigUInt &coeff_modulus, BigPoly &destination, const MemoryPoolHandle &pool) { if (!pool) { throw invalid_argument("pool is uninitialized"); } if (poly_to_evaluate.significant_coeff_count() > poly_modulus.coeff_count() || poly_to_evaluate.significant_coeff_bit_count() > coeff_modulus.significant_bit_count()) { throw invalid_argument("poly_to_evaluate is not reduced"); } if (poly_to_evaluate_at.significant_coeff_count() > poly_modulus.coeff_count() || poly_to_evaluate_at.significant_coeff_bit_count() > coeff_modulus.significant_bit_count()) { throw invalid_argument("poly_to_evaluate_at is not reduced"); } int poly_to_eval_coeff_uint64_count = poly_to_evaluate.coeff_uint64_count(); int coeff_modulus_bit_count = coeff_modulus.significant_bit_count(); if (poly_to_evaluate.is_zero()) { destination.set_zero(); } if (poly_to_evaluate_at.is_zero()) { destination.resize(1, coeff_modulus_bit_count); modulo_uint(poly_to_evaluate.data(), poly_to_eval_coeff_uint64_count, Modulus(coeff_modulus.data(), coeff_modulus.uint64_count(), pool), destination.data(), pool); return; } ConstPointer poly_to_eval_ptr = duplicate_poly_if_needed(poly_to_evaluate, poly_modulus.coeff_count(), coeff_modulus.uint64_count(), false, pool); ConstPointer poly_to_eval_at_ptr = duplicate_poly_if_needed(poly_to_evaluate_at, poly_modulus.coeff_count(), coeff_modulus.uint64_count(), false, pool); destination.resize(poly_modulus.coeff_count(), coeff_modulus_bit_count); util::poly_eval_poly_polymod_coeffmod(poly_to_eval_ptr.get(), poly_to_eval_at_ptr.get(), PolyModulus(poly_modulus.data(), poly_modulus.coeff_count(), poly_modulus.coeff_uint64_count()), Modulus(coeff_modulus.data(), coeff_modulus.uint64_count(), pool), destination.data(), pool); }
void exponentiate_poly_polymod_coeffmod(const BigPoly &operand, const BigUInt &exponent, const BigPoly &poly_modulus, const BigUInt &coeff_modulus, BigPoly &destination, const MemoryPoolHandle &pool) { if (operand.significant_coeff_count() > poly_modulus.coeff_count() || operand.significant_coeff_bit_count() > coeff_modulus.significant_bit_count()) { throw invalid_argument("operand is not reduced"); } if (exponent < 0) { throw invalid_argument("exponent must be a non-negative integer"); } if (operand.is_zero() && exponent == 0) { throw invalid_argument("undefined operation"); } if (!pool) { throw invalid_argument("pool is uninitialized"); } if (operand.is_zero()) { destination.set_zero(); return; } if (destination.coeff_bit_count() != coeff_modulus.significant_bit_count() || destination.coeff_count() != poly_modulus.coeff_count()) { destination.resize(poly_modulus.coeff_count(), coeff_modulus.significant_bit_count()); } ConstPointer operand_ptr = duplicate_poly_if_needed(operand, poly_modulus.coeff_count(), coeff_modulus.uint64_count(), false, pool); util::exponentiate_poly_polymod_coeffmod(operand_ptr.get(), exponent.data(), exponent.uint64_count(), PolyModulus(poly_modulus.data(), poly_modulus.coeff_count(), poly_modulus.coeff_uint64_count()), Modulus(coeff_modulus.data(), coeff_modulus.uint64_count(), pool), destination.data(), pool); }
BigUInt poly_infty_norm(const BigPoly &poly) { if (poly.is_zero()) { return BigUInt(); } int coeff_count = poly.coeff_count(); int coeff_bit_count = poly.coeff_bit_count(); int coeff_uint64_count = divide_round_up(coeff_bit_count, bits_per_uint64); BigUInt result(coeff_bit_count); util::poly_infty_norm(poly.data(), coeff_count, coeff_uint64_count, result.data()); return result; }
void poly_eval_uint_mod(const BigPoly &poly_to_evaluate, const BigUInt &value, const BigUInt &modulus, BigUInt &destination, const MemoryPoolHandle &pool) { if (poly_to_evaluate.significant_coeff_bit_count() > modulus.significant_bit_count()) { throw invalid_argument("poly_to_evaluate is not reduced"); } if (value.significant_bit_count() > modulus.significant_bit_count()) { throw invalid_argument("value is not reduced"); } if (!pool) { throw invalid_argument("pool is uninitialized"); } int poly_to_eval_coeff_uint64_count = poly_to_evaluate.coeff_uint64_count(); int modulus_bit_count = modulus.significant_bit_count(); if (poly_to_evaluate.is_zero()) { destination.set_zero(); } if (value.is_zero()) { destination.resize(modulus_bit_count); modulo_uint(poly_to_evaluate.data(), poly_to_eval_coeff_uint64_count, Modulus(modulus.data(), modulus.uint64_count(), pool), destination.data(), pool); return; } ConstPointer value_ptr = duplicate_uint_if_needed(value, modulus.uint64_count(), false, pool); destination.resize(modulus_bit_count); util::poly_eval_uint_mod(poly_to_evaluate.data(), poly_to_evaluate.coeff_count(), value_ptr.get(), Modulus(modulus.data(), modulus.uint64_count(), pool), destination.data(), 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()); } }