1#![deny(
20 missing_docs,
21 trivial_casts,
22 trivial_numeric_casts,
23 unconditional_recursion,
24 unused_import_braces,
25 unused_lifetimes,
26 unused_qualifications,
27 unused_extern_crates,
28 unused_parens,
29 while_true
30)]
31
32#[cfg(all(feature = "wasm", feature = "rayon"))]
33compile_error!("wasm does not support rayon. Remove the dependency on rayon.");
34
35#[macro_use]
36extern crate arrayref;
37
38use blake2::digest::{generic_array::GenericArray, Input, VariableOutput};
39use errors::{BBSError, BBSErrorKind};
40use ff_zeroize::{Field, PrimeField};
41use keys::prelude::*;
42use pairing_plus::{
43 bls12_381::{Fr, G1Affine, G1, G2},
44 hash_to_curve::HashToCurve,
45 hash_to_field::{BaseFromRO, ExpandMsgXmd},
46 serdes::SerDes,
47 CurveAffine, CurveProjective,
48};
49use pok_sig::prelude::*;
50use pok_vc::prelude::*;
51use rand::prelude::*;
52#[cfg(feature = "rayon")]
53use rayon::prelude::*;
54use std::fmt::{Display, Formatter};
55
56use serde::{
57 de::{Error as DError, Visitor},
58 Deserialize, Deserializer, Serialize, Serializer,
59};
60use std::collections::{BTreeMap, BTreeSet};
61use std::convert::TryFrom;
62use std::io::Cursor;
63#[cfg(feature = "wasm")]
64use wasm_bindgen::JsValue;
65
66pub const FR_COMPRESSED_SIZE: usize = 32;
68pub const FR_UNCOMPRESSED_SIZE: usize = 48;
70pub const G1_COMPRESSED_SIZE: usize = 48;
72pub const G1_UNCOMPRESSED_SIZE: usize = 96;
74pub const G2_COMPRESSED_SIZE: usize = 96;
76pub const G2_UNCOMPRESSED_SIZE: usize = 192;
78
79#[macro_use]
80mod macros;
81#[macro_use]
83pub mod messages;
84#[macro_use]
86pub mod pok_vc;
87pub mod errors;
89pub mod issuer;
92pub mod keys;
94pub mod pok_sig;
96pub mod prover;
99pub mod signature;
101pub mod verifier;
104
105pub trait ToVariableLengthBytes {
107 type Output;
109 type Error;
111
112 fn to_bytes_compressed_form(&self) -> Vec<u8>;
114
115 fn from_bytes_compressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error>;
117
118 fn to_bytes_uncompressed_form(&self) -> Vec<u8>;
120
121 fn from_bytes_uncompressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error>;
123}
124
125pub trait RandomElem {
127 type Output;
129
130 fn random() -> Self::Output;
132}
133
134pub trait HashElem {
136 type Output;
138
139 fn hash<I: AsRef<[u8]>>(data: I) -> Self;
141}
142
143#[derive(Copy, Clone, Debug, Eq, PartialEq)]
145pub struct Commitment(pub(crate) G1);
146
147impl Commitment {
148 pub fn new<B: AsRef<[G1]>, S: AsRef<[Fr]>>(bases: B, scalars: S) -> Self {
150 Commitment(multi_scalar_mul_const_time_g1(bases, scalars))
151 }
152
153 to_fixed_length_bytes_impl!(Commitment, G1, G1_COMPRESSED_SIZE, G1_UNCOMPRESSED_SIZE);
154}
155
156default_zero_impl!(Commitment, G1);
157as_ref_impl!(Commitment, G1);
158from_impl!(Commitment, G1, G1_COMPRESSED_SIZE, G1_UNCOMPRESSED_SIZE);
159display_impl!(Commitment);
160serdes_impl!(Commitment);
161hash_elem_impl!(Commitment, |data| { Commitment(hash_to_g1(data)) });
162
163#[cfg(feature = "wasm")]
164wasm_slice_impl!(Commitment);
165
166#[derive(Copy, Clone, Debug, Eq, PartialEq)]
168pub struct GeneratorG1(pub(crate) G1);
169
170impl GeneratorG1 {
171 to_fixed_length_bytes_impl!(GeneratorG1, G1, G1_COMPRESSED_SIZE, G1_UNCOMPRESSED_SIZE);
172}
173
174default_zero_impl!(GeneratorG1, G1);
175as_ref_impl!(GeneratorG1, G1);
176from_impl!(GeneratorG1, G1, G1_COMPRESSED_SIZE, G1_UNCOMPRESSED_SIZE);
177display_impl!(GeneratorG1);
178serdes_impl!(GeneratorG1);
179hash_elem_impl!(GeneratorG1, |data| { GeneratorG1(hash_to_g1(data)) });
180random_elem_impl!(GeneratorG1, { Self(G1::random(&mut thread_rng())) });
181#[cfg(feature = "wasm")]
182wasm_slice_impl!(GeneratorG1);
183
184#[derive(Copy, Clone, Debug, Eq, PartialEq)]
186pub struct GeneratorG2(pub(crate) G2);
187
188impl GeneratorG2 {
189 to_fixed_length_bytes_impl!(GeneratorG2, G2, G2_COMPRESSED_SIZE, G2_UNCOMPRESSED_SIZE);
190}
191
192default_zero_impl!(GeneratorG2, G2);
193as_ref_impl!(GeneratorG2, G2);
194from_impl!(GeneratorG2, G2, G2_COMPRESSED_SIZE, G2_UNCOMPRESSED_SIZE);
195display_impl!(GeneratorG2);
196serdes_impl!(GeneratorG2);
197hash_elem_impl!(GeneratorG2, |data| { GeneratorG2(hash_to_g2(data)) });
198#[cfg(feature = "wasm")]
199wasm_slice_impl!(GeneratorG2);
200
201#[derive(Clone, Debug, Default)]
203pub struct CommitmentBuilder {
204 bases: Vec<G1>,
205 scalars: Vec<Fr>,
206}
207
208impl CommitmentBuilder {
209 pub fn new() -> Self {
211 Self {
212 bases: Vec::new(),
213 scalars: Vec::new(),
214 }
215 }
216
217 pub fn add<B: AsRef<G1>, S: AsRef<Fr>>(&mut self, base: B, scalar: S) {
219 self.bases.push(*base.as_ref());
220 self.scalars.push(*scalar.as_ref());
221 }
222
223 pub fn finalize(self) -> Commitment {
225 Commitment(multi_scalar_mul_const_time_g1(&self.bases, &self.scalars))
226 }
227}
228
229#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
231pub struct SignatureMessage(pub(crate) Fr);
232
233impl SignatureMessage {
234 to_fixed_length_bytes_impl!(SignatureMessage, Fr, FR_COMPRESSED_SIZE, FR_COMPRESSED_SIZE);
235}
236
237default_zero_impl!(SignatureMessage, Fr);
238as_ref_impl!(SignatureMessage, Fr);
239from_impl!(SignatureMessage, Fr, FR_COMPRESSED_SIZE);
240display_impl!(SignatureMessage);
241serdes_impl!(SignatureMessage);
242hash_elem_impl!(SignatureMessage, |data| {
243 SignatureMessage(hash_to_fr(data))
244});
245random_elem_impl!(SignatureMessage, { Self(Fr::random(&mut thread_rng())) });
246#[cfg(feature = "wasm")]
247wasm_slice_impl!(SignatureMessage);
248
249#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
251pub struct ProofNonce(pub(crate) Fr);
252
253impl ProofNonce {
254 to_fixed_length_bytes_impl!(ProofNonce, Fr, FR_COMPRESSED_SIZE, FR_COMPRESSED_SIZE);
255}
256
257default_zero_impl!(ProofNonce, Fr);
258as_ref_impl!(ProofNonce, Fr);
259from_impl!(ProofNonce, Fr, FR_COMPRESSED_SIZE);
260display_impl!(ProofNonce);
261serdes_impl!(ProofNonce);
262hash_elem_impl!(ProofNonce, |data| { ProofNonce(hash_to_fr(data)) });
263random_elem_impl!(ProofNonce, { Self(Fr::random(&mut thread_rng())) });
264#[cfg(feature = "wasm")]
265wasm_slice_impl!(ProofNonce);
266
267#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
269pub struct ProofChallenge(pub(crate) Fr);
270
271impl ProofChallenge {
272 to_fixed_length_bytes_impl!(ProofChallenge, Fr, FR_COMPRESSED_SIZE, FR_COMPRESSED_SIZE);
273}
274
275default_zero_impl!(ProofChallenge, Fr);
276as_ref_impl!(ProofChallenge, Fr);
277from_impl!(ProofChallenge, Fr, FR_COMPRESSED_SIZE);
278display_impl!(ProofChallenge);
279serdes_impl!(ProofChallenge);
280hash_elem_impl!(ProofChallenge, |data| { ProofChallenge(hash_to_fr(data)) });
281random_elem_impl!(ProofChallenge, { Self(Fr::random(&mut thread_rng())) });
282#[cfg(feature = "wasm")]
283wasm_slice_impl!(ProofChallenge);
284
285#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
287pub struct SignatureBlinding(pub(crate) Fr);
288
289impl SignatureBlinding {
290 to_fixed_length_bytes_impl!(
291 SignatureBlinding,
292 Fr,
293 FR_COMPRESSED_SIZE,
294 FR_COMPRESSED_SIZE
295 );
296}
297
298default_zero_impl!(SignatureBlinding, Fr);
299as_ref_impl!(SignatureBlinding, Fr);
300from_impl!(SignatureBlinding, Fr, FR_COMPRESSED_SIZE);
301display_impl!(SignatureBlinding);
302serdes_impl!(SignatureBlinding);
303hash_elem_impl!(SignatureBlinding, |data| {
304 SignatureBlinding(hash_to_fr(data))
305});
306random_elem_impl!(SignatureBlinding, { Self(Fr::random(&mut thread_rng())) });
307#[cfg(feature = "wasm")]
308wasm_slice_impl!(SignatureBlinding);
309
310pub(crate) fn hash_to_g1<I: AsRef<[u8]>>(data: I) -> G1 {
311 const DST: &[u8] = b"BLS12381G1_XMD:BLAKE2B_SSWU_RO_BBS+_SIGNATURES:1_0_0";
312 <G1 as HashToCurve<ExpandMsgXmd<blake2::Blake2b>>>::hash_to_curve(data.as_ref(), DST)
313}
314
315pub(crate) fn hash_to_g2<I: AsRef<[u8]>>(data: I) -> G2 {
316 const DST: &[u8] = b"BLS12381G2_XMD:BLAKE2B_SSWU_RO_BBS+_SIGNATURES:1_0_0";
317 <G2 as HashToCurve<ExpandMsgXmd<blake2::Blake2b>>>::hash_to_curve(data.as_ref(), DST)
318}
319
320pub(crate) fn hash_to_fr<I: AsRef<[u8]>>(data: I) -> Fr {
321 let mut res = GenericArray::default();
322 let mut hasher = blake2::VarBlake2b::new(FR_UNCOMPRESSED_SIZE).unwrap();
323 hasher.input(data.as_ref());
324 hasher.variable_result(|out| {
325 res.copy_from_slice(out);
326 });
327 Fr::from_okm(&res)
328}
329
330pub(crate) fn multi_scalar_mul_const_time_g1<G: AsRef<[G1]>, S: AsRef<[Fr]>>(
331 bases: G,
332 scalars: S,
333) -> G1 {
334 let bases: Vec<_> = bases.as_ref().iter().map(|b| b.into_affine()).collect();
335 let scalars: Vec<[u64; 4]> = scalars
336 .as_ref()
337 .iter()
338 .map(|s| {
339 let mut t = [0u64; 4];
340 t.clone_from_slice(s.into_repr().as_ref());
341 t
342 })
343 .collect();
344 let s: Vec<&[u64; 4]> = scalars.iter().map(|u| u).collect();
346 G1Affine::sum_of_products(bases.as_slice(), s.as_slice())
347}
348
349pub(crate) fn multi_scalar_mul_var_time_g1<G: AsRef<[G1]>, S: AsRef<[Fr]>>(
350 bases: G,
351 scalars: S,
352) -> G1 {
353 let bases = bases.as_ref();
354 let scalars = scalars.as_ref();
355 #[cfg(feature = "rayon")]
356 {
357 bases
358 .par_iter()
359 .zip(scalars.par_iter())
360 .map(|(b, s)| {
361 let mut t = *b;
362 t.mul_assign(*s);
363 t
364 })
365 .reduce(G1::zero, |mut acc, b| {
366 acc.add_assign(&b);
367 acc
368 })
369 }
370 #[cfg(not(feature = "rayon"))]
371 {
372 bases
373 .iter()
374 .zip(scalars.iter())
375 .map(|(b, s)| {
376 let mut t = b.clone();
377 t.mul_assign(*s);
378 t
379 })
380 .fold(G1::zero(), |mut acc, b| {
381 acc.add_assign(&b);
382 acc
383 })
384 }
385}
386
387#[derive(Debug, Clone)]
390pub struct BlindSignatureContext {
391 pub commitment: Commitment,
393 pub challenge_hash: ProofChallenge,
395 pub proof_of_hidden_messages: ProofG1,
397}
398
399impl BlindSignatureContext {
400 fn to_bytes(&self, compressed: bool) -> Vec<u8> {
401 let mut output = Vec::new();
402 self.commitment
403 .0
404 .serialize(&mut output, compressed)
405 .unwrap();
406 self.challenge_hash
407 .0
408 .serialize(&mut output, compressed)
409 .unwrap();
410 output.append(&mut self.proof_of_hidden_messages.to_bytes(compressed));
411 output
412 }
413
414 fn from_bytes(data: &[u8], g1_size: usize, compressed: bool) -> Result<Self, BBSError> {
415 let min_size = g1_size * 2 + FR_COMPRESSED_SIZE + 4;
416 let mut cursor = Cursor::new(data);
417 if data.len() < min_size {
418 return Err(BBSError::from(BBSErrorKind::InvalidNumberOfBytes(
419 min_size,
420 data.len(),
421 )));
422 }
423
424 let commitment = Commitment(slice_to_elem!(&mut cursor, G1, compressed)?);
425
426 let end = g1_size + FR_COMPRESSED_SIZE;
427
428 let challenge_hash = ProofChallenge(slice_to_elem!(&mut cursor, Fr, compressed)?);
429
430 let proof_of_hidden_messages = ProofG1::from_bytes(&data[end..], g1_size, compressed)?;
431 Ok(Self {
432 commitment,
433 challenge_hash,
434 proof_of_hidden_messages,
435 })
436 }
437
438 pub fn verify(
442 &self,
443 revealed_messages: &BTreeSet<usize>,
444 verkey: &PublicKey,
445 nonce: &ProofNonce,
446 ) -> Result<bool, BBSError> {
447 let mut bases = Vec::new();
450 bases.push(verkey.h0);
451 for i in 0..verkey.message_count() {
452 if !revealed_messages.contains(&i) {
453 bases.push(verkey.h[i]);
454 }
455 }
456
457 let mut commitment = self.proof_of_hidden_messages.get_challenge_contribution(
458 bases.as_slice(),
459 &self.commitment,
460 &self.challenge_hash,
461 )?;
462
463 let mut challenge_bytes = Vec::new();
464 for b in bases.iter() {
465 b.0.serialize(&mut challenge_bytes, false).unwrap();
466 }
467 commitment.0.serialize(&mut challenge_bytes, false).unwrap();
468 self.commitment
469 .0
470 .serialize(&mut challenge_bytes, false)
471 .unwrap();
472 challenge_bytes.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]);
473
474 let mut challenge = SignatureMessage::hash(&challenge_bytes);
475 challenge.0.sub_assign(&self.challenge_hash.0);
476
477 commitment
478 .0
479 .sub_assign(&self.proof_of_hidden_messages.commitment);
480
481 Ok(commitment.0.is_zero() && challenge.0.is_zero())
482 }
483}
484
485impl ToVariableLengthBytes for BlindSignatureContext {
486 type Output = Self;
487 type Error = BBSError;
488
489 fn to_bytes_compressed_form(&self) -> Vec<u8> {
490 self.to_bytes(true)
491 }
492
493 fn from_bytes_compressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error> {
494 Self::from_bytes(data.as_ref(), G1_COMPRESSED_SIZE, true)
495 }
496
497 fn to_bytes_uncompressed_form(&self) -> Vec<u8> {
498 self.to_bytes(false)
499 }
500
501 fn from_bytes_uncompressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error> {
502 Self::from_bytes(data.as_ref(), G1_UNCOMPRESSED_SIZE, false)
503 }
504}
505
506impl Default for BlindSignatureContext {
507 fn default() -> Self {
508 Self {
509 commitment: Commitment::default(),
510 challenge_hash: ProofChallenge::default(),
511 proof_of_hidden_messages: ProofG1::default(),
512 }
513 }
514}
515
516try_from_impl!(BlindSignatureContext, BBSError);
517serdes_impl!(BlindSignatureContext);
518#[cfg(feature = "wasm")]
519wasm_slice_impl!(BlindSignatureContext);
520
521#[derive(Debug, Clone)]
523pub struct ProofRequest {
524 pub revealed_messages: BTreeSet<usize>,
527 pub verification_key: PublicKey,
530}
531
532impl ProofRequest {
533 pub(crate) fn to_bytes(&self, compressed: bool) -> Vec<u8> {
534 let revealed: Vec<usize> = (&self.revealed_messages).iter().copied().collect();
535 let mut temp =
536 revealed_to_bitvector(self.verification_key.message_count(), revealed.as_slice());
537 let mut key = self.verification_key.to_bytes(compressed);
538 let mut output = (temp.len() as u32).to_be_bytes().to_vec();
539 output.append(&mut temp);
540 output.append(&mut key);
541 output
542 }
543
544 pub(crate) fn from_bytes(
545 data: &[u8],
546 g1_size: usize,
547 g2_size: usize,
548 compressed: bool,
549 ) -> Result<Self, BBSError> {
550 let min_len = 8 + g1_size + g2_size;
551 if data.len() < min_len {
552 return Err(BBSErrorKind::InvalidNumberOfBytes(min_len, data.len()).into());
553 }
554 let bitvector_len = u32::from_be_bytes(*array_ref![data, 0, 4]) as usize;
555 let offset = 4 + bitvector_len;
556 let revealed_messages = bitvector_to_revealed(&data[4..offset]);
557 let verification_key = PublicKey::from_bytes(&data[offset..], g1_size, compressed)?;
558 Ok(Self {
559 revealed_messages,
560 verification_key,
561 })
562 }
563}
564
565impl Default for ProofRequest {
566 fn default() -> Self {
567 Self {
568 revealed_messages: BTreeSet::new(),
569 verification_key: PublicKey::default(),
570 }
571 }
572}
573
574try_from_impl!(ProofRequest, BBSError);
575serdes_impl!(ProofRequest);
576#[cfg(feature = "wasm")]
577wasm_slice_impl!(ProofRequest);
578
579impl ToVariableLengthBytes for ProofRequest {
580 type Output = ProofRequest;
581 type Error = BBSError;
582
583 fn to_bytes_compressed_form(&self) -> Vec<u8> {
584 self.to_bytes(true)
585 }
586
587 fn from_bytes_compressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error> {
588 Self::from_bytes(data.as_ref(), G1_COMPRESSED_SIZE, G2_COMPRESSED_SIZE, true)
589 }
590
591 fn to_bytes_uncompressed_form(&self) -> Vec<u8> {
592 self.to_bytes(false)
593 }
594
595 fn from_bytes_uncompressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error> {
596 Self::from_bytes(
597 data.as_ref(),
598 G1_UNCOMPRESSED_SIZE,
599 G2_UNCOMPRESSED_SIZE,
600 false,
601 )
602 }
603}
604
605#[derive(Debug, Clone)]
607pub struct SignatureProof {
608 pub revealed_messages: BTreeMap<usize, SignatureMessage>,
610 pub proof: PoKOfSignatureProof,
612}
613
614impl SignatureProof {
615 pub(crate) fn to_bytes(&self, compressed: bool) -> Vec<u8> {
617 let proof_bytes = self.proof.to_bytes(compressed);
618 let proof_len = proof_bytes.len() as u32;
619
620 let mut output =
621 Vec::with_capacity(proof_len as usize + 4 * (self.revealed_messages.len() + 1));
622 output.extend_from_slice(&proof_len.to_be_bytes()[..]);
623 output.extend_from_slice(proof_bytes.as_slice());
624
625 let revealed_messages_len = self.revealed_messages.len() as u32;
626 output.extend_from_slice(&revealed_messages_len.to_be_bytes()[..]);
627 for (i, m) in &self.revealed_messages {
628 let ii = *i as u32;
629 output.extend_from_slice(&ii.to_be_bytes()[..]);
630 m.0.serialize(&mut output, compressed).unwrap();
631 }
632
633 output
634 }
635
636 pub(crate) fn from_bytes(
638 data: &[u8],
639 g1_size: usize,
640 compressed: bool,
641 ) -> Result<Self, BBSError> {
642 if data.len() < 8 {
643 return Err(BBSError::from(BBSErrorKind::InvalidNumberOfBytes(
644 8,
645 data.len(),
646 )));
647 }
648
649 let proof_len = u32::from_be_bytes(*array_ref![data, 0, 4]) as usize + 4;
650 let proof = PoKOfSignatureProof::from_bytes(&data[4..proof_len], g1_size, compressed)?;
651
652 let mut offset = proof_len;
653 let revealed_messages_len = u32::from_be_bytes(*array_ref![data, offset, 4]) as usize;
654 offset += 4;
655 let mut end = offset + 4;
656
657 let mut revealed_messages = BTreeMap::new();
658 for _ in 0..revealed_messages_len {
659 let i = u32::from_be_bytes(*array_ref![data, offset, 4]) as usize;
660
661 offset = end;
662 end = offset + FR_COMPRESSED_SIZE;
663
664 let m = SignatureMessage::from(array_ref![data, offset, FR_COMPRESSED_SIZE]);
665
666 offset = end;
667 end = offset + 4;
668
669 revealed_messages.insert(i, m);
670 }
671
672 Ok(Self {
673 revealed_messages,
674 proof,
675 })
676 }
677}
678
679impl ToVariableLengthBytes for SignatureProof {
680 type Output = SignatureProof;
681 type Error = BBSError;
682
683 fn to_bytes_compressed_form(&self) -> Vec<u8> {
685 self.to_bytes(true)
686 }
687
688 fn from_bytes_compressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self, BBSError> {
690 Self::from_bytes(data.as_ref(), G1_COMPRESSED_SIZE, true)
691 }
692
693 fn to_bytes_uncompressed_form(&self) -> Vec<u8> {
694 self.to_bytes(false)
695 }
696
697 fn from_bytes_uncompressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error> {
698 Self::from_bytes(data.as_ref(), G1_UNCOMPRESSED_SIZE, false)
699 }
700}
701
702impl Default for SignatureProof {
703 fn default() -> Self {
704 Self {
705 revealed_messages: BTreeMap::new(),
706 proof: PoKOfSignatureProof::default(),
707 }
708 }
709}
710
711try_from_impl!(SignatureProof, BBSError);
712serdes_impl!(SignatureProof);
713#[cfg(feature = "wasm")]
714wasm_slice_impl!(SignatureProof);
715
716fn revealed_to_bitvector(total: usize, revealed: &[usize]) -> Vec<u8> {
718 let mut bytes = vec![0u8; (total / 8) + 1];
719
720 for r in revealed {
721 let idx = *r / 8;
722 let bit = (*r % 8) as u8;
723 bytes[idx] |= 1u8 << bit;
724 }
725
726 bytes.reverse();
728 bytes
729}
730
731fn bitvector_to_revealed(data: &[u8]) -> BTreeSet<usize> {
733 let mut revealed_messages = BTreeSet::new();
734 let mut scalar = 0;
735
736 for b in data.iter().rev() {
737 let mut v = *b;
738 let mut remaining = 8;
739 while v > 0 {
740 let revealed = v & 1u8;
741 if revealed == 1 {
742 revealed_messages.insert(scalar);
743 }
744 v >>= 1;
745 scalar += 1;
746 remaining -= 1;
747 }
748 scalar += remaining;
749 }
750 revealed_messages
751}
752
753fn rand_non_zero_fr() -> Fr {
754 let mut rng = thread_rng();
755 let mut r = Fr::random(&mut rng);
756 loop {
757 if !r.is_zero() {
758 return r;
759 }
760 r = Fr::random(&mut rng);
761 }
762}
763
764pub mod prelude {
766 pub use super::{
767 errors::BBSError, errors::BBSErrorKind, issuer::Issuer, keys::prelude::*, messages::*,
768 pok_sig::prelude::*, pok_vc::prelude::*, prover::Prover, signature::prelude::*,
769 verifier::Verifier, BlindSignatureContext, Commitment, CommitmentBuilder, GeneratorG1,
770 GeneratorG2, HashElem, ProofChallenge, ProofNonce, ProofRequest, RandomElem,
771 SignatureBlinding, SignatureMessage, SignatureProof, ToVariableLengthBytes,
772 FR_COMPRESSED_SIZE, G1_COMPRESSED_SIZE, G1_UNCOMPRESSED_SIZE, G2_COMPRESSED_SIZE,
773 G2_UNCOMPRESSED_SIZE,
774 };
775}
776
777#[cfg(test)]
778mod tests {
779 use crate::prelude::*;
780 use ff_zeroize::Field;
781 use pairing_plus::{
782 bls12_381::{Fr, G1},
783 CurveProjective,
784 };
785 use rand::thread_rng;
786 use std::collections::BTreeMap;
787
788 #[ignore]
789 #[test]
790 fn speed_multi_scalar_test() {
791 let count = 5;
792 let mut scalars = Vec::new();
794 let mut rng = thread_rng();
795 for _ in 0..count {
797 scalars.push(Fr::random(&mut rng));
799 }
800 let start = std::time::Instant::now();
801 let (pk, sk) = generate(count).unwrap();
802 println!("keygen = {:?}", std::time::Instant::now() - start);
803
804 let msgs: Vec<SignatureMessage> = scalars.iter().map(|e| SignatureMessage(*e)).collect();
805 let start = std::time::Instant::now();
806 let sig = Signature::new(msgs.as_slice(), &sk, &pk).unwrap();
807 println!("sig gen = {:?}", std::time::Instant::now() - start);
808 let start = std::time::Instant::now();
809 let temp = sig.verify(msgs.as_slice(), &pk);
810 println!("sig verify = {:?}", std::time::Instant::now() - start);
811 println!("temp = {:?}", temp);
812
813 let start = std::time::Instant::now();
814 let (dpk, _) = DeterministicPublicKey::new(Some(KeyGenOption::FromSecretKey(sk))).unwrap();
815 println!("dpkgen = {:?}", std::time::Instant::now() - start);
816 let start = std::time::Instant::now();
817 let _ = dpk.to_public_key(count);
818 println!("to_public_key = {:?}", std::time::Instant::now() - start);
819 }
820
821 #[test]
822 fn proof_request_bytes_test() {
823 let (pk, _) = generate(5).unwrap();
824 let pr = Verifier::new_proof_request(&[2, 3, 4], &pk).unwrap();
825
826 let bytes = pr.to_bytes_compressed_form();
827 let pr_1 = ProofRequest::from_bytes_compressed_form(&bytes);
828 assert!(pr_1.is_ok());
829 let pr_1 = pr_1.unwrap();
830 let bytes_1 = pr_1.to_bytes_compressed_form();
831 assert_eq!(bytes[..], bytes_1[..]);
832 }
833
834 #[test]
835 fn blind_signature_context_bytes_test() {
836 let b = BlindSignatureContext {
837 commitment: Commitment(G1::one()),
838 challenge_hash: ProofChallenge::random(),
839 proof_of_hidden_messages: ProofG1 {
840 commitment: G1::one(),
841 responses: Vec::new(),
842 },
843 };
844
845 let bytes = b.to_bytes_uncompressed_form();
846 let res = BlindSignatureContext::from_bytes_uncompressed_form(&bytes);
847 assert!(res.is_ok());
848 assert_eq!(res.unwrap().to_bytes_uncompressed_form(), bytes);
849
850 let b = BlindSignatureContext {
851 commitment: Commitment(G1::one()),
852 challenge_hash: ProofChallenge::random(),
853 proof_of_hidden_messages: ProofG1 {
854 commitment: G1::one(),
855 responses: (0..10)
856 .collect::<Vec<usize>>()
857 .iter()
858 .map(|_| SignatureMessage::random().0)
859 .collect(),
860 },
861 };
862
863 let bytes = b.to_bytes_compressed_form();
864 let res = BlindSignatureContext::from_bytes_compressed_form(&bytes);
865 assert!(res.is_ok());
866 assert_eq!(res.unwrap().to_bytes_compressed_form(), bytes);
867 }
868
869 #[test]
870 fn proof_bytes_test() {
871 let proof = SignatureProof {
873 revealed_messages: BTreeMap::new(),
874 proof: PoKOfSignatureProof {
875 a_prime: G1::zero(),
876 a_bar: G1::zero(),
877 d: G1::zero(),
878 proof_vc_1: ProofG1 {
879 commitment: G1::zero(),
880 responses: Vec::with_capacity(1),
881 },
882 proof_vc_2: ProofG1 {
883 commitment: G1::zero(),
884 responses: Vec::with_capacity(1),
885 },
886 },
887 };
888
889 let proof_bytes = proof.to_bytes_uncompressed_form();
890
891 let proof_dup = SignatureProof::from_bytes_uncompressed_form(&proof_bytes);
892 assert!(proof_dup.is_ok());
893
894 let (pk, sk) = Issuer::new_keys(1).unwrap();
895 let messages = vec![SignatureMessage::random()];
896 let sig = Signature::new(messages.as_slice(), &sk, &pk).unwrap();
897
898 let pr = Verifier::new_proof_request(&[0], &pk).unwrap();
899 let pm = vec![pm_revealed_raw!(messages[0].clone())];
900 let pok = Prover::commit_signature_pok(&pr, pm.as_slice(), &sig).unwrap();
901 let nonce = ProofNonce::hash(&[0u8, 1u8, 2u8, 3u8, 4u8, 5u8, 6u8, 7u8, 8u8, 9u8]);
902 let mut challenge_bytes = pok.to_bytes();
903 challenge_bytes.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]);
904 let challenge = ProofChallenge::hash(challenge_bytes.as_slice());
905
906 let sig_proof = Prover::generate_signature_pok(pok, &challenge).unwrap();
907
908 assert!(
909 Verifier::verify_signature_pok(&pr, &sig_proof, &nonce)
910 .unwrap()
911 .len()
912 == 1
913 );
914 let sig_proof_bytes = sig_proof.to_bytes_uncompressed_form();
915
916 let sig_proof_dup = SignatureProof::from_bytes_uncompressed_form(&sig_proof_bytes);
917 assert!(sig_proof_dup.is_ok());
918 let sig_proof_dup = sig_proof_dup.unwrap();
919 assert!(
920 Verifier::verify_signature_pok(&pr, &sig_proof_dup, &nonce)
921 .unwrap()
922 .len()
923 == 1
924 );
925
926 let sig_proof_bytes = sig_proof.to_bytes_compressed_form();
927
928 let sig_proof_dup = SignatureProof::from_bytes_compressed_form(&sig_proof_bytes);
929 assert!(sig_proof_dup.is_ok());
930 }
931}