int get_significant_coeff_count_poly(const uint64_t *poly, int coeff_count, int coeff_uint64_count) { #ifdef _DEBUG if (poly == nullptr && coeff_count > 0 && coeff_uint64_count > 0) { throw invalid_argument("poly"); } if (coeff_count < 0) { throw invalid_argument("coeff_count"); } if (coeff_uint64_count < 0) { throw invalid_argument("coeff_uint64_count"); } #endif poly += coeff_count * coeff_uint64_count; for (int i = coeff_count; i > 0; --i) { poly -= coeff_uint64_count; if (!is_zero_uint(poly, coeff_uint64_count)) { return i; } } return 0; }
Modulus::Modulus(const std::uint64_t *modulus, int uint64_count, MemoryPool &pool) : modulus_(modulus), uint64_count_(uint64_count) { #ifdef SEAL_DEBUG if (modulus == nullptr) { throw invalid_argument("modulus"); } if (uint64_count <= 0) { throw invalid_argument("uint64_count"); } if (is_zero_uint(modulus, uint64_count)) { throw invalid_argument("modulus"); } #endif significant_bit_count_ = get_significant_bit_count_uint(modulus, uint64_count); power_of_two_minus_one_ = get_power_of_two_minus_one_uint(modulus, uint64_count); if (is_inverse_small(modulus, significant_bit_count_)) { // Calculate inverse modulus (clipped to modulus_bits). inverse_modulus_ = allocate_uint(uint64_count, pool); negate_uint(modulus, uint64_count, inverse_modulus_.get()); filter_highbits_uint(inverse_modulus_.get(), uint64_count, significant_bit_count_ - 1); inverse_significant_bit_count_ = get_significant_bit_count_uint(inverse_modulus_.get(), uint64_count); } }
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 exponentiate_poly(const std::uint64_t *poly, int poly_coeff_count, int poly_coeff_uint64_count, const uint64_t *exponent, int exponent_uint64_count, int result_coeff_count, int result_coeff_uint64_count, std::uint64_t *result, MemoryPool &pool) { #ifdef SEAL_DEBUG if (poly == nullptr) { throw invalid_argument("poly"); } if (poly_coeff_count <= 0) { throw invalid_argument("poly_coeff_count"); } if (poly_coeff_count <= 0) { throw invalid_argument("poly_coeff_uint64_count"); } if (exponent == nullptr) { throw invalid_argument("exponent"); } if (exponent_uint64_count <= 0) { throw invalid_argument("exponent_uint64_count"); } if (result == nullptr) { throw invalid_argument("result"); } if (result_coeff_count <= 0) { throw invalid_argument("result_coeff_count"); } if (result_coeff_uint64_count <= 0) { throw invalid_argument("result_coeff_uint64_count"); } #endif // Fast cases if (is_zero_uint(exponent, exponent_uint64_count)) { set_zero_poly(result_coeff_count, result_coeff_uint64_count, result); *result = 1; return; } if (is_equal_uint(exponent, exponent_uint64_count, 1)) { set_poly_poly(poly, poly_coeff_count, poly_coeff_uint64_count, result_coeff_count, result_coeff_uint64_count, result); return; } // Need to make a copy of exponent Pointer exponent_copy(allocate_uint(exponent_uint64_count, pool)); set_uint_uint(exponent, exponent_uint64_count, exponent_copy.get()); // Perform binary exponentiation. Pointer big_alloc(allocate_uint((static_cast<int64_t>(result_coeff_count) + result_coeff_count + result_coeff_count) * result_coeff_uint64_count, pool)); uint64_t *powerptr = big_alloc.get(); uint64_t *productptr = get_poly_coeff(powerptr, result_coeff_count, result_coeff_uint64_count); uint64_t *intermediateptr = get_poly_coeff(productptr, result_coeff_count, result_coeff_uint64_count); set_poly_poly(poly, poly_coeff_count, poly_coeff_uint64_count, result_coeff_count, result_coeff_uint64_count, powerptr); set_zero_poly(result_coeff_count, result_coeff_uint64_count, intermediateptr); *intermediateptr = 1; // Initially: power = operand and intermediate = 1, product is not initialized. while (true) { if ((*exponent_copy.get() % 2) == 1) { multiply_poly_poly(powerptr, result_coeff_count, result_coeff_uint64_count, intermediateptr, result_coeff_count, result_coeff_uint64_count, result_coeff_count, result_coeff_uint64_count, productptr, pool); swap(productptr, intermediateptr); } right_shift_uint(exponent_copy.get(), 1, exponent_uint64_count, exponent_copy.get()); if (is_zero_uint(exponent_copy.get(), exponent_uint64_count)) { break; } multiply_poly_poly(powerptr, result_coeff_count, result_coeff_uint64_count, powerptr, result_coeff_count, result_coeff_uint64_count, result_coeff_count, result_coeff_uint64_count, productptr, pool); swap(productptr, powerptr); } set_poly_poly(intermediateptr, result_coeff_count, result_coeff_uint64_count, result); }
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_); } }