issue_invite.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  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::{pt_dbl, scalar_dbl, 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. inv_id_server: Scalar,
  115. TInvId: RistrettoPoint,
  116. // The ZKP
  117. piBlindIssue: CompactProof,
  118. }
  119. define_proof! {
  120. requestproof,
  121. "Issue Invite Request",
  122. (bucket, level, since, invremain, blockages, zbucket, zlevel,
  123. zsince, zinvremain, zblockages, negzQ,
  124. zbucket_reach, negzQ_reach,
  125. d, eid_client, ebucket, elevel, esince, einvremain, eblockages, id_client,
  126. inv_id_client, einv_id_client,
  127. invremain_inverse, zinvremain_inverse),
  128. (P, CBucket, CLevel, CSince, CInvRemain, CBlockages, V, Xbucket,
  129. Xlevel, Xsince, Xinvremain, Xblockages,
  130. P_reach, CBucket_reach, V_reach, Xbucket_reach,
  131. D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
  132. EncLevel0, EncLevel1, EncSince0, EncSince1,
  133. EncInvRemain0, EncInvRemain1_plus_B, EncBlockages0, EncBlockages1,
  134. EncInvIdClient0, EncInvIdClient1),
  135. (A, B):
  136. // Blind showing of the Lox credential
  137. CBucket = (bucket*P + zbucket*A),
  138. CLevel = (level*P + zlevel*A),
  139. CSince = (since*P + zsince*A),
  140. CInvRemain = (invremain*P + zinvremain*A),
  141. CBlockages = (blockages*P + zblockages*A),
  142. // Proof that invremain is not 0
  143. P = (invremain_inverse*CInvRemain + zinvremain_inverse*A),
  144. // Blind showing of the Bucket Reachability credential; note the
  145. // same bucket is used in the proof
  146. CBucket_reach = (bucket*P_reach + zbucket_reach*A),
  147. // User blinding of the Lox credential to be issued
  148. D = (d*B),
  149. EncIdClient0 = (eid_client*B),
  150. EncIdClient1 = (id_client*B + eid_client*D),
  151. EncBucket0 = (ebucket*B),
  152. EncBucket1 = (bucket*B + ebucket*D),
  153. EncLevel0 = (elevel*B),
  154. EncLevel1 = (level*B + elevel*D),
  155. EncSince0 = (esince*B),
  156. EncSince1 = (since*B + esince*D),
  157. EncInvRemain0 = (einvremain*B),
  158. EncInvRemain1_plus_B = (invremain*B + einvremain*D),
  159. EncBlockages0 = (eblockages*B),
  160. EncBlockages1 = (blockages*B + eblockages*D),
  161. // User blinding of the Invitation to be issued
  162. EncInvIdClient0 = (einv_id_client*B),
  163. EncInvIdClient1 = (inv_id_client*B + einv_id_client*D)
  164. }
  165. pub fn request(
  166. lox_cred: &cred::Lox,
  167. reach_cred: &cred::BucketReachability,
  168. lox_pub: &IssuerPubKey,
  169. reach_pub: &IssuerPubKey,
  170. today: u32,
  171. ) -> Result<(Request, State), ProofError> {
  172. let A: &RistrettoPoint = &CMZ_A;
  173. let B: &RistrettoPoint = &CMZ_B;
  174. let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
  175. let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
  176. // Ensure the credential can be correctly shown: it must be the case
  177. // that invites_remaining not be 0
  178. if lox_cred.invites_remaining == Scalar::zero() {
  179. return Err(ProofError::VerificationFailure);
  180. }
  181. // The buckets in the Lox and Bucket Reachability credentials have
  182. // to match
  183. if lox_cred.bucket != reach_cred.bucket {
  184. return Err(ProofError::VerificationFailure);
  185. }
  186. // The Bucket Reachability credential has to be dated today
  187. let reach_date: u32 = match scalar_u32(&reach_cred.date) {
  188. Some(v) => v,
  189. None => return Err(ProofError::VerificationFailure),
  190. };
  191. if reach_date != today {
  192. return Err(ProofError::VerificationFailure);
  193. }
  194. // The new invites_remaining
  195. let new_invites_remaining = &lox_cred.invites_remaining - Scalar::one();
  196. // Blind showing the Lox credential
  197. // Reblind P and Q
  198. let mut rng = rand::thread_rng();
  199. let t = Scalar::random(&mut rng);
  200. let P = t * lox_cred.P;
  201. let Q = t * lox_cred.Q;
  202. // Form Pedersen commitments to the blinded attributes
  203. let zbucket = Scalar::random(&mut rng);
  204. let zlevel = Scalar::random(&mut rng);
  205. let zsince = Scalar::random(&mut rng);
  206. let zinvremain = Scalar::random(&mut rng);
  207. let zblockages = Scalar::random(&mut rng);
  208. let CBucket = lox_cred.bucket * P + &zbucket * Atable;
  209. let CLevel = lox_cred.bucket * P + &zlevel * Atable;
  210. let CSince = lox_cred.level_since * P + &zsince * Atable;
  211. let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
  212. let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
  213. // Form a Pedersen commitment to the MAC Q
  214. // We flip the sign of zQ from that of the Hyphae paper so that
  215. // the ZKP has a "+" instead of a "-", as that's what the zkp
  216. // macro supports.
  217. let negzQ = Scalar::random(&mut rng);
  218. let CQ = Q - &negzQ * Atable;
  219. // Compute the "error factor"
  220. let V = zbucket * lox_pub.X[2]
  221. + zlevel * lox_pub.X[3]
  222. + zsince * lox_pub.X[4]
  223. + zinvremain * lox_pub.X[5]
  224. + zblockages * lox_pub.X[6]
  225. + &negzQ * Atable;
  226. // Blind showing the Bucket Reachability credential
  227. // Reblind P and Q
  228. let t_reach = Scalar::random(&mut rng);
  229. let P_reach = t_reach * reach_cred.P;
  230. let Q_reach = t_reach * reach_cred.Q;
  231. // Form Pedersen commitments to the blinded attributes
  232. let zbucket_reach = Scalar::random(&mut rng);
  233. let CBucket_reach = reach_cred.bucket * P_reach + &zbucket_reach * Atable;
  234. // Form a Pedersen commitment to the MAC Q
  235. // We flip the sign of zQ from that of the Hyphae paper so that
  236. // the ZKP has a "+" instead of a "-", as that's what the zkp
  237. // macro supports.
  238. let negzQ_reach = Scalar::random(&mut rng);
  239. let CQ_reach = Q_reach - &negzQ_reach * Atable;
  240. // Compute the "error factor"
  241. let V_reach = zbucket_reach * reach_pub.X[2] + &negzQ_reach * Atable;
  242. // User blinding for the Lox certificate to be issued
  243. // Pick an ElGamal keypair
  244. let d = Scalar::random(&mut rng);
  245. let D = &d * Btable;
  246. // Pick a random client component of the id
  247. let id_client = Scalar::random(&mut rng);
  248. // Encrypt it (times the basepoint B) to the ElGamal public key D we
  249. // just created
  250. let eid_client = Scalar::random(&mut rng);
  251. let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
  252. // Encrypt the other blinded fields (times B) to D as well
  253. let ebucket = Scalar::random(&mut rng);
  254. let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
  255. let elevel = Scalar::random(&mut rng);
  256. let EncLevel = (
  257. &elevel * Btable,
  258. &lox_cred.trust_level * Btable + elevel * D,
  259. );
  260. let esince = Scalar::random(&mut rng);
  261. let EncSince = (
  262. &esince * Btable,
  263. &lox_cred.level_since * Btable + esince * D,
  264. );
  265. let einvremain = Scalar::random(&mut rng);
  266. let EncInvRemain = (
  267. &einvremain * Btable,
  268. &new_invites_remaining * Btable + einvremain * D,
  269. );
  270. let eblockages = Scalar::random(&mut rng);
  271. let EncBlockages = (
  272. &eblockages * Btable,
  273. &lox_cred.blockages * Btable + eblockages * D,
  274. );
  275. // User blinding for the Invitation certificate to be issued
  276. // Pick a random client component of the id
  277. let inv_id_client = Scalar::random(&mut rng);
  278. // Encrypt it (times the basepoint B) to the ElGamal public key D we
  279. // just created
  280. let einv_id_client = Scalar::random(&mut rng);
  281. let EncInvIdClient = (
  282. &einv_id_client * Btable,
  283. &id_client * Btable + einv_id_client * D,
  284. );
  285. // The proof that invites_remaining is not zero. We prove this by
  286. // demonstrating that we know its inverse.
  287. let invremain_inverse = &lox_cred.invites_remaining.invert();
  288. let zinvremain_inverse = -zinvremain * invremain_inverse;
  289. // So now invremain_inverse * CInvRemain + zinvremain_inverse * A = P
  290. // Construct the proof
  291. let mut transcript = Transcript::new(b"issue invite request");
  292. let piUser = requestproof::prove_compact(
  293. &mut transcript,
  294. requestproof::ProveAssignments {
  295. A: &A,
  296. B: &B,
  297. P: &P,
  298. CBucket: &CBucket,
  299. CLevel: &CLevel,
  300. CSince: &CSince,
  301. CInvRemain: &CInvRemain,
  302. CBlockages: &CBlockages,
  303. V: &V,
  304. Xbucket: &lox_pub.X[2],
  305. Xlevel: &lox_pub.X[3],
  306. Xsince: &lox_pub.X[4],
  307. Xinvremain: &lox_pub.X[5],
  308. Xblockages: &lox_pub.X[6],
  309. P_reach: &P_reach,
  310. CBucket_reach: &CBucket_reach,
  311. V_reach: &V_reach,
  312. Xbucket_reach: &reach_pub.X[2],
  313. D: &D,
  314. EncIdClient0: &EncIdClient.0,
  315. EncIdClient1: &EncIdClient.1,
  316. EncBucket0: &EncBucket.0,
  317. EncBucket1: &EncBucket.1,
  318. EncLevel0: &EncLevel.0,
  319. EncLevel1: &EncLevel.1,
  320. EncSince0: &EncSince.0,
  321. EncSince1: &EncSince.1,
  322. EncInvRemain0: &EncInvRemain.0,
  323. EncInvRemain1_plus_B: &(EncInvRemain.1 + B),
  324. EncBlockages0: &EncBlockages.0,
  325. EncBlockages1: &EncBlockages.1,
  326. EncInvIdClient0: &EncInvIdClient.0,
  327. EncInvIdClient1: &EncInvIdClient.1,
  328. bucket: &lox_cred.bucket,
  329. level: &lox_cred.trust_level,
  330. since: &lox_cred.level_since,
  331. invremain: &lox_cred.invites_remaining,
  332. blockages: &lox_cred.blockages,
  333. zbucket: &zbucket,
  334. zlevel: &zlevel,
  335. zsince: &zsince,
  336. zinvremain: &zinvremain,
  337. zblockages: &zblockages,
  338. negzQ: &negzQ,
  339. zbucket_reach: &zbucket_reach,
  340. negzQ_reach: &negzQ_reach,
  341. d: &d,
  342. eid_client: &eid_client,
  343. ebucket: &ebucket,
  344. elevel: &elevel,
  345. esince: &esince,
  346. einvremain: &einvremain,
  347. eblockages: &eblockages,
  348. id_client: &id_client,
  349. inv_id_client: &inv_id_client,
  350. einv_id_client: &einv_id_client,
  351. invremain_inverse: &invremain_inverse,
  352. zinvremain_inverse: &zinvremain_inverse,
  353. },
  354. )
  355. .0;
  356. Ok((
  357. Request {
  358. P,
  359. id: lox_cred.id,
  360. CBucket,
  361. CLevel,
  362. CSince,
  363. CInvRemain,
  364. CBlockages,
  365. CQ,
  366. P_reach,
  367. CBucket_reach,
  368. CQ_reach,
  369. D,
  370. EncIdClient,
  371. EncBucket,
  372. EncLevel,
  373. EncSince,
  374. EncInvRemain,
  375. EncBlockages,
  376. EncInvIdClient,
  377. piUser,
  378. },
  379. State {
  380. d,
  381. D,
  382. EncIdClient,
  383. EncBucket,
  384. EncLevel,
  385. EncSince,
  386. EncInvRemain,
  387. EncBlockages,
  388. EncInvIdClient,
  389. id_client,
  390. bucket: lox_cred.bucket,
  391. level: lox_cred.trust_level,
  392. since: lox_cred.level_since,
  393. invremain: new_invites_remaining,
  394. blockages: lox_cred.blockages,
  395. inv_id_client,
  396. },
  397. ))
  398. }