123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- /*! A module for the protocol for a new user to redeem an Invitation
- credential. The user will start at trust level 1 (instead of 0 for
- untrusted uninvited users).
- The user presents the Invitation credential:
- - id: revealed
- - date: blinded, but proved in ZK to be at most INVITATION_EXPIRY days ago
- - bucket: blinded
- - blockages: blinded
- 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
- Invitation credential above
- - trust_level: revealed to be 1
- - level_since: today
- - invites_remaining: revealed to be 0
- - blockages: blinded, but proved in ZK that it's the same as in the
- Invitations 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};
- /// Invitations must be used within this many days of being issued.
- /// Note that if you change this number to be larger than 15, you must
- /// also add bits to the zero knowledge proof.
- pub const INVITATION_EXPIRY: u32 = 15;
- pub struct Request {
- // Fields for showing the Invitation credential
- P: RistrettoPoint,
- id: Scalar,
- CDate: RistrettoPoint,
- CBucket: RistrettoPoint,
- CBlockages: RistrettoPoint,
- CQ: RistrettoPoint,
- // Fields for the inequality proof
- // date + INVITATION_EXPIRY >= today
- CG1: RistrettoPoint,
- CG2: RistrettoPoint,
- CG3: RistrettoPoint,
- CG0sq: RistrettoPoint,
- CG1sq: RistrettoPoint,
- CG2sq: RistrettoPoint,
- CG3sq: RistrettoPoint,
- // Fields for user blinding of the Lox credential to be issued
- D: RistrettoPoint,
- EncIdClient: (RistrettoPoint, RistrettoPoint),
- EncBucket: (RistrettoPoint, RistrettoPoint),
- EncBlockages: (RistrettoPoint, RistrettoPoint),
- // The combined ZKP
- piUser: CompactProof,
- }
- #[derive(Debug)]
- pub struct State {
- d: Scalar,
- D: RistrettoPoint,
- EncIdClient: (RistrettoPoint, RistrettoPoint),
- EncBucket: (RistrettoPoint, RistrettoPoint),
- EncBlockages: (RistrettoPoint, RistrettoPoint),
- id_client: Scalar,
- bucket: Scalar,
- blockages: Scalar,
- }
- pub struct Response {
- // The fields for the new Lox credential; the new trust level is 1
- // and the new invites_remaining is 0, so we don't have to include
- // them here explicitly
- P: RistrettoPoint,
- EncQ: (RistrettoPoint, RistrettoPoint),
- id_server: Scalar,
- level_since: Scalar,
- TId: RistrettoPoint,
- TBucket: RistrettoPoint,
- TBlockages: RistrettoPoint,
- // The ZKP
- piBlindIssue: CompactProof,
- }
- define_proof! {
- requestproof,
- "Redeem Invite Request",
- (date, bucket, blockages, zdate, zbucket, zblockages, negzQ,
- d, eid_client, ebucket, eblockages, id_client,
- g0, g1, g2, g3,
- zg0, zg1, zg2, zg3,
- wg0, wg1, wg2, wg3,
- yg0, yg1, yg2, yg3),
- (P, CDate, CBucket, CBlockages, V, Xdate, Xbucket, Xblockages,
- D, EncIdClient0, EncIdClient1, EncBucket0, EncBucket1,
- EncBlockages0, EncBlockages1,
- CG0, CG1, CG2, CG3,
- CG0sq, CG1sq, CG2sq, CG3sq),
- (A, B):
- // Blind showing of the Invitation credential
- CDate = (date*P + zdate*A),
- CBucket = (bucket*P + zbucket*A),
- CBlockages = (blockages*P + zblockages*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),
- EncBlockages0 = (eblockages*B),
- EncBlockages1 = (blockages*B + eblockages*D),
- // Prove CDate encodes a value at most INVITATION_EXPIRY
- // days ago: first prove each of g0, ..., g3 is a bit by
- // proving that gi = gi^2
- CG0 = (g0*P + zg0*A), CG0sq = (g0*CG0 + wg0*A), CG0sq = (g0*P + yg0*A),
- CG1 = (g1*P + zg1*A), CG1sq = (g1*CG1 + wg1*A), CG1sq = (g1*P + yg1*A),
- CG2 = (g2*P + zg2*A), CG2sq = (g2*CG2 + wg2*A), CG2sq = (g2*P + yg2*A),
- CG3 = (g3*P + zg3*A), CG3sq = (g3*CG3 + wg3*A), CG3sq = (g3*P + yg3*A)
- // Then we'll check that today*P + CG0 + 2*CG1 + 4*CG2 + 8*CG3 =
- // CDate + INVITATION_EXPIRY*P by having the verifier
- // plug in CDate + INVITATION_EXPIRY*P - (today*P + 2*CG1 + 4*CG2
- // + 8*CG3) as its value of CG0.
- }
- pub fn request(
- inv_cred: &cred::Invitation,
- invitation_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 date + INVITATION_EXPIRY >= today.
- let date: u32 = match scalar_u32(&inv_cred.date) {
- Some(v) => v,
- None => return Err(ProofError::VerificationFailure),
- };
- if date + INVITATION_EXPIRY < today {
- return Err(ProofError::VerificationFailure);
- }
- let diffdays = date + INVITATION_EXPIRY - today;
- // If diffdays > 15, then since INVITATION_EXPIRY <= 15, then date
- // must be in the future. Reject.
- if diffdays > 15 {
- return Err(ProofError::VerificationFailure);
- }
- // Blind showing the Invitation credential
- // Reblind P and Q
- let mut rng = rand::thread_rng();
- let t = Scalar::random(&mut rng);
- let P = t * inv_cred.P;
- let Q = t * inv_cred.Q;
- // Form Pedersen commitments to the blinded attributes
- let zdate = Scalar::random(&mut rng);
- let zbucket = Scalar::random(&mut rng);
- let zblockages = Scalar::random(&mut rng);
- let CDate = inv_cred.date * P + &zdate * Atable;
- let CBucket = inv_cred.bucket * P + &zbucket * Atable;
- let CBlockages = inv_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 = zdate * invitation_pub.X[2]
- + zbucket * invitation_pub.X[3]
- + zblockages * invitation_pub.X[4]
- + &negzQ * 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, &inv_cred.bucket * Btable + ebucket * D);
- let eblockages = Scalar::random(&mut rng);
- let EncBlockages = (
- &eblockages * Btable,
- &inv_cred.blockages * Btable + eblockages * D,
- );
- // The range proof that 0 <= diffdays <= 15
- // Extract the 4 bits from diffdays
- let g0: Scalar = (diffdays & 1).into();
- let g1: Scalar = ((diffdays >> 1) & 1).into();
- let g2: Scalar = ((diffdays >> 2) & 1).into();
- let g3: Scalar = ((diffdays >> 3) & 1).into();
- // Pick random factors for the Pedersen commitments
- let wg0 = Scalar::random(&mut rng);
- let zg1 = Scalar::random(&mut rng);
- let wg1 = Scalar::random(&mut rng);
- let zg2 = Scalar::random(&mut rng);
- let wg2 = Scalar::random(&mut rng);
- let zg3 = Scalar::random(&mut rng);
- let wg3 = Scalar::random(&mut rng);
- // Compute zg0 to cancel things out as
- // zg0 = -(zdate + 2*zg1 + 4*zg2 + 8*zg3)
- // but use Horner's method
- let zg0 = -(scalar_dbl(&(scalar_dbl(&(scalar_dbl(&zg3) + zg2)) + zg1)) + zdate);
- let yg0 = wg0 + g0 * zg0;
- let yg1 = wg1 + g1 * zg1;
- let yg2 = wg2 + g2 * zg2;
- let yg3 = wg3 + g3 * zg3;
- let CG0 = g0 * P + &zg0 * Atable;
- let CG1 = g1 * P + &zg1 * Atable;
- let CG2 = g2 * P + &zg2 * Atable;
- let CG3 = g3 * P + &zg3 * Atable;
- let CG0sq = g0 * P + &yg0 * Atable;
- let CG1sq = g1 * P + &yg1 * Atable;
- let CG2sq = g2 * P + &yg2 * Atable;
- let CG3sq = g3 * P + &yg3 * Atable;
- // Construct the proof
- let mut transcript = Transcript::new(b"redeem invite request");
- let piUser = requestproof::prove_compact(
- &mut transcript,
- requestproof::ProveAssignments {
- A: &A,
- B: &B,
- P: &P,
- CDate: &CDate,
- CBucket: &CBucket,
- CBlockages: &CBlockages,
- V: &V,
- Xdate: &invitation_pub.X[2],
- Xbucket: &invitation_pub.X[3],
- Xblockages: &invitation_pub.X[4],
- D: &D,
- EncIdClient0: &EncIdClient.0,
- EncIdClient1: &EncIdClient.1,
- EncBucket0: &EncBucket.0,
- EncBucket1: &EncBucket.1,
- EncBlockages0: &EncBlockages.0,
- EncBlockages1: &EncBlockages.1,
- CG0: &CG0,
- CG1: &CG1,
- CG2: &CG2,
- CG3: &CG3,
- CG0sq: &CG0sq,
- CG1sq: &CG1sq,
- CG2sq: &CG2sq,
- CG3sq: &CG3sq,
- date: &inv_cred.date,
- bucket: &inv_cred.bucket,
- blockages: &inv_cred.blockages,
- zdate: &zdate,
- zbucket: &zbucket,
- zblockages: &zblockages,
- negzQ: &negzQ,
- d: &d,
- eid_client: &eid_client,
- ebucket: &ebucket,
- eblockages: &eblockages,
- id_client: &id_client,
- g0: &g0,
- g1: &g1,
- g2: &g2,
- g3: &g3,
- zg0: &zg0,
- zg1: &zg1,
- zg2: &zg2,
- zg3: &zg3,
- wg0: &wg0,
- wg1: &wg1,
- wg2: &wg2,
- wg3: &wg3,
- yg0: &yg0,
- yg1: &yg1,
- yg2: &yg2,
- yg3: &yg3,
- },
- )
- .0;
- Ok((
- Request {
- P,
- id: inv_cred.inv_id,
- CDate,
- CBucket,
- CBlockages,
- CQ,
- D,
- EncIdClient,
- EncBucket,
- EncBlockages,
- CG1,
- CG2,
- CG3,
- CG0sq,
- CG1sq,
- CG2sq,
- CG3sq,
- piUser,
- },
- State {
- d,
- D,
- EncIdClient,
- EncBucket,
- EncBlockages,
- id_client,
- bucket: inv_cred.bucket,
- blockages: inv_cred.blockages,
- },
- ))
- }
|