1use curve25519_dalek::ristretto::RistrettoBasepointTable;
29use curve25519_dalek::ristretto::RistrettoPoint;
30use curve25519_dalek::scalar::Scalar;
31use curve25519_dalek::traits::IsIdentity;
32
33use lox_zkp::CompactProof;
34use lox_zkp::ProofError;
35use lox_zkp::Transcript;
36
37use serde::{Deserialize, Serialize};
38
39use super::super::cred;
40#[cfg(feature = "bridgeauth")]
41use super::super::dup_filter::SeenType;
42#[cfg(feature = "bridgeauth")]
43use super::super::BridgeAuth;
44use super::super::IssuerPubKey;
45use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
46
47use super::errors::CredentialError;
48
49#[derive(Serialize, Deserialize)]
50pub struct Request {
51 OldPubKey: IssuerPubKey,
53 P: RistrettoPoint,
54 id: Scalar,
55 CBucket: RistrettoPoint,
56 CLevel: RistrettoPoint,
57 CSince: RistrettoPoint,
58 CInvRemain: RistrettoPoint,
59 CBlockages: RistrettoPoint,
60 CQ: RistrettoPoint,
61
62 D: RistrettoPoint,
64 EncIdClient: (RistrettoPoint, RistrettoPoint),
65 EncBucket: (RistrettoPoint, RistrettoPoint),
66 EncLevel: (RistrettoPoint, RistrettoPoint),
67 EncSince: (RistrettoPoint, RistrettoPoint),
68 EncInvRemain: (RistrettoPoint, RistrettoPoint),
69 EncBlockages: (RistrettoPoint, RistrettoPoint),
70
71 piUser: CompactProof,
73}
74
75#[derive(Debug, Serialize, Deserialize)]
76pub struct State {
77 d: Scalar,
78 D: RistrettoPoint,
79 EncIdClient: (RistrettoPoint, RistrettoPoint),
80 EncBucket: (RistrettoPoint, RistrettoPoint),
81 EncLevel: (RistrettoPoint, RistrettoPoint),
82 EncSince: (RistrettoPoint, RistrettoPoint),
83 EncInvRemain: (RistrettoPoint, RistrettoPoint),
84 EncBlockages: (RistrettoPoint, RistrettoPoint),
85 id_client: Scalar,
86 bucket: Scalar,
87 level: Scalar,
88 since: Scalar,
89 invremain: Scalar,
90 blockages: Scalar,
91}
92
93#[derive(Serialize, Deserialize)]
94pub struct Response {
95 P: RistrettoPoint,
99 EncQ: (RistrettoPoint, RistrettoPoint),
100 id_server: Scalar,
101 TId: RistrettoPoint,
102 TBucket: RistrettoPoint,
103 TLevel: RistrettoPoint,
104 TSince: RistrettoPoint,
105 TInvRemain: RistrettoPoint,
106 TBlockages: RistrettoPoint,
107
108 piBlindIssue: CompactProof,
110}
111
112define_proof! {
113 requestproof,
114 "Update Credential Key Request",
115 (bucket, level, since, invremain, blockages, zbucket, zlevel,
116 zsince, zinvremain, zblockages, negzQ,
117 d, eid_client, ebucket, elevel, esince, einvremain, eblockages, id_client
118 ),
119 (P, CBucket, CLevel, CSince, CInvRemain, CBlockages, V, Xbucket,
120 Xlevel, Xsince, Xinvremain, Xblockages,
121 D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
122 EncLevel0, EncLevel1, EncSince0, EncSince1,
123 EncInvRemain0, EncInvRemain1, EncBlockages0, EncBlockages1
124 ),
125 (A, B):
126 CBucket = (bucket*P + zbucket*A),
128 CLevel = (level*P + zlevel*A),
129 CSince = (since*P + zsince*A),
130 CInvRemain = (invremain*P + zinvremain*A),
131 CBlockages = (blockages*P + zblockages*A),
132 D = (d*B),
134 EncIdClient0 = (eid_client*B),
135 EncIdClient1 = (id_client*B + eid_client*D),
136 EncBucket0 = (ebucket*B),
137 EncBucket1 = (bucket*B + ebucket*D),
138 EncLevel0 = (elevel*B),
139 EncLevel1 = (level*B + elevel*D),
140 EncSince0 = (esince*B),
141 EncSince1 = (since*B + esince*D),
142 EncInvRemain0 = (einvremain*B),
143 EncInvRemain1 = (invremain*B + einvremain*D),
144 EncBlockages0 = (eblockages*B),
145 EncBlockages1 = (blockages*B + eblockages*D)
146}
147
148define_proof! {
149 blindissue,
150 "Issue updated cred",
151 (x0, x0tilde, xid, xbucket, xlevel, xsince, xinvremain, xblockages,
152 s, b, tid, tbucket, tlevel, tsince, tinvremain, tblockages),
153 (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Xinvremain,
154 Xblockages, TId, TBucket, TLevel, TSince, TInvRemain, TBlockages,
155 D, EncId0, EncId1, EncBucket0, EncBucket1, EncLevel0, EncLevel1,
156 EncSince0, EncSince1, EncInvRemain0, EncInvRemain1,
157 EncBlockages0, EncBlockages1
158 ),
159 (A, B):
160 Xid = (xid*A),
161 Xbucket = (xbucket*A),
162 Xlevel = (xlevel*A),
163 Xsince = (xsince*A),
164 Xinvremain = (xinvremain*A),
165 Xblockages = (xblockages*A),
166 X0 = (x0*B + x0tilde*A),
167 P = (b*B),
168 TId = (b*Xid),
169 TId = (tid*A),
170 TBucket = (b*Xbucket),
171 TBucket = (tbucket*A),
172 TLevel = (b*Xlevel),
173 TLevel = (tlevel*A),
174 TSince = (b*Xsince),
175 TSince = (tsince*A),
176 TInvRemain = (b*Xinvremain),
177 TInvRemain = (tinvremain*A),
178 TBlockages = (b*Xblockages),
179 TBlockages = (tblockages*A),
180 EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0 + tlevel*EncLevel0
181 + tsince*EncSince0 + tinvremain*EncInvRemain0 + tblockages*EncBlockages0),
182 EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1 + tlevel*EncLevel1
183 + tsince*EncSince1 + tinvremain*EncInvRemain1 + tblockages*EncBlockages1
184 + x0*P)
185}
186
187pub fn request(
188 lox_cred: &cred::Lox,
189 lox_pub: &IssuerPubKey,
190) -> Result<(Request, State), CredentialError> {
191 let A: &RistrettoPoint = &CMZ_A;
192 let B: &RistrettoPoint = &CMZ_B;
193 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
194 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
195
196 let mut rng = rand::thread_rng();
200 let t = Scalar::random(&mut rng);
201 let P = t * lox_cred.P;
202 let Q = t * lox_cred.Q;
203
204 let zbucket = Scalar::random(&mut rng);
206 let zlevel = Scalar::random(&mut rng);
207 let zsince = Scalar::random(&mut rng);
208 let zinvremain = Scalar::random(&mut rng);
209 let zblockages = Scalar::random(&mut rng);
210 let CBucket = lox_cred.bucket * P + &zbucket * Atable;
211 let CLevel = lox_cred.trust_level * P + &zlevel * Atable;
212 let CSince = lox_cred.level_since * P + &zsince * Atable;
213 let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
214 let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
215
216 let negzQ = Scalar::random(&mut rng);
221 let CQ = Q - &negzQ * Atable;
222
223 let V = zbucket * lox_pub.X[2]
225 + zlevel * lox_pub.X[3]
226 + zsince * lox_pub.X[4]
227 + zinvremain * lox_pub.X[5]
228 + zblockages * lox_pub.X[6]
229 + &negzQ * Atable;
230
231 let d = Scalar::random(&mut rng);
235 let D = &d * Btable;
236
237 let id_client = Scalar::random(&mut rng);
239
240 let eid_client = Scalar::random(&mut rng);
243 let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
244
245 let ebucket = Scalar::random(&mut rng);
247 let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
248 let elevel = Scalar::random(&mut rng);
249 let EncLevel = (
250 &elevel * Btable,
251 &lox_cred.trust_level * Btable + elevel * D,
252 );
253 let esince = Scalar::random(&mut rng);
254 let EncSince = (
255 &esince * Btable,
256 &lox_cred.level_since * Btable + esince * D,
257 );
258 let einvremain = Scalar::random(&mut rng);
259 let EncInvRemain = (
260 &einvremain * Btable,
261 &lox_cred.invites_remaining * Btable + einvremain * D,
262 );
263 let eblockages = Scalar::random(&mut rng);
264 let EncBlockages = (
265 &eblockages * Btable,
266 &lox_cred.blockages * Btable + eblockages * D,
267 );
268
269 let mut transcript = Transcript::new(b"update credential key request");
271 let piUser = requestproof::prove_compact(
272 &mut transcript,
273 requestproof::ProveAssignments {
274 A,
275 B,
276 P: &P,
277 CBucket: &CBucket,
278 CLevel: &CLevel,
279 CSince: &CSince,
280 CInvRemain: &CInvRemain,
281 CBlockages: &CBlockages,
282 V: &V,
283 Xbucket: &lox_pub.X[2],
284 Xlevel: &lox_pub.X[3],
285 Xsince: &lox_pub.X[4],
286 Xinvremain: &lox_pub.X[5],
287 Xblockages: &lox_pub.X[6],
288 D: &D,
289 EncIdClient0: &EncIdClient.0,
290 EncIdClient1: &EncIdClient.1,
291 EncBucket0: &EncBucket.0,
292 EncBucket1: &EncBucket.1,
293 EncLevel0: &EncLevel.0,
294 EncLevel1: &EncLevel.1,
295 EncSince0: &EncSince.0,
296 EncSince1: &EncSince.1,
297 EncInvRemain0: &EncInvRemain.0,
298 EncInvRemain1: &EncInvRemain.1,
299 EncBlockages0: &EncBlockages.0,
300 EncBlockages1: &EncBlockages.1,
301 bucket: &lox_cred.bucket,
302 level: &lox_cred.trust_level,
303 since: &lox_cred.level_since,
304 invremain: &lox_cred.invites_remaining,
305 blockages: &lox_cred.blockages,
306 zbucket: &zbucket,
307 zlevel: &zlevel,
308 zsince: &zsince,
309 zinvremain: &zinvremain,
310 zblockages: &zblockages,
311 negzQ: &negzQ,
312 d: &d,
313 eid_client: &eid_client,
314 ebucket: &ebucket,
315 elevel: &elevel,
316 esince: &esince,
317 einvremain: &einvremain,
318 eblockages: &eblockages,
319 id_client: &id_client,
320 },
321 )
322 .0;
323
324 Ok((
325 Request {
326 OldPubKey: lox_pub.clone(),
327 P,
328 id: lox_cred.id,
329 CBucket,
330 CLevel,
331 CSince,
332 CInvRemain,
333 CBlockages,
334 CQ,
335 D,
336 EncIdClient,
337 EncBucket,
338 EncLevel,
339 EncSince,
340 EncInvRemain,
341 EncBlockages,
342 piUser,
343 },
344 State {
345 d,
346 D,
347 EncIdClient,
348 EncBucket,
349 EncLevel,
350 EncSince,
351 EncInvRemain,
352 EncBlockages,
353 id_client,
354 bucket: lox_cred.bucket,
355 level: lox_cred.trust_level,
356 since: lox_cred.level_since,
357 invremain: lox_cred.invites_remaining,
358 blockages: lox_cred.blockages,
359 },
360 ))
361}
362
363#[cfg(feature = "bridgeauth")]
364impl BridgeAuth {
365 pub fn handle_update_cred(&mut self, req: Request) -> Result<Response, ProofError> {
367 let A: &RistrettoPoint = &CMZ_A;
368 let B: &RistrettoPoint = &CMZ_B;
369 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
370 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
371
372 if req.P.is_identity() {
373 return Err(ProofError::VerificationFailure);
374 }
375
376 if self.old_keys.lox_keys.is_empty() || self.old_filters.lox_filter.is_empty() {
378 return Err(ProofError::VerificationFailure);
379 }
380
381 let old_keys = match self
388 .old_keys
389 .lox_keys
390 .iter()
391 .find(|x| x.pub_key == req.OldPubKey)
392 {
393 Some(old_keys) => old_keys,
394 None => return Err(ProofError::VerificationFailure),
395 };
396 let index = self
397 .old_keys
398 .lox_keys
399 .iter()
400 .position(|x| x.pub_key == old_keys.pub_key)
401 .unwrap();
402
403 let old_priv_key = old_keys.priv_key.clone();
404 let old_pub_key = old_keys.pub_key.clone();
405 let Vprime = (old_priv_key.x[0] + old_priv_key.x[1] * req.id) * req.P
406 + old_priv_key.x[2] * req.CBucket
407 + old_priv_key.x[3] * req.CLevel
408 + old_priv_key.x[4] * req.CSince
409 + old_priv_key.x[5] * req.CInvRemain
410 + old_priv_key.x[6] * req.CBlockages
411 - req.CQ;
412
413 let mut transcript = Transcript::new(b"update credential key request");
415 requestproof::verify_compact(
416 &req.piUser,
417 &mut transcript,
418 requestproof::VerifyAssignments {
419 A: &A.compress(),
420 B: &B.compress(),
421 P: &req.P.compress(),
422 CBucket: &req.CBucket.compress(),
423 CLevel: &req.CLevel.compress(),
424 CSince: &req.CSince.compress(),
425 CInvRemain: &req.CInvRemain.compress(),
426 CBlockages: &req.CBlockages.compress(),
427 V: &Vprime.compress(),
428 Xbucket: &old_pub_key.X[2].compress(),
429 Xlevel: &old_pub_key.X[3].compress(),
430 Xsince: &old_pub_key.X[4].compress(),
431 Xinvremain: &old_pub_key.X[5].compress(),
432 Xblockages: &old_pub_key.X[6].compress(),
433 D: &req.D.compress(),
434 EncIdClient0: &req.EncIdClient.0.compress(),
435 EncIdClient1: &req.EncIdClient.1.compress(),
436 EncBucket0: &req.EncBucket.0.compress(),
437 EncBucket1: &req.EncBucket.1.compress(),
438 EncLevel0: &req.EncLevel.0.compress(),
439 EncLevel1: &req.EncLevel.1.compress(),
440 EncSince0: &req.EncSince.0.compress(),
441 EncSince1: &req.EncSince.1.compress(),
442 EncInvRemain0: &req.EncInvRemain.0.compress(),
443 EncInvRemain1: &req.EncInvRemain.1.compress(),
444 EncBlockages0: &req.EncBlockages.0.compress(),
445 EncBlockages1: &req.EncBlockages.1.compress(),
446 },
447 )?;
448
449 if self
453 .old_filters
454 .lox_filter
455 .get_mut(index)
456 .unwrap()
457 .filter(&req.id)
458 == SeenType::Seen
459 {
460 return Err(ProofError::VerificationFailure);
461 }
462
463 let mut rng = rand::thread_rng();
468 let id_server = Scalar::random(&mut rng);
469 let EncId = (req.EncIdClient.0, req.EncIdClient.1 + &id_server * Btable);
470
471 let b = Scalar::random(&mut rng);
473 let P = &b * Btable;
474 let QHc = self.lox_priv.x[0] * P;
475
476 let s = Scalar::random(&mut rng);
478 let EncQHc = (&s * Btable, QHc + s * req.D);
479
480 let tid = self.lox_priv.x[1] * b;
483 let TId = &tid * Atable;
484 let EncQId = (tid * EncId.0, tid * EncId.1);
485 let tbucket = self.lox_priv.x[2] * b;
486 let TBucket = &tbucket * Atable;
487 let EncQBucket = (tbucket * req.EncBucket.0, tbucket * req.EncBucket.1);
488 let tlevel = self.lox_priv.x[3] * b;
489 let TLevel = &tlevel * Atable;
490 let EncQLevel = (tlevel * req.EncLevel.0, tlevel * req.EncLevel.1);
491 let tsince = self.lox_priv.x[4] * b;
492 let TSince = &tsince * Atable;
493 let EncQSince = (tsince * req.EncSince.0, tsince * req.EncSince.1);
494 let tinvremain = self.lox_priv.x[5] * b;
495 let TInvRemain = &tinvremain * Atable;
496 let EncQInvRemain = (
497 tinvremain * req.EncInvRemain.0,
498 tinvremain * req.EncInvRemain.1,
499 );
500 let tblockages = self.lox_priv.x[6] * b;
501 let TBlockages = &tblockages * Atable;
502 let EncQBlockages = (
503 tblockages * req.EncBlockages.0,
504 tblockages * req.EncBlockages.1,
505 );
506
507 let EncQ = (
508 EncQHc.0
509 + EncQId.0
510 + EncQBucket.0
511 + EncQLevel.0
512 + EncQSince.0
513 + EncQInvRemain.0
514 + EncQBlockages.0,
515 EncQHc.1
516 + EncQId.1
517 + EncQBucket.1
518 + EncQLevel.1
519 + EncQSince.1
520 + EncQInvRemain.1
521 + EncQBlockages.1,
522 );
523
524 let mut transcript = Transcript::new(b"issue updated cred");
525 let piBlindIssue = blindissue::prove_compact(
526 &mut transcript,
527 blindissue::ProveAssignments {
528 A,
529 B,
530 P: &P,
531 EncQ0: &EncQ.0,
532 EncQ1: &EncQ.1,
533 X0: &self.lox_pub.X[0],
534 Xid: &self.lox_pub.X[1],
535 Xbucket: &self.lox_pub.X[2],
536 Xlevel: &self.lox_pub.X[3],
537 Xsince: &self.lox_pub.X[4],
538 Xinvremain: &self.lox_pub.X[5],
539 Xblockages: &self.lox_pub.X[6],
540 TId: &TId,
541 TBucket: &TBucket,
542 TLevel: &TLevel,
543 TSince: &TSince,
544 TInvRemain: &TInvRemain,
545 TBlockages: &TBlockages,
546 D: &req.D,
547 EncId0: &EncId.0,
548 EncId1: &EncId.1,
549 EncBucket0: &req.EncBucket.0,
550 EncBucket1: &req.EncBucket.1,
551 EncLevel0: &req.EncLevel.0,
552 EncLevel1: &req.EncLevel.1,
553 EncSince0: &req.EncSince.0,
554 EncSince1: &req.EncSince.1,
555 EncInvRemain0: &req.EncInvRemain.0,
556 EncInvRemain1: &req.EncInvRemain.1,
557 EncBlockages0: &req.EncBlockages.0,
558 EncBlockages1: &req.EncBlockages.1,
559 x0: &self.lox_priv.x[0],
560 x0tilde: &self.lox_priv.x0tilde,
561 xid: &self.lox_priv.x[1],
562 xbucket: &self.lox_priv.x[2],
563 xlevel: &self.lox_priv.x[3],
564 xsince: &self.lox_priv.x[4],
565 xinvremain: &self.lox_priv.x[5],
566 xblockages: &self.lox_priv.x[6],
567 s: &s,
568 b: &b,
569 tid: &tid,
570 tbucket: &tbucket,
571 tlevel: &tlevel,
572 tsince: &tsince,
573 tinvremain: &tinvremain,
574 tblockages: &tblockages,
575 },
576 )
577 .0;
578
579 Ok(Response {
580 P,
581 EncQ,
582 id_server,
583 TId,
584 TBucket,
585 TLevel,
586 TSince,
587 TInvRemain,
588 TBlockages,
589 piBlindIssue,
590 })
591 }
592}
593
594pub fn handle_response(
597 state: State,
598 resp: Response,
599 lox_pub: &IssuerPubKey,
600) -> Result<cred::Lox, ProofError> {
601 let A: &RistrettoPoint = &CMZ_A;
602 let B: &RistrettoPoint = &CMZ_B;
603 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
604
605 if resp.P.is_identity() {
606 return Err(ProofError::VerificationFailure);
607 }
608
609 let id = state.id_client + resp.id_server;
613 let EncId = (
614 state.EncIdClient.0,
615 state.EncIdClient.1 + &resp.id_server * Btable,
616 );
617
618 let mut transcript = Transcript::new(b"issue updated cred");
620 blindissue::verify_compact(
621 &resp.piBlindIssue,
622 &mut transcript,
623 blindissue::VerifyAssignments {
624 A: &A.compress(),
625 B: &B.compress(),
626 P: &resp.P.compress(),
627 EncQ0: &resp.EncQ.0.compress(),
628 EncQ1: &resp.EncQ.1.compress(),
629 X0: &lox_pub.X[0].compress(),
630 Xid: &lox_pub.X[1].compress(),
631 Xbucket: &lox_pub.X[2].compress(),
632 Xlevel: &lox_pub.X[3].compress(),
633 Xsince: &lox_pub.X[4].compress(),
634 Xinvremain: &lox_pub.X[5].compress(),
635 Xblockages: &lox_pub.X[6].compress(),
636 TId: &resp.TId.compress(),
637 TBucket: &resp.TBucket.compress(),
638 TLevel: &resp.TLevel.compress(),
639 TSince: &resp.TSince.compress(),
640 TInvRemain: &resp.TInvRemain.compress(),
641 TBlockages: &resp.TBlockages.compress(),
642 D: &state.D.compress(),
643 EncId0: &EncId.0.compress(),
644 EncId1: &EncId.1.compress(),
645 EncBucket0: &state.EncBucket.0.compress(),
646 EncBucket1: &state.EncBucket.1.compress(),
647 EncLevel0: &state.EncLevel.0.compress(),
648 EncLevel1: &state.EncLevel.1.compress(),
649 EncSince0: &state.EncSince.0.compress(),
650 EncSince1: &state.EncSince.1.compress(),
651 EncInvRemain0: &state.EncInvRemain.0.compress(),
652 EncInvRemain1: &state.EncInvRemain.1.compress(),
653 EncBlockages0: &state.EncBlockages.0.compress(),
654 EncBlockages1: &state.EncBlockages.1.compress(),
655 },
656 )?;
657
658 let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
660
661 Ok(cred::Lox {
662 P: resp.P,
663 Q,
664 id,
665 bucket: state.bucket,
666 trust_level: state.level,
667 level_since: state.since,
668 invites_remaining: state.invremain,
669 blockages: state.blockages,
670 })
671}