|
@@ -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,
|
|
|
+ })
|
|
|
+}
|