<jupyter_start><jupyter_text>Packing multiple numbers<jupyter_code>import phe
import struct
import random
publickey, privatekey = phe.generate_paillier_keypair(n_length=2048)<jupyter_output><empty_output><jupyter_text>Pack 4 byte numbers into a single number<jupyter_code>x = 20
endian = 'little'
packed_fmt = "x4p" * x
struct.calcsize(packed_fmt)*8
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)]
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
ciphertext_a = publickey.raw_encrypt(encoded_a)

ciphertext_b = publickey.raw_encrypt(encoded_b)<jupyter_output><empty_output><jupyter_text>Now I assume that we can add them together.I'm not so confident about multiplying by a scalar:- E(a) * b<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>Case 1$E(a) + E(b)$<jupyter_code>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)
# 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)<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11405584477046853, 'fraction_numerical': 0.013251301467108376, 'mean_word_length': 5.711111111111111, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '4', 'dir': 'jupyter-structured-clean-dedup', 'id': '645036', 'license': 'Apache-2.0', 'n_tokens_mistral': 829, 'n_tokens_neox': 772, 'n_words': 163, 'path': 'notebooks/Packed+Paillier.ipynb', 'repo_name': 'guypod/PySyft', 'size': '2113'}