phantom-zone/examples/div_by_zero.rs
examples/div_by_zero.rsRaw
1use bin_rs::*;
2use itertools::Itertools;
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 "ient_enc,
51 &cks.iter()
52 .map(|k| k.gen_decryption_share("ient_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 denominator = thread_rng().gen::<u8>();
87 let numerator_enc = cks[0]
88 .encrypt(vec![numerator].as_slice())
89 .unseed::<Vec<Vec<u64>>>()
90 .key_switch(0)
91 .extract_at(0);
92 let denominator_enc = cks[1]
93 .encrypt(vec![denominator].as_slice())
94 .unseed::<Vec<Vec<u64>>>()
95 .key_switch(1)
96 .extract_at(0);
97
98 let (quotient_enc, remainder_enc) = numerator_enc.div_rem(&denominator_enc);
99 let quotient = cks[0].aggregate_decryption_shares(
100 "ient_enc,
101 &cks.iter()
102 .map(|k| k.gen_decryption_share("ient_enc))
103 .collect_vec(),
104 );
105 let remainder = cks[0].aggregate_decryption_shares(
106 &remainder_enc,
107 &cks.iter()
108 .map(|k| k.gen_decryption_share(&remainder_enc))
109 .collect_vec(),
110 );
111 assert!(quotient == numerator.div_euclid(denominator));
112 assert!(remainder == numerator.rem_euclid(denominator));
113
114 // Div by zero error flag must be set to False
115 let div_by_zero_enc = div_zero_error_flag().expect("We performed division. Flag must be set");
116 let div_by_zero = cks[0].aggregate_decryption_shares(
117 &div_by_zero_enc,
118 &cks.iter()
119 .map(|k| k.gen_decryption_share(&div_by_zero_enc))
120 .collect_vec(),
121 );
122 assert!(div_by_zero == false);
123}