1use curve25519_dalek::ristretto::RistrettoBasepointTable;
42use curve25519_dalek::ristretto::RistrettoPoint;
43use curve25519_dalek::scalar::Scalar;
44use curve25519_dalek::traits::IsIdentity;
45
46use lox_zkp::CompactProof;
47use lox_zkp::ProofError;
48use lox_zkp::Transcript;
49
50use serde::{Deserialize, Serialize};
51
52use super::super::cred;
53#[cfg(feature = "bridgeauth")]
54use super::super::dup_filter::SeenType;
55#[cfg(feature = "bridgeauth")]
56use super::super::pt_dbl;
57#[cfg(feature = "bridgeauth")]
58use super::super::BridgeAuth;
59use super::super::IssuerPubKey;
60use super::super::{scalar_dbl, scalar_u32};
61use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
62
63use super::errors::CredentialError;
64
65pub const MAX_LEVEL: usize = 4;
70
71pub const LEVEL_INTERVAL: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56, 84];
77
78pub const LEVEL_INVITATIONS: [u32; MAX_LEVEL + 1] = [0, 2, 4, 6, 8];
83
84pub const MAX_BLOCKAGES: [u32; MAX_LEVEL + 1] = [0, 4, 3, 2, 2];
91
92#[derive(Serialize, Deserialize)]
93pub struct Request {
94 P: RistrettoPoint,
96 id: Scalar,
97 CBucket: RistrettoPoint,
98 level: Scalar,
99 CSince: RistrettoPoint,
100 CInvRemain: RistrettoPoint,
101 CBlockages: RistrettoPoint,
102 CQ: RistrettoPoint,
103
104 P_reach: RistrettoPoint,
106 CBucket_reach: RistrettoPoint,
107 CQ_reach: RistrettoPoint,
108
109 CG1: RistrettoPoint,
112 CG2: RistrettoPoint,
113 CG3: RistrettoPoint,
114 CG4: RistrettoPoint,
115 CG5: RistrettoPoint,
116 CG6: RistrettoPoint,
117 CG7: RistrettoPoint,
118 CG8: RistrettoPoint,
119 CG0sq: RistrettoPoint,
120 CG1sq: RistrettoPoint,
121 CG2sq: RistrettoPoint,
122 CG3sq: RistrettoPoint,
123 CG4sq: RistrettoPoint,
124 CG5sq: RistrettoPoint,
125 CG6sq: RistrettoPoint,
126 CG7sq: RistrettoPoint,
127 CG8sq: RistrettoPoint,
128
129 CH1: RistrettoPoint,
132 CH2: RistrettoPoint,
133 CH0sq: RistrettoPoint,
134 CH1sq: RistrettoPoint,
135 CH2sq: RistrettoPoint,
136
137 D: RistrettoPoint,
139 EncIdClient: (RistrettoPoint, RistrettoPoint),
140 EncBucket: (RistrettoPoint, RistrettoPoint),
141 EncBlockages: (RistrettoPoint, RistrettoPoint),
142
143 piUser: CompactProof,
145}
146
147#[derive(Debug, Serialize, Deserialize)]
148pub struct State {
149 d: Scalar,
150 D: RistrettoPoint,
151 EncIdClient: (RistrettoPoint, RistrettoPoint),
152 EncBucket: (RistrettoPoint, RistrettoPoint),
153 EncBlockages: (RistrettoPoint, RistrettoPoint),
154 id_client: Scalar,
155 bucket: Scalar,
156 level: Scalar,
157 invremain: Scalar,
158 blockages: Scalar,
159}
160
161#[derive(Serialize, Deserialize)]
162pub struct Response {
163 P: RistrettoPoint,
167 EncQ: (RistrettoPoint, RistrettoPoint),
168 id_server: Scalar,
169 level_since: Scalar,
170 TId: RistrettoPoint,
171 TBucket: RistrettoPoint,
172 TBlockages: RistrettoPoint,
173
174 piBlindIssue: CompactProof,
176}
177
178define_proof! {
179 requestproof,
180 "Level Upgrade Request",
181 (bucket, since, invremain, blockages, zbucket, zsince, zinvremain,
182 zblockages, negzQ,
183 zbucket_reach, negzQ_reach,
184 d, eid_client, ebucket, eblockages, id_client,
185 g0, g1, g2, g3, g4, g5, g6, g7, g8,
186 zg0, zg1, zg2, zg3, zg4, zg5, zg6, zg7, zg8,
187 wg0, wg1, wg2, wg3, wg4, wg5, wg6, wg7, wg8,
188 yg0, yg1, yg2, yg3, yg4, yg5, yg6, yg7, yg8,
189 h0, h1, h2,
190 zh0, zh1, zh2,
191 wh0, wh1, wh2,
192 yh0, yh1, yh2),
193 (P, CBucket, CSince, CInvRemain, CBlockages, V, Xbucket, Xsince,
194 Xinvremain, Xblockages,
195 P_reach, CBucket_reach, V_reach, Xbucket_reach,
196 D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
197 EncBlockages0, EncBlockages1,
198 CG0, CG1, CG2, CG3, CG4, CG5, CG6, CG7, CG8,
199 CG0sq, CG1sq, CG2sq, CG3sq, CG4sq, CG5sq, CG6sq, CG7sq, CG8sq,
200 CH0, CH1, CH2,
201 CH0sq, CH1sq, CH2sq),
202 (A, B) :
203 CBucket = (bucket*P + zbucket*A),
205 CSince = (since*P + zsince*A),
206 CInvRemain = (invremain*P + zinvremain*A),
207 CBlockages = (blockages*P + zblockages*A),
208 CBucket_reach = (bucket*P_reach + zbucket_reach*A),
211 D = (d*B),
213 EncIdClient0 = (eid_client*B),
214 EncIdClient1 = (id_client*B + eid_client*D),
215 EncBucket0 = (ebucket*B),
216 EncBucket1 = (bucket*B + ebucket*D),
217 EncBlockages0 = (eblockages*B),
218 EncBlockages1 = (blockages*B + eblockages*D),
219 CG0 = (g0*P + zg0*A), CG0sq = (g0*CG0 + wg0*A), CG0sq = (g0*P + yg0*A),
224 CG1 = (g1*P + zg1*A), CG1sq = (g1*CG1 + wg1*A), CG1sq = (g1*P + yg1*A),
225 CG2 = (g2*P + zg2*A), CG2sq = (g2*CG2 + wg2*A), CG2sq = (g2*P + yg2*A),
226 CG3 = (g3*P + zg3*A), CG3sq = (g3*CG3 + wg3*A), CG3sq = (g3*P + yg3*A),
227 CG4 = (g4*P + zg4*A), CG4sq = (g4*CG4 + wg4*A), CG4sq = (g4*P + yg4*A),
228 CG5 = (g5*P + zg5*A), CG5sq = (g5*CG5 + wg5*A), CG5sq = (g5*P + yg5*A),
229 CG6 = (g6*P + zg6*A), CG6sq = (g6*CG6 + wg6*A), CG6sq = (g6*P + yg6*A),
230 CG7 = (g7*P + zg7*A), CG7sq = (g7*CG7 + wg7*A), CG7sq = (g7*P + yg7*A),
231 CG8 = (g8*P + zg8*A), CG8sq = (g8*CG8 + wg8*A), CG8sq = (g8*P + yg8*A),
232 CH0 = (h0*P + zh0*A), CH0sq = (h0*CH0 + wh0*A), CH0sq = (h0*P + yh0*A),
240 CH1 = (h1*P + zh1*A), CH1sq = (h1*CH1 + wh1*A), CH1sq = (h1*P + yh1*A),
241 CH2 = (h2*P + zh2*A), CH2sq = (h2*CH2 + wh2*A), CH2sq = (h2*P + yh2*A)
242 }
246
247define_proof! {
248 blindissue,
249 "Level Upgrade Issuing",
250 (x0, x0tilde, xid, xbucket, xlevel, xsince, xinvremain, xblockages,
251 s, b, tid, tbucket, tblockages),
252 (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Xinvremain,
253 Xblockages, Plevel, Psince, Pinvremain, TId, TBucket, TBlockages,
254 D, EncId0, EncId1, EncBucket0, EncBucket1, EncBlockages0, EncBlockages1),
255 (A, B):
256 Xid = (xid*A),
257 Xbucket = (xbucket*A),
258 Xlevel = (xlevel*A),
259 Xsince = (xsince*A),
260 Xinvremain = (xinvremain*A),
261 Xblockages = (xblockages*A),
262 X0 = (x0*B + x0tilde*A),
263 P = (b*B),
264 TId = (b*Xid),
265 TId = (tid*A),
266 TBucket = (b*Xbucket),
267 TBucket = (tbucket*A),
268 TBlockages = (b*Xblockages),
269 TBlockages = (tblockages*A),
270 EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0 + tblockages*EncBlockages0),
271 EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1
272 + tblockages*EncBlockages1 + x0*P + xlevel*Plevel + xsince*Psince
273 + xinvremain*Pinvremain)
274}
275
276pub fn request(
277 lox_cred: &cred::Lox,
278 reach_cred: &cred::BucketReachability,
279 lox_pub: &IssuerPubKey,
280 reach_pub: &IssuerPubKey,
281 today: u32,
282) -> Result<(Request, State), CredentialError> {
283 let A: &RistrettoPoint = &CMZ_A;
284 let B: &RistrettoPoint = &CMZ_B;
285 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
286 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
287
288 let level_since: u32 = match scalar_u32(&lox_cred.level_since) {
291 Some(v) => v,
292 None => {
293 return Err(CredentialError::InvalidField(
294 String::from("level_since"),
295 String::from("could not be converted to u32"),
296 ))
297 }
298 };
299 let trust_level: u32 = match scalar_u32(&lox_cred.trust_level) {
301 Some(v) => v,
302 None => {
303 return Err(CredentialError::InvalidField(
304 String::from("trust_level"),
305 String::from("could not be converted to u32"),
306 ))
307 }
308 };
309 if trust_level < 1 || (trust_level as usize) > MAX_LEVEL {
310 return Err(CredentialError::InvalidField(
311 String::from("trust_level"),
312 format!("level {:?} not in range", trust_level),
313 ));
314 }
315 let level_interval: u32 = match LEVEL_INTERVAL.get(trust_level as usize) {
317 Some(&v) => v,
318 None => {
319 return Err(CredentialError::InvalidField(
320 String::from("trust_level"),
321 format!("level {:?} not in range", trust_level),
322 ))
323 }
324 };
325 if level_since + level_interval > today {
326 return Err(CredentialError::TimeThresholdNotMet(
327 level_since + level_interval - today,
328 ));
329 }
330 let diffdays = today - (level_since + level_interval);
332 if diffdays > 511 {
333 return Err(CredentialError::CredentialExpired);
334 }
335 let blockages: u32 = match scalar_u32(&lox_cred.blockages) {
337 Some(v) => v,
338 None => {
339 return Err(CredentialError::InvalidField(
340 String::from("blockages"),
341 String::from("could not be converted to u32"),
342 ))
343 }
344 };
345 if blockages > MAX_BLOCKAGES[trust_level as usize] {
346 return Err(CredentialError::ExceededBlockagesThreshold);
347 }
348 let blockage_diff = MAX_BLOCKAGES[trust_level as usize] - blockages;
349 if lox_cred.bucket != reach_cred.bucket {
352 return Err(CredentialError::CredentialMismatch);
353 }
354 let reach_date: u32 = match scalar_u32(&reach_cred.date) {
356 Some(v) => v,
357 None => {
358 return Err(CredentialError::InvalidField(
359 String::from("date"),
360 String::from("could not be converted to u32"),
361 ))
362 }
363 };
364 if reach_date != today {
365 return Err(CredentialError::InvalidField(
366 String::from("date"),
367 String::from("reachability credential must be generated today"),
368 ));
369 }
370 let new_level = if (trust_level as usize) < MAX_LEVEL {
372 trust_level + 1
373 } else {
374 trust_level
375 };
376
377 let mut rng = rand::thread_rng();
381 let t = Scalar::random(&mut rng);
382 let P = t * lox_cred.P;
383 let Q = t * lox_cred.Q;
384
385 let zbucket = Scalar::random(&mut rng);
387 let zsince = Scalar::random(&mut rng);
388 let zinvremain = Scalar::random(&mut rng);
389 let zblockages = Scalar::random(&mut rng);
390 let CBucket = lox_cred.bucket * P + &zbucket * Atable;
391 let CSince = lox_cred.level_since * P + &zsince * Atable;
392 let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
393 let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
394
395 let negzQ = Scalar::random(&mut rng);
400 let CQ = Q - &negzQ * Atable;
401
402 let V = zbucket * lox_pub.X[2]
404 + zsince * lox_pub.X[4]
405 + zinvremain * lox_pub.X[5]
406 + zblockages * lox_pub.X[6]
407 + &negzQ * Atable;
408
409 let t_reach = Scalar::random(&mut rng);
413 let P_reach = t_reach * reach_cred.P;
414 let Q_reach = t_reach * reach_cred.Q;
415
416 let zbucket_reach = Scalar::random(&mut rng);
418 let CBucket_reach = reach_cred.bucket * P_reach + &zbucket_reach * Atable;
419
420 let negzQ_reach = Scalar::random(&mut rng);
425 let CQ_reach = Q_reach - &negzQ_reach * Atable;
426
427 let V_reach = zbucket_reach * reach_pub.X[2] + &negzQ_reach * Atable;
429
430 let d = Scalar::random(&mut rng);
434 let D = &d * Btable;
435
436 let id_client = Scalar::random(&mut rng);
438
439 let eid_client = Scalar::random(&mut rng);
442 let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
443
444 let ebucket = Scalar::random(&mut rng);
446 let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
447 let newinvites: Scalar = LEVEL_INVITATIONS[trust_level as usize].into();
448 let eblockages = Scalar::random(&mut rng);
449 let EncBlockages = (
450 &eblockages * Btable,
451 &lox_cred.blockages * Btable + eblockages * D,
452 );
453
454 let g0: Scalar = (diffdays & 1).into();
458 let g1: Scalar = ((diffdays >> 1) & 1).into();
459 let g2: Scalar = ((diffdays >> 2) & 1).into();
460 let g3: Scalar = ((diffdays >> 3) & 1).into();
461 let g4: Scalar = ((diffdays >> 4) & 1).into();
462 let g5: Scalar = ((diffdays >> 5) & 1).into();
463 let g6: Scalar = ((diffdays >> 6) & 1).into();
464 let g7: Scalar = ((diffdays >> 7) & 1).into();
465 let g8: Scalar = ((diffdays >> 8) & 1).into();
466
467 let wg0 = Scalar::random(&mut rng);
469 let zg1 = Scalar::random(&mut rng);
470 let wg1 = Scalar::random(&mut rng);
471 let zg2 = Scalar::random(&mut rng);
472 let wg2 = Scalar::random(&mut rng);
473 let zg3 = Scalar::random(&mut rng);
474 let wg3 = Scalar::random(&mut rng);
475 let zg4 = Scalar::random(&mut rng);
476 let wg4 = Scalar::random(&mut rng);
477 let zg5 = Scalar::random(&mut rng);
478 let wg5 = Scalar::random(&mut rng);
479 let zg6 = Scalar::random(&mut rng);
480 let wg6 = Scalar::random(&mut rng);
481 let zg7 = Scalar::random(&mut rng);
482 let wg7 = Scalar::random(&mut rng);
483 let zg8 = Scalar::random(&mut rng);
484 let wg8 = Scalar::random(&mut rng);
485
486 let zg0 = -(scalar_dbl(
490 &(scalar_dbl(
491 &(scalar_dbl(
492 &(scalar_dbl(
493 &(scalar_dbl(
494 &(scalar_dbl(&(scalar_dbl(&(scalar_dbl(&zg8) + zg7)) + zg6)) + zg5),
495 ) + zg4),
496 ) + zg3),
497 ) + zg2),
498 ) + zg1),
499 ) + zsince);
500
501 let yg0 = wg0 + g0 * zg0;
502 let yg1 = wg1 + g1 * zg1;
503 let yg2 = wg2 + g2 * zg2;
504 let yg3 = wg3 + g3 * zg3;
505 let yg4 = wg4 + g4 * zg4;
506 let yg5 = wg5 + g5 * zg5;
507 let yg6 = wg6 + g6 * zg6;
508 let yg7 = wg7 + g7 * zg7;
509 let yg8 = wg8 + g8 * zg8;
510
511 let CG0 = g0 * P + &zg0 * Atable;
512 let CG1 = g1 * P + &zg1 * Atable;
513 let CG2 = g2 * P + &zg2 * Atable;
514 let CG3 = g3 * P + &zg3 * Atable;
515 let CG4 = g4 * P + &zg4 * Atable;
516 let CG5 = g5 * P + &zg5 * Atable;
517 let CG6 = g6 * P + &zg6 * Atable;
518 let CG7 = g7 * P + &zg7 * Atable;
519 let CG8 = g8 * P + &zg8 * Atable;
520
521 let CG0sq = g0 * P + &yg0 * Atable;
522 let CG1sq = g1 * P + &yg1 * Atable;
523 let CG2sq = g2 * P + &yg2 * Atable;
524 let CG3sq = g3 * P + &yg3 * Atable;
525 let CG4sq = g4 * P + &yg4 * Atable;
526 let CG5sq = g5 * P + &yg5 * Atable;
527 let CG6sq = g6 * P + &yg6 * Atable;
528 let CG7sq = g7 * P + &yg7 * Atable;
529 let CG8sq = g8 * P + &yg8 * Atable;
530
531 let h0: Scalar = (blockage_diff & 1).into();
535 let h1: Scalar = ((blockage_diff >> 1) & 1).into();
536 let h2: Scalar = ((blockage_diff >> 2) & 1).into();
537
538 let wh0 = Scalar::random(&mut rng);
540 let zh1 = Scalar::random(&mut rng);
541 let wh1 = Scalar::random(&mut rng);
542 let zh2 = Scalar::random(&mut rng);
543 let wh2 = Scalar::random(&mut rng);
544
545 let zh0 = -(scalar_dbl(&(scalar_dbl(&zh2) + zh1)) + zblockages);
549
550 let yh0 = wh0 + h0 * zh0;
551 let yh1 = wh1 + h1 * zh1;
552 let yh2 = wh2 + h2 * zh2;
553
554 let CH0 = h0 * P + &zh0 * Atable;
555 let CH1 = h1 * P + &zh1 * Atable;
556 let CH2 = h2 * P + &zh2 * Atable;
557
558 let CH0sq = h0 * P + &yh0 * Atable;
559 let CH1sq = h1 * P + &yh1 * Atable;
560 let CH2sq = h2 * P + &yh2 * Atable;
561
562 let mut transcript = Transcript::new(b"level upgrade request");
564 let piUser = requestproof::prove_compact(
565 &mut transcript,
566 requestproof::ProveAssignments {
567 A,
568 B,
569 P: &P,
570 CBucket: &CBucket,
571 CSince: &CSince,
572 CInvRemain: &CInvRemain,
573 CBlockages: &CBlockages,
574 V: &V,
575 Xbucket: &lox_pub.X[2],
576 Xsince: &lox_pub.X[4],
577 Xinvremain: &lox_pub.X[5],
578 Xblockages: &lox_pub.X[6],
579 P_reach: &P_reach,
580 CBucket_reach: &CBucket_reach,
581 V_reach: &V_reach,
582 Xbucket_reach: &reach_pub.X[2],
583 D: &D,
584 EncIdClient0: &EncIdClient.0,
585 EncIdClient1: &EncIdClient.1,
586 EncBucket0: &EncBucket.0,
587 EncBucket1: &EncBucket.1,
588 EncBlockages0: &EncBlockages.0,
589 EncBlockages1: &EncBlockages.1,
590 CG0: &CG0,
591 CG1: &CG1,
592 CG2: &CG2,
593 CG3: &CG3,
594 CG4: &CG4,
595 CG5: &CG5,
596 CG6: &CG6,
597 CG7: &CG7,
598 CG8: &CG8,
599 CG0sq: &CG0sq,
600 CG1sq: &CG1sq,
601 CG2sq: &CG2sq,
602 CG3sq: &CG3sq,
603 CG4sq: &CG4sq,
604 CG5sq: &CG5sq,
605 CG6sq: &CG6sq,
606 CG7sq: &CG7sq,
607 CG8sq: &CG8sq,
608 CH0: &CH0,
609 CH1: &CH1,
610 CH2: &CH2,
611 CH0sq: &CH0sq,
612 CH1sq: &CH1sq,
613 CH2sq: &CH2sq,
614 bucket: &lox_cred.bucket,
615 since: &lox_cred.level_since,
616 invremain: &lox_cred.invites_remaining,
617 blockages: &lox_cred.blockages,
618 zbucket: &zbucket,
619 zsince: &zsince,
620 zinvremain: &zinvremain,
621 zblockages: &zblockages,
622 negzQ: &negzQ,
623 zbucket_reach: &zbucket_reach,
624 negzQ_reach: &negzQ_reach,
625 d: &d,
626 eid_client: &eid_client,
627 ebucket: &ebucket,
628 eblockages: &eblockages,
629 id_client: &id_client,
630 g0: &g0,
631 g1: &g1,
632 g2: &g2,
633 g3: &g3,
634 g4: &g4,
635 g5: &g5,
636 g6: &g6,
637 g7: &g7,
638 g8: &g8,
639 zg0: &zg0,
640 zg1: &zg1,
641 zg2: &zg2,
642 zg3: &zg3,
643 zg4: &zg4,
644 zg5: &zg5,
645 zg6: &zg6,
646 zg7: &zg7,
647 zg8: &zg8,
648 wg0: &wg0,
649 wg1: &wg1,
650 wg2: &wg2,
651 wg3: &wg3,
652 wg4: &wg4,
653 wg5: &wg5,
654 wg6: &wg6,
655 wg7: &wg7,
656 wg8: &wg8,
657 yg0: &yg0,
658 yg1: &yg1,
659 yg2: &yg2,
660 yg3: &yg3,
661 yg4: &yg4,
662 yg5: &yg5,
663 yg6: &yg6,
664 yg7: &yg7,
665 yg8: &yg8,
666 h0: &h0,
667 h1: &h1,
668 h2: &h2,
669 zh0: &zh0,
670 zh1: &zh1,
671 zh2: &zh2,
672 wh0: &wh0,
673 wh1: &wh1,
674 wh2: &wh2,
675 yh0: &yh0,
676 yh1: &yh1,
677 yh2: &yh2,
678 },
679 )
680 .0;
681
682 Ok((
683 Request {
684 P,
685 id: lox_cred.id,
686 CBucket,
687 level: lox_cred.trust_level,
688 CSince,
689 CInvRemain,
690 CBlockages,
691 CQ,
692 P_reach,
693 CBucket_reach,
694 CQ_reach,
695 D,
696 EncIdClient,
697 EncBucket,
698 EncBlockages,
699 CG1,
700 CG2,
701 CG3,
702 CG4,
703 CG5,
704 CG6,
705 CG7,
706 CG8,
707 CG0sq,
708 CG1sq,
709 CG2sq,
710 CG3sq,
711 CG4sq,
712 CG5sq,
713 CG6sq,
714 CG7sq,
715 CG8sq,
716 CH1,
717 CH2,
718 CH0sq,
719 CH1sq,
720 CH2sq,
721 piUser,
722 },
723 State {
724 d,
725 D,
726 EncIdClient,
727 EncBucket,
728 EncBlockages,
729 id_client,
730 bucket: lox_cred.bucket,
731 level: new_level.into(),
732 invremain: newinvites,
733 blockages: lox_cred.blockages,
734 },
735 ))
736}
737
738#[cfg(feature = "bridgeauth")]
739impl BridgeAuth {
740 pub fn handle_level_up(&mut self, req: Request) -> Result<Response, ProofError> {
742 let A: &RistrettoPoint = &CMZ_A;
743 let B: &RistrettoPoint = &CMZ_B;
744 let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
745 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
746
747 if req.P.is_identity() || req.P_reach.is_identity() {
748 return Err(ProofError::VerificationFailure);
749 }
750
751 let today: Scalar = self.today().into();
752
753 let level: usize = match scalar_u32(&req.level) {
755 Some(l) if l as usize <= MAX_LEVEL => l as usize,
756 _ => return Err(ProofError::VerificationFailure),
757 };
758
759 let Vprime =
763 (self.lox_priv.x[0] + self.lox_priv.x[1] * req.id + self.lox_priv.x[3] * req.level)
764 * req.P
765 + self.lox_priv.x[2] * req.CBucket
766 + self.lox_priv.x[4] * req.CSince
767 + self.lox_priv.x[5] * req.CInvRemain
768 + self.lox_priv.x[6] * req.CBlockages
769 - req.CQ;
770
771 let Vprime_reach = (self.reachability_priv.x[0] + self.reachability_priv.x[1] * today)
772 * req.P_reach
773 + self.reachability_priv.x[2] * req.CBucket_reach
774 - req.CQ_reach;
775
776 let interval: Scalar = LEVEL_INTERVAL[level].into();
778 let CG0prime = (today - interval) * req.P
779 - req.CSince
780 - pt_dbl(
781 &(pt_dbl(
782 &(pt_dbl(
783 &(pt_dbl(
784 &(pt_dbl(
785 &(pt_dbl(&(pt_dbl(&(pt_dbl(&req.CG8) + req.CG7)) + req.CG6))
786 + req.CG5),
787 ) + req.CG4),
788 ) + req.CG3),
789 ) + req.CG2),
790 ) + req.CG1),
791 );
792
793 let mblk: Scalar = MAX_BLOCKAGES[level].into();
795 let CH0prime = mblk * req.P - req.CBlockages - pt_dbl(&(pt_dbl(&req.CH2) + req.CH1));
796
797 let mut transcript = Transcript::new(b"level upgrade request");
799 requestproof::verify_compact(
800 &req.piUser,
801 &mut transcript,
802 requestproof::VerifyAssignments {
803 A: &A.compress(),
804 B: &B.compress(),
805 P: &req.P.compress(),
806 CBucket: &req.CBucket.compress(),
807 CSince: &req.CSince.compress(),
808 CInvRemain: &req.CInvRemain.compress(),
809 CBlockages: &req.CBlockages.compress(),
810 V: &Vprime.compress(),
811 Xbucket: &self.lox_pub.X[2].compress(),
812 Xsince: &self.lox_pub.X[4].compress(),
813 Xinvremain: &self.lox_pub.X[5].compress(),
814 Xblockages: &self.lox_pub.X[6].compress(),
815 P_reach: &req.P_reach.compress(),
816 CBucket_reach: &req.CBucket_reach.compress(),
817 V_reach: &Vprime_reach.compress(),
818 Xbucket_reach: &self.reachability_pub.X[2].compress(),
819 D: &req.D.compress(),
820 EncIdClient0: &req.EncIdClient.0.compress(),
821 EncIdClient1: &req.EncIdClient.1.compress(),
822 EncBucket0: &req.EncBucket.0.compress(),
823 EncBucket1: &req.EncBucket.1.compress(),
824 EncBlockages0: &req.EncBlockages.0.compress(),
825 EncBlockages1: &req.EncBlockages.1.compress(),
826 CG0: &CG0prime.compress(),
827 CG1: &req.CG1.compress(),
828 CG2: &req.CG2.compress(),
829 CG3: &req.CG3.compress(),
830 CG4: &req.CG4.compress(),
831 CG5: &req.CG5.compress(),
832 CG6: &req.CG6.compress(),
833 CG7: &req.CG7.compress(),
834 CG8: &req.CG8.compress(),
835 CG0sq: &req.CG0sq.compress(),
836 CG1sq: &req.CG1sq.compress(),
837 CG2sq: &req.CG2sq.compress(),
838 CG3sq: &req.CG3sq.compress(),
839 CG4sq: &req.CG4sq.compress(),
840 CG5sq: &req.CG5sq.compress(),
841 CG6sq: &req.CG6sq.compress(),
842 CG7sq: &req.CG7sq.compress(),
843 CG8sq: &req.CG8sq.compress(),
844 CH0: &CH0prime.compress(),
845 CH1: &req.CH1.compress(),
846 CH2: &req.CH2.compress(),
847 CH0sq: &req.CH0sq.compress(),
848 CH1sq: &req.CH1sq.compress(),
849 CH2sq: &req.CH2sq.compress(),
850 },
851 )?;
852
853 if self.id_filter.filter(&req.id) == SeenType::Seen {
856 return Err(ProofError::VerificationFailure);
857 }
858
859 let mut rng = rand::thread_rng();
864 let id_server = Scalar::random(&mut rng);
865 let EncId = (req.EncIdClient.0, req.EncIdClient.1 + &id_server * Btable);
866
867 let new_level = if level < MAX_LEVEL { level + 1 } else { level };
871 let trust_level: Scalar = (new_level as u64).into();
872
873 let level_since: Scalar = self.today().into();
876
877 let invitations_remaining: Scalar = LEVEL_INVITATIONS[level].into();
880
881 let b = Scalar::random(&mut rng);
883 let P = &b * Btable;
884 let QHc = (self.lox_priv.x[0]
885 + self.lox_priv.x[3] * trust_level
886 + self.lox_priv.x[4] * level_since
887 + self.lox_priv.x[5] * invitations_remaining)
888 * P;
889
890 let s = Scalar::random(&mut rng);
892 let EncQHc = (&s * Btable, QHc + s * req.D);
893
894 let tid = self.lox_priv.x[1] * b;
897 let TId = &tid * Atable;
898 let EncQId = (tid * EncId.0, tid * EncId.1);
899 let tbucket = self.lox_priv.x[2] * b;
900 let TBucket = &tbucket * Atable;
901 let EncQBucket = (tbucket * req.EncBucket.0, tbucket * req.EncBucket.1);
902 let tblockages = self.lox_priv.x[6] * b;
903 let TBlockages = &tblockages * Atable;
904 let EncQBlockages = (
905 tblockages * req.EncBlockages.0,
906 tblockages * req.EncBlockages.1,
907 );
908
909 let EncQ = (
910 EncQHc.0 + EncQId.0 + EncQBucket.0 + EncQBlockages.0,
911 EncQHc.1 + EncQId.1 + EncQBucket.1 + EncQBlockages.1,
912 );
913
914 let mut transcript = Transcript::new(b"level upgrade issuing");
915 let piBlindIssue = blindissue::prove_compact(
916 &mut transcript,
917 blindissue::ProveAssignments {
918 A,
919 B,
920 P: &P,
921 EncQ0: &EncQ.0,
922 EncQ1: &EncQ.1,
923 X0: &self.lox_pub.X[0],
924 Xid: &self.lox_pub.X[1],
925 Xbucket: &self.lox_pub.X[2],
926 Xlevel: &self.lox_pub.X[3],
927 Xsince: &self.lox_pub.X[4],
928 Xinvremain: &self.lox_pub.X[5],
929 Xblockages: &self.lox_pub.X[6],
930 Plevel: &(trust_level * P),
931 Psince: &(level_since * P),
932 Pinvremain: &(invitations_remaining * P),
933 TId: &TId,
934 TBucket: &TBucket,
935 TBlockages: &TBlockages,
936 D: &req.D,
937 EncId0: &EncId.0,
938 EncId1: &EncId.1,
939 EncBucket0: &req.EncBucket.0,
940 EncBucket1: &req.EncBucket.1,
941 EncBlockages0: &req.EncBlockages.0,
942 EncBlockages1: &req.EncBlockages.1,
943 x0: &self.lox_priv.x[0],
944 x0tilde: &self.lox_priv.x0tilde,
945 xid: &self.lox_priv.x[1],
946 xbucket: &self.lox_priv.x[2],
947 xlevel: &self.lox_priv.x[3],
948 xsince: &self.lox_priv.x[4],
949 xinvremain: &self.lox_priv.x[5],
950 xblockages: &self.lox_priv.x[6],
951 s: &s,
952 b: &b,
953 tid: &tid,
954 tbucket: &tbucket,
955 tblockages: &tblockages,
956 },
957 )
958 .0;
959
960 Ok(Response {
961 P,
962 EncQ,
963 id_server,
964 level_since,
965 TId,
966 TBucket,
967 TBlockages,
968 piBlindIssue,
969 })
970 }
971}
972
973pub fn handle_response(
976 state: State,
977 resp: Response,
978 lox_pub: &IssuerPubKey,
979) -> Result<cred::Lox, ProofError> {
980 let A: &RistrettoPoint = &CMZ_A;
981 let B: &RistrettoPoint = &CMZ_B;
982 let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
983
984 if resp.P.is_identity() {
985 return Err(ProofError::VerificationFailure);
986 }
987
988 let id = state.id_client + resp.id_server;
991 let EncId = (
992 state.EncIdClient.0,
993 state.EncIdClient.1 + &resp.id_server * Btable,
994 );
995
996 let mut transcript = Transcript::new(b"level upgrade issuing");
998 blindissue::verify_compact(
999 &resp.piBlindIssue,
1000 &mut transcript,
1001 blindissue::VerifyAssignments {
1002 A: &A.compress(),
1003 B: &B.compress(),
1004 P: &resp.P.compress(),
1005 EncQ0: &resp.EncQ.0.compress(),
1006 EncQ1: &resp.EncQ.1.compress(),
1007 X0: &lox_pub.X[0].compress(),
1008 Xid: &lox_pub.X[1].compress(),
1009 Xbucket: &lox_pub.X[2].compress(),
1010 Xlevel: &lox_pub.X[3].compress(),
1011 Xsince: &lox_pub.X[4].compress(),
1012 Xinvremain: &lox_pub.X[5].compress(),
1013 Xblockages: &lox_pub.X[6].compress(),
1014 Plevel: &(state.level * resp.P).compress(),
1015 Psince: &(resp.level_since * resp.P).compress(),
1016 Pinvremain: &(state.invremain * resp.P).compress(),
1017 TId: &resp.TId.compress(),
1018 TBucket: &resp.TBucket.compress(),
1019 TBlockages: &resp.TBlockages.compress(),
1020 D: &state.D.compress(),
1021 EncId0: &EncId.0.compress(),
1022 EncId1: &EncId.1.compress(),
1023 EncBucket0: &state.EncBucket.0.compress(),
1024 EncBucket1: &state.EncBucket.1.compress(),
1025 EncBlockages0: &state.EncBlockages.0.compress(),
1026 EncBlockages1: &state.EncBlockages.1.compress(),
1027 },
1028 )?;
1029
1030 let Q = resp.EncQ.1 - (state.d * resp.EncQ.0);
1032
1033 Ok(cred::Lox {
1034 P: resp.P,
1035 Q,
1036 id,
1037 bucket: state.bucket,
1038 trust_level: state.level,
1039 level_since: resp.level_since,
1040 invites_remaining: state.invremain,
1041 blockages: state.blockages,
1042 })
1043}