Packing multiple numbers
In [1]:
import phe
import struct
import random
In [2]:
publickey, privatekey = phe.generate_paillier_keypair(n_length=2048)
Pack 4 byte numbers into a single number
In [3]:
x = 20
In [4]:
endian = 'little'
packed_fmt = "x4p" * x
struct.calcsize(packed_fmt)*8
Out[4]:
In [5]:
def pack_numbers(numbers):
p = []
for n in numbers:
n_bytes = n.to_bytes(4, endian)
p.append(n_bytes)
assert n == int.from_bytes(n_bytes, endian)
#print(n_bytes)
encoded_bytes = struct.pack(packed_fmt, *p)
encoded_num = int.from_bytes(encoded_bytes, endian)
return encoded_num
def unpack(encoded):
enc_bytes = encoded.to_bytes(struct.calcsize(packed_fmt), endian)
return [int.from_bytes(b, endian) for b in struct.unpack(packed_fmt, enc_bytes)]
In [6]:
numbers_a = [random.randint(0, 2**20) for _ in range(x)]
encoded_a = pack_numbers(numbers_a)
assert unpack(encoded_a) == numbers_a
numbers_b = [random.randint(0, 2**20) for i in range(x)]
numbers_b[0] = 0
numbers_b[1] = 1
numbers_b[2] = 2**20
encoded_b = pack_numbers(numbers_b)
assert unpack(encoded_b) == numbers_b
In [7]:
ciphertext_a = publickey.raw_encrypt(encoded_a)
ciphertext_b = publickey.raw_encrypt(encoded_b)
Now I assume that we can add them together.
I'm not so confident about multiplying by a scalar:
In [8]:
def compare(operation, res):
for a, b, r in zip(numbers_a, numbers_b, res):
opres = operation(a, b)
assert opres == r
print(opres, r)
In [9]:
ea = phe.EncryptedNumber(publickey, ciphertext_a)
cipher_both = ea._raw_add(ciphertext_a, ciphertext_b)
result = unpack(privatekey.raw_decrypt(cipher_both))
compare(lambda a,b: a+b, result)
In [10]:
# Case 2 multiplying be a vector encoded number
ea = phe.EncryptedNumber(publickey, ciphertext_a)
cipher_both = ea._raw_mul(encoded_b)
result = unpack(privatekey.raw_decrypt(cipher_both))
compare(lambda a,b: a*b, result)
In [ ]: