Browse Source

Nonblind credential issuing and verification of the resulting proof

Ian Goldberg 3 years ago
parent
commit
1a145a6952
3 changed files with 170 additions and 5 deletions
  1. 1 1
      Cargo.toml
  2. 151 1
      src/ggm.rs
  3. 18 3
      tests/ggm.rs

+ 1 - 1
Cargo.toml

@@ -6,7 +6,7 @@ edition = "2018"
 
 [dependencies]
 curve25519-dalek = { package = "curve25519-dalek-ng", version = "3", default-features = false, features = ["serde", "std"] }
-zkp = "0.8"
+zkp = { version = "0.8", features = ["debug-transcript"] }
 bincode = "1"
 rand = "0.7"
 serde = "1"

+ 151 - 1
src/ggm.rs

@@ -7,6 +7,7 @@
 // Sharing" (Lovecruft and de Valence, 2017), Section 4.
 
 #![allow(non_snake_case)]
+#![allow(non_camel_case_types)]
 
 use sha2::Sha512;
 
@@ -14,6 +15,11 @@ use curve25519_dalek::constants as dalek_constants;
 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 lazy_static::lazy_static;
 
@@ -77,9 +83,23 @@ impl IssuerPubKey {
 #[derive(Debug)]
 pub struct Issuer {
     privkey: IssuerPrivKey,
-    pubkey: IssuerPubKey,
+    pub pubkey: IssuerPubKey,
 }
 
+define_proof! {
+    issue_nonblind_5,
+    "Nonblind 5 issuing proof",
+    (x0, x0tilde, x1, x2, x3, x4, x5),
+    (P, Q, X0, X1, X2, X3, X4, X5, P1, P2, P3, P4, P5),
+    (A, B) :
+    X1 = (x1*A),
+    X2 = (x2*A),
+    X3 = (x3*A),
+    X4 = (x4*A),
+    X5 = (x5*A),
+    X0 = (x0*B + x0tilde*A),
+    Q = (x0*P + x1*P1 + x2*P2 + x3*P3 + x4*P4 + x5*P5) }
+
 impl Issuer {
     // Create an issuer for credentials with the given number of
     // attributes
@@ -88,5 +108,135 @@ impl Issuer {
         let pubkey = IssuerPubKey::new(&privkey);
         Issuer { privkey, pubkey }
     }
+
+    // Issue a credential with (for example) 5 given attributes.  In
+    // this (nonblinded) version, the issuer sees all of the attributes.
+    pub fn issue_nonblind_5(&self, req: &CredentialRequest_Nonblind_5)
+            -> CredentialResponse_Nonblind_5 {
+        let A : &RistrettoPoint = &CMZ_A;
+        let B : &RistrettoPoint = &CMZ_B;
+
+        let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
+        let b: Scalar = Scalar::random(&mut rng);
+        let P: RistrettoPoint = b * B;
+        // There is a typo in the Hyphae paper: in Section 4.1, Q should
+        // also have an x0*P term (also in Q').  (You can see that term
+        // in Section 4.2.)
+        let Q: RistrettoPoint = (self.privkey.x[0] + (
+            self.privkey.x[1] * req.m1 +
+            self.privkey.x[2] * req.m2 +
+            self.privkey.x[3] * req.m3 +
+            self.privkey.x[4] * req.m4 +
+            self.privkey.x[5] * req.m5)) * P;
+
+        let mut transcript = Transcript::new(b"Nonblind 5 issuing proof");
+        let pi: CompactProof = issue_nonblind_5::prove_compact(
+            &mut transcript,
+            issue_nonblind_5::ProveAssignments {
+                A: &A,
+                B: &B,
+                P: &P,
+                Q: &Q,
+                X0: &self.pubkey.X[0],
+                X1: &self.pubkey.X[1],
+                X2: &self.pubkey.X[2],
+                X3: &self.pubkey.X[3],
+                X4: &self.pubkey.X[4],
+                X5: &self.pubkey.X[5],
+                P1: &(&req.m1 * &P),
+                P2: &(&req.m2 * &P),
+                P3: &(&req.m3 * &P),
+                P4: &(&req.m4 * &P),
+                P5: &(&req.m5 * &P),
+                x0: &self.privkey.x[0],
+                x1: &self.privkey.x[1],
+                x2: &self.privkey.x[2],
+                x3: &self.privkey.x[3],
+                x4: &self.privkey.x[4],
+                x5: &self.privkey.x[5],
+                x0tilde: &self.privkey.x0tilde
+            }).0;
+
+        CredentialResponse_Nonblind_5 { P, Q, pi }
+    }
+}
+
+#[derive(Debug)]
+pub struct CredentialRequest_Nonblind_5 {
+    m1: Scalar,
+    m2: Scalar,
+    m3: Scalar,
+    m4: Scalar,
+    m5: Scalar,
+}
+
+pub struct CredentialResponse_Nonblind_5 {
+    P: RistrettoPoint,
+    Q: RistrettoPoint,
+    pi: CompactProof,
 }
 
+#[derive(Debug)]
+pub struct Credential_5 {
+    P: RistrettoPoint,
+    Q: RistrettoPoint,
+    m1: Scalar,
+    m2: Scalar,
+    m3: Scalar,
+    m4: Scalar,
+    m5: Scalar,
+}
+
+pub fn request_nonblind_5(m1: &Scalar, m2: &Scalar, m3: &Scalar,
+        m4: &Scalar, m5: &Scalar) -> CredentialRequest_Nonblind_5 {
+    // For nonblind requests, just send the attributes in the clear
+    CredentialRequest_Nonblind_5 {
+        m1: *m1,
+        m2: *m2,
+        m3: *m3,
+        m4: *m4,
+        m5: *m5
+    }
+}
+
+pub fn verify_nonblind_5(req: &CredentialRequest_Nonblind_5,
+        resp: CredentialResponse_Nonblind_5, pubkey: &IssuerPubKey)
+        -> Result<Credential_5, ProofError> {
+    let A : &RistrettoPoint = &CMZ_A;
+    let B : &RistrettoPoint = &CMZ_B;
+
+    if resp.P.is_identity() {
+        return Err(ProofError::VerificationFailure);
+    }
+    let mut transcript = Transcript::new(b"Nonblind 5 issuing proof");
+    issue_nonblind_5::verify_compact(
+        &resp.pi,
+        &mut transcript,
+        issue_nonblind_5::VerifyAssignments {
+            A: &A.compress(),
+            B: &B.compress(),
+            P: &resp.P.compress(),
+            Q: &resp.Q.compress(),
+            X0: &pubkey.X[0].compress(),
+            X1: &pubkey.X[1].compress(),
+            X2: &pubkey.X[2].compress(),
+            X3: &pubkey.X[3].compress(),
+            X4: &pubkey.X[4].compress(),
+            X5: &pubkey.X[5].compress(),
+            P1: &(&req.m1 * &resp.P).compress(),
+            P2: &(&req.m2 * &resp.P).compress(),
+            P3: &(&req.m3 * &resp.P).compress(),
+            P4: &(&req.m4 * &resp.P).compress(),
+            P5: &(&req.m5 * &resp.P).compress(),
+        }
+    )?;
+    Ok(Credential_5 {
+        P: resp.P,
+        Q: resp.Q,
+        m1: req.m1,
+        m2: req.m2,
+        m3: req.m3,
+        m4: req.m4,
+        m5: req.m5,
+    })
+}

+ 18 - 3
tests/ggm.rs

@@ -6,9 +6,7 @@ extern crate zkp;
 use curve25519_dalek::ristretto::RistrettoPoint;
 use curve25519_dalek::scalar::Scalar;
 
-use cmz::ggm::CMZ_A;
-use cmz::ggm::CMZ_B;
-use cmz::ggm::Issuer;
+use cmz::ggm::*;
 
 #[test]
 fn create_issuer() {
@@ -16,6 +14,8 @@ fn create_issuer() {
     println!("i0 = {:?}", i0);
     let i1 = Issuer::new(1);
     println!("i1 = {:?}", i1);
+    let i5 = Issuer::new(5);
+    println!("i5 = {:?}", i5);
 }
 
 #[test]
@@ -32,3 +32,18 @@ fn generator_test() {
     println!("2*B = {}", HexFmt((two*B).compress().to_bytes()));
     println!("2*B = {}", HexFmt((B+B).compress().to_bytes()));
 }
+
+#[test]
+fn nonblind_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 = request_nonblind_5(&m1, &m2, &m3, &m4, &m5);
+    let resp = issuer.issue_nonblind_5(&req);
+    let result = verify_nonblind_5(&req, resp, &issuer.pubkey);
+    assert!(result.is_ok());
+}