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