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]:
800

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:

  • E(a) * b

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)

Case 1

$E(a) + E(b)$


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)


230434 230434
193515 193515
1438910 1438910
1359267 1359267
1515364 1515364
1319562 1319562
1125473 1125473
1641695 1641695
582305 582305
956673 956673
462229 462229
243885 243885
622645 622645
928660 928660
1251032 1251032
1593311 1593311
1466206 1466206
1041035 1041035
1734044 1734044
1588096 1588096

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)


---------------------------------------------------------------------------
OverflowError                             Traceback (most recent call last)
<ipython-input-10-3f2a4f3dd82e> in <module>()
      2 ea = phe.EncryptedNumber(publickey, ciphertext_a)
      3 cipher_both = ea._raw_mul(encoded_b)
----> 4 result = unpack(privatekey.raw_decrypt(cipher_both))
      5 compare(lambda a,b: a*b, result)

<ipython-input-5-2a2dbaadc88c> in unpack(encoded)
     12 
     13 def unpack(encoded):
---> 14     enc_bytes = encoded.to_bytes(struct.calcsize(packed_fmt), endian)
     15     return [int.from_bytes(b, endian) for b in struct.unpack(packed_fmt, enc_bytes)]

OverflowError: int too big to convert

In [ ]: