phantom-zone/examples/meeting_friends.rs
examples/meeting_friends.rsRaw
1use bin_rs::*;
2use itertools::Itertools;
3use rand::{thread_rng, RngCore};
4
5struct Location<T>(T, T);
6
7impl<T> Location<T> {
8 fn new(x: T, y: T) -> Self {
9 Location(x, y)
10 }
11
12 fn x(&self) -> &T {
13 &self.0
14 }
15 fn y(&self) -> &T {
16 &self.1
17 }
18}
19
20fn should_meet(a: &Location<u8>, b: &Location<u8>, b_threshold: &u8) -> bool {
21 let diff_x = a.x() - b.x();
22 let diff_y = a.y() - b.y();
23 let d_sq = &(&diff_x * &diff_x) + &(&diff_y * &diff_y);
24
25 d_sq.le(b_threshold)
26}
27
28/// Calculates distance square between a's and b's location. Returns a boolean
29/// indicating whether diatance sqaure is <= `b_threshold`.
30fn should_meet_fhe(
31 a: &Location<FheUint8>,
32 b: &Location<FheUint8>,
33 b_threshold: &FheUint8,
34) -> FheBool {
35 let diff_x = a.x() - b.x();
36 let diff_y = a.y() - b.y();
37 let d_sq = &(&diff_x * &diff_x) + &(&diff_y * &diff_y);
38
39 d_sq.le(b_threshold)
40}
41
42// Even wondered who are the long distance friends (friends of friends or
43// friends of friends of friends...) that live nearby ? But how do you find
44// them? Surely no-one will simply reveal their exact location just because
45// there's a slight chance that a long distance friend lives nearby.
46//
47// Here we write a simple application with two users `a` and `b`. User `a` wants
48// to find (long distance) friends that live in their neighbourhood. User `b` is
49// open to meeting new friends within some distance of their location. Both user
50// `a` and `b` encrypt their location and upload to the server. User `b` also
51// encrypts the distance square threshold within which they are interested in
52// meeting new friends. The server calculates the square of the distance between
53// user a's location and user b's location and returns encrypted boolean output
54// indicating whether square of distance is <= user b's supplied distance square
55// threshold. User `a` then comes online, downloads output ciphertext, produces
56// their decryption share for user `b`, and uploads the decryption share to the
57// server. User `b` comes online, downloads output ciphertext and user a's
58// decryption share, produces their own decryption share, and then decrypts the
59// encrypted boolean output. If the output is `True`, it indicates
60// user `a` is within the distance square threshold defined by user `b`.
61fn main() {
62 set_parameter_set(ParameterSelector::NonInteractiveLTE2Party);
63
64 // set application's common reference seed
65 let mut seed = [0u8; 32];
66 thread_rng().fill_bytes(&mut seed);
67 set_common_reference_seed(seed);
68
69 let no_of_parties = 2;
70
71 // Client Side //
72
73 // Generate client keys
74 let cks = (0..no_of_parties).map(|_| gen_client_key()).collect_vec();
75
76 // We assign id 0 to client 0 and id 1 to client 1
77 let a_id = 0;
78 let b_id = 1;
79 let user_a_secret = &cks[0];
80 let user_b_secret = &cks[1];
81
82 // User a and b generate server key shares
83 let a_server_key_share = gen_server_key_share(a_id, no_of_parties, user_a_secret);
84 let b_server_key_share = gen_server_key_share(b_id, no_of_parties, user_b_secret);
85
86 // User a and b encrypt their locations
87 let user_a_secret = &cks[0];
88 let user_a_location = Location::new(50, 60);
89 let user_a_enc =
90 user_a_secret.encrypt(vec![*user_a_location.x(), *user_a_location.y()].as_slice());
91
92 let user_b_location = Location::new(50, 60);
93 // User b also encrypts the distance sq threshold
94 let user_b_threshold = 20;
95 let user_b_enc = user_b_secret
96 .encrypt(vec![*user_b_location.x(), *user_b_location.y(), user_b_threshold].as_slice());
97
98 // Server Side //
99
100 // Both user a and b upload their private inputs and server key shares to
101 // the server in one shot message
102 let server_key = aggregate_server_key_shares(&vec![a_server_key_share, b_server_key_share]);
103 server_key.set_server_key();
104
105 // Server parses private inputs from user a and b
106 let user_a_location_enc = {
107 let c = user_a_enc.unseed::<Vec<Vec<u64>>>().key_switch(0);
108 Location::new(c.extract_at(0), c.extract_at(1))
109 };
110 let (user_b_location_enc, user_b_threshold_enc) = {
111 let c = user_b_enc.unseed::<Vec<Vec<u64>>>().key_switch(1);
112 (
113 Location::new(c.extract_at(0), c.extract_at(1)),
114 c.extract_at(2),
115 )
116 };
117
118 // run the circuit
119 let out_c = should_meet_fhe(
120 &user_a_location_enc,
121 &user_b_location_enc,
122 &user_b_threshold_enc,
123 );
124
125 // Client Side //
126
127 // user a comes online, downloads out_c, produces a decryption share, and
128 // uploads the decryption share to the server.
129 let a_dec_share = user_a_secret.gen_decryption_share(&out_c);
130
131 // user b comes online downloads user a's decryption share, generates their
132 // own decryption share, decrypts the output ciphertext. If the output is
133 // True, they contact user a to meet.
134 let b_dec_share = user_b_secret.gen_decryption_share(&out_c);
135 let out_bool =
136 user_b_secret.aggregate_decryption_shares(&out_c, &vec![b_dec_share, a_dec_share]);
137
138 assert_eq!(
139 out_bool,
140 should_meet(&user_a_location, &user_b_location, &user_b_threshold)
141 );
142
143 if out_bool {
144 println!("A lives nearby. B should meet A.");
145 } else {
146 println!("A lives too far away!")
147 }
148}