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); }
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 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 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); */ }
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); }
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()); }
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_); }