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 "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 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 "ient_enc,
104 &cks.iter()
105 .map(|k| k.gen_decryption_share("ient_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}