def test_ope_deterministic(): """Test that encrypting the same values yields the same results""" values = [0, 314, 1337, 1338, 10000] cipher = OPE(b'key-la-la') encrypted_values_first = [cipher.encrypt(value) for value in values] encrypted_values_second = [cipher.encrypt(value) for value in values] assert encrypted_values_first == encrypted_values_second
def test_big_ranges(): in_range = ValueRange(2**32, 2**33) out_range = ValueRange(2**48, 2**49) ope = OPE(b'test-big-ranges', in_range, out_range) plaintext = in_range.start while plaintext <= in_range.end: assert ope.encrypt(plaintext) plaintext += 2**24
def test_encrypt_small_out_range_issue(): """Regression test for this issue: https://github.com/tonyo/pyope/issues/13""" cipher = OPE(b'fresh key', in_range=ValueRange(0, 2), out_range=ValueRange(2, 5)) assert cipher.encrypt(0) assert cipher.encrypt(1) assert cipher.encrypt(2)
def test_long_different_keys(): """Test that different keys yield different ciphertexts""" key1 = b'\x12\x23\x34\x45\x56\x67\x78\x89\x90\x0A\xAB\xBC\xCD\xDE\xEF\xF0\x13\x14\x15\x16' key2 = b'\x0A\xAB\xBC\xCD\xDE\xEF\xF0\x13\x14\x15\x16\x12\x23\x34\x45\x56\x67\x78\x89\x90\x12\x13' ope1, ope2 = OPE(key1), OPE(key2) values = [0, 1, 10, 100, 1000, 2000, 3000, 4000, 5000] for v in values: assert ope1.encrypt(v) != ope2.encrypt(v)
def test_order_guarantees(): """Test that encryption is order-preserving""" # add adjusted values. values = [0, 1, 2, 10, 28, 42, 1000, 1001, 2**15 - 1, 2**30, 2**31 - 1] key = b'key' cipher = OPE(key) encrypted_values = [cipher.encrypt(value) for value in values] assert encrypted_values == sorted( set(encrypted_values)), "Order is not preserved"
def test_dense_range(): """Equal ranges must yield 1-to-1 mapping""" range_start = 0 range_end = 2**15 in_range = ValueRange(range_start, range_end) out_range = in_range.copy() key = b'123' cipher = OPE(key, in_range, out_range) values = [0, 10, 20, 50, 100, 1000, 2**10, 2**15] for v in values: assert cipher.encrypt(v) == v assert cipher.decrypt(v) == v with pytest.raises(Exception): OPE(key, ValueRange(0, 10), ValueRange(1, 2))
def test_ope_encrypt_decrypt(): """Encrypt and then decrypt""" values = [-1000, -100, -20, -1, 0, 1, 10, 100, 314, 1337, 1338, 10000] key = b'key' in_range = ValueRange(-1000, 2**20) out_range = ValueRange(-10000, 2**32) # Client encrypts values cipher = OPE(key, in_range, out_range) encrypted_values = [cipher.encrypt(value) for value in values] # Decryption at the peer side cipher_dec = OPE(key, in_range, out_range) for value, encrypted in zip(values, encrypted_values): decrypted = cipher_dec.decrypt(encrypted) assert value == decrypted, "Dec(Enc(P)) != P"
def test_get_private_key(self): """ Testing the Client Key Wrapper. """ # Build the ClientKey prf_key = token_bytes(16) ope_encrypter = OPE(token_bytes(16)) public_key, private_key = paillier.he_key_gen() clientKey = ClientKey(private_key, prf_key, ope_encrypter) a = randrange(pow(2, 30)) b = randrange(pow(2, 30)) # test the ope key ea = clientKey.get_ope_encryptor().encrypt(a) eb = clientKey.get_ope_encryptor().encrypt(b) assert (a < b) == (ea < eb) ea = public_key.encrypt(a) eb = public_key.encrypt(b) assert clientKey.get_private_key().decrypt(ea + eb) == a + b
def test_ope_node(self): """ Test vector on evaluating the decision tree based on OPE :return: """ t1 = '0:[Pclass<3] yes=1,no=2,missing=1\n\t1:[Fare<13] yes=3,no=4,missing=3\n\t\t3:leaf=323\n\t\t4:[' \ 'Age<42] yes=9,no=10,missing=10\n\t\t\t9:leaf=32434\n\t\t\t10:leaf=43124\n\t2:[Age<6] yes=5,' \ 'no=6,missing=6\n\t\t5:[SibSp<32] yes=11,no=12,' \ 'missing=11\n\t\t\t11:leaf=9473\n\t\t\t12:leaf=836\n\t\t6:leaf=46\n ' input_vector = pd.read_csv('test_files/test_prediction_input.csv') ################################################################################################ # The folowing is to compute the scores for the decision tree on input vectors in plaintext! ################################################################################################ feature_set = set() # As this test just to test the correctness of the encrypt_tree_node method # add min_max just to 'fake' some min-max value for this test tree = boostparser.parse_tree(t1, feature_set, min_max={ 'min': 0, 'max': 1 }) # The score list value in plaintext. score_value = list() # get each row indexing with input vector's head for index, row in input_vector.iterrows(): score_value.append(tree.eval(row)) ################################################################################################ # The folowing is to compute the scores based on the OPE processed decision tree ################################################################################################ # Set up encrytion materials. # token bytes calls the os.urandom(). prf_key = token_bytes(16) OPE_key = token_bytes(16) encrypter = OPE(OPE_key) # create a copy of the input vector and plaintext trees test_input_vector = input_vector.copy() enc_tree = tree public_key, private_key = paillier.he_key_gen() # as this only test the enc_tree_node ope, add fake metadata (min and max) for this computation # just for testing purposes. metaDataMinMax = MetaData({'min': 0, 'max': 1000}) # 1. Encrypts the input vector for prediction (using prf_key_hash and ope-encrypter) based on the feature set. ppbooster.enc_input_vector(prf_key, encrypter, feature_set, test_input_vector, metaDataMinMax) # 2. process the tree into ope_enc_tree ppbooster.enc_tree_node(public_key, prf_key, encrypter, enc_tree, metaDataMinMax) # 3. OPE evaluation based on OPE encrypted values in the tree nodes. encrypted_value = list() for index, row in test_input_vector.iterrows(): score = enc_tree.eval(row) encrypted_value.append(score) dec_value = list() for c in encrypted_value: dec_value.append(paillier.decrypt(private_key, c)) # 4. compare assert dec_value == score_value
def test_huge_output_range(): """Regression test for https://github.com/tonyo/pyope/pull/16""" cipher = OPE(b'key11', in_range=ValueRange(0, 0), out_range=ValueRange(0, 2**65)) assert cipher.encrypt(0)