1use crate::{basic::matrix_sigma::SigmaTranscript, confidential_anon_creds::CACTranscript};
5use merlin::Transcript;
6use noah_algebra::{prelude::*, traits::Pairing};
7use serde_derive::{Deserialize, Serialize};
8
9pub(crate) const REVEAL_PROOF_DOMAIN: &[u8] = b"AC Reveal PoK";
10pub(crate) const REVEAL_PROOF_NEW_TRANSCRIPT_INSTANCE: &[u8] = b"AC Reveal PoK Instance";
11pub(crate) const COMMIT_NEW_TRANSCRIPT_INSTANCE: &[u8] = b"AC Commit SoK Instance";
12pub(crate) const POK_LABEL: &[u8] = b"Signature Message";
13
14#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub struct CredentialIssuerPK<G1, G2> {
17 pub gen2: G2,
19 pub xx2: G2,
21 pub zz1: G1,
23 pub zz2: G2,
25 pub yy2: Vec<G2>,
27}
28
29impl<G1: Group, G2: Group> CredentialIssuerPK<G1, G2> {
30 pub fn num_attrs(&self) -> usize {
32 self.yy2.len()
33 }
34}
35
36#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
38pub struct CredentialIssuerSK<G1, S> {
39 pub gen1: G1,
41 pub x: S,
43 pub y: Vec<S>,
45}
46
47#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
49pub struct CredentialSig<G1> {
50 pub sigma1: G1,
52 pub sigma2: G1,
54}
55
56impl<G: Group> Default for CredentialSig<G> {
57 fn default() -> CredentialSig<G> {
58 CredentialSig {
59 sigma1: G::get_identity(),
60 sigma2: G::get_identity(),
61 }
62 }
63}
64
65#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
67pub struct Credential<G1, G2, AttrType> {
68 pub sig: CredentialSig<G1>,
70 pub attrs: Vec<AttrType>,
72 pub ipk: CredentialIssuerPK<G1, G2>,
74}
75
76impl<G1: Group, G2: Group, AttrType: Copy> Credential<G1, G2, AttrType> {
77 pub fn get_revealed_attributes(&self, reveal_map: &[bool]) -> Result<Vec<AttrType>> {
79 if reveal_map.len() != self.attrs.len() {
80 return Err(eg!(NoahError::ParameterError));
81 }
82 Ok(self
83 .attrs
84 .iter()
85 .zip(reveal_map)
86 .filter(|(_, b)| *(*b))
87 .map(|(a, _)| *a)
88 .collect())
89 }
90}
91
92#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
95pub struct CredentialComm<G1>(pub(crate) CredentialSig<G1>);
96
97impl<G1: Group> Default for CredentialComm<G1> {
98 fn default() -> Self {
99 Self(CredentialSig::<G1>::default())
100 }
101}
102
103impl<G1: Group> CredentialComm<G1> {
104 pub fn new(sig: &CredentialSig<G1>, rand: &CredentialCommRandomizer<G1::ScalarType>) -> Self {
106 let sigma1_r = sig.sigma1.mul(&rand.r);
107 let sigma2_r = sig.sigma2.add(&sig.sigma1.mul(&rand.t)).mul(&rand.r);
108 Self(CredentialSig::<G1> {
111 sigma1: sigma1_r,
112 sigma2: sigma2_r,
113 })
114 }
115}
116
117#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
119pub struct CredentialUserPK<G1>(pub(crate) G1);
120
121#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
123pub struct CredentialUserSK<S>(pub(crate) S);
124
125#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
127pub struct CredentialSigOpenProof<G1, G2, S> {
128 pub cm: CredentialComm<G1>,
130 pub proof_open: CredentialPoK<G2, S>,
132}
133
134pub type CredentialCommOpenProof<G2, S> = CredentialPoK<G2, S>;
136
137#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
140pub struct CredentialPoK<G2, S> {
141 pub(crate) blinding: G2, pub(crate) response_t: S, pub(crate) response_sk: S, pub(crate) response_attrs: Vec<S>, }
146
147#[derive(Clone)]
148pub enum Attribute<AttrType: Copy> {
150 Revealed(AttrType),
152 Hidden(Option<AttrType>),
155}
156
157#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
159pub struct CredentialCommRandomizer<S> {
160 pub r: S,
162 pub t: S,
164}
165
166pub type CommOutput<G1, G2, S> = (
168 CredentialComm<G1>,
169 CredentialPoK<G2, S>,
170 Option<CredentialCommRandomizer<S>>,
171);
172
173pub fn issuer_keygen<R: CryptoRng + RngCore, P: Pairing>(
177 prng: &mut R,
178 num_attrs: usize,
179) -> (
180 CredentialIssuerSK<P::G1, P::ScalarField>,
181 CredentialIssuerPK<P::G1, P::G2>,
182) {
183 let x = P::ScalarField::random(prng);
184 let z = P::ScalarField::random(prng);
185 let gen1: P::G1 = P::G1::random(prng);
186 let gen2 = P::G2::random(prng);
187 let mut y = vec![];
188 let mut yy2 = vec![];
189 for _ in 0..num_attrs {
190 let yi = P::ScalarField::random(prng);
191 yy2.push(gen2.mul(&yi));
192 y.push(yi);
193 }
194 let xx2 = gen2.mul(&x);
195 let zz1 = gen1.mul(&z);
196 let zz2 = gen2.mul(&z);
197 (
198 CredentialIssuerSK { gen1, x, y },
199 CredentialIssuerPK {
200 gen2,
201 xx2,
202 zz1,
203 zz2,
204 yy2,
205 },
206 )
207}
208
209pub fn user_keygen<R: CryptoRng + RngCore, P: Pairing>(
213 prng: &mut R,
214 ipk: &CredentialIssuerPK<P::G1, P::G2>,
215) -> (CredentialUserSK<P::ScalarField>, CredentialUserPK<P::G1>) {
216 let sk = P::ScalarField::random(prng);
217 let pk = ipk.zz1.mul(&sk);
218 (CredentialUserSK(sk), CredentialUserPK(pk))
219}
220
221pub fn grant_credential<R: CryptoRng + RngCore, P: Pairing>(
225 prng: &mut R,
226 isk: &CredentialIssuerSK<P::G1, P::ScalarField>,
227 upk: &CredentialUserPK<P::G1>,
228 attrs: &[P::ScalarField],
229) -> Result<CredentialSig<P::G1>> {
230 let number_attributes_from_issuer_sk = isk.y.len();
231 let n = attrs.len();
232 if number_attributes_from_issuer_sk != n {
233 return Err(eg!(NoahError::AnonymousCredentialSignError));
234 }
235
236 let u = P::ScalarField::random(prng);
237 let mut exponent = isk.x;
238 for (attr, yi) in attrs.iter().zip(isk.y.iter()) {
239 exponent = exponent.add(&attr.mul(yi));
240 }
241 let cc = isk.gen1.mul(&exponent);
242 Ok(CredentialSig::<P::G1> {
243 sigma1: isk.gen1.mul(&u),
244 sigma2: upk.0.add(&cc).mul(&u),
245 })
246}
247
248pub fn open_credential<R: CryptoRng + RngCore, P: Pairing>(
251 prng: &mut R,
252 usk: &CredentialUserSK<P::ScalarField>,
253 credential: &Credential<P::G1, P::G2, P::ScalarField>,
254 reveal_map: &[bool],
255) -> Result<CredentialSigOpenProof<P::G1, P::G2, P::ScalarField>> {
256 let rand = randomizer_gen::<_, P>(prng);
257 let cm = CredentialComm::<P::G1>::new(&credential.sig, &rand);
258
259 let proof_open = open_comm::<_, P>(prng, usk, credential, &cm, &rand, reveal_map)?;
260
261 Ok(CredentialSigOpenProof { cm, proof_open })
262}
263
264pub fn randomizer_gen<R: CryptoRng + RngCore, P: Pairing>(
266 prng: &mut R,
267) -> CredentialCommRandomizer<P::ScalarField> {
268 CredentialCommRandomizer {
269 r: P::ScalarField::random(prng),
270 t: P::ScalarField::random(prng),
271 }
272}
273
274pub fn commit_without_randomizer<R: CryptoRng + RngCore, P: Pairing>(
276 prng: &mut R,
277 usk: &CredentialUserSK<P::ScalarField>,
278 credential: &Credential<P::G1, P::G2, P::ScalarField>,
279 m: &[u8],
280) -> Result<CommOutput<P::G1, P::G2, P::ScalarField>> {
281 let rand = randomizer_gen::<_, P>(prng);
282 let output = commit::<_, P>(prng, usk, credential, &rand, m).c(d!())?;
283 let cm = output.0;
284 let proof_valid = output.1;
285
286 Ok((cm, proof_valid, Some(rand)))
287}
288
289pub fn commit<R: CryptoRng + RngCore, P: Pairing>(
294 prng: &mut R,
295 usk: &CredentialUserSK<P::ScalarField>,
296 credential: &Credential<P::G1, P::G2, P::ScalarField>,
297 rand: &CredentialCommRandomizer<P::ScalarField>,
298 m: &[u8],
299) -> Result<CommOutput<P::G1, P::G2, P::ScalarField>> {
300 let hidden_attrs = credential
301 .attrs
302 .iter()
303 .map(|attr| Attribute::Hidden(Some(*attr)))
304 .collect_vec(); let cm = CredentialComm::<P::G1>::new(&credential.sig, rand);
307 let mut transcript = Transcript::new(COMMIT_NEW_TRANSCRIPT_INSTANCE);
308 init_pok_transcript::<P>(&mut transcript, &credential.ipk, &cm);
309 transcript.append_message(POK_LABEL, m);
310 let proof_valid = prove_pok::<_, P>(
311 &mut transcript,
312 prng,
313 usk,
314 &credential.ipk,
315 &rand.t,
316 hidden_attrs.as_slice(),
317 )
318 .c(d!())?;
319
320 Ok((cm, proof_valid, None))
321}
322
323pub fn check_comm<P: Pairing>(
325 ipk: &CredentialIssuerPK<P::G1, P::G2>,
326 cm: &CredentialComm<P::G1>,
327 proof_valid: &CredentialPoK<P::G2, P::ScalarField>,
328 m: &[u8],
329) -> Result<()> {
330 let mut transcript = Transcript::new(COMMIT_NEW_TRANSCRIPT_INSTANCE);
331 init_pok_transcript::<P>(&mut transcript, ipk, cm);
332 transcript.append_message(POK_LABEL, m);
333
334 transcript.append_proof_commitment(&proof_valid.blinding);
335 let challenge = transcript.get_challenge::<P::ScalarField>();
336
337 let attrs: Vec<Attribute<P::ScalarField>> = vec![Attribute::Hidden(None); ipk.num_attrs()];
338
339 verify_pok::<P>(ipk, cm, proof_valid, attrs.as_slice(), &challenge)
340}
341
342pub fn open_comm<R: CryptoRng + RngCore, P: Pairing>(
347 prng: &mut R,
348 usk: &CredentialUserSK<P::ScalarField>,
349 credential: &Credential<P::G1, P::G2, P::ScalarField>,
350 cm: &CredentialComm<P::G1>,
351 rand: &CredentialCommRandomizer<P::ScalarField>,
352 reveal_map: &[bool],
353) -> Result<CredentialCommOpenProof<P::G2, P::ScalarField>> {
354 if credential.attrs.len() != reveal_map.len() {
355 return Err(eg!(NoahError::ParameterError));
356 }
357
358 let revealed_attrs = credential
359 .attrs
360 .iter()
361 .zip(reveal_map.iter())
362 .map(|(attr, b)| {
363 if *b {
364 Attribute::Revealed(*attr)
365 } else {
366 Attribute::Hidden(Some(*attr))
367 }
368 })
369 .collect_vec();
370
371 let mut transcript = Transcript::new(REVEAL_PROOF_NEW_TRANSCRIPT_INSTANCE);
372 init_pok_transcript::<P>(&mut transcript, &credential.ipk, &cm); let pok = prove_pok::<_, P>(
374 &mut transcript,
375 prng,
376 usk,
377 &credential.ipk,
378 &rand.t,
379 revealed_attrs.as_slice(),
380 )
381 .c(d!())?;
382
383 Ok(pok)
384}
385
386pub fn verify_open<P: Pairing>(
391 ipk: &CredentialIssuerPK<P::G1, P::G2>,
392 cm: &CredentialComm<P::G1>,
393 proof_open: &CredentialCommOpenProof<P::G2, P::ScalarField>,
394 attrs: &[Attribute<P::ScalarField>],
395) -> Result<()> {
396 let mut transcript = Transcript::new(REVEAL_PROOF_NEW_TRANSCRIPT_INSTANCE);
397 init_pok_transcript::<P>(&mut transcript, ipk, cm);
398
399 transcript.append_proof_commitment(&proof_open.blinding);
400 let challenge = transcript.get_challenge::<P::ScalarField>();
401
402 verify_pok::<P>(ipk, cm, proof_open, attrs, &challenge)
403}
404
405pub(super) fn init_pok_transcript<P: Pairing>(
406 transcript: &mut Transcript,
407 ipk: &CredentialIssuerPK<P::G1, P::G2>,
408 cm: &CredentialComm<P::G1>,
409) {
410 let g1 = P::G1::get_base();
411 let g2 = P::G2::get_base();
412 let g1_elems = vec![&g1, &ipk.zz1, &cm.0.sigma1, &cm.0.sigma2];
413 let mut g2_elems = vec![&g2, &ipk.gen2, &ipk.xx2, &ipk.zz2];
414 for e in ipk.yy2.iter() {
415 g2_elems.push(e);
416 }
417 transcript.init_sigma_pairing::<P>(REVEAL_PROOF_DOMAIN, &g1_elems[..], g2_elems.as_slice());
418}
419
420fn prove_pok<R: CryptoRng + RngCore, P: Pairing>(
422 transcript: &mut Transcript,
423 prng: &mut R,
424 usk: &CredentialUserSK<P::ScalarField>,
425 ipk: &CredentialIssuerPK<P::G1, P::G2>,
426 t: &P::ScalarField,
427 attrs: &[Attribute<P::ScalarField>],
428) -> Result<CredentialPoK<P::G2, P::ScalarField>> {
429 let beta1 = P::ScalarField::random(prng);
430 let beta2 = P::ScalarField::random(prng);
431 let mut gamma = vec![];
432 let mut blinding = ipk.gen2.mul(&beta1).add(&ipk.zz2.mul(&beta2));
433 for (yy2i, attr) in ipk.yy2.iter().zip(attrs) {
434 match attr {
435 Attribute::Hidden(Some(_)) => {
436 let gamma_i = P::ScalarField::random(prng);
437 let elem = yy2i.mul(&gamma_i);
438 blinding = blinding.add(&elem);
439 gamma.push(gamma_i);
440 }
441 Attribute::Hidden(None) => {
442 return Err(eg!(NoahError::ParameterError));
443 }
444 _ => {}
445 }
446 }
447 transcript.append_proof_commitment(&blinding);
448 let challenge = transcript.get_challenge::<P::ScalarField>();
449 let response_t = challenge.mul(t).add(&beta1); let response_sk = challenge.mul(&usk.0).add(&beta2);
451 let mut response_attrs = vec![];
452 let mut gamma_iter = gamma.iter();
453 for attr_enum in attrs {
454 if let Attribute::Hidden(Some(attr)) = attr_enum {
455 let gamma = gamma_iter.next().unwrap(); let resp_attr_i = challenge.mul(*attr).add(gamma);
457 response_attrs.push(resp_attr_i);
458 }
459 }
460 Ok(CredentialPoK {
461 blinding,
462 response_t,
463 response_sk,
464 response_attrs,
465 })
466}
467
468pub(crate) fn verify_pok<P: Pairing>(
470 ipk: &CredentialIssuerPK<P::G1, P::G2>,
471 cm: &CredentialComm<P::G1>,
472 proof_open: &CredentialPoK<P::G2, P::ScalarField>,
473 attrs: &[Attribute<P::ScalarField>],
474 challenge: &P::ScalarField,
475) -> Result<()> {
476 let minus_one: P::ScalarField = P::ScalarField::one().neg();
478 let mut scalars = vec![
479 &proof_open.response_t, challenge, &proof_open.response_sk, &minus_one, ];
484
485 let mut resp_attr_iter = proof_open.response_attrs.iter();
486
487 let attrs_times_challenge = attrs
488 .iter()
489 .map(|attr| match attr {
490 Attribute::Revealed(attr) => Some(attr.mul(challenge)),
491 _ => None,
492 })
493 .collect_vec();
494 for attr in attrs_times_challenge.iter() {
495 match attr {
496 Some(a) => {
497 scalars.push(a);
498 }
499 None => {
500 let response = resp_attr_iter.next().c(d!(NoahError::ParameterError))?;
501 scalars.push(response);
502 }
503 }
504 }
505 let mut elems = vec![&ipk.gen2, &ipk.xx2, &ipk.zz2, &proof_open.blinding];
506
507 for y in ipk.yy2.iter() {
508 elems.push(y);
509 }
510 let p = P::G2::multi_exp(scalars.as_slice(), elems.as_slice());
511
512 let lhs = P::pairing(&cm.0.sigma1, &p);
513 let rhs = P::pairing(&cm.0.sigma2.mul(challenge), &ipk.gen2);
514
515 if lhs == rhs {
516 Ok(())
517 } else {
518 Err(eg!(NoahError::IdentityRevealVerifyError))
519 }
520}
521
522#[cfg(test)]
523pub(crate) mod credentials_tests {
524 use super::*;
525 use crate::anon_creds::Attribute::{Hidden, Revealed};
526 use noah_algebra::bls12_381::BLSPairingEngine;
527
528 fn check_signatures<P: Pairing>(n: usize) {
529 let mut prng = test_rng();
530
531 let ikeypair = issuer_keygen::<_, P>(&mut prng, n);
532 let isk = &ikeypair.0;
533 let ipk = &ikeypair.1;
534 let (_, upk) = user_keygen::<_, P>(&mut prng, ipk);
535
536 let mut attrs = vec![];
537 for _ in 0..n {
538 attrs.push(P::ScalarField::random(&mut prng));
539 }
540
541 let sig = grant_credential::<_, P>(&mut prng, &isk, &upk, &attrs);
542 assert!(sig.is_ok());
543
544 if n > 1 {
545 let error = grant_credential::<_, P>(&mut prng, &isk, &upk, &attrs[0..0]);
546 assert!(error.is_err());
547 }
548 }
549
550 #[test]
551 fn test_issuer_keygen() {
552 let mut prng = test_rng();
553
554 let _ = issuer_keygen::<_, BLSPairingEngine>(&mut prng, 5);
555 let _ = issuer_keygen::<_, BLSPairingEngine>(&mut prng, 0);
556 }
557
558 #[test]
559 fn test_signing() {
560 for n in 0..16 {
561 check_signatures::<BLSPairingEngine>(n);
562 }
563 }
564
565 fn reveal(reveal_map: &[bool]) {
566 type P = BLSPairingEngine;
567 let n = reveal_map.len();
568 let mut prng = test_rng();
569
570 let ikeypair = issuer_keygen::<_, P>(&mut prng, n);
571 let isk = &ikeypair.0;
572 let ipk = &ikeypair.1;
573 let (usk, upk) = user_keygen::<_, P>(&mut prng, ipk);
574
575 let mut attrs = vec![];
576 for _ in reveal_map.iter() {
577 attrs.push(<P as Pairing>::ScalarField::random(&mut prng));
578 }
579
580 let sig = grant_credential::<_, P>(&mut prng, &isk, &upk, attrs.as_slice()).unwrap();
581
582 let credential = Credential {
583 sig,
584 attrs,
585 ipk: ipk.clone(),
586 };
587
588 let reveal_sig = open_credential::<_, P>(&mut prng, &usk, &credential, reveal_map).unwrap();
589
590 let revealed_attrs = credential
591 .attrs
592 .iter()
593 .zip(reveal_map.iter())
594 .map(|(a, b)| if *b { Revealed(*a) } else { Hidden(None) })
595 .collect_vec();
596
597 assert_eq!(
598 true,
599 verify_open::<P>(
600 &ipk,
601 &reveal_sig.cm,
602 &reveal_sig.proof_open,
603 revealed_attrs.as_slice()
604 )
605 .is_ok()
606 )
607 }
608
609 pub(crate) fn no_attributes() {
610 reveal(&[]);
611 }
612
613 pub(crate) fn single_attribute() {
614 reveal(&[false]);
615 reveal(&[true]);
616 }
617
618 pub(crate) fn two_attributes() {
619 reveal(&[false, false]);
620 reveal(&[true, false]);
621 reveal(&[false, true]);
622 reveal(&[true, true]);
623 }
624
625 pub(crate) fn ten_attributes() {
626 reveal(&[false; 10]);
627 reveal(&[
628 true, false, true, false, true, false, true, false, true, false,
629 ]);
630 reveal(&[
631 false, true, false, true, false, true, false, true, false, true,
632 ]);
633 reveal(&[true; 10]);
634 }
635
636 #[test]
637 pub(crate) fn test_attributes() {
638 no_attributes();
639 single_attribute();
640 two_attributes();
641 ten_attributes();
642 }
643}