From c38d9108461e937174b157170cb950ee3a6bf1a8 Mon Sep 17 00:00:00 2001 From: Janmajaya Mall Date: Sat, 6 Jul 2024 22:29:45 +0530 Subject: [PATCH] fix examples --- README.md | 8 +++--- examples/bomberman.rs | 2 +- examples/div_by_zero.rs | 9 ++++--- examples/if_and_else.rs | 6 ++--- examples/interactive_fheuint8.rs | 37 ++++++++++++++-------------- examples/meeting_friends.rs | 20 +++++++-------- examples/non_interactive_fheuint8.rs | 6 ++--- 7 files changed, 45 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index e374289..0a62520 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -"Phantom zone" is similar to the zone in which superman gets locked, but it's not meant to lock anyone. It's meant to be a new zone in parallel to reality. It's the zone to which you port yourself, with others, to, and take arbitrary actions but only remember the things you preconditioned yourself to rememeber when you are back. Think of the zone as a computer that erases itself off of the face of the earth after it returns the output, leaving no trace behind. +"**Phantom zone**" is similar to the zone in which superman gets locked, but it's not meant to lock anyone. It's meant to be a new zone in parallel to reality. It's the zone to which you teleport yourself with others, perform arbitrary actions together, and remember only predefined set of memories when you're back. Think of the zone as a computer that erases itself off of the face of the earth after it returns the output, leaving no trace behind. -More formally, phantom-zone is a experimental multi-party computation library that uses fully homomorphic encryption to compute arbitrary functions on private inputs from several parties. +**More formally, phantom-zone is a experimental multi-party computation library that uses multi-party fully homomorphic encryption to compute arbitrary functions on private inputs from several parties.** At the moment phantom-zone is pretty limited in its functionality. It offers to write circuits with encrypted 8 bit unsigned integers (referred to as FheUint8). You can work with FheUint8 like any normal Uint8 with a few exceptions mentioned below. We don't plan to just stick with 8 bit types and have plans to extend the APIs to more unsigned / signed types. @@ -28,7 +28,7 @@ To decrypt encrypted outputs obtained as result of some computation, the clients We provide parameters to run both multi-party protocols for upto 8 parties. -| <= # Parties | Interactive multi-party | Non-interactive multi-party | +| $\leq$ # Parties | Interactive multi-party | Non-interactive multi-party | | ------------ | ----------------------- | --------------------------- | | 2 | InteractiveLTE2Party | NonInteractiveLTE2Party | | 4 | InteractiveLTE4Party | NonInteractiveLTE4Party | @@ -67,7 +67,7 @@ Branching in encrypted domain is expensive because the code must execute all the > [!WARNING] > Code has not been audited and, at the moment, we don't provide any security guarantees. We don't recommend to deploy it in production or to be used to handle important data. -All provided parameters are $2^{128}$ ring operations secure and have failure probability of at-least $2^{-40}$. However, there are two vital points to keep in mind: +All provided parameters are $2^{128}$ ring operations secure and have failure probability of $ \leq 2^{-40}$. However, there are two vital points to keep in mind: 1. Any user, without refreshing secrets, must not generate decryption shares for a given ciphertext more than once. Technically, it is insecure if a secret key generates two different decryption shares for the same ciphertext because it may lead to recovery of the ideal secret key with certain probability. At the moment, we recommend the users to maintain a local table that tracks ciphertexts for which they have generated decryption shares using their secret. And only generate a new decryption share for a ciphertext if the ciphertext does not exists in the local table. 2. At the moment, users, without refreshing secrets, must not run the protocol twice using the same application seed and produce different outputs. Technically, it is insecure if two different MPC transcripts are produced using same application seed and user secret. However, this must be handled within the library and is a pending feature to be implemented in future. diff --git a/examples/bomberman.rs b/examples/bomberman.rs index fe5bba2..8438c09 100644 --- a/examples/bomberman.rs +++ b/examples/bomberman.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; struct Coordinates(T, T); diff --git a/examples/div_by_zero.rs b/examples/div_by_zero.rs index 2a525ce..e5b56f5 100644 --- a/examples/div_by_zero.rs +++ b/examples/div_by_zero.rs @@ -1,5 +1,5 @@ -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; fn main() { @@ -44,7 +44,7 @@ fn main() { let (quotient_enc, remainder_enc) = numerator_enc.div_rem(&zero_enc); - // When attempting to divide by zero, for uint8, quotient is always 255 and + // When attempting to divide by zero, for uint8 quotient is always 255 and // remainder = numerator let quotient = cks[0].aggregate_decryption_shares( "ient_enc, @@ -83,7 +83,10 @@ fn main() { // We divide again but with non-zero denominator this time and check that div // by zero flag is set to False let numerator = thread_rng().gen::(); - let denominator = thread_rng().gen::(); + let mut denominator = thread_rng().gen::(); + while denominator == 0 { + denominator = thread_rng().gen::(); + } let numerator_enc = cks[0] .encrypt(vec![numerator].as_slice()) .unseed::>>() diff --git a/examples/if_and_else.rs b/examples/if_and_else.rs index dff8047..bf2f8ea 100644 --- a/examples/if_and_else.rs +++ b/examples/if_and_else.rs @@ -1,13 +1,13 @@ -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; -/// Code that runs if condition of conditional branch is `True` +/// Code that runs when conditional branch is `True` fn circuit_branch_true(a: &FheUint8, b: &FheUint8) -> FheUint8 { a + b } -/// Code that runs if condition of conditional branch is `False` +/// Code that runs when conditional branch is `False` fn circuit_branch_false(a: &FheUint8, b: &FheUint8) -> FheUint8 { a * b } diff --git a/examples/interactive_fheuint8.rs b/examples/interactive_fheuint8.rs index 3064d5a..117afd7 100644 --- a/examples/interactive_fheuint8.rs +++ b/examples/interactive_fheuint8.rs @@ -1,5 +1,5 @@ -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; fn function1(a: u8, b: u8, c: u8, d: u8) -> u8 { @@ -39,9 +39,9 @@ fn main() { // -- Round 1 -- // // In round 1 each client generates their share for the collective public key. - // They send public key shares to each other with out without server. After - // receiving others public key shares client independently aggregates the share - // and produces the collective public key `pk` + // They send public key shares to each other with or out without the server. + // After receiving others public key shares clients independently aggregate + // the shares and produce the collective public key `pk` let pk_shares = cks .iter() @@ -52,7 +52,7 @@ fn main() { let pk = aggregate_public_key_shares(&pk_shares); // -- Round 2 -- // - // In round 2 each client generates server key shares using the public key `pk`. + // In round 2 each client generates server key share using the public key `pk`. // Clients may also encrypt their private inputs using collective public key // `pk`. Each client then uploads their server key share and private input // ciphertexts to the server. @@ -71,9 +71,8 @@ fn main() { .collect_vec(); // Each client encrypts their private inputs using the collective public key - // `pk`. Unlike non-inteactive MPC protocol, given that private inputs are - // encrypted using collective public key, the private inputs are directly - // encrypted under the ideal RLWE secret `s`. + // `pk`. Unlike non-inteactive MPC protocol, private inputs are + // encrypted using collective public key. let c0_a = thread_rng().gen::(); let c0_enc = pk.encrypt(vec![c0_a].as_slice()); let c1_a = thread_rng().gen::(); @@ -89,7 +88,7 @@ fn main() { // Server side // // Server receives server key shares from each client and proceeds to - // aggregated the shares and produce the server key + // aggregate the shares and produce the server key let server_key = aggregate_server_key_shares(&server_key_shares); server_key.set_server_key(); @@ -98,8 +97,8 @@ fn main() { // Clients encrypt their FheUint8s inputs packed in a batched ciphertext. // The server must extract clients private inputs from the batch ciphertext // either (1) using `extract_at(index)` to extract `index`^{th} FheUint8 - // ciphertext (2) `extract_all()` to extract all available FheUint8s (3) - // `extract_many(many)` to extract first `many` available FheUint8s + // ciphertext (2) or using `extract_all()` to extract all available FheUint8s + // (3) or using `extract_many(many)` to extract first `many` available FheUint8s let c0_a_enc = c0_enc.extract_at(0); let c1_a_enc = c1_enc.extract_at(0); let c2_a_enc = c2_enc.extract_at(0); @@ -109,25 +108,25 @@ fn main() { let ct_out_f1 = function1_fhe(&c0_a_enc, &c1_a_enc, &c2_a_enc, &c3_a_enc); // After server has finished evaluating the circuit on client private - // inputs. Clients can proceed to multi-party decryption protocol to - // decryption output ciphertext + // inputs, clients can proceed to multi-party decryption protocol to + // decrypt output ciphertext // Client Side // // In multi-party decryption protocol, client must come online, download the // output ciphertext from the server, product "output ciphertext" dependent // decryption share, and send it to other parties. After receiving - // decryption shares of other parties, client independently aggregates the - // decrytion shares and decrypts the output ciphertext. + // decryption shares of other parties, clients independently aggregate the + // decrytion shares and decrypt the output ciphertext. - // Client generate decryption shares + // Clients generate decryption shares let decryption_shares = cks .iter() .map(|k| k.gen_decryption_share(&ct_out_f1)) .collect_vec(); - // After receiving decryption shares from other parties, client aggregates the - // shares and decryption output ciphertext + // After receiving decryption shares from other parties, clients aggregate the + // shares and decrypt output ciphertext let out_f1 = cks[0].aggregate_decryption_shares(&ct_out_f1, &decryption_shares); // Check correctness of function1 output @@ -158,7 +157,7 @@ fn main() { // Server side // - // Server receives private inputs from the clients, extract them, and + // Server receives private inputs from the clients, extracts them, and // proceeds to evaluate `function2_fhe` let c0_a_enc = c0_enc.extract_at(0); let c1_a_enc = c1_enc.extract_at(0); diff --git a/examples/meeting_friends.rs b/examples/meeting_friends.rs index 856b28f..d3a877c 100644 --- a/examples/meeting_friends.rs +++ b/examples/meeting_friends.rs @@ -1,5 +1,5 @@ -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; struct Location(T, T); @@ -39,7 +39,7 @@ fn should_meet_fhe( d_sq.le(b_threshold) } -// Even wondered who are the long distance friends (friends of friends or +// Ever wondered who are the long distance friends (friends of friends or // friends of friends of friends...) that live nearby ? But how do you find // them? Surely no-one will simply reveal their exact location just because // there's a slight chance that a long distance friend lives nearby. @@ -49,7 +49,7 @@ fn should_meet_fhe( // open to meeting new friends within some distance of their location. Both user // `a` and `b` encrypt their locations and upload their encrypted locations to // the server. User `b` also encrypts the distance square threshold within which -// they are interested in meeting new friends. and send encrypted distance +// they are interested in meeting new friends and sends encrypted distance // square threshold to the server. // The server calculates the square of the distance between user a's location // and user b's location and produces encrypted boolean output indicating @@ -75,36 +75,36 @@ fn main() { // Generate client keys let cks = (0..no_of_parties).map(|_| gen_client_key()).collect_vec(); - // We assign user_id 0 to client 0 and user_id 1 to client 1 + // We assign user_id 0 to user `a` and user_id 1 user `b` let a_id = 0; let b_id = 1; let user_a_secret = &cks[0]; let user_b_secret = &cks[1]; - // User a and b generate server key shares + // User `a` and `b` generate server key shares let a_server_key_share = gen_server_key_share(a_id, no_of_parties, user_a_secret); let b_server_key_share = gen_server_key_share(b_id, no_of_parties, user_b_secret); - // User a and b encrypt their locations + // User `a` and `b` encrypt their locations let user_a_secret = &cks[0]; let user_a_location = Location::new(thread_rng().gen::(), thread_rng().gen::()); let user_a_enc = user_a_secret.encrypt(vec![*user_a_location.x(), *user_a_location.y()].as_slice()); let user_b_location = Location::new(thread_rng().gen::(), thread_rng().gen::()); - // User b also encrypts the distance square threshold + // User `b` also encrypts the distance square threshold let user_b_threshold = 40; let user_b_enc = user_b_secret .encrypt(vec![*user_b_location.x(), *user_b_location.y(), user_b_threshold].as_slice()); // Server Side // - // Both user a and b upload their private inputs and server key shares to + // Both user `a` and `b` upload their private inputs and server key shares to // the server in single shot message let server_key = aggregate_server_key_shares(&vec![a_server_key_share, b_server_key_share]); server_key.set_server_key(); - // Server parses private inputs from user a and b + // Server parses private inputs from user `a` and `b` let user_a_location_enc = { let c = user_a_enc.unseed::>>().key_switch(a_id); Location::new(c.extract_at(0), c.extract_at(1)) @@ -132,7 +132,7 @@ fn main() { // user `b` comes online downloads user `a`'s decryption share, generates their // own decryption share, decrypts the output ciphertext. If the output is - // True, they contact user `a` to meet. + // True, user `b` contacts user `a` to meet. let b_dec_share = user_b_secret.gen_decryption_share(&out_c); let out_bool = user_b_secret.aggregate_decryption_shares(&out_c, &vec![b_dec_share, a_dec_share]); diff --git a/examples/non_interactive_fheuint8.rs b/examples/non_interactive_fheuint8.rs index 3680477..19b09d6 100644 --- a/examples/non_interactive_fheuint8.rs +++ b/examples/non_interactive_fheuint8.rs @@ -1,5 +1,5 @@ -use bin_rs::*; use itertools::Itertools; +use phantom_zone::*; use rand::{thread_rng, Rng, RngCore}; fn function1(a: u8, b: u8, c: u8, d: u8) -> u8 { @@ -81,7 +81,7 @@ fn main() { // Server proceeds to extract private inputs sent by clients // // To extract client 0's (with user_id=0) private inputs we first key switch - // client 0's private inputs from theit secret to ideal secret of the mpc + // client 0's private inputs from theit secret `u_j` to ideal secret of the mpc // protocol. To indicate we're key switching client 0's private input we // supply client 0's `user_id` i.e. we call `key_switch(0)`. Then we extract // the first ciphertext by calling `extract_at(0)`. @@ -119,7 +119,7 @@ fn main() { .map(|k| k.gen_decryption_share(&ct_out_f1)) .collect_vec(); - // With all decrytpion shares, clients can aggregate the shares and decrypt the + // With all decryption shares, clients can aggregate the shares and decrypt the // ciphertext let out_f1 = cks[0].aggregate_decryption_shares(&ct_out_f1, &decryption_shares);