ggm.rs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Implementation of CMZ14 credentials (GGM version, which is more
  2. // efficient, but makes a stronger security assumption): "Algebraic MACs
  3. // and Keyed-Verification Anonymous Credentials" (Chase, Meiklejohn,
  4. // and Zaverucha, CCS 2014)
  5. // The notation follows that of the paper "Hyphae: Social Secret
  6. // Sharing" (Lovecruft and de Valence, 2017), Section 4.
  7. #![allow(non_snake_case)]
  8. #![allow(non_camel_case_types)]
  9. use sha2::Sha512;
  10. use curve25519_dalek::constants as dalek_constants;
  11. use curve25519_dalek::ristretto::RistrettoPoint;
  12. use curve25519_dalek::ristretto::RistrettoBasepointTable;
  13. use curve25519_dalek::scalar::Scalar;
  14. use curve25519_dalek::traits::IsIdentity;
  15. use zkp::CompactProof;
  16. use zkp::ProofError;
  17. use zkp::Transcript;
  18. use lazy_static::lazy_static;
  19. lazy_static! {
  20. pub static ref CMZ_A: RistrettoPoint =
  21. RistrettoPoint::hash_from_bytes::<Sha512>(b"CMZ Generator A");
  22. pub static ref CMZ_B: RistrettoPoint =
  23. dalek_constants::RISTRETTO_BASEPOINT_POINT;
  24. pub static ref CMZ_A_TABLE: RistrettoBasepointTable =
  25. RistrettoBasepointTable::create(&CMZ_A);
  26. pub static ref CMZ_B_TABLE: RistrettoBasepointTable =
  27. dalek_constants::RISTRETTO_BASEPOINT_TABLE;
  28. }
  29. #[derive(Clone,Debug)]
  30. pub struct IssuerPrivKey {
  31. x0tilde: Scalar,
  32. x: Vec<Scalar>,
  33. }
  34. impl IssuerPrivKey {
  35. // Create an IssuerPrivKey for credentials with the given number of
  36. // attributes.
  37. pub fn new(n: u16) -> IssuerPrivKey {
  38. let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
  39. let x0tilde: Scalar = Scalar::random(&mut rng);
  40. let mut x: Vec<Scalar> = Vec::with_capacity((n+1) as usize);
  41. // Set x to a vector of n+1 random Scalars
  42. x.resize_with((n+1) as usize, || { Scalar::random(&mut rng) });
  43. IssuerPrivKey { x0tilde, x }
  44. }
  45. }
  46. #[derive(Clone,Debug)]
  47. pub struct IssuerPubKey {
  48. X: Vec<RistrettoPoint>,
  49. }
  50. impl IssuerPubKey {
  51. // Create an IssuerPubKey from the corresponding IssuerPrivKey
  52. pub fn new(privkey: &IssuerPrivKey) -> IssuerPubKey {
  53. let Atable : &RistrettoBasepointTable = &CMZ_A_TABLE;
  54. let Btable : &RistrettoBasepointTable = &CMZ_B_TABLE;
  55. let n_plus_one: usize = privkey.x.len();
  56. let mut X: Vec<RistrettoPoint> = Vec::with_capacity(n_plus_one);
  57. // The first element is a special case; it is
  58. // X[0] = x0tilde*A + x[0]*B
  59. X.push(&privkey.x0tilde * Atable + &privkey.x[0] * Btable);
  60. // The other elements (1 through n) are X[i] = x[i]*A
  61. for i in 1..n_plus_one {
  62. X.push(&privkey.x[i] * Atable);
  63. }
  64. IssuerPubKey { X }
  65. }
  66. }
  67. #[derive(Debug)]
  68. pub struct Issuer {
  69. privkey: IssuerPrivKey,
  70. pub pubkey: IssuerPubKey,
  71. }
  72. define_proof! {
  73. issue_nonblind_5,
  74. "Nonblind 5 issuing proof",
  75. (x0, x0tilde, x1, x2, x3, x4, x5),
  76. (P, Q, X0, X1, X2, X3, X4, X5, P1, P2, P3, P4, P5),
  77. (A, B) :
  78. X1 = (x1*A),
  79. X2 = (x2*A),
  80. X3 = (x3*A),
  81. X4 = (x4*A),
  82. X5 = (x5*A),
  83. X0 = (x0*B + x0tilde*A),
  84. Q = (x0*P + x1*P1 + x2*P2 + x3*P3 + x4*P4 + x5*P5) }
  85. impl Issuer {
  86. // Create an issuer for credentials with the given number of
  87. // attributes
  88. pub fn new(n: u16) -> Issuer {
  89. let privkey = IssuerPrivKey::new(n);
  90. let pubkey = IssuerPubKey::new(&privkey);
  91. Issuer { privkey, pubkey }
  92. }
  93. // Issue a credential with (for example) 5 given attributes. In
  94. // this (nonblinded) version, the issuer sees all of the attributes.
  95. pub fn issue_nonblind_5(&self, req: &CredentialRequest_Nonblind_5)
  96. -> CredentialResponse_Nonblind_5 {
  97. let A : &RistrettoPoint = &CMZ_A;
  98. let B : &RistrettoPoint = &CMZ_B;
  99. let mut rng: rand::rngs::ThreadRng = rand::thread_rng();
  100. let b: Scalar = Scalar::random(&mut rng);
  101. let P: RistrettoPoint = b * B;
  102. // There is a typo in the Hyphae paper: in Section 4.1, Q should
  103. // also have an x0*P term (also in Q'). (You can see that term
  104. // in Section 4.2.)
  105. let Q: RistrettoPoint = (self.privkey.x[0] + (
  106. self.privkey.x[1] * req.m1 +
  107. self.privkey.x[2] * req.m2 +
  108. self.privkey.x[3] * req.m3 +
  109. self.privkey.x[4] * req.m4 +
  110. self.privkey.x[5] * req.m5)) * P;
  111. let mut transcript = Transcript::new(b"Nonblind 5 issuing proof");
  112. let pi: CompactProof = issue_nonblind_5::prove_compact(
  113. &mut transcript,
  114. issue_nonblind_5::ProveAssignments {
  115. A: &A,
  116. B: &B,
  117. P: &P,
  118. Q: &Q,
  119. X0: &self.pubkey.X[0],
  120. X1: &self.pubkey.X[1],
  121. X2: &self.pubkey.X[2],
  122. X3: &self.pubkey.X[3],
  123. X4: &self.pubkey.X[4],
  124. X5: &self.pubkey.X[5],
  125. P1: &(&req.m1 * &P),
  126. P2: &(&req.m2 * &P),
  127. P3: &(&req.m3 * &P),
  128. P4: &(&req.m4 * &P),
  129. P5: &(&req.m5 * &P),
  130. x0: &self.privkey.x[0],
  131. x1: &self.privkey.x[1],
  132. x2: &self.privkey.x[2],
  133. x3: &self.privkey.x[3],
  134. x4: &self.privkey.x[4],
  135. x5: &self.privkey.x[5],
  136. x0tilde: &self.privkey.x0tilde
  137. }).0;
  138. CredentialResponse_Nonblind_5 { P, Q, pi }
  139. }
  140. }
  141. #[derive(Debug)]
  142. pub struct CredentialRequest_Nonblind_5 {
  143. m1: Scalar,
  144. m2: Scalar,
  145. m3: Scalar,
  146. m4: Scalar,
  147. m5: Scalar,
  148. }
  149. pub struct CredentialResponse_Nonblind_5 {
  150. P: RistrettoPoint,
  151. Q: RistrettoPoint,
  152. pi: CompactProof,
  153. }
  154. #[derive(Debug)]
  155. pub struct Credential_5 {
  156. P: RistrettoPoint,
  157. Q: RistrettoPoint,
  158. m1: Scalar,
  159. m2: Scalar,
  160. m3: Scalar,
  161. m4: Scalar,
  162. m5: Scalar,
  163. }
  164. pub fn request_nonblind_5(m1: &Scalar, m2: &Scalar, m3: &Scalar,
  165. m4: &Scalar, m5: &Scalar) -> CredentialRequest_Nonblind_5 {
  166. // For nonblind requests, just send the attributes in the clear
  167. CredentialRequest_Nonblind_5 {
  168. m1: *m1,
  169. m2: *m2,
  170. m3: *m3,
  171. m4: *m4,
  172. m5: *m5
  173. }
  174. }
  175. pub fn verify_nonblind_5(req: &CredentialRequest_Nonblind_5,
  176. resp: CredentialResponse_Nonblind_5, pubkey: &IssuerPubKey)
  177. -> Result<Credential_5, ProofError> {
  178. let A : &RistrettoPoint = &CMZ_A;
  179. let B : &RistrettoPoint = &CMZ_B;
  180. if resp.P.is_identity() {
  181. return Err(ProofError::VerificationFailure);
  182. }
  183. let mut transcript = Transcript::new(b"Nonblind 5 issuing proof");
  184. issue_nonblind_5::verify_compact(
  185. &resp.pi,
  186. &mut transcript,
  187. issue_nonblind_5::VerifyAssignments {
  188. A: &A.compress(),
  189. B: &B.compress(),
  190. P: &resp.P.compress(),
  191. Q: &resp.Q.compress(),
  192. X0: &pubkey.X[0].compress(),
  193. X1: &pubkey.X[1].compress(),
  194. X2: &pubkey.X[2].compress(),
  195. X3: &pubkey.X[3].compress(),
  196. X4: &pubkey.X[4].compress(),
  197. X5: &pubkey.X[5].compress(),
  198. P1: &(&req.m1 * &resp.P).compress(),
  199. P2: &(&req.m2 * &resp.P).compress(),
  200. P3: &(&req.m3 * &resp.P).compress(),
  201. P4: &(&req.m4 * &resp.P).compress(),
  202. P5: &(&req.m5 * &resp.P).compress(),
  203. }
  204. )?;
  205. Ok(Credential_5 {
  206. P: resp.P,
  207. Q: resp.Q,
  208. m1: req.m1,
  209. m2: req.m2,
  210. m3: req.m3,
  211. m4: req.m4,
  212. m5: req.m5,
  213. })
  214. }