Skip to content

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).

data = [1, 2, 3]
encrypted = engine1.encrypt(data, public_key)

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

decrypted_share1 = engine1.individual_decrypt(encrypted, secret_key1)

Step 2: User 2 generates a decrypted share using its own secret key

decrypted_share2 = engine2.individual_decrypt(encrypted, secret_key2)

Step 3: The coordinator decrypts the data using the decrypted shares

decrypted = common_engine.multiparty_decrypt(
    encrypted, [decrypted_share1, decrypted_share2]
)

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

relinearization_key1 = engine1.create_individual_relinearization_key(
    secret_key1, public_key
)

Step 2: User 2 generates an individual relinearization key

relinearization_key2 = engine2.create_individual_relinearization_key(
    secret_key2, public_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.

multiplied = engine1.multiply(encrypted1, encrypted2, relinearization_key)

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

fixed_roll_key1 = engine1.create_individual_fixed_roll_key(
    secret_key1, public_key, shift=2
)

Step 2: User 2 generates an individual fixed roll key

fixed_roll_key2 = engine2.create_individual_fixed_roll_key(
    secret_key2, public_key, shift=2
)

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

roll_key1 = engine1.create_individual_roll_key(secret_key1, public_key)

Step 2: User 2 generates an individual roll key

roll_key2 = engine2.create_individual_roll_key(secret_key2, public_key)

Step 3: The coordinator generates the multiparty roll key

roll_key = common_engine.create_multiparty_roll_key([roll_key1, roll_key2])

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

rotation_key1 = engine1.create_individual_rotation_key(secret_key1, public_key)

Step 2: User 2 generates an individual rotation key

rotation_key2 = engine2.create_individual_rotation_key(secret_key2, public_key)

Step 3: The coordinator generates the multiparty rotation key

rotation_key = common_engine.create_multiparty_rotation_key(
    [rotation_key1, rotation_key2]
)

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.

Step 1: User 1 generates an individual conjugation key

conjugation_key1 = engine1.create_individual_conjugation_key(
    secret_key1, public_key
)

Step 2: User 2 generates an individual conjugation key

conjugation_key2 = engine2.create_individual_conjugation_key(
    secret_key2, public_key
)

Step 3: The coordinator generates the multiparty conjugation key

conjugation_key = common_engine.create_multiparty_conjugation_key(
    [conjugation_key1, conjugation_key2]
)