|
@@ -0,0 +1,92 @@
|
|
|
+// Implementation of CMZ14 credentials (GGM version, which is more
|
|
|
+// efficient, but makes a stronger security assumption): "Algebraic MACs
|
|
|
+// and Keyed-Verification Anonymous Credentials" (Chase, Meiklejohn,
|
|
|
+// and Zaverucha, CCS 2014)
|
|
|
+
|
|
|
+// The notation follows that of the paper "Hyphae: Social Secret
|
|
|
+// Sharing" (Lovecruft and de Valence, 2017), Section 4.
|
|
|
+
|
|
|
+#![allow(non_snake_case)]
|
|
|
+
|
|
|
+use sha2::Sha512;
|
|
|
+
|
|
|
+use curve25519_dalek::constants as dalek_constants;
|
|
|
+use curve25519_dalek::ristretto::RistrettoPoint;
|
|
|
+use curve25519_dalek::ristretto::RistrettoBasepointTable;
|
|
|
+use curve25519_dalek::scalar::Scalar;
|
|
|
+
|
|
|
+use lazy_static::lazy_static;
|
|
|
+
|
|
|
+lazy_static! {
|
|
|
+ pub static ref CMZ_A: RistrettoPoint =
|
|
|
+ RistrettoPoint::hash_from_bytes::<Sha512>(b"CMZ Generator A");
|
|
|
+ pub static ref CMZ_B: RistrettoPoint =
|
|
|
+ dalek_constants::RISTRETTO_BASEPOINT_POINT;
|
|
|
+ pub static ref CMZ_A_TABLE: RistrettoBasepointTable =
|
|
|
+ RistrettoBasepointTable::create(&CMZ_A);
|
|
|
+ pub static ref CMZ_B_TABLE: RistrettoBasepointTable =
|
|
|
+ dalek_constants::RISTRETTO_BASEPOINT_TABLE;
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Clone,Debug)]
|
|
|
+pub struct IssuerPrivKey {
|
|
|
+ x0tilde: Scalar,
|
|
|
+ x: Vec<Scalar>,
|
|
|
+}
|
|
|
+
|
|
|
+impl IssuerPrivKey {
|
|
|
+ // Create an IssuerPrivKey for credentials with the given number of
|
|
|
+ // attributes.
|
|
|
+ pub fn new(n: u16) -> IssuerPrivKey {
|
|
|
+ let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
|
|
|
+ let x0tilde: Scalar = Scalar::random(&mut rng);
|
|
|
+ let mut x: Vec<Scalar> = Vec::with_capacity((n+1) as usize);
|
|
|
+
|
|
|
+ // Set x to a vector of n+1 random Scalars
|
|
|
+ x.resize_with((n+1) as usize, || { Scalar::random(&mut rng) });
|
|
|
+
|
|
|
+ IssuerPrivKey { x0tilde, x }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Clone,Debug)]
|
|
|
+pub struct IssuerPubKey {
|
|
|
+ X: Vec<RistrettoPoint>,
|
|
|
+}
|
|
|
+
|
|
|
+impl IssuerPubKey {
|
|
|
+ // Create an IssuerPubKey from the corresponding IssuerPrivKey
|
|
|
+ pub fn new(privkey: &IssuerPrivKey) -> IssuerPubKey {
|
|
|
+ let Atable : &RistrettoBasepointTable = &CMZ_A_TABLE;
|
|
|
+ let Btable : &RistrettoBasepointTable = &CMZ_B_TABLE;
|
|
|
+ let n_plus_one: usize = privkey.x.len();
|
|
|
+ let mut X: Vec<RistrettoPoint> = Vec::with_capacity(n_plus_one);
|
|
|
+
|
|
|
+ // The first element is a special case; it is
|
|
|
+ // X[0] = x0tilde*A + x[0]*B
|
|
|
+ X.push(&privkey.x0tilde * Atable + &privkey.x[0] * Btable);
|
|
|
+
|
|
|
+ // The other elements (1 through n) are X[i] = x[i]*A
|
|
|
+ for i in 1..n_plus_one {
|
|
|
+ X.push(&privkey.x[i] * Atable);
|
|
|
+ }
|
|
|
+ IssuerPubKey { X }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+#[derive(Debug)]
|
|
|
+pub struct Issuer {
|
|
|
+ privkey: IssuerPrivKey,
|
|
|
+ pubkey: IssuerPubKey,
|
|
|
+}
|
|
|
+
|
|
|
+impl Issuer {
|
|
|
+ // Create an issuer for credentials with the given number of
|
|
|
+ // attributes
|
|
|
+ pub fn new(n: u16) -> Issuer {
|
|
|
+ let privkey = IssuerPrivKey::new(n);
|
|
|
+ let pubkey = IssuerPubKey::new(&privkey);
|
|
|
+ Issuer { privkey, pubkey }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|