arnaucube
arnaucube/phantom-zonePublic Self-hosted repository
phantom-zone/examples/div_by_zero.rs
examples/div_by_zero.rsRaw
  1use itertools::Itertools;
  2use phantom_zone::*;
  3use rand::{thread_rng, Rng, RngCore};
  4
  5fn main() {
  6    set_parameter_set(ParameterSelector::NonInteractiveLTE2Party);
  7
  8    // set application's common reference seed
  9    let mut seed = [0u8; 32];
 10    thread_rng().fill_bytes(&mut seed);
 11    set_common_reference_seed(seed);
 12
 13    let no_of_parties = 2;
 14
 15    // Generate client keys
 16    let cks = (0..no_of_parties).map(|_| gen_client_key()).collect_vec();
 17
 18    // Generate server key shares
 19    let server_key_shares = cks
 20        .iter()
 21        .enumerate()
 22        .map(|(id, k)| gen_server_key_share(id, no_of_parties, k))
 23        .collect_vec();
 24
 25    // Aggregate server key shares and set the server key
 26    let server_key = aggregate_server_key_shares(&server_key_shares);
 27    server_key.set_server_key();
 28
 29    // --------
 30
 31    // We attempt to divide by 0 in encrypted domain and then check whether div by 0
 32    // error flag is set to True.
 33    let numerator = thread_rng().gen::<u8>();
 34    let numerator_enc = cks[0]
 35        .encrypt(vec![numerator].as_slice())
 36        .unseed::<Vec<Vec<u64>>>()
 37        .key_switch(0)
 38        .extract_at(0);
 39    let zero_enc = cks[1]
 40        .encrypt(vec![0].as_slice())
 41        .unseed::<Vec<Vec<u64>>>()
 42        .key_switch(1)
 43        .extract_at(0);
 44
 45    let (quotient_enc, remainder_enc) = numerator_enc.div_rem(&zero_enc);
 46
 47    // When attempting to divide by zero, for uint8 quotient is always 255 and
 48    // remainder = numerator
 49    let quotient = cks[0].aggregate_decryption_shares(
 50        &quotient_enc,
 51        &cks.iter()
 52            .map(|k| k.gen_decryption_share(&quotient_enc))
 53            .collect_vec(),
 54    );
 55    let remainder = cks[0].aggregate_decryption_shares(
 56        &remainder_enc,
 57        &cks.iter()
 58            .map(|k| k.gen_decryption_share(&remainder_enc))
 59            .collect_vec(),
 60    );
 61    assert!(quotient == 255);
 62    assert!(remainder == numerator);
 63
 64    // Div by zero error flag must be True
 65    let div_by_zero_enc = div_zero_error_flag().expect("We performed division. Flag must be set");
 66    let div_by_zero = cks[0].aggregate_decryption_shares(
 67        &div_by_zero_enc,
 68        &cks.iter()
 69            .map(|k| k.gen_decryption_share(&div_by_zero_enc))
 70            .collect_vec(),
 71    );
 72    assert!(div_by_zero == true);
 73
 74    // -------
 75
 76    // div by zero error flag is thread local. If we were to run another circuit
 77    // without stopping the thread (i.e. within the same program as previous
 78    // one), we must reset errors flags set by previous circuit with
 79    // `reset_error_flags()` to prevent error flags of previous circuit affecting
 80    // the flags of the next circuit.
 81    reset_error_flags();
 82
 83    // We divide again but with non-zero denominator this time and check that div
 84    // by zero flag is set to False
 85    let numerator = thread_rng().gen::<u8>();
 86    let mut denominator = thread_rng().gen::<u8>();
 87    while denominator == 0 {
 88        denominator = thread_rng().gen::<u8>();
 89    }
 90    let numerator_enc = cks[0]
 91        .encrypt(vec![numerator].as_slice())
 92        .unseed::<Vec<Vec<u64>>>()
 93        .key_switch(0)
 94        .extract_at(0);
 95    let denominator_enc = cks[1]
 96        .encrypt(vec![denominator].as_slice())
 97        .unseed::<Vec<Vec<u64>>>()
 98        .key_switch(1)
 99        .extract_at(0);
100
101    let (quotient_enc, remainder_enc) = numerator_enc.div_rem(&denominator_enc);
102    let quotient = cks[0].aggregate_decryption_shares(
103        &quotient_enc,
104        &cks.iter()
105            .map(|k| k.gen_decryption_share(&quotient_enc))
106            .collect_vec(),
107    );
108    let remainder = cks[0].aggregate_decryption_shares(
109        &remainder_enc,
110        &cks.iter()
111            .map(|k| k.gen_decryption_share(&remainder_enc))
112            .collect_vec(),
113    );
114    assert!(quotient == numerator.div_euclid(denominator));
115    assert!(remainder == numerator.rem_euclid(denominator));
116
117    // Div by zero error flag must be set to False
118    let div_by_zero_enc = div_zero_error_flag().expect("We performed division. Flag must be set");
119    let div_by_zero = cks[0].aggregate_decryption_shares(
120        &div_by_zero_enc,
121        &cks.iter()
122            .map(|k| k.gen_decryption_share(&div_by_zero_enc))
123            .collect_vec(),
124    );
125    assert!(div_by_zero == false);
126}