1use curve25519_dalek::ristretto::RistrettoBasepointTable;
17use curve25519_dalek::ristretto::RistrettoPoint;
18use curve25519_dalek::scalar::Scalar;
19use curve25519_dalek::traits::IsIdentity;
20
21use lox_zkp::CompactProof;
22use lox_zkp::ProofError;
23use lox_zkp::Transcript;
24
25use serde::{Deserialize, Serialize};
26use serde_with::serde_as;
27
28#[cfg(feature = "bridgeauth")]
29use super::super::bridge_table;
30use super::super::bridge_table::BridgeLine;
31use super::super::cred;
32#[cfg(feature = "bridgeauth")]
33use super::super::dup_filter::SeenType;
34use super::super::IssuerPubKey;
35#[cfg(feature = "bridgeauth")]
36use super::super::CMZ_A_TABLE;
37use super::super::OPENINV_LENGTH;
38#[cfg(feature = "bridgeauth")]
39use super::super::{BridgeAuth, BridgeDb};
40use super::super::{CMZ_A, CMZ_B, CMZ_B_TABLE};
41
42#[serde_as]
44#[derive(Serialize, Deserialize)]
45pub struct Request {
46 #[serde_as(as = "[_; OPENINV_LENGTH]")]
47 invite: [u8; OPENINV_LENGTH],
48 D: RistrettoPoint,
49 EncIdClient: (RistrettoPoint, RistrettoPoint),
50 piUserBlinding: CompactProof,
51}
52
53#[derive(Debug, Serialize, Deserialize)]
55pub struct State {
56 d: Scalar,
57 D: RistrettoPoint,
58 EncIdClient: (RistrettoPoint, RistrettoPoint),
59 id_client: Scalar,
60}
61
62#[derive(Serialize, Deserialize)]
64pub struct Response {
65 P: RistrettoPoint,
66 EncQ: (RistrettoPoint, RistrettoPoint),
67 id_server: Scalar,
68 TId: RistrettoPoint,
69 bucket: Scalar,
70 level_since: Scalar,
71 piBlindIssue: CompactProof,
72 bridge_line: BridgeLine,
73}
74
75define_proof! {
77 userblinding,
78 "Open Invitation User Blinding",
79 (d, eid_client, id_client),
80 (D, EncIdClient0, EncIdClient1),
81 (B) :
82 D = (d*B),
83 EncIdClient0 = (eid_client*B),
84 EncIdClient1 = (id_client*B + eid_client*D)
85}
86
87define_proof! {
89 blindissue,
90 "Open Invitation Blind Issuing",
91 (x0, x0tilde, xid, xbucket, xsince, s, b, tid),
92 (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xsince, Pbucket, Psince, TId,
93 D, EncId0, EncId1),
94 (A, B) :
95 Xid = (xid*A),
96 Xbucket = (xbucket*A),
97 Xsince = (xsince*A),
98 X0 = (x0*B + x0tilde*A),
99 P = (b*B),
100 TId = (b*Xid),
101 TId = (tid*A),
102 EncQ0 = (s*B + tid*EncId0),
103 EncQ1 = (s*D + tid*EncId1 + x0*P + xbucket*Pbucket + xsince*Psince)
104}
105
106pub fn request(invite: &[u8; OPENINV_LENGTH]) -> (Request, State) {
109 let B: &RistrettoPoint = &CMZ_B;
110 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
111
112 let mut rng = rand::thread_rng();
114 let d = Scalar::random(&mut rng);
115 let D = &d * Btable;
116
117 let id_client = Scalar::random(&mut rng);
119
120 let eid_client = Scalar::random(&mut rng);
123 let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
124
125 let mut transcript = Transcript::new(b"open invite user blinding");
127 let piUserBlinding = userblinding::prove_compact(
128 &mut transcript,
129 userblinding::ProveAssignments {
130 B,
131 D: &D,
132 EncIdClient0: &EncIdClient.0,
133 EncIdClient1: &EncIdClient.1,
134 d: &d,
135 eid_client: &eid_client,
136 id_client: &id_client,
137 },
138 )
139 .0;
140 (
141 Request {
142 invite: *invite,
143 D,
144 EncIdClient,
145 piUserBlinding,
146 },
147 State {
148 d,
149 D,
150 EncIdClient,
151 id_client,
152 },
153 )
154}
155
156#[cfg(feature = "bridgeauth")]
157impl BridgeAuth {
158 pub fn handle_open_invite(&mut self, req: Request) -> Result<Response, ProofError> {
161 let mut old_token: Option<((Scalar, u32), usize)> = Default::default();
165 let invite_id: Scalar;
166 let bucket_id: u32;
167 for (i, old_openinv_key) in self.old_keys.bridgedb_key.iter().enumerate() {
169 old_token = match BridgeDb::verify(req.invite, *old_openinv_key) {
170 Ok(res) => Some((res, i)),
171 Err(_) => None,
172 };
173 }
174
175 if old_token.is_some() {
177 (invite_id, bucket_id) = old_token.unwrap().0;
179 if self
180 .old_filters
181 .openinv_filter
182 .get_mut(old_token.unwrap().1)
183 .unwrap()
184 .filter(&invite_id)
185 == SeenType::Seen
186 {
187 return Err(ProofError::VerificationFailure);
188 }
189 } else {
191 (invite_id, bucket_id) = match BridgeDb::verify(req.invite, self.bridgedb_pub) {
192 Ok(res) => res,
193 Err(_) => return Err(ProofError::VerificationFailure),
195 };
196 if self.bridgedb_pub_filter.filter(&invite_id) == SeenType::Seen {
198 return Err(ProofError::VerificationFailure);
199 }
200 }
201
202 if !self.bridge_table.buckets.contains_key(&bucket_id) {
204 return Err(ProofError::VerificationFailure);
205 }
206
207 let A: &RistrettoPoint = &CMZ_A;
208 let B: &RistrettoPoint = &CMZ_B;
209 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
210 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
211
212 let mut transcript = Transcript::new(b"open invite user blinding");
214 userblinding::verify_compact(
215 &req.piUserBlinding,
216 &mut transcript,
217 userblinding::VerifyAssignments {
218 B: &B.compress(),
219 EncIdClient0: &req.EncIdClient.0.compress(),
220 EncIdClient1: &req.EncIdClient.1.compress(),
221 D: &req.D.compress(),
222 },
223 )?;
224
225 let mut rng = rand::thread_rng();
228 let id_server = Scalar::random(&mut rng);
229 let EncId = (req.EncIdClient.0, req.EncIdClient.1 + &id_server * Btable);
230
231 let bucket_key = self.bridge_table.keys.get(&bucket_id).unwrap();
234 let bucket: Scalar = bridge_table::to_scalar(bucket_id, bucket_key);
235 let bridge_lines = self.bridge_table.buckets.get(&bucket_id).unwrap();
236 let bridge_line = bridge_lines[0];
237
238 let level_since: Scalar = self.today().into();
241
242 let b = Scalar::random(&mut rng);
244 let P = &b * Btable;
245 let QHc =
247 (self.lox_priv.x[0] + self.lox_priv.x[2] * bucket + self.lox_priv.x[4] * level_since)
248 * P;
249
250 let s = Scalar::random(&mut rng);
252 let EncQHc = (&s * Btable, QHc + s * req.D);
253
254 let tid = self.lox_priv.x[1] * b;
257 let TId = &tid * Atable;
258 let EncQId = (tid * EncId.0, tid * EncId.1);
259
260 let EncQ = (EncQHc.0 + EncQId.0, EncQHc.1 + EncQId.1);
261
262 let mut transcript = Transcript::new(b"open invite issuing");
263 let piBlindIssue = blindissue::prove_compact(
264 &mut transcript,
265 blindissue::ProveAssignments {
266 A,
267 B,
268 P: &P,
269 EncQ0: &EncQ.0,
270 EncQ1: &EncQ.1,
271 X0: &self.lox_pub.X[0],
272 Xid: &self.lox_pub.X[1],
273 Xbucket: &self.lox_pub.X[2],
274 Xsince: &self.lox_pub.X[4],
275 Pbucket: &(bucket * P),
276 Psince: &(level_since * P),
277 TId: &TId,
278 D: &req.D,
279 EncId0: &EncId.0,
280 EncId1: &EncId.1,
281 x0: &self.lox_priv.x[0],
282 x0tilde: &self.lox_priv.x0tilde,
283 xid: &self.lox_priv.x[1],
284 xbucket: &self.lox_priv.x[2],
285 xsince: &self.lox_priv.x[4],
286 s: &s,
287 b: &b,
288 tid: &tid,
289 },
290 )
291 .0;
292
293 Ok(Response {
294 P,
295 EncQ,
296 id_server,
297 TId,
298 bucket,
299 level_since,
300 piBlindIssue,
301 bridge_line,
302 })
303 }
304}
305
306pub fn handle_response(
309 state: State,
310 resp: Response,
311 lox_pub: &IssuerPubKey,
312) -> Result<(cred::Lox, BridgeLine), ProofError> {
313 let A: &RistrettoPoint = &CMZ_A;
314 let B: &RistrettoPoint = &CMZ_B;
315 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
316
317 if resp.P.is_identity() {
318 return Err(ProofError::VerificationFailure);
319 }
320
321 let id = state.id_client + resp.id_server;
324 let EncId = (
325 state.EncIdClient.0,
326 state.EncIdClient.1 + &resp.id_server * Btable,
327 );
328
329 let mut transcript = Transcript::new(b"open invite issuing");
331 blindissue::verify_compact(
332 &resp.piBlindIssue,
333 &mut transcript,
334 blindissue::VerifyAssignments {
335 A: &A.compress(),
336 B: &B.compress(),
337 P: &resp.P.compress(),
338 EncQ0: &resp.EncQ.0.compress(),
339 EncQ1: &resp.EncQ.1.compress(),
340 X0: &lox_pub.X[0].compress(),
341 Xid: &lox_pub.X[1].compress(),
342 Xbucket: &lox_pub.X[2].compress(),
343 Xsince: &lox_pub.X[4].compress(),
344 Pbucket: &(resp.bucket * resp.P).compress(),
345 Psince: &(resp.level_since * resp.P).compress(),
346 TId: &resp.TId.compress(),
347 D: &state.D.compress(),
348 EncId0: &EncId.0.compress(),
349 EncId1: &EncId.1.compress(),
350 },
351 )?;
352
353 let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
355
356 Ok((
357 cred::Lox {
358 P: resp.P,
359 Q,
360 id,
361 bucket: resp.bucket,
362 trust_level: Scalar::ZERO,
363 level_since: resp.level_since,
364 invites_remaining: Scalar::ZERO,
365 blockages: Scalar::ZERO,
366 },
367 resp.bridge_line,
368 ))
369}