def test_ckks_encoder(testcase): ctx = helper_context_ckks() encoder = sealapi.CKKSEncoder(ctx) plaintext = sealapi.Plaintext() encoder.encode(testcase, 2**40, plaintext) out = encoder.decode_double(plaintext) is_close_enough(out, testcase) keygen = sealapi.KeyGenerator(ctx) public_key = keygen.public_key() secret_key = keygen.secret_key() decryptor = sealapi.Decryptor(ctx, secret_key) encryptor = sealapi.Encryptor(ctx, public_key, secret_key) plaintext = sealapi.Plaintext() ciphertext = sealapi.Ciphertext(ctx) encoder.encode(testcase, 2**40, plaintext) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) decrypted = encoder.decode_double(plaintext) is_close_enough(decrypted, testcase)
def test_evaluator_exp(scheme, ctx, exp, left): evaluator, encryptor, decryptor, relin_keys = helper_generate_evaluator( ctx) expected = [i**exp for i in left] # exponentiate in place cleft = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) evaluator.exponentiate_inplace(cleft, exp, relin_keys) out = sealapi.Plaintext() decryptor.decrypt(cleft, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected) # exponentiate cleft = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) evaluator.exponentiate(cleft, exp, relin_keys, cout) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected)
def _test_encryptor_symmetric_setup(encryptor): # encrypt symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_symmetric(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == expected_value def save_load(path): serial = encryptor.encrypt_symmetric(plaintext) serial.save(path) assert Path(path).stat().st_size > 0 tmp_file(save_load) plaintext_out.set_zero() # zero symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0 # zero symmetric parms_id ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0
def save_load(path): testcase = sealapi.Plaintext("7FFx^3 + 2x^1 + 3") testcase.save(path) ctx = helper_context_bfv() save_test = sealapi.Plaintext() save_test.load(ctx, path) assert save_test.coeff_count() == 4
def _test_encryptor_pk_setup(encryptor): ciphertext = sealapi.Ciphertext(ctx) plaintext = sealapi.Plaintext() batchenc.encode(batch, plaintext) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[:len(batch)] == batch plaintext_out.set_zero()
def test_evaluator_binary(scheme, ctx, left, right): evaluator, encryptor, decryptor, _ = helper_generate_evaluator(ctx) # binary in place for (op, expected) in [ (evaluator.add_inplace, [left[idx] + right[idx] for idx in range(len(left))]), (evaluator.sub_inplace, [left[idx] - right[idx] for idx in range(len(left))]), (evaluator.multiply_inplace, [left[idx] * right[idx] for idx in range(len(left))]), ]: cleft = sealapi.Ciphertext(ctx) cright = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) pright = helper_encode(scheme, ctx, right) encryptor.encrypt(pleft, cleft) encryptor.encrypt(pright, cright) op(cleft, cright) out = sealapi.Plaintext() decryptor.decrypt(cleft, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected) # binary for (op, expected) in [ (evaluator.add, [left[idx] + right[idx] for idx in range(len(left))]), (evaluator.sub, [left[idx] - right[idx] for idx in range(len(left))]), (evaluator.multiply, [left[idx] * right[idx] for idx in range(len(left))]), ]: cleft = sealapi.Ciphertext(ctx) cright = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) pright = helper_encode(scheme, ctx, right) encryptor.encrypt(pleft, cleft) encryptor.encrypt(pright, cright) op(cleft, cright, cout) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected)
def test_evaluator_relin(scheme, ctx, left, right): evaluator, encryptor, decryptor, relin_keys = helper_generate_evaluator( ctx) expected = [left[idx] * right[idx] for idx in range(len(left))] # relin inplace cleft = sealapi.Ciphertext(ctx) cright = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) pright = helper_encode(scheme, ctx, right) encryptor.encrypt(pleft, cleft) encryptor.encrypt(pright, cright) evaluator.multiply_inplace(cleft, cright) assert cleft.size() > 2 evaluator.relinearize_inplace(cleft, relin_keys) assert cleft.size() == 2 out = sealapi.Plaintext() decryptor.decrypt(cleft, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected) # relin cleft = sealapi.Ciphertext(ctx) cright = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) pright = helper_encode(scheme, ctx, right) encryptor.encrypt(pleft, cleft) encryptor.encrypt(pright, cright) evaluator.multiply_inplace(cleft, cright) assert cleft.size() > 2 evaluator.relinearize(cleft, relin_keys, cout) assert cout.size() == 2 out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected)
def test_evaluator_galois(): parms = sealapi.EncryptionParameters(sealapi.SCHEME_TYPE.BFV) parms.set_poly_modulus_degree(8) parms.set_plain_modulus(257) coeff = sealapi.CoeffModulus.Create(8, [40, 40]) parms.set_coeff_modulus(coeff) ctx = sealapi.SEALContext(parms, False, sealapi.SEC_LEVEL_TYPE.NONE) keygen = sealapi.KeyGenerator(ctx) public_key = sealapi.PublicKey() keygen.create_public_key(public_key) secret_key = keygen.secret_key() galois_keys = sealapi.GaloisKeys() keygen.create_galois_keys([1, 3, 5], galois_keys) decryptor = sealapi.Decryptor(ctx, secret_key) encryptor = sealapi.Encryptor(ctx, public_key) evaluator = sealapi.Evaluator(ctx) plain = sealapi.Plaintext("1x^2") encrypted = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, encrypted) evaluator.apply_galois_inplace(encrypted, 1, galois_keys) decryptor.decrypt(encrypted, plain) assert plain.to_string() == "1x^2" out = sealapi.Ciphertext(ctx) evaluator.apply_galois(encrypted, 3, galois_keys, out) decryptor.decrypt(out, plain) assert plain.to_string() == "1x^6"
def test_evaluator_multiply_many(scheme, ctx, many): evaluator, encryptor, decryptor, relin_keys = helper_generate_evaluator( ctx) expected = [1] * len(many[0]) for idx in range(len(many)): for jdx in range(len(many[idx])): expected[jdx] *= many[idx][jdx] cmany = [] pmany = [helper_encode(scheme, ctx, left) for left in many] cout = sealapi.Ciphertext(ctx) for idx in range(len(many)): c = sealapi.Ciphertext(ctx) encryptor.encrypt(pmany[idx], c) cmany.append(c) evaluator.multiply_many(cmany, relin_keys, cout) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(many[0])], expected)
def test_valcheck(check): ctx = helper_context_bfv(8192) other_ctx = helper_context_ckks(8192) invalid_ctx = helper_context_invalid() ciphertext = sealapi.Ciphertext(ctx) assert check(ciphertext, ctx) is True assert check(ciphertext, other_ctx) is False assert check(ciphertext, invalid_ctx) is False assert sealapi.is_buffer_valid(ciphertext) is True plaintext = sealapi.Plaintext() assert check(plaintext, ctx) is True assert check(plaintext, other_ctx) is True assert check(plaintext, invalid_ctx) is False keygen = sealapi.KeyGenerator(ctx) for key in [ keygen.public_key(), keygen.secret_key(), keygen.galois_keys_local(), keygen.relin_keys_local(), ]: assert check(key, ctx) is True assert check(key, other_ctx) is False assert check(key, invalid_ctx) is False assert sealapi.is_buffer_valid(key) is True
def test_valcheck(check): ctx = helper_context_bfv(8192) other_ctx = helper_context_ckks(8192) invalid_ctx = helper_context_invalid() ciphertext = sealapi.Ciphertext(ctx) assert check(ciphertext, ctx) is True assert check(ciphertext, other_ctx) is False assert check(ciphertext, invalid_ctx) is False assert sealapi.is_buffer_valid(ciphertext) is True plaintext = sealapi.Plaintext() assert check(plaintext, ctx) is True assert check(plaintext, other_ctx) is True assert check(plaintext, invalid_ctx) is False keygen = sealapi.KeyGenerator(ctx) pk = sealapi.PublicKey() keygen.create_public_key(pk) rk = sealapi.RelinKeys() keygen.create_relin_keys(rk) gk = sealapi.GaloisKeys() keygen.create_galois_keys(gk) for key in [pk, keygen.secret_key(), gk, rk]: assert check(key, ctx) is True assert check(key, other_ctx) is False assert check(key, invalid_ctx) is False assert sealapi.is_buffer_valid(key) is True
def test_scale_manually(): scheme = sealapi.SCHEME_TYPE.CKKS ctx = helper_context_ckks(8192) evaluator, encryptor, decryptor, _ = helper_generate_evaluator(ctx) cleft = sealapi.Ciphertext(ctx) cright = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, [2, 3]) pright = helper_encode(scheme, ctx, [5, 7]) encryptor.encrypt(pleft, cleft) encryptor.encrypt(pright, cright) evaluator.multiply(cleft, cright, cout) evaluator.rescale_to_next_inplace(cout) evaluator.mod_switch_to_inplace(pright, cout.parms_id()) cout.scale = pright.scale evaluator.add_plain_inplace(cout, pright) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:2], [15, 28])
def test_batchencoder(ctx): poly_modulus_degree = helper_poly_modulus_degree(ctx) enc_out = sealapi.Plaintext() testcase = [1, 2, 3, 4, 5] encoder = sealapi.BatchEncoder(ctx) encoder.encode(testcase, enc_out) assert enc_out.int_array().size() == poly_modulus_degree assert encoder.decode_uint64(enc_out)[:len(testcase)] == testcase assert encoder.decode_int64(enc_out)[:len(testcase)] == testcase test_str = "7FFx^3 + 1x^1 + 3" testcase = sealapi.Plaintext(test_str) encoder.encode(testcase) assert testcase.to_string() != test_str encoder.decode(testcase) assert testcase.to_string() == test_str
def test_evaluator_rotate_vector(): testcase = [complex(i, i) for i in range(4)] slot_size = len(testcase) delta = 1 << 30 parms = sealapi.EncryptionParameters(sealapi.SCHEME_TYPE.CKKS) poly_modulus = 2 * slot_size parms.set_poly_modulus_degree(poly_modulus) parms.set_plain_modulus(0) coeff = sealapi.CoeffModulus.Create(poly_modulus, [40, 40, 40, 40]) parms.set_coeff_modulus(coeff) ctx = sealapi.SEALContext(parms, False, sealapi.SEC_LEVEL_TYPE.NONE) ctx = helper_context_ckks() keygen = sealapi.KeyGenerator(ctx) galois_keys = sealapi.GaloisKeys() keygen.create_galois_keys(galois_keys) pk = sealapi.PublicKey() keygen.create_public_key(pk) decryptor = sealapi.Decryptor(ctx, keygen.secret_key()) encryptor = sealapi.Encryptor(ctx, pk) evaluator = sealapi.Evaluator(ctx) encoder = sealapi.CKKSEncoder(ctx) plain = sealapi.Plaintext() encoder.encode(testcase, ctx.first_parms_id(), delta, plain) encrypted = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, encrypted) # inplace steps = 1 evaluator.rotate_vector_inplace(encrypted, steps, galois_keys) decryptor.decrypt(encrypted, plain) decoded = encoder.decode_complex(plain)[:slot_size] for idx in range(slot_size): off = (idx + steps) % slot_size assert abs(testcase[off].real - decoded[idx].real) < 0.1 assert abs(testcase[off].imag - decoded[idx].imag) < 0.1 # to another ciphertext steps = -steps out = sealapi.Ciphertext(ctx) evaluator.rotate_vector(encrypted, steps, galois_keys, out) decryptor.decrypt(out, plain) decoded = encoder.decode_complex(plain)[:slot_size] for idx in range(slot_size): assert abs(testcase[idx].real - decoded[idx].real) < 0.1 assert abs(testcase[idx].imag - decoded[idx].imag) < 0.1
def test_evaluator_rotate_bfv(): parms = sealapi.EncryptionParameters(sealapi.SCHEME_TYPE.BFV) parms.set_poly_modulus_degree(8) parms.set_plain_modulus(257) coeff = sealapi.CoeffModulus.Create(8, [40, 40]) parms.set_coeff_modulus(coeff) ctx = sealapi.SEALContext.Create(parms, False, sealapi.SEC_LEVEL_TYPE.NONE) keygen = sealapi.KeyGenerator(ctx) galois_keys = keygen.galois_keys_local() decryptor = sealapi.Decryptor(ctx, keygen.secret_key()) encryptor = sealapi.Encryptor(ctx, keygen.public_key()) evaluator = sealapi.Evaluator(ctx) encoder = sealapi.BatchEncoder(ctx) testcase = [1, 2, 3, 4, 5, 6, 7, 8] # Input # 1, 2, 3, 4, # 5, 6, 7, 8 plain = sealapi.Plaintext() encoder.encode(testcase, plain) encrypted = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, encrypted) evaluator.rotate_columns_inplace(encrypted, galois_keys) decryptor.decrypt(encrypted, plain) # Rotate columns # 5, 6, 7, 8, # 1, 2, 3, 4 assert encoder.decode_int64(plain) == [5, 6, 7, 8, 1, 2, 3, 4] evaluator.rotate_rows_inplace(encrypted, -1, galois_keys) decryptor.decrypt(encrypted, plain) # Shift rows -1 # 8, 5, 6, 7, # 4, 1, 2, 3, assert encoder.decode_int64(plain) == [8, 5, 6, 7, 4, 1, 2, 3] cout = sealapi.Ciphertext(ctx) evaluator.rotate_rows(encrypted, 2, galois_keys, cout) decryptor.decrypt(cout, plain) # Shift rows +2 # 6, 7, 8, 5, # 2, 3, 4, 1, assert encoder.decode_int64(plain) == [6, 7, 8, 5, 2, 3, 4, 1] evaluator.rotate_columns(cout, galois_keys, encrypted) decryptor.decrypt(encrypted, plain) # Rotate columns # 2, 3, 4, 1, # 6, 7, 8, 5, assert encoder.decode_int64(plain) == [2, 3, 4, 1, 6, 7, 8, 5]
def test_evaluator_plain(scheme, ctx, left): evaluator, encryptor, decryptor, _ = helper_generate_evaluator(ctx) # plain op in place for (op, plain, expected) in [ (evaluator.add_plain_inplace, [100] * len(left), [100 + v for v in left]), (evaluator.sub_plain_inplace, [5] * len(left), [v - 5 for v in left]), (evaluator.multiply_plain_inplace, [2] * len(left), [2 * v for v in left]), ]: cleft = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) op(cleft, helper_encode(scheme, ctx, plain)) out = sealapi.Plaintext() decryptor.decrypt(cleft, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected) # plain op for (op, plain, expected) in [ (evaluator.add_plain, [100] * len(left), [100 + v for v in left]), (evaluator.sub_plain, [5] * len(left), [v - 5 for v in left]), (evaluator.multiply_plain, [2] * len(left), [2 * v for v in left]), ]: cleft = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) op(cleft, helper_encode(scheme, ctx, plain), cout) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected)
def helper_encode(scheme, ctx, test): plaintext = sealapi.Plaintext() if scheme == sealapi.SCHEME_TYPE.CKKS: encoder = sealapi.CKKSEncoder(ctx) encoder.encode(test, 2 ** 40, plaintext) else: encoder = sealapi.BatchEncoder(ctx) encoder.encode(test, plaintext) return plaintext
def test_batchencoder(ctx): poly_modulus_degree = helper_poly_modulus_degree(ctx) enc_out = sealapi.Plaintext() testcase = [1, 2, 3, 4, 5] encoder = sealapi.BatchEncoder(ctx) encoder.encode(testcase, enc_out) assert enc_out.dyn_array().size() == poly_modulus_degree assert encoder.decode_uint64(enc_out)[:len(testcase)] == testcase assert encoder.decode_int64(enc_out)[:len(testcase)] == testcase
def _test_encryptor_pk_setup(encryptor): ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == batch plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero()
def _test_encryptor_pk_setup(encryptor): ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == expected_value plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0 plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0 plaintext_out.set_zero()
def test_evaluator_unary(scheme, ctx, left): evaluator, encryptor, decryptor, _ = helper_generate_evaluator(ctx) # unary in place for (op, expected) in [ (evaluator.negate_inplace, [-v for v in left]), (evaluator.square_inplace, [v * v for v in left]), (evaluator.mod_switch_to_next_inplace, left), ]: cleft = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) op(cleft) out = sealapi.Plaintext() decryptor.decrypt(cleft, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected) # unary for (op, expected) in [ (evaluator.negate, [-v for v in left]), (evaluator.square, [v * v for v in left]), (evaluator.mod_switch_to_next, left), ]: cleft = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) pleft = helper_encode(scheme, ctx, left) encryptor.encrypt(pleft, cleft) op(cleft, cout) out = sealapi.Plaintext() decryptor.decrypt(cout, out) out = helper_decode(scheme, ctx, out) is_close_enough(out[:len(left)], expected)
def _test_encryptor_symmetric_setup(encryptor): # encrypt symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_symmetric(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == expected_value tmp = NamedTemporaryFile() serial = encryptor.encrypt_symmetric(plaintext) serial.save(tmp.name) assert Path(tmp.name).stat().st_size > 0 plaintext_out.set_zero() # zero symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0 tmp = NamedTemporaryFile() serial = encryptor.encrypt_zero_symmetric() serial.save(tmp.name) assert Path(tmp.name).stat().st_size > 0 plaintext_out.set_zero() # zero symmetric parms_id ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == 0 tmp = NamedTemporaryFile() serial = encryptor.encrypt_zero_symmetric(ctx.last_parms_id()) serial.save(tmp.name) assert Path(tmp.name).stat().st_size > 0
def test_intencoder(ctx): encoder = sealapi.IntegerEncoder(ctx) enc = encoder.encode(5) assert enc.to_string() == "1x^2 + 1" assert enc.int_array()[2] == 1 assert encoder.decode_uint32(enc) == 5 assert encoder.decode_int32(enc) == 5 assert encoder.decode_uint64(enc) == 5 assert encoder.decode_int32(enc) == 5 enc = sealapi.Plaintext() encoder.encode(7, enc) assert enc.to_string() == "1x^2 + 1x^1 + 1" big = sealapi.BigUInt("5555555555") enc = encoder.encode(big) assert enc.int_array()[0] == 1 assert encoder.decode_biguint(enc) == 0x5555555555 enc = sealapi.Plaintext() encoder.encode(big + 1, enc) assert encoder.decode_biguint(enc) == 0x5555555556
def test_evaluator_conjugate(): testcase = [complex(i, i) for i in range(32)] slot_size = len(testcase) delta = 1 << 30 parms = sealapi.EncryptionParameters(sealapi.SCHEME_TYPE.CKKS) poly_modulus = 2 * slot_size parms.set_poly_modulus_degree(poly_modulus) parms.set_plain_modulus(0) coeff = sealapi.CoeffModulus.Create(poly_modulus, [40, 40, 40, 40]) parms.set_coeff_modulus(coeff) ctx = sealapi.SEALContext.Create(parms, False, sealapi.SEC_LEVEL_TYPE.NONE) ctx = helper_context_ckks() keygen = sealapi.KeyGenerator(ctx) galois_keys = keygen.galois_keys_local() decryptor = sealapi.Decryptor(ctx, keygen.secret_key()) encryptor = sealapi.Encryptor(ctx, keygen.public_key()) evaluator = sealapi.Evaluator(ctx) encoder = sealapi.CKKSEncoder(ctx) plain = sealapi.Plaintext() encoder.encode(testcase, ctx.first_parms_id(), delta, plain) encrypted = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, encrypted) evaluator.complex_conjugate_inplace(encrypted, galois_keys) decryptor.decrypt(encrypted, plain) decoded = encoder.decode_complex(plain)[:slot_size] for idx in range(slot_size): assert abs(testcase[idx].real - decoded[idx].real) < 0.1 assert abs(testcase[idx].imag + decoded[idx].imag) < 0.1 out = sealapi.Ciphertext(ctx) evaluator.complex_conjugate(encrypted, galois_keys, out) decryptor.decrypt(out, plain) decoded = encoder.decode_complex(plain)[:slot_size] for idx in range(slot_size): assert abs(testcase[idx].real - decoded[idx].real) < 0.1 assert abs(testcase[idx].imag - decoded[idx].imag) < 0.1
def test_intarray(): testcase = sealapi.Plaintext("3x^3 + 1x^1 + 3") int_arr = testcase.dyn_array() assert int_arr[0] == 3 assert int_arr.at(3) == 3 assert int_arr.empty() is False assert int_arr.max_size() == 2 ** 64 - 1 assert int_arr.size() == 4 assert int_arr.capacity() == 4 def save_load(path): int_arr.save(path) save_test = sealapi.DynArray() save_test.load(path) assert save_test[0] == 3 tmp_file(save_load) int_arr.resize(10, True) assert int_arr.capacity() == 10 assert int_arr.size() == 10 int_arr.reserve(30) assert int_arr.capacity() == 30 assert int_arr.capacity() == 30 int_arr.shrink_to_fit() assert int_arr.capacity() == 10 assert int_arr.size() == 10 int_arr.clear() assert int_arr.size() == 0 assert int_arr.capacity() == 10 assert int_arr.empty() is True int_arr.release() assert int_arr.capacity() == 0
def test_intarray(): testcase = sealapi.Plaintext("3x^3 + 1x^1 + 3") int_arr = testcase.int_array() assert int_arr[0] == 3 assert int_arr.at(3) == 3 assert int_arr.empty() is False assert int_arr.max_size() == 2 ** 64 - 1 assert int_arr.size() == 4 assert int_arr.capacity() == 4 tmp = NamedTemporaryFile() int_arr.save(tmp.name) save_test = sealapi.IntArray() save_test.load(tmp.name) assert save_test[0] == 3 int_arr.resize(10, True) assert int_arr.capacity() == 10 assert int_arr.size() == 10 int_arr.reserve(30) assert int_arr.capacity() == 30 assert int_arr.capacity() == 30 int_arr.shrink_to_fit() assert int_arr.capacity() == 10 assert int_arr.size() == 10 int_arr.clear() assert int_arr.size() == 0 assert int_arr.capacity() == 10 assert int_arr.empty() is True int_arr.release() assert int_arr.capacity() == 0
def test_decryptor(): poly_modulus_degree = 4096 plain_modulus = 1024 ctx = helper_context_bfv(poly_modulus_degree, plain_modulus) keygen = sealapi.KeyGenerator(ctx) intenc = sealapi.IntegerEncoder(ctx) public_key = keygen.public_key() secret_key = keygen.secret_key() decryptor = sealapi.Decryptor(ctx, secret_key) encryptor = sealapi.Encryptor(ctx, public_key, secret_key) expected_value = 1234 plaintext = intenc.encode(expected_value) ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() assert decryptor.invariant_noise_budget(ciphertext) > 0 decryptor.decrypt(ciphertext, plaintext_out) assert intenc.decode_int64(plaintext_out) == expected_value
def test_encryptor_bfv(): batch = [1, 2, 3, 4, 5] poly_modulus_degree = 8192 plain_modulus = 1032193 ctx = helper_context_bfv(poly_modulus_degree, plain_modulus) keygen = sealapi.KeyGenerator(ctx) batchenc = sealapi.BatchEncoder(ctx) public_key = sealapi.PublicKey() keygen.create_public_key(public_key) secret_key = keygen.secret_key() decryptor = sealapi.Decryptor(ctx, secret_key) plaintext = sealapi.Plaintext() batchenc.encode(batch, plaintext) def _test_encryptor_symmetric_setup(encryptor): # encrypt symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_symmetric(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == batch plaintext_out.set_zero() def save_load(path): serial = encryptor.encrypt_symmetric(plaintext) serial.save(path) assert Path(path).stat().st_size > 0 tmp_file(save_load) plaintext_out.set_zero() # zero symmetric ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero() # zero symmetric parms_id ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero_symmetric(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero() def _test_encryptor_pk_setup(encryptor): ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt(plaintext, ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == batch plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero() ciphertext = sealapi.Ciphertext(ctx) encryptor.encrypt_zero(ctx.last_parms_id(), ciphertext) plaintext_out = sealapi.Plaintext() decryptor.decrypt(ciphertext, plaintext_out) assert batchenc.decode_int64(plaintext_out)[: len(batch)] == [0] * len(batch) plaintext_out.set_zero() encryptor = sealapi.Encryptor(ctx, public_key) _test_encryptor_pk_setup(encryptor) encryptor = sealapi.Encryptor(ctx, public_key, secret_key) _test_encryptor_symmetric_setup(encryptor) _test_encryptor_pk_setup(encryptor) encryptor = sealapi.Encryptor(ctx, secret_key) _test_encryptor_symmetric_setup(encryptor) encryptor = sealapi.Encryptor(ctx, public_key) encryptor.set_secret_key(secret_key) _test_encryptor_pk_setup(encryptor) _test_encryptor_symmetric_setup(encryptor) encryptor = sealapi.Encryptor(ctx, secret_key) encryptor.set_public_key(public_key) _test_encryptor_pk_setup(encryptor) _test_encryptor_symmetric_setup(encryptor)
def test_plaintext(): testcase = sealapi.Plaintext() assert testcase.coeff_count() == 0 testcase = sealapi.Plaintext(15) assert testcase.coeff_count() == 15 testcase = sealapi.Plaintext(100, 15) assert testcase.coeff_count() == 15 assert testcase.capacity() == 100 testcase = sealapi.Plaintext("7FFx^3 + 1x^1 + 3") assert testcase.coeff_count() == 4 assert testcase.significant_coeff_count() == 4 assert testcase.capacity() == 4 testcase2 = testcase assert testcase2.coeff_count() == 4 assert testcase2.capacity() == 4 testcase = sealapi.Plaintext(100, 15) testcase.reserve(200) assert testcase.capacity() == 200 testcase = sealapi.Plaintext("7FFx^3 + 1x^1 + 3") assert testcase.capacity() == 4 testcase.reserve(200) assert testcase.capacity() == 200 testcase.shrink_to_fit() assert testcase.capacity() == 4 assert testcase.dyn_array()[3] == 0x7FF assert testcase.data(3) == 0x7FF assert testcase.parms_id() == [0, 0, 0, 0] assert testcase.scale == 1.0 assert testcase[3] == 0x7FF assert testcase.to_string() == "7FFx^3 + 1x^1 + 3" testcase.release() assert testcase.coeff_count() == 0 testcase = sealapi.Plaintext("7FFx^3 + 1x^1 + 3") assert testcase.coeff_count() == 4 assert testcase.nonzero_coeff_count() == 3 testcase.resize(10) assert testcase.coeff_count() == 10 testcase.set_zero() assert testcase.is_zero() assert testcase.nonzero_coeff_count() == 0 testcase = sealapi.Plaintext("7FFx^3 + 2x^1 + 3") assert testcase.is_ntt_form() is False def save_load(path): testcase = sealapi.Plaintext("7FFx^3 + 2x^1 + 3") testcase.save(path) ctx = helper_context_bfv() save_test = sealapi.Plaintext() save_test.load(ctx, path) assert save_test.coeff_count() == 4 tmp_file(save_load)
def test_evaluator_mod_switch(): poly_modulus_degree = 8192 plain_modulus = 1032193 ctx = helper_context_bfv(poly_modulus_degree, plain_modulus) batchenc = sealapi.BatchEncoder(ctx) keygen = sealapi.KeyGenerator(ctx) public_key = sealapi.PublicKey() keygen.create_public_key(public_key) secret_key = keygen.secret_key() decryptor = sealapi.Decryptor(ctx, secret_key) encryptor = sealapi.Encryptor(ctx, public_key) evaluator = sealapi.Evaluator(ctx) # cphertext mod switch to next expected_value = [1, 2, 3, 4, 5] plain = sealapi.Plaintext() batchenc.encode(expected_value, plain) out = sealapi.Plaintext() enc = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, enc) before = decryptor.invariant_noise_budget(enc) evaluator.mod_switch_to_next_inplace(enc) after = decryptor.invariant_noise_budget(enc) assert before > after decryptor.decrypt(enc, out) assert batchenc.decode_int64(out)[:len(expected_value)] == expected_value # ciphertext mod switch to next expected_value = [1, 2, 3, 4, 5] plain = sealapi.Plaintext() batchenc.encode(expected_value, plain) out = sealapi.Plaintext() enc = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, enc) before = decryptor.invariant_noise_budget(enc) evaluator.mod_switch_to_next(enc, cout) after = decryptor.invariant_noise_budget(cout) assert before > after decryptor.decrypt(cout, out) assert batchenc.decode_int64(out)[:len(expected_value)] == expected_value # cphertext mod switch to inplace parms_id = ctx.last_parms_id() expected_value = [1, 2, 3, 4, 5] plain = sealapi.Plaintext() batchenc.encode(expected_value, plain) out = sealapi.Plaintext() enc = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, enc) before = decryptor.invariant_noise_budget(enc) evaluator.mod_switch_to_inplace(enc, parms_id) after = decryptor.invariant_noise_budget(enc) assert before > after decryptor.decrypt(enc, out) assert batchenc.decode_int64(out)[:len(expected_value)] == expected_value assert enc.parms_id() == parms_id # ciphertext mod switch to parms_id = ctx.last_parms_id() expected_value = [1, 2, 3, 4, 5] plain = sealapi.Plaintext() batchenc.encode(expected_value, plain) out = sealapi.Plaintext() enc = sealapi.Ciphertext(ctx) cout = sealapi.Ciphertext(ctx) encryptor.encrypt(plain, enc) before = decryptor.invariant_noise_budget(enc) evaluator.mod_switch_to(enc, parms_id, cout) after = decryptor.invariant_noise_budget(cout) assert before > after decryptor.decrypt(cout, out) assert batchenc.decode_int64(out)[:len(expected_value)] == expected_value assert cout.parms_id() == parms_id pol_str = "1x^3 + 1x^1 + 3" # plaintext mod switch to next inplace plain = sealapi.Plaintext(pol_str) evaluator.transform_to_ntt_inplace(plain, ctx.first_parms_id()) assert plain.is_ntt_form() is True evaluator.mod_switch_to_next_inplace(plain) assert plain.parms_id() != ctx.first_parms_id() # plaintext mod switch to next inplace failure plain = sealapi.Plaintext(pol_str) evaluator.transform_to_ntt_inplace(plain, ctx.last_parms_id()) assert plain.is_ntt_form() is True with pytest.raises(BaseException): evaluator.mod_switch_to_next_inplace(plain) # plaintext mod switch to inplace plain = sealapi.Plaintext(pol_str) evaluator.transform_to_ntt_inplace(plain, ctx.first_parms_id()) assert plain.is_ntt_form() is True evaluator.mod_switch_to_inplace(plain, ctx.last_parms_id()) assert plain.parms_id() == ctx.last_parms_id() # plaintext mod switch to next plain = sealapi.Plaintext(pol_str) plain_out = sealapi.Plaintext() evaluator.transform_to_ntt(plain, ctx.first_parms_id(), plain_out) assert plain_out.is_ntt_form() is True plain_next = sealapi.Plaintext() evaluator.mod_switch_to_next(plain_out, plain_next) assert plain_out.parms_id() == ctx.first_parms_id() assert plain_next.parms_id() != ctx.first_parms_id() # plaintext mod switch to plain = sealapi.Plaintext(pol_str) plain_out = sealapi.Plaintext() evaluator.transform_to_ntt(plain, ctx.first_parms_id(), plain_out) assert plain_out.is_ntt_form() is True plain_next = sealapi.Plaintext() evaluator.mod_switch_to(plain_out, ctx.last_parms_id(), plain_next) assert plain_out.parms_id() == ctx.first_parms_id() assert plain_next.parms_id() == ctx.last_parms_id()