Multiparty Computation
Multiparty computation allows several parties to participate in a computation with their respective secret keys.
Every party has its own secret key and every single secret key is required to decrypt an encrypted data.
This makes collaborative data processing possible without the risk of the raw data being exposed.
This document explains in a step-by-step manner how to do a multiparty computation.
All engines in this document are created with Engine(multiparty=True).
You can run all the codes in Google Colab.
A. Create Secret Keys and Multiparty Public Key
Each user creates its own secret key in the same way as in a single-party computation. The secret keys must never be shared with anyone.
Public keys, on the other hand, are generated differently in multiparty computation.
- step 1: The coordinator generates public key a, which is shared by all users.
- step 2: User 1 generates its secret key, and its public key b from public key a and its secret key.
- step 3: User 2 does the exact same thing.
- step 4: They both share their public key b's with the coordinator. Using public key a and all the shared public key b's, the coordinator generates the multiparty public key.
Please check out the data structure document if you want more details about those special types of multiparty public keys.
Step 1: The coordinator generates public key a
from desilofhe import Engine
common_engine = Engine(multiparty=True)
public_key_a = common_engine.create_public_key_a()
Step 2: User 1 generates a secret key and public key b
from desilofhe import Engine
engine1 = Engine(multiparty=True)
secret_key1 = engine1.create_secret_key()
public_key_b1 = engine1.create_public_key_b(secret_key1, public_key_a)
Step 3: User 2 generates a secret key and public key b
from desilofhe import Engine
engine2 = Engine(multiparty=True)
secret_key2 = engine2.create_secret_key()
public_key_b2 = engine2.create_public_key_b(secret_key2, public_key_a)
Step 4: The coordinator generates the multiparty public key
public_key = common_engine.create_multiparty_public_key(
[public_key_b1, public_key_b2], public_key_a
)
B. Encryption in Multiparty Computation
In multiparty computation, encryption is performed using the multiparty public key (generated in section A).
C. Decryption in Multiparty Computation
In multiparty computation, secret keys must not be exposed, so when a decryption is needed, each user generates a decrypted share using its own secret key (steps 1 and 2). These decrypted shares are combined to decrypt the data (step 3).
Step 1: User 1 generates a decrypted share using its own secret key
Step 2: User 2 generates a decrypted share using its own secret key
Step 3: The coordinator decrypts the data using the decrypted shares
D. Create Multiparty Relinearization Key
Using the multiparty public key (generated in section A), each user generates its own individual relinearization key (steps 1 and 2) and shares it with the coordinator. Finally, the individual relinearization keys are combined to create a multiparty relinearization key (step 3).
Step 1: User 1 generates an individual relinearization key
Step 2: User 2 generates an individual relinearization key
Step 3: The coordinator generates the multiparty relinearization key
relinearization_key = common_engine.create_multiparty_relinearization_key(
[relinearization_key1, relinearization_key2]
)
E. Multiplication in Multiparty Computation
In multiparty computation, multiplications are performed using the multiparty relinearization key (generated in section D). This operation can be done by anyone, including the coordinator. The same applies to the other operations that require a key, such as roll, rotation, and conjugation, which use the multiparty keys of the following sections.
Step 1: Users encrypt their data with the multiparty public key
data1 = [1, 2, 3]
encrypted1 = engine1.encrypt(data1, public_key)
data2 = [4, 5, 6]
encrypted2 = engine2.encrypt(data2, public_key)
Step 2: Multiply the ciphertexts with the multiparty relinearization key
In this example, user 1 performs the multiplication.
Step 3: Decrypt the result as in section C
decrypted_share1 = engine1.individual_decrypt(multiplied, secret_key1)
decrypted_share2 = engine2.individual_decrypt(multiplied, secret_key2)
decrypted = common_engine.multiparty_decrypt(
multiplied, [decrypted_share1, decrypted_share2]
)
F. Create Multiparty Fixed Roll Key
Using the multiparty public key (generated in section A), each user generates its own individual fixed roll key (steps 1 and 2) and shares it with the coordinator. These individual fixed roll keys are then used to create a multiparty fixed roll key (step 3). With the multiparty fixed roll key, it is possible to roll any ciphertext encrypted with the multiparty public key to the right by the fixed shift value.
Step 1: User 1 generates an individual fixed roll key
Step 2: User 2 generates an individual fixed roll key
Step 3: The coordinator generates the multiparty fixed roll key
fixed_roll_key = common_engine.create_multiparty_fixed_roll_key(
[fixed_roll_key1, fixed_roll_key2]
)
G. Create Multiparty Roll Key
Using the multiparty public key (generated in section A), each user generates its own individual roll key (steps 1 and 2) and shares it with the coordinator. These individual roll keys are then used to create a multiparty roll key (step 3). With the multiparty roll key, it is possible to roll any ciphertext encrypted with the multiparty public key to the right by any shift value.
Step 1: User 1 generates an individual roll key
Step 2: User 2 generates an individual roll key
Step 3: The coordinator generates the multiparty roll key
H. Create Multiparty Fixed Rotation Key
Using the multiparty public key (generated in section A), each user generates its own individual fixed rotation key (steps 1 and 2) and shares it with the coordinator. These individual fixed rotation keys are then used to create a multiparty fixed rotation key (step 3). With the multiparty fixed rotation key, it is possible to rotate any ciphertext encrypted with the multiparty public key to the left by the fixed delta value.
Step 1: User 1 generates an individual fixed rotation key
fixed_rotation_key1 = engine1.create_individual_fixed_rotation_key(
secret_key1, public_key, delta=2
)
Step 2: User 2 generates an individual fixed rotation key
fixed_rotation_key2 = engine2.create_individual_fixed_rotation_key(
secret_key2, public_key, delta=2
)
Step 3: The coordinator generates the multiparty fixed rotation key
fixed_rotation_key = common_engine.create_multiparty_fixed_rotation_key(
[fixed_rotation_key1, fixed_rotation_key2]
)
I. Create Multiparty Rotation Key
Using the multiparty public key (generated in section A), each user generates its own individual rotation key (steps 1 and 2) and shares it with the coordinator. These individual rotation keys are then used to create a multiparty rotation key (step 3). With the multiparty rotation key, it is possible to rotate any ciphertext encrypted with the multiparty public key to the left by any delta value.
Step 1: User 1 generates an individual rotation key
Step 2: User 2 generates an individual rotation key
Step 3: The coordinator generates the multiparty rotation key
J. Create Multiparty Conjugation Key
Using the multiparty public key (generated in section A), each user generates its own individual conjugation key (steps 1 and 2) and shares it with the coordinator. These individual conjugation keys are then used to create a multiparty conjugation key (step 3). With the multiparty conjugation key, it is possible to apply a conjugation to any ciphertext encrypted with the multiparty public key.