Browse Source

Credential showing and verification

Ian Goldberg 3 years ago
parent
commit
a7813bc519
2 changed files with 191 additions and 0 deletions
  1. 169 0
      src/ggm.rs
  2. 22 0
      tests/ggm.rs

+ 169 - 0
src/ggm.rs

@@ -591,3 +591,172 @@ pub mod issue_blind124_5 {
         })
     }
 }
+
+// A submodule for showing credentials with 5 attributes, blinding
+// attributes 3, 4, and 5, and displaying attributes 1 and 2.
+pub mod show_blind345_5 {
+    use curve25519_dalek::ristretto::RistrettoPoint;
+    use curve25519_dalek::ristretto::RistrettoBasepointTable;
+    use curve25519_dalek::scalar::Scalar;
+    use curve25519_dalek::traits::IsIdentity;
+
+    use zkp::CompactProof;
+    use zkp::ProofError;
+    use zkp::Transcript;
+
+    use super::{CMZ_A,CMZ_A_TABLE,Issuer,IssuerPubKey,Credential5};
+
+    // A typo in the Hyphae paper (Section 4.4): P must also be sent to
+    // the issuer in the credential presentation message.
+    pub struct ShowMessage {
+        P: RistrettoPoint,
+        m1: Scalar,
+        m2: Scalar,
+        Cm3: RistrettoPoint,
+        Cm4: RistrettoPoint,
+        Cm5: RistrettoPoint,
+        CQ: RistrettoPoint,
+        piCredShow: CompactProof,
+    }
+
+    #[derive(Debug)]
+    pub struct VerifiedCredential {
+        m1: Scalar,
+        m2: Scalar,
+        Cm3: RistrettoPoint,
+        Cm4: RistrettoPoint,
+        Cm5: RistrettoPoint,
+    }
+
+    // If you want to prove additional statements about the blinded
+    // attributes when showing them, this is the place to add those 
+    // statements (and also the code that creates and verifies this
+    // proof).
+    define_proof! {
+        show,
+        "Blind345 5 showing proof",
+        (m3, m4, m5, z3, z4, z5, negzQ),
+        (P, Cm3, Cm4, Cm5, V, X3, X4, X5),
+        (A) :
+        Cm3 = (m3*P + z3*A),
+        Cm4 = (m4*P + z4*A),
+        Cm5 = (m5*P + z5*A),
+        V = (z3*X3 + z4*X4 + z5*X5 + negzQ*A)
+    }
+
+    pub fn show(cred: &Credential5, pubkey: &IssuerPubKey)
+            -> ShowMessage {
+        let A : &RistrettoPoint = &CMZ_A;
+        let Atable : &RistrettoBasepointTable = &CMZ_A_TABLE;
+
+        // Reblind P and Q
+        let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
+        let t: Scalar = Scalar::random(&mut rng);
+        let P: RistrettoPoint = &t * &cred.P;
+        let Q: RistrettoPoint = &t * &cred.Q;
+
+        // Form Pedersen commitments to the blinded attributes
+        let z3: Scalar = Scalar::random(&mut rng);
+        let z4: Scalar = Scalar::random(&mut rng);
+        let z5: Scalar = Scalar::random(&mut rng);
+        let Cm3: RistrettoPoint = &cred.m3 * &P + &z3 * Atable;
+        let Cm4: RistrettoPoint = &cred.m4 * &P + &z4 * Atable;
+        let Cm5: RistrettoPoint = &cred.m5 * &P + &z5 * 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 = Scalar::random(&mut rng);
+        let CQ: RistrettoPoint = &Q - &negzQ * Atable;
+
+        // Compute the "error factor"
+        let V: RistrettoPoint = &z3 * &pubkey.X[3]
+                + &z4 * &pubkey.X[4] + &z5 * &pubkey.X[5]
+                + &negzQ * Atable;
+
+        // Create the ZKP
+        let mut transcript = Transcript::new(b"Blind345 5 showing proof");
+        let piCredShow: CompactProof = show::prove_compact(
+            &mut transcript,
+            show::ProveAssignments {
+                A: &A,
+                P: &P,
+                Cm3: &Cm3,
+                Cm4: &Cm4,
+                Cm5: &Cm5,
+                V: &V,
+                X3: &pubkey.X[3],
+                X4: &pubkey.X[4],
+                X5: &pubkey.X[5],
+                m3: &cred.m3,
+                m4: &cred.m4,
+                m5: &cred.m5,
+                z3: &z3,
+                z4: &z4,
+                z5: &z5,
+                negzQ: &negzQ
+            }).0;
+
+        ShowMessage {
+            P,
+            m1: cred.m1,
+            m2: cred.m2,
+            Cm3, Cm4, Cm5, CQ, piCredShow
+        }
+    }
+
+    impl Issuer {
+        // Verify a showing of an attribute from a user to the issuer
+        // with 5 credentials, of which attributes 3, 4, and 5 are
+        // blinded, and attributes 1 and 2 are revealed.  The issuer
+        // will end up with verified Pedersen commitments Cm3, Cm4, Cm5
+        // to the blinded attributes, so that additional things can be
+        // proved about those attributes in zero knowledge if desired.
+        pub fn verify_blind345_5(&self, showmsg: &ShowMessage)
+                -> Result<VerifiedCredential, ProofError> {
+            let A : &RistrettoPoint = &CMZ_A;
+
+            if showmsg.P.is_identity() {
+                return Err(ProofError::VerificationFailure);
+            }
+
+            // Recompute the "error factor" using knowledge of our own
+            // (the issuer's) private key instead of knowledge of the
+            // hidden attributes
+            let Vprime: RistrettoPoint =
+                (self.privkey.x[0]
+                   + (self.privkey.x[1] * showmsg.m1
+                       + self.privkey.x[2] * showmsg.m2)) * showmsg.P
+                + self.privkey.x[3] * &showmsg.Cm3
+                + self.privkey.x[4] * &showmsg.Cm4
+                + self.privkey.x[5] * &showmsg.Cm5
+                - &showmsg.CQ;
+
+            // Verify the ZKP using Vprime
+            let mut transcript = Transcript::new(b"Blind345 5 showing proof");
+            show::verify_compact(
+                &showmsg.piCredShow,
+                &mut transcript,
+                show::VerifyAssignments {
+                    A: &A.compress(),
+                    P: &showmsg.P.compress(),
+                    Cm3: &showmsg.Cm3.compress(),
+                    Cm4: &showmsg.Cm4.compress(),
+                    Cm5: &showmsg.Cm5.compress(),
+                    V: &Vprime.compress(),
+                    X3: &self.pubkey.X[3].compress(),
+                    X4: &self.pubkey.X[4].compress(),
+                    X5: &self.pubkey.X[5].compress(),
+                }
+            )?;
+            Ok(VerifiedCredential {
+                m1: showmsg.m1,
+                m2: showmsg.m2,
+                Cm3: showmsg.Cm3,
+                Cm4: showmsg.Cm4,
+                Cm5: showmsg.Cm5,
+            })
+        }
+    }
+}

