def test_multiply_01(self): poly1 = Polynomial(4, sample_uniform(0, 30, 4)) poly2 = Polynomial(4, sample_uniform(0, 30, 4)) poly_prod = poly1.multiply_fft(poly2) poly_prod2 = poly1.multiply_naive(poly2) self.assertEqual(poly_prod.coeffs, poly_prod2.coeffs)
def test_multiply_time(self): self.params.print_parameters() num_iterations = 1 print("Number of multiplications: %d" % (num_iterations)) total_time = 0 for _ in range(num_iterations): vec1 = sample_uniform(0, self.plain_modulus, self.degree) vec2 = sample_uniform(0, self.plain_modulus, self.degree) total_time += self.run_test_multiply(vec1, vec2) print("Average time per multiply operation: %f seconds" % (total_time / num_iterations))
def generate_relin_key(self, params): """Generates a relinearization key for BFV scheme. Args: params (Parameters): Parameters including polynomial degree, plaintext, and ciphertext modulus. """ base = ceil(sqrt(params.ciph_modulus)) num_levels = floor(log(params.ciph_modulus, base)) + 1 keys = [0] * num_levels power = 1 sk_squared = self.secret_key.s.multiply(self.secret_key.s, params.ciph_modulus) for i in range(num_levels): k1 = Polynomial( params.poly_degree, sample_uniform(0, params.ciph_modulus, params.poly_degree)) error = Polynomial(params.poly_degree, sample_triangle(params.poly_degree)) k0 = self.secret_key.s.multiply(k1, params.ciph_modulus).add( error, params.ciph_modulus).scalar_multiply(-1).add( sk_squared.scalar_multiply(power), params.ciph_modulus).mod(params.ciph_modulus) keys[i] = (k0, k1) power *= base power %= params.ciph_modulus self.relin_key = BFVRelinKey(base, keys)
def generate_switching_key(self, new_key): """Generates a switching key for CKKS scheme. Generates a switching key as described in KSGen in the CKKS paper. Args: new_key (Polynomial): New key to generate switching key. Returns: A switching key. """ mod = self.params.big_modulus mod_squared = mod**2 swk_coeff = Polynomial( self.params.poly_degree, sample_uniform(0, mod_squared, self.params.poly_degree)) swk_error = Polynomial(self.params.poly_degree, sample_triangle(self.params.poly_degree)) sw0 = swk_coeff.multiply(self.secret_key.s, mod_squared) sw0 = sw0.scalar_multiply(-1, mod_squared) sw0 = sw0.add(swk_error, mod_squared) temp = new_key.scalar_multiply(mod, mod_squared) sw0 = sw0.add(temp, mod_squared) sw1 = swk_coeff return PublicKey(sw0, sw1)
def test_fft_inverses(self): """Checks that fft_fwd and fft_inv are inverses. Performs the FFT on the input vector, performs the inverse FFT on the result, and checks that they match. Raises: ValueError: An error if test fails. """ vec = sample_uniform(0, 7, self.num_slots) fft_vec = self.fft.fft_fwd(vec) to_check = self.fft.fft_inv(fft_vec) check_complex_vector_approx_eq(vec, to_check, 0.000001, "fft_inv is not the inverse of fft_fwd")
def generate_public_key(self, params): """Generates a public key for BFV scheme. Args: params (Parameters): Parameters including polynomial degree, plaintext, and ciphertext modulus. """ pk_coeff = Polynomial( params.poly_degree, sample_uniform(0, params.ciph_modulus, params.poly_degree)) pk_error = Polynomial(params.poly_degree, sample_triangle(params.poly_degree)) p0 = pk_error.add( pk_coeff.multiply(self.secret_key.s, params.ciph_modulus), params.ciph_modulus).scalar_multiply(-1, params.ciph_modulus) p1 = pk_coeff self.public_key = PublicKey(p0, p1)
def test_embedding_inverses(self): """Checks that embedding and embedding_inv are inverses. Computes the canonical embedding on the input vector, performs the inverse embedding on the result, and checks that they match. Raises: ValueError: An error if test fails. """ n = 1 << 5 context = FFTContext(fft_length=4 * n) vec = sample_uniform(0, 7, n) fft_vec = context.embedding(vec) to_check = context.embedding_inv(fft_vec) check_complex_vector_approx_eq(vec, to_check, 0.000001, "embedding_inv is not the inverse of embedding")
def test_large_encrypt_decrypt_01(self): vec = sample_uniform(0, self.large_plain_modulus, self.large_degree) self.run_test_large_encrypt_decrypt(vec)
def test_multiply_01(self): vec1 = sample_uniform(0, self.plain_modulus, self.degree) vec2 = sample_uniform(0, self.plain_modulus, self.degree) self.run_test_multiply(vec1, vec2)
def test_encode_decode_01(self): vec = sample_uniform(0, self.plain_modulus, self.degree) self.run_test_encode_decode(vec)