123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443 |
- /*! A module for the protocol for a user to request the issuing of an
- Invitation credential they can pass to someone they know.
- They are allowed to do this as long as their current Lox credentials has
- a non-zero "invites_remaining" attribute (which will be decreased by
- one), and they have a Bucket Reachability credential for their current
- bucket and today's date. (Such credentials are placed daily in the
- encrypted bridge table.)
- The user presents their current Lox credential:
- - id: revealed
- - bucket: blinded
- - trust_level: blinded
- - level_since: blinded
- - invites_remaining: blinded, but proved in ZK that it's not zero
- - blockages: blinded
- and a Bucket Reachability credential:
- - date: revealed to be today
- - bucket: blinded, but proved in ZK that it's the same as in the Lox
- credential above
- and a new Lox credential to be issued:
- - id: jointly chosen by the user and BA
- - bucket: blinded, but proved in ZK that it's the same as in the Lox
- credential above
- - trust_level: blinded, but proved in ZK that it's the same as in the
- Lox credential above
- - level_since: blinded, but proved in ZK that it's the same as in the
- Lox credential above
- - invites_remaining: blinded, but proved in ZK that it's one less than
- the number in the Lox credential above
- - blockages: blinded, but proved in ZK that it's the same as in the
- Lox credential above
- and a new Invitation credential to be issued:
- - inv_id: jointly chosen by the user and BA
- - date: revealed to be today
- - bucket: blinded, but proved in ZK that it's the same as in the Lox
- credential above
- - blockages: blinded, but proved in ZK that it's the same as in the Lox
- credential above
- */
- use curve25519_dalek::ristretto::RistrettoBasepointTable;
- use curve25519_dalek::ristretto::RistrettoPoint;
- use curve25519_dalek::scalar::Scalar;
- use curve25519_dalek::traits::IsIdentity;
- use zkp::CompactProof;
- use zkp::ProofError;
- use zkp::Transcript;
- use super::super::cred;
- use super::super::dup_filter::SeenType;
- use super::super::{pt_dbl, scalar_dbl, scalar_u32};
- use super::super::{BridgeAuth, IssuerPubKey};
- use super::super::{CMZ_A, CMZ_A_TABLE, CMZ_B, CMZ_B_TABLE};
- pub struct Request {
- // Fields for blind showing the Lox credential
- P: RistrettoPoint,
- id: Scalar,
- CBucket: RistrettoPoint,
- CLevel: RistrettoPoint,
- CSince: RistrettoPoint,
- CInvRemain: RistrettoPoint,
- CBlockages: RistrettoPoint,
- CQ: RistrettoPoint,
- // Fields for blind showing the Bucket Reachability credential
- P_reach: RistrettoPoint,
- CBucket_reach: RistrettoPoint,
- CQ_reach: RistrettoPoint,
- // Fields for user blinding of the Lox credential to be issued
- D: RistrettoPoint,
- EncIdClient: (RistrettoPoint, RistrettoPoint),
- EncBucket: (RistrettoPoint, RistrettoPoint),
- EncLevel: (RistrettoPoint, RistrettoPoint),
- EncSince: (RistrettoPoint, RistrettoPoint),
- EncInvRemain: (RistrettoPoint, RistrettoPoint),
- EncBlockages: (RistrettoPoint, RistrettoPoint),
- // Fields for user blinding of the Inivtation credential to be
- // issued
- EncInvIdClient: (RistrettoPoint, RistrettoPoint),
- // The bucket and blockages attributes in the Invitation credential
- // issuing protocol can just reuse the exact encryptions as for the
- // Lox credential issuing protocol above.
- // The combined ZKP
- piUser: CompactProof,
- }
- #[derive(Debug)]
- pub struct State {
- d: Scalar,
- D: RistrettoPoint,
- EncIdClient: (RistrettoPoint, RistrettoPoint),
- EncBucket: (RistrettoPoint, RistrettoPoint),
- EncLevel: (RistrettoPoint, RistrettoPoint),
- EncSince: (RistrettoPoint, RistrettoPoint),
- EncInvRemain: (RistrettoPoint, RistrettoPoint),
- EncBlockages: (RistrettoPoint, RistrettoPoint),
- EncInvIdClient: (RistrettoPoint, RistrettoPoint),
- id_client: Scalar,
- bucket: Scalar,
- level: Scalar,
- since: Scalar,
- invremain: Scalar,
- blockages: Scalar,
- inv_id_client: Scalar,
- }
- pub struct Response {
- // The fields for the new Lox credential; the new invites_remaining
- // is one less than the old value, so we don't have to include it
- // here explicitly
- P: RistrettoPoint,
- EncQ: (RistrettoPoint, RistrettoPoint),
- id_server: Scalar,
- TId: RistrettoPoint,
- TBucket: RistrettoPoint,
- TLevel: RistrettoPoint,
- TSince: RistrettoPoint,
- TInvRemain: RistrettoPoint,
- TBlockages: RistrettoPoint,
- inv_id_server: Scalar,
- TInvId: RistrettoPoint,
- // The ZKP
- piBlindIssue: CompactProof,
- }
- define_proof! {
- requestproof,
- "Issue Invite Request",
- (bucket, level, since, invremain, blockages, zbucket, zlevel,
- zsince, zinvremain, zblockages, negzQ,
- zbucket_reach, negzQ_reach,
- d, eid_client, ebucket, elevel, esince, einvremain, eblockages, id_client,
- inv_id_client, einv_id_client,
- invremain_inverse, zinvremain_inverse),
- (P, CBucket, CLevel, CSince, CInvRemain, CBlockages, V, Xbucket,
- Xlevel, Xsince, Xinvremain, Xblockages,
- P_reach, CBucket_reach, V_reach, Xbucket_reach,
- D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
- EncLevel0, EncLevel1, EncSince0, EncSince1,
- EncInvRemain0, EncInvRemain1_plus_B, EncBlockages0, EncBlockages1,
- EncInvIdClient0, EncInvIdClient1),
- (A, B):
- // Blind showing of the Lox credential
- CBucket = (bucket*P + zbucket*A),
- CLevel = (level*P + zlevel*A),
- CSince = (since*P + zsince*A),
- CInvRemain = (invremain*P + zinvremain*A),
- CBlockages = (blockages*P + zblockages*A),
- // Proof that invremain is not 0
- P = (invremain_inverse*CInvRemain + zinvremain_inverse*A),
- // Blind showing of the Bucket Reachability credential; note the
- // same bucket is used in the proof
- CBucket_reach = (bucket*P_reach + zbucket_reach*A),
- // User blinding of the Lox credential to be issued
- D = (d*B),
- EncIdClient0 = (eid_client*B),
- EncIdClient1 = (id_client*B + eid_client*D),
- EncBucket0 = (ebucket*B),
- EncBucket1 = (bucket*B + ebucket*D),
- EncLevel0 = (elevel*B),
- EncLevel1 = (level*B + elevel*D),
- EncSince0 = (esince*B),
- EncSince1 = (since*B + esince*D),
- EncInvRemain0 = (einvremain*B),
- EncInvRemain1_plus_B = (invremain*B + einvremain*D),
- EncBlockages0 = (eblockages*B),
- EncBlockages1 = (blockages*B + eblockages*D),
- // User blinding of the Invitation to be issued
- EncInvIdClient0 = (einv_id_client*B),
- EncInvIdClient1 = (inv_id_client*B + einv_id_client*D)
- }
- pub fn request(
- lox_cred: &cred::Lox,
- reach_cred: &cred::BucketReachability,
- lox_pub: &IssuerPubKey,
- reach_pub: &IssuerPubKey,
- today: u32,
- ) -> Result<(Request, State), ProofError> {
- let A: &RistrettoPoint = &CMZ_A;
- let B: &RistrettoPoint = &CMZ_B;
- let Atable: &RistrettoBasepointTable = &CMZ_A_TABLE;
- let Btable: &RistrettoBasepointTable = &CMZ_B_TABLE;
- // Ensure the credential can be correctly shown: it must be the case
- // that invites_remaining not be 0
- if lox_cred.invites_remaining == Scalar::zero() {
- return Err(ProofError::VerificationFailure);
- }
- // The buckets in the Lox and Bucket Reachability credentials have
- // to match
- if lox_cred.bucket != reach_cred.bucket {
- return Err(ProofError::VerificationFailure);
- }
- // The Bucket Reachability credential has to be dated today
- let reach_date: u32 = match scalar_u32(&reach_cred.date) {
- Some(v) => v,
- None => return Err(ProofError::VerificationFailure),
- };
- if reach_date != today {
- return Err(ProofError::VerificationFailure);
- }
- // The new invites_remaining
- let new_invites_remaining = &lox_cred.invites_remaining - Scalar::one();
- // Blind showing the Lox credential
- // Reblind P and Q
- let mut rng = rand::thread_rng();
- let t = Scalar::random(&mut rng);
- let P = t * lox_cred.P;
- let Q = t * lox_cred.Q;
- // Form Pedersen commitments to the blinded attributes
- let zbucket = Scalar::random(&mut rng);
- let zlevel = Scalar::random(&mut rng);
- let zsince = Scalar::random(&mut rng);
- let zinvremain = Scalar::random(&mut rng);
- let zblockages = Scalar::random(&mut rng);
- let CBucket = lox_cred.bucket * P + &zbucket * Atable;
- let CLevel = lox_cred.bucket * P + &zlevel * Atable;
- let CSince = lox_cred.level_since * P + &zsince * Atable;
- let CInvRemain = lox_cred.invites_remaining * P + &zinvremain * Atable;
- let CBlockages = lox_cred.blockages * P + &zblockages * Atable;
- // Form a Pedersen commitment to the MAC Q
- // We flip the sign of zQ from that of the Hyphae paper so that
- // the ZKP has a "+" instead of a "-", as that's what the zkp
- // macro supports.
- let negzQ = Scalar::random(&mut rng);
- let CQ = Q - &negzQ * Atable;
- // Compute the "error factor"
- let V = zbucket * lox_pub.X[2]
- + zlevel * lox_pub.X[3]
- + zsince * lox_pub.X[4]
- + zinvremain * lox_pub.X[5]
- + zblockages * lox_pub.X[6]
- + &negzQ * Atable;
- // Blind showing the Bucket Reachability credential
- // Reblind P and Q
- let t_reach = Scalar::random(&mut rng);
- let P_reach = t_reach * reach_cred.P;
- let Q_reach = t_reach * reach_cred.Q;
- // Form Pedersen commitments to the blinded attributes
- let zbucket_reach = Scalar::random(&mut rng);
- let CBucket_reach = reach_cred.bucket * P_reach + &zbucket_reach * Atable;
- // Form a Pedersen commitment to the MAC Q
- // We flip the sign of zQ from that of the Hyphae paper so that
- // the ZKP has a "+" instead of a "-", as that's what the zkp
- // macro supports.
- let negzQ_reach = Scalar::random(&mut rng);
- let CQ_reach = Q_reach - &negzQ_reach * Atable;
- // Compute the "error factor"
- let V_reach = zbucket_reach * reach_pub.X[2] + &negzQ_reach * Atable;
- // User blinding for the Lox certificate to be issued
- // Pick an ElGamal keypair
- let d = Scalar::random(&mut rng);
- let D = &d * Btable;
- // Pick a random client component of the id
- let id_client = Scalar::random(&mut rng);
- // Encrypt it (times the basepoint B) to the ElGamal public key D we
- // just created
- let eid_client = Scalar::random(&mut rng);
- let EncIdClient = (&eid_client * Btable, &id_client * Btable + eid_client * D);
- // Encrypt the other blinded fields (times B) to D as well
- let ebucket = Scalar::random(&mut rng);
- let EncBucket = (&ebucket * Btable, &lox_cred.bucket * Btable + ebucket * D);
- let elevel = Scalar::random(&mut rng);
- let EncLevel = (
- &elevel * Btable,
- &lox_cred.trust_level * Btable + elevel * D,
- );
- let esince = Scalar::random(&mut rng);
- let EncSince = (
- &esince * Btable,
- &lox_cred.level_since * Btable + esince * D,
- );
- let einvremain = Scalar::random(&mut rng);
- let EncInvRemain = (
- &einvremain * Btable,
- &new_invites_remaining * Btable + einvremain * D,
- );
- let eblockages = Scalar::random(&mut rng);
- let EncBlockages = (
- &eblockages * Btable,
- &lox_cred.blockages * Btable + eblockages * D,
- );
- // User blinding for the Invitation certificate to be issued
- // Pick a random client component of the id
- let inv_id_client = Scalar::random(&mut rng);
- // Encrypt it (times the basepoint B) to the ElGamal public key D we
- // just created
- let einv_id_client = Scalar::random(&mut rng);
- let EncInvIdClient = (
- &einv_id_client * Btable,
- &id_client * Btable + einv_id_client * D,
- );
- // The proof that invites_remaining is not zero. We prove this by
- // demonstrating that we know its inverse.
- let invremain_inverse = &lox_cred.invites_remaining.invert();
- let zinvremain_inverse = -zinvremain * invremain_inverse;
- // So now invremain_inverse * CInvRemain + zinvremain_inverse * A = P
- // Construct the proof
- let mut transcript = Transcript::new(b"issue invite request");
- let piUser = requestproof::prove_compact(
- &mut transcript,
- requestproof::ProveAssignments {
- A: &A,
- B: &B,
- P: &P,
- CBucket: &CBucket,
- CLevel: &CLevel,
- CSince: &CSince,
- CInvRemain: &CInvRemain,
- CBlockages: &CBlockages,
- V: &V,
- Xbucket: &lox_pub.X[2],
- Xlevel: &lox_pub.X[3],
- Xsince: &lox_pub.X[4],
- Xinvremain: &lox_pub.X[5],
- Xblockages: &lox_pub.X[6],
- P_reach: &P_reach,
- CBucket_reach: &CBucket_reach,
- V_reach: &V_reach,
- Xbucket_reach: &reach_pub.X[2],
- D: &D,
- EncIdClient0: &EncIdClient.0,
- EncIdClient1: &EncIdClient.1,
- EncBucket0: &EncBucket.0,
- EncBucket1: &EncBucket.1,
- EncLevel0: &EncLevel.0,
- EncLevel1: &EncLevel.1,
- EncSince0: &EncSince.0,
- EncSince1: &EncSince.1,
- EncInvRemain0: &EncInvRemain.0,
- EncInvRemain1_plus_B: &(EncInvRemain.1 + B),
- EncBlockages0: &EncBlockages.0,
- EncBlockages1: &EncBlockages.1,
- EncInvIdClient0: &EncInvIdClient.0,
- EncInvIdClient1: &EncInvIdClient.1,
- bucket: &lox_cred.bucket,
- level: &lox_cred.trust_level,
- since: &lox_cred.level_since,
- invremain: &lox_cred.invites_remaining,
- blockages: &lox_cred.blockages,
- zbucket: &zbucket,
- zlevel: &zlevel,
- zsince: &zsince,
- zinvremain: &zinvremain,
- zblockages: &zblockages,
- negzQ: &negzQ,
- zbucket_reach: &zbucket_reach,
- negzQ_reach: &negzQ_reach,
- d: &d,
- eid_client: &eid_client,
- ebucket: &ebucket,
- elevel: &elevel,
- esince: &esince,
- einvremain: &einvremain,
- eblockages: &eblockages,
- id_client: &id_client,
- inv_id_client: &inv_id_client,
- einv_id_client: &einv_id_client,
- invremain_inverse: &invremain_inverse,
- zinvremain_inverse: &zinvremain_inverse,
- },
- )
- .0;
- Ok((
- Request {
- P,
- id: lox_cred.id,
- CBucket,
- CLevel,
- CSince,
- CInvRemain,
- CBlockages,
- CQ,
- P_reach,
- CBucket_reach,
- CQ_reach,
- D,
- EncIdClient,
- EncBucket,
- EncLevel,
- EncSince,
- EncInvRemain,
- EncBlockages,
- EncInvIdClient,
- piUser,
- },
- State {
- d,
- D,
- EncIdClient,
- EncBucket,
- EncLevel,
- EncSince,
- EncInvRemain,
- EncBlockages,
- EncInvIdClient,
- id_client,
- bucket: lox_cred.bucket,
- level: lox_cred.trust_level,
- since: lox_cred.level_since,
- invremain: new_invites_remaining,
- blockages: lox_cred.blockages,
- inv_id_client,
- },
- ))
- }
|