+ 22 - 0
tests/ggm.rs

@@ -60,3 +60,25 @@ fn blind124_5_test() {
     let result = issue_blind124_5::verify(state, resp.unwrap(), &issuer.pubkey);
     assert!(result.is_ok());
 }
+
+#[test]
+fn show_blind345_5_test() {
+    let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
+    let issuer = Issuer::new(5);
+    let m1 = Scalar::random(&mut rng);
+    let m2 = Scalar::random(&mut rng);
+    let m3 = Scalar::random(&mut rng);
+    let m4 = Scalar::random(&mut rng);
+    let m5 = Scalar::random(&mut rng);
+    let (req,state) = issue_blind124_5::request(&m1, &m2, &m3, &m4, &m5);
+    let resp = issuer.issue_blind124_5(&req);
+    assert!(resp.is_ok());
+    let result = issue_blind124_5::verify(state, resp.unwrap(), &issuer.pubkey);
+    assert!(result.is_ok());
+    let cred = result.unwrap();
+    let showmsg = show_blind345_5::show(&cred, &issuer.pubkey);
+    let showresult = issuer.verify_blind345_5(&showmsg);
+    assert!(showresult.is_ok());
+    let verifiedcred = showresult.unwrap();
+    println!("Received credential: {:?}", verifiedcred);
+}