issue_invite.rs 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793
  1. /*! A module for the protocol for a user to request the issuing of an
  2. Invitation credential they can pass to someone they know.
  3. They are allowed to do this as long as their current Lox credentials has
  4. a non-zero "invites_remaining" attribute (which will be decreased by
  5. one), and they have a Bucket Reachability credential for their current
  6. bucket and today's date. (Such credentials are placed daily in the
  7. encrypted bridge table.)
  8. The user presents their current Lox credential:
  9. - id: revealed
  10. - bucket: blinded
  11. - trust_level: blinded
  12. - level_since: blinded
  13. - invites_remaining: blinded, but proved in ZK that it's not zero
  14. - blockages: blinded
  15. and a Bucket Reachability credential:
  16. - date: revealed to be today
  17. - bucket: blinded, but proved in ZK that it's the same as in the Lox
  18. credential above
  19. and a new Lox credential to be issued:
  20. - id: jointly chosen by the user and BA
  21. - bucket: blinded, but proved in ZK that it's the same as in the Lox
  22. credential above
  23. - trust_level: blinded, but proved in ZK that it's the same as in the
  24. Lox credential above
  25. - level_since: blinded, but proved in ZK that it's the same as in the
  26. Lox credential above
  27. - invites_remaining: blinded, but proved in ZK that it's one less than
  28. the number in the Lox credential above
  29. - blockages: blinded, but proved in ZK that it's the same as in the
  30. Lox credential above
  31. and a new Invitation credential to be issued:
  32. - inv_id: jointly chosen by the user and BA
  33. - date: revealed to be today
  34. - bucket: blinded, but proved in ZK that it's the same as in the Lox
  35. credential above
  36. - blockages: blinded, but proved in ZK that it's the same as in the Lox
  37. credential above
  38. */
  39. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  40. use curve25519_dalek::ristretto::RistrettoPoint;
  41. use curve25519_dalek::scalar::Scalar;
  42. use curve25519_dalek::traits::IsIdentity;
  43. use zkp::CompactProof;
  44. use zkp::ProofError;
  45. use zkp::Transcript;
  46. use super::super::cred;
  47. use super::super::dup_filter::SeenType;
  48. use super::super::scalar_u32;
  49. use super::super::{BridgeAuth, IssuerPubKey};
  50. use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
  51. pub struct Request {
  52. // Fields for blind showing the Lox credential
  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. // Fields for blind showing the Bucket Reachability credential
  62. P_reach: RistrettoPoint,
  63. CBucket_reach: RistrettoPoint,
  64. CQ_reach: RistrettoPoint,
  65. // Fields for user blinding of the Lox credential to be issued
  66. D: RistrettoPoint,
  67. EncIdClient: (RistrettoPoint, RistrettoPoint),
  68. EncBucket: (RistrettoPoint, RistrettoPoint),
  69. EncLevel: (RistrettoPoint, RistrettoPoint),
  70. EncSince: (RistrettoPoint, RistrettoPoint),
  71. EncInvRemain: (RistrettoPoint, RistrettoPoint),
  72. EncBlockages: (RistrettoPoint, RistrettoPoint),
  73. // Fields for user blinding of the Inivtation credential to be
  74. // issued
  75. EncInvIdClient: (RistrettoPoint, RistrettoPoint),
  76. // The bucket and blockages attributes in the Invitation credential
  77. // issuing protocol can just reuse the exact encryptions as for the
  78. // Lox credential issuing protocol above.
  79. // The combined ZKP
  80. piUser: CompactProof,
  81. }
  82. #[derive(Debug)]
  83. pub struct State {
  84. d: Scalar,
  85. D: RistrettoPoint,
  86. EncIdClient: (RistrettoPoint, RistrettoPoint),
  87. EncBucket: (RistrettoPoint, RistrettoPoint),
  88. EncLevel: (RistrettoPoint, RistrettoPoint),
  89. EncSince: (RistrettoPoint, RistrettoPoint),
  90. EncInvRemain: (RistrettoPoint, RistrettoPoint),
  91. EncBlockages: (RistrettoPoint, RistrettoPoint),
  92. EncInvIdClient: (RistrettoPoint, RistrettoPoint),
  93. id_client: Scalar,
  94. bucket: Scalar,
  95. level: Scalar,
  96. since: Scalar,
  97. invremain: Scalar,
  98. blockages: Scalar,
  99. inv_id_client: Scalar,
  100. }
  101. pub struct Response {
  102. // The fields for the new Lox credential; the new invites_remaining
  103. // is one less than the old value, so we don't have to include it
  104. // here explicitly
  105. P: RistrettoPoint,
  106. EncQ: (RistrettoPoint, RistrettoPoint),
  107. id_server: Scalar,
  108. TId: RistrettoPoint,
  109. TBucket: RistrettoPoint,
  110. TLevel: RistrettoPoint,
  111. TSince: RistrettoPoint,
  112. TInvRemain: RistrettoPoint,
  113. TBlockages: RistrettoPoint,
  114. // The fields for the new Invitation credential
  115. P_inv: RistrettoPoint,
  116. EncQ_inv: (RistrettoPoint, RistrettoPoint),
  117. inv_id_server: Scalar,
  118. TId_inv: RistrettoPoint,
  119. date_inv: Scalar,
  120. TBucket_inv: RistrettoPoint,
  121. TBlockages_inv: RistrettoPoint,
  122. // The ZKP
  123. piBlindIssue: CompactProof,
  124. }
  125. define_proof! {
  126. requestproof,
  127. "Issue Invite Request",
  128. (bucket, level, since, invremain, blockages, zbucket, zlevel,
  129. zsince, zinvremain, zblockages, negzQ,
  130. zbucket_reach, negzQ_reach,
  131. d, eid_client, ebucket, elevel, esince, einvremain, eblockages, id_client,
  132. inv_id_client, einv_id_client,
  133. invremain_inverse, zinvremain_inverse),
  134. (P, CBucket, CLevel, CSince, CInvRemain, CBlockages, V, Xbucket,
  135. Xlevel, Xsince, Xinvremain, Xblockages,
  136. P_reach, CBucket_reach, V_reach, Xbucket_reach,
  137. D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
  138. EncLevel0, EncLevel1, EncSince0, EncSince1,
  139. EncInvRemain0, EncInvRemain1_plus_B, EncBlockages0, EncBlockages1,
  140. EncInvIdClient0, EncInvIdClient1),
  141. (A, B):
  142. // Blind showing of the Lox credential
  143. CBucket = (bucket*P + zbucket*A),
  144. CLevel = (level*P + zlevel*A),
  145. CSince = (since*P + zsince*A),
  146. CInvRemain = (invremain*P + zinvremain*A),
  147. CBlockages = (blockages*P + zblockages*A),
  148. // Proof that invremain is not 0
  149. P = (invremain_inverse*CInvRemain + zinvremain_inverse*A),
  150. // Blind showing of the Bucket Reachability credential; note the
  151. // same bucket is used in the proof
  152. CBucket_reach = (bucket*P_reach + zbucket_reach*A),
  153. // User blinding of the Lox credential to be issued
  154. D = (d*B),
  155. EncIdClient0 = (eid_client*B),
  156. EncIdClient1 = (id_client*B + eid_client*D),
  157. EncBucket0 = (ebucket*B),
  158. EncBucket1 = (bucket*B + ebucket*D),
  159. EncLevel0 = (elevel*B),
  160. EncLevel1 = (level*B + elevel*D),
  161. EncSince0 = (esince*B),
  162. EncSince1 = (since*B + esince*D),
  163. EncInvRemain0 = (einvremain*B),
  164. EncInvRemain1_plus_B = (invremain*B + einvremain*D),
  165. EncBlockages0 = (eblockages*B),
  166. EncBlockages1 = (blockages*B + eblockages*D),
  167. // User blinding of the Invitation to be issued
  168. EncInvIdClient0 = (einv_id_client*B),
  169. EncInvIdClient1 = (inv_id_client*B + einv_id_client*D)
  170. }
  171. define_proof! {
  172. blindissue,
  173. "Issue Invite Issuing",
  174. (x0, x0tilde, xid, xbucket, xlevel, xsince, xinvremain, xblockages,
  175. s, b, tid, tbucket, tlevel, tsince, tinvremain, tblockages,
  176. x0_inv, x0tilde_inv, xid_inv, xdate_inv, xbucket_inv,
  177. xblockages_inv,
  178. s_inv, b_inv, tid_inv, tbucket_inv, tblockages_inv),
  179. (P, EncQ0, EncQ1, X0, Xid, Xbucket, Xlevel, Xsince, Xinvremain,
  180. Xblockages, TId, TBucket, TLevel, TSince, TInvRemain, TBlockages,
  181. P_inv, EncQ_inv0, EncQ_inv1, X0_inv, Xid_inv, Xdate_inv,
  182. Xbucket_inv, Xblockages_inv, Pdate_inv, TId_inv, TBucket_inv,
  183. TBlockages_inv,
  184. D, EncId0, EncId1, EncBucket0, EncBucket1, EncLevel0, EncLevel1,
  185. EncSince0, EncSince1, EncInvRemain0, EncInvRemain1,
  186. EncBlockages0, EncBlockages1,
  187. EncInvId0, EncInvId1),
  188. (A, B):
  189. Xid = (xid*A),
  190. Xbucket = (xbucket*A),
  191. Xlevel = (xlevel*A),
  192. Xsince = (xsince*A),
  193. Xinvremain = (xinvremain*A),
  194. Xblockages = (xblockages*A),
  195. X0 = (x0*B + x0tilde*A),
  196. P = (b*B),
  197. TId = (b*Xid),
  198. TId = (tid*A),
  199. TBucket = (b*Xbucket),
  200. TBucket = (tbucket*A),
  201. TLevel = (b*Xlevel),
  202. TLevel = (tlevel*A),
  203. TSince = (b*Xsince),
  204. TSince = (tsince*A),
  205. TInvRemain = (b*Xinvremain),
  206. TInvRemain = (tinvremain*A),
  207. TBlockages = (b*Xblockages),
  208. TBlockages = (tblockages*A),
  209. EncQ0 = (s*B + tid*EncId0 + tbucket*EncBucket0 + tlevel*EncLevel0
  210. + tsince*EncSince0 + tinvremain*EncInvRemain0 + tblockages*EncBlockages0),
  211. EncQ1 = (s*D + tid*EncId1 + tbucket*EncBucket1 + tlevel*EncLevel1
  212. + tsince*EncSince1 + tinvremain*EncInvRemain1 + tblockages*EncBlockages1
  213. + x0*P),
  214. Xid_inv = (xid_inv*A),
  215. Xdate_inv = (xdate_inv*A),
  216. Xbucket_inv = (xbucket_inv*A),
  217. Xblockages_inv = (xblockages_inv*A),
  218. X0_inv = (x0_inv*B + x0tilde_inv*A),
  219. P_inv = (b_inv*B),
  220. TId_inv = (b_inv*Xid_inv),
  221. TId_inv = (tid_inv*A),
  222. TBucket_inv = (b_inv*Xbucket_inv),
  223. TBucket_inv = (tbucket_inv*A),
  224. TBlockages_inv = (b_inv*Xblockages_inv),
  225. TBlockages_inv = (tblockages_inv*A),
  226. EncQ_inv0 = (s_inv*B + tid_inv*EncInvId0 + tbucket_inv*EncBucket0
  227. + tblockages_inv*EncBlockages0),
  228. EncQ_inv1 = (s_inv*D + tid_inv*EncInvId1 + tbucket_inv*EncBucket1
  229. + tblockages_inv*EncBlockages1 + x0_inv*P_inv + xdate_inv*Pdate_inv)
  230. }
  231. pub fn request(
  232. lox_cred: &cred::Lox,
  233. reach_cred: &cred::BucketReachability,
  234. lox_pub: &IssuerPubKey,
  235. reach_pub: &IssuerPubKey,
  236. today: u32,
  237. ) -> Result<(Request, State), ProofError> {
  238. let A: &RistrettoPoint = &CMZ_A;
  239. let B: &RistrettoPoint = &CMZ_B;
  240. let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
  241. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  242. // Ensure the credential can be correctly shown: it must be the case
  243. // that invites_remaining not be 0
  244. if lox_cred.invites_remaining == Scalar::zero() {
  245. return Err(ProofError::VerificationFailure);
  246. }
  247. // The buckets in the Lox and Bucket Reachability credentials have
  248. // to match
  249. if lox_cred.bucket != reach_cred.bucket {
  250. return Err(ProofError::VerificationFailure);
  251. }
  252. // The Bucket Reachability credential has to be dated today
  253. let reach_date: u32 = match scalar_u32(&reach_cred.date) {
  254. Some(v) => v,
  255. None => return Err(ProofError::VerificationFailure),
  256. };
  257. if reach_date != today {
  258. return Err(ProofError::VerificationFailure);
  259. }
  260. // The new invites_remaining
  261. let new_invites_remaining = &lox_cred.invites_remaining - Scalar::one();
  262. // Blind showing the Lox credential
  263. // Reblind P and Q
  264. let mut rng = rand::thread_rng();
  265. let t = Scalar::random(&mut rng);
  266. let P = t * lox_cred.P;
  267. let Q = t * lox_cred.Q;
  268. // Form Pedersen commitments to the blinded attributes
  269. let zbucket = Scalar::random(&mut rng);
  270. let zlevel = Scalar::random(&mut rng);
  271. let zsince = Scalar::random(&mut rng);
  272. let zinvremain = Scalar::random(&mut rng);
  273. let zblockages = Scalar::random(&mut rng);
  274. let CBucket = lox_cred.bucket * P + &zbucket * Atable;
  275. let CLevel = lox_cred.trust_level * P + &zlevel * Atable;
  276. let CSince = lox_cred.level_since * P + &zsince * Atable;
  277. let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
  278. let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
  279. // Form a Pedersen commitment to the MAC Q
  280. // We flip the sign of zQ from that of the Hyphae paper so that
  281. // the ZKP has a "+" instead of a "-", as that's what the zkp
  282. // macro supports.
  283. let negzQ = Scalar::random(&mut rng);
  284. let CQ = Q - &negzQ * Atable;
  285. // Compute the "error factor"
  286. let V = zbucket * lox_pub.X[2]
  287. + zlevel * lox_pub.X[3]
  288. + zsince * lox_pub.X[4]
  289. + zinvremain * lox_pub.X[5]
  290. + zblockages * lox_pub.X[6]
  291. + &negzQ * Atable;
  292. // Blind showing the Bucket Reachability credential
  293. // Reblind P and Q
  294. let t_reach = Scalar::random(&mut rng);
  295. let P_reach = t_reach * reach_cred.P;
  296. let Q_reach = t_reach * reach_cred.Q;
  297. // Form Pedersen commitments to the blinded attributes
  298. let zbucket_reach = Scalar::random(&mut rng);
  299. let CBucket_reach = reach_cred.bucket * P_reach + &zbucket_reach * Atable;
  300. // Form a Pedersen commitment to the MAC Q
  301. // We flip the sign of zQ from that of the Hyphae paper so that
  302. // the ZKP has a "+" instead of a "-", as that's what the zkp
  303. // macro supports.
  304. let negzQ_reach = Scalar::random(&mut rng);
  305. let CQ_reach = Q_reach - &negzQ_reach * Atable;
  306. // Compute the "error factor"
  307. let V_reach = zbucket_reach * reach_pub.X[2] + &negzQ_reach * Atable;
  308. // User blinding for the Lox certificate to be issued
  309. // Pick an ElGamal keypair
  310. let d = Scalar::random(&mut rng);
  311. let D = &d * Btable;
  312. // Pick a random client component of the id
  313. let id_client = Scalar::random(&mut rng);
  314. // Encrypt it (times the basepoint B) to the ElGamal public key D we
  315. // just created
  316. let eid_client = Scalar::random(&mut rng);
  317. let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
  318. // Encrypt the other blinded fields (times B) to D as well
  319. let ebucket = Scalar::random(&mut rng);
  320. let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
  321. let elevel = Scalar::random(&mut rng);
  322. let EncLevel = (
  323. &elevel * Btable,
  324. &lox_cred.trust_level * Btable + elevel * D,
  325. );
  326. let esince = Scalar::random(&mut rng);
  327. let EncSince = (
  328. &esince * Btable,
  329. &lox_cred.level_since * Btable + esince * D,
  330. );
  331. let einvremain = Scalar::random(&mut rng);
  332. let EncInvRemain = (
  333. &einvremain * Btable,
  334. &new_invites_remaining * Btable + einvremain * D,
  335. );
  336. let eblockages = Scalar::random(&mut rng);
  337. let EncBlockages = (
  338. &eblockages * Btable,
  339. &lox_cred.blockages * Btable + eblockages * D,
  340. );
  341. // User blinding for the Invitation certificate to be issued
  342. // Pick a random client component of the id
  343. let inv_id_client = Scalar::random(&mut rng);
  344. // Encrypt it (times the basepoint B) to the ElGamal public key D we
  345. // just created
  346. let einv_id_client = Scalar::random(&mut rng);
  347. let EncInvIdClient = (
  348. &einv_id_client * Btable,
  349. &inv_id_client * Btable + einv_id_client * D,
  350. );
  351. // The proof that invites_remaining is not zero. We prove this by
  352. // demonstrating that we know its inverse.
  353. let invremain_inverse = &lox_cred.invites_remaining.invert();
  354. let zinvremain_inverse = -zinvremain * invremain_inverse;
  355. // So now invremain_inverse * CInvRemain + zinvremain_inverse * A = P
  356. // Construct the proof
  357. let mut transcript = Transcript::new(b"issue invite request");
  358. let piUser = requestproof::prove_compact(
  359. &mut transcript,
  360. requestproof::ProveAssignments {
  361. A: &A,
  362. B: &B,
  363. P: &P,
  364. CBucket: &CBucket,
  365. CLevel: &CLevel,
  366. CSince: &CSince,
  367. CInvRemain: &CInvRemain,
  368. CBlockages: &CBlockages,
  369. V: &V,
  370. Xbucket: &lox_pub.X[2],
  371. Xlevel: &lox_pub.X[3],
  372. Xsince: &lox_pub.X[4],
  373. Xinvremain: &lox_pub.X[5],
  374. Xblockages: &lox_pub.X[6],
  375. P_reach: &P_reach,
  376. CBucket_reach: &CBucket_reach,
  377. V_reach: &V_reach,
  378. Xbucket_reach: &reach_pub.X[2],
  379. D: &D,
  380. EncIdClient0: &EncIdClient.0,
  381. EncIdClient1: &EncIdClient.1,
  382. EncBucket0: &EncBucket.0,
  383. EncBucket1: &EncBucket.1,
  384. EncLevel0: &EncLevel.0,
  385. EncLevel1: &EncLevel.1,
  386. EncSince0: &EncSince.0,
  387. EncSince1: &EncSince.1,
  388. EncInvRemain0: &EncInvRemain.0,
  389. EncInvRemain1_plus_B: &(EncInvRemain.1 + B),
  390. EncBlockages0: &EncBlockages.0,
  391. EncBlockages1: &EncBlockages.1,
  392. EncInvIdClient0: &EncInvIdClient.0,
  393. EncInvIdClient1: &EncInvIdClient.1,
  394. bucket: &lox_cred.bucket,
  395. level: &lox_cred.trust_level,
  396. since: &lox_cred.level_since,
  397. invremain: &lox_cred.invites_remaining,
  398. blockages: &lox_cred.blockages,
  399. zbucket: &zbucket,
  400. zlevel: &zlevel,
  401. zsince: &zsince,
  402. zinvremain: &zinvremain,
  403. zblockages: &zblockages,
  404. negzQ: &negzQ,
  405. zbucket_reach: &zbucket_reach,
  406. negzQ_reach: &negzQ_reach,
  407. d: &d,
  408. eid_client: &eid_client,
  409. ebucket: &ebucket,
  410. elevel: &elevel,
  411. esince: &esince,
  412. einvremain: &einvremain,
  413. eblockages: &eblockages,
  414. id_client: &id_client,
  415. inv_id_client: &inv_id_client,
  416. einv_id_client: &einv_id_client,
  417. invremain_inverse: &invremain_inverse,
  418. zinvremain_inverse: &zinvremain_inverse,
  419. },
  420. )
  421. .0;
  422. Ok((
  423. Request {
  424. P,
  425. id: lox_cred.id,
  426. CBucket,
  427. CLevel,
  428. CSince,
  429. CInvRemain,
  430. CBlockages,
  431. CQ,
  432. P_reach,
  433. CBucket_reach,
  434. CQ_reach,
  435. D,
  436. EncIdClient,
  437. EncBucket,
  438. EncLevel,
  439. EncSince,
  440. EncInvRemain,
  441. EncBlockages,
  442. EncInvIdClient,
  443. piUser,
  444. },
  445. State {
  446. d,
  447. D,
  448. EncIdClient,
  449. EncBucket,
  450. EncLevel,
  451. EncSince,
  452. EncInvRemain,
  453. EncBlockages,
  454. EncInvIdClient,
  455. id_client,
  456. bucket: lox_cred.bucket,
  457. level: lox_cred.trust_level,
  458. since: lox_cred.level_since,
  459. invremain: new_invites_remaining,
  460. blockages: lox_cred.blockages,
  461. inv_id_client,
  462. },
  463. ))
  464. }
  465. impl BridgeAuth {
  466. /// Receive an issue invite request
  467. pub fn handle_issue_invite(&mut self, req: Request) -> Result<Response, ProofError> {
  468. let A: &RistrettoPoint = &CMZ_A;
  469. let B: &RistrettoPoint = &CMZ_B;
  470. let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
  471. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  472. if req.P.is_identity() || req.P_reach.is_identity() {
  473. return Err(ProofError::VerificationFailure);
  474. }
  475. let today: Scalar = self.today().into();
  476. // Recompute the "error factors" using knowledge of our own
  477. // (the issuer's) private key instead of knowledge of the
  478. // hidden attributes
  479. let Vprime = (self.lox_priv.x[0] + self.lox_priv.x[1] * req.id) * req.P
  480. + self.lox_priv.x[2] * req.CBucket
  481. + self.lox_priv.x[3] * req.CLevel
  482. + self.lox_priv.x[4] * req.CSince
  483. + self.lox_priv.x[5] * req.CInvRemain
  484. + self.lox_priv.x[6] * req.CBlockages
  485. - req.CQ;
  486. let Vprime_reach = (self.reachability_priv.x[0] + self.reachability_priv.x[1] * today)
  487. * req.P_reach
  488. + self.reachability_priv.x[2] * req.CBucket_reach
  489. - req.CQ_reach;
  490. // Verify the ZKP
  491. let mut transcript = Transcript::new(b"issue invite request");
  492. requestproof::verify_compact(
  493. &req.piUser,
  494. &mut transcript,
  495. requestproof::VerifyAssignments {
  496. A: &A.compress(),
  497. B: &B.compress(),
  498. P: &req.P.compress(),
  499. CBucket: &req.CBucket.compress(),
  500. CLevel: &req.CLevel.compress(),
  501. CSince: &req.CSince.compress(),
  502. CInvRemain: &req.CInvRemain.compress(),
  503. CBlockages: &req.CBlockages.compress(),
  504. V: &Vprime.compress(),
  505. Xbucket: &self.lox_pub.X[2].compress(),
  506. Xlevel: &self.lox_pub.X[3].compress(),
  507. Xsince: &self.lox_pub.X[4].compress(),
  508. Xinvremain: &self.lox_pub.X[5].compress(),
  509. Xblockages: &self.lox_pub.X[6].compress(),
  510. P_reach: &req.P_reach.compress(),
  511. CBucket_reach: &req.CBucket_reach.compress(),
  512. V_reach: &Vprime_reach.compress(),
  513. Xbucket_reach: &self.reachability_pub.X[2].compress(),
  514. D: &req.D.compress(),
  515. EncIdClient0: &req.EncIdClient.0.compress(),
  516. EncIdClient1: &req.EncIdClient.1.compress(),
  517. EncBucket0: &req.EncBucket.0.compress(),
  518. EncBucket1: &req.EncBucket.1.compress(),
  519. EncLevel0: &req.EncLevel.0.compress(),
  520. EncLevel1: &req.EncLevel.1.compress(),
  521. EncSince0: &req.EncSince.0.compress(),
  522. EncSince1: &req.EncSince.1.compress(),
  523. EncInvRemain0: &req.EncInvRemain.0.compress(),
  524. EncInvRemain1_plus_B: &(req.EncInvRemain.1 + B).compress(),
  525. EncBlockages0: &req.EncBlockages.0.compress(),
  526. EncBlockages1: &req.EncBlockages.1.compress(),
  527. EncInvIdClient0: &req.EncInvIdClient.0.compress(),
  528. EncInvIdClient1: &req.EncInvIdClient.1.compress(),
  529. },
  530. )?;
  531. // Ensure the id has not been seen before, and add it to the
  532. // seen list.
  533. if self.id_filter.filter(&req.id) == SeenType::Seen {
  534. return Err(ProofError::VerificationFailure);
  535. }
  536. // Blind issuing of the new Lox credential
  537. // Choose a random server id component to add to the client's
  538. // (blinded) id component
  539. let mut rng = rand::thread_rng();
  540. let id_server = Scalar::random(&mut rng);
  541. let EncId = (req.EncIdClient.0, req.EncIdClient.1 + &id_server * Btable);
  542. // Compute the MAC on the visible attributes (none here)
  543. let b = Scalar::random(&mut rng);
  544. let P = &b * Btable;
  545. let QHc = self.lox_priv.x[0] * P;
  546. // El Gamal encrypt it to the public key req.D
  547. let s = Scalar::random(&mut rng);
  548. let EncQHc = (&s * Btable, QHc + s * req.D);
  549. // Homomorphically compute the part of the MAC corresponding to
  550. // the blinded attributes
  551. let tid = self.lox_priv.x[1] * b;
  552. let TId = &tid * Atable;
  553. let EncQId = (tid * EncId.0, tid * EncId.1);
  554. let tbucket = self.lox_priv.x[2] * b;
  555. let TBucket = &tbucket * Atable;
  556. let EncQBucket = (tbucket * req.EncBucket.0, tbucket * req.EncBucket.1);
  557. let tlevel = self.lox_priv.x[3] * b;
  558. let TLevel = &tlevel * Atable;
  559. let EncQLevel = (tlevel * req.EncLevel.0, tlevel * req.EncLevel.1);
  560. let tsince = self.lox_priv.x[4] * b;
  561. let TSince = &tsince * Atable;
  562. let EncQSince = (tsince * req.EncSince.0, tsince * req.EncSince.1);
  563. let tinvremain = self.lox_priv.x[5] * b;
  564. let TInvRemain = &tinvremain * Atable;
  565. let EncQInvRemain = (
  566. tinvremain * req.EncInvRemain.0,
  567. tinvremain * req.EncInvRemain.1,
  568. );
  569. let tblockages = self.lox_priv.x[6] * b;
  570. let TBlockages = &tblockages * Atable;
  571. let EncQBlockages = (
  572. tblockages * req.EncBlockages.0,
  573. tblockages * req.EncBlockages.1,
  574. );
  575. let EncQ = (
  576. EncQHc.0
  577. + EncQId.0
  578. + EncQBucket.0
  579. + EncQLevel.0
  580. + EncQSince.0
  581. + EncQInvRemain.0
  582. + EncQBlockages.0,
  583. EncQHc.1
  584. + EncQId.1
  585. + EncQBucket.1
  586. + EncQLevel.1
  587. + EncQSince.1
  588. + EncQInvRemain.1
  589. + EncQBlockages.1,
  590. );
  591. // Blind issuing of the new Invitation credential
  592. // Choose a random server id component to add to the client's
  593. // (blinded) id component
  594. let inv_id_server = Scalar::random(&mut rng);
  595. let EncInvId = (
  596. req.EncInvIdClient.0,
  597. req.EncInvIdClient.1 + &inv_id_server * Btable,
  598. );
  599. // Compute the MAC on the visible attributes
  600. let b_inv = Scalar::random(&mut rng);
  601. let P_inv = &b_inv * Btable;
  602. let QHc_inv = (self.invitation_priv.x[0] + self.invitation_priv.x[2] * today) * P;
  603. // El Gamal encrypt it to the public key req.D
  604. let s_inv = Scalar::random(&mut rng);
  605. let EncQHc_inv = (&s_inv * Btable, QHc_inv + s_inv * req.D);
  606. // Homomorphically compute the part of the MAC corresponding to
  607. // the blinded attributes
  608. let tinvid = self.invitation_priv.x[1] * b_inv;
  609. let TId_inv = &tinvid * Atable;
  610. let EncQInvId = (tinvid * EncInvId.0, tinvid * EncInvId.1);
  611. let tinvbucket = self.invitation_priv.x[3] * b_inv;
  612. let TBucket_inv = &tinvbucket * Atable;
  613. // The bucket and blockages encrypted attributes are reused from
  614. // the Lox credential
  615. let EncQInvBucket = (tinvbucket * req.EncBucket.0, tinvbucket * req.EncBucket.1);
  616. let tinvblockages = self.invitation_priv.x[4] * b_inv;
  617. let TBlockages_inv = &tinvblockages * Atable;
  618. let EncQInvBlockages = (
  619. tinvblockages * req.EncBlockages.0,
  620. tinvblockages * req.EncBlockages.1,
  621. );
  622. let EncQ_inv = (
  623. EncQHc_inv.0 + EncQInvId.0 + EncQInvBucket.0 + EncQInvBlockages.0,
  624. EncQHc_inv.1 + EncQInvId.1 + EncQInvBucket.1 + EncQInvBlockages.1,
  625. );
  626. let mut transcript = Transcript::new(b"issue invite issuing");
  627. let piBlindIssue = blindissue::prove_compact(
  628. &mut transcript,
  629. blindissue::ProveAssignments {
  630. A: &A,
  631. B: &B,
  632. P: &P,
  633. EncQ0: &EncQ.0,
  634. EncQ1: &EncQ.1,
  635. X0: &self.lox_pub.X[0],
  636. Xid: &self.lox_pub.X[1],
  637. Xbucket: &self.lox_pub.X[2],
  638. Xlevel: &self.lox_pub.X[3],
  639. Xsince: &self.lox_pub.X[4],
  640. Xinvremain: &self.lox_pub.X[5],
  641. Xblockages: &self.lox_pub.X[6],
  642. TId: &TId,
  643. TBucket: &TBucket,
  644. TLevel: &TLevel,
  645. TSince: &TSince,
  646. TInvRemain: &TInvRemain,
  647. TBlockages: &TBlockages,
  648. P_inv: &P_inv,
  649. EncQ_inv0: &EncQ_inv.0,
  650. EncQ_inv1: &EncQ_inv.1,
  651. X0_inv: &self.invitation_pub.X[0],
  652. Xid_inv: &self.invitation_pub.X[1],
  653. Xdate_inv: &self.invitation_pub.X[2],
  654. Xbucket_inv: &self.invitation_pub.X[3],
  655. Xblockages_inv: &self.invitation_pub.X[4],
  656. Pdate_inv: &(today * P_inv),
  657. TId_inv: &TId_inv,
  658. TBucket_inv: &TBucket_inv,
  659. TBlockages_inv: &TBlockages_inv,
  660. D: &req.D,
  661. EncId0: &EncId.0,
  662. EncId1: &EncId.1,
  663. EncBucket0: &req.EncBucket.0,
  664. EncBucket1: &req.EncBucket.1,
  665. EncLevel0: &req.EncLevel.0,
  666. EncLevel1: &req.EncLevel.1,
  667. EncSince0: &req.EncSince.0,
  668. EncSince1: &req.EncSince.1,
  669. EncInvRemain0: &req.EncInvRemain.0,
  670. EncInvRemain1: &req.EncInvRemain.1,
  671. EncBlockages0: &req.EncBlockages.0,
  672. EncBlockages1: &req.EncBlockages.1,
  673. EncInvId0: &EncInvId.0,
  674. EncInvId1: &EncInvId.1,
  675. x0: &self.lox_priv.x[0],
  676. x0tilde: &self.lox_priv.x0tilde,
  677. xid: &self.lox_priv.x[1],
  678. xbucket: &self.lox_priv.x[2],
  679. xlevel: &self.lox_priv.x[3],
  680. xsince: &self.lox_priv.x[4],
  681. xinvremain: &self.lox_priv.x[5],
  682. xblockages: &self.lox_priv.x[6],
  683. s: &s,
  684. b: &b,
  685. tid: &tid,
  686. tbucket: &tbucket,
  687. tlevel: &tlevel,
  688. tsince: &tsince,
  689. tinvremain: &tinvremain,
  690. tblockages: &tblockages,
  691. x0_inv: &self.invitation_priv.x[0],
  692. x0tilde_inv: &self.invitation_priv.x0tilde,
  693. xid_inv: &self.invitation_priv.x[1],
  694. xdate_inv: &self.invitation_priv.x[2],
  695. xbucket_inv: &self.invitation_priv.x[3],
  696. xblockages_inv: &self.invitation_priv.x[4],
  697. s_inv: &s_inv,
  698. b_inv: &b_inv,
  699. tid_inv: &tinvid,
  700. tbucket_inv: &tinvbucket,
  701. tblockages_inv: &tinvblockages,
  702. },
  703. )
  704. .0;
  705. Ok(Response {
  706. P,
  707. EncQ,
  708. id_server,
  709. TId,
  710. TBucket,
  711. TLevel,
  712. TSince,
  713. TInvRemain,
  714. TBlockages,
  715. P_inv,
  716. EncQ_inv,
  717. inv_id_server,
  718. TId_inv,
  719. date_inv: today,
  720. TBucket_inv,
  721. TBlockages_inv,
  722. piBlindIssue,
  723. })
  724. }
  725. }