aries_bbssignatures/
lib.rs

1//! Implements the BBS+ signature as defined in <https://eprint.iacr.org/2016/663.pdf>
2//! in Section 4.3. Also included is ability to do zero-knowledge proofs as described
3//! in Section 4.4 and 4.5.
4//!
5//! The BBS+ signature is a pairing-based ECC signature
6//! that signs multiple messages instead of just one.
7//! The signature and messages can be used to create signature proofs of knowledge
8//! in zero-knowledge proofs in which the signature is not revealed and messages
9//! can be selectively disclosed––some are revealed and some remain hidden.
10//!
11//! The signature also supports separating the signer and signature holder
12//! where the holder creates commitments to messages which are hidden from the signer
13//! and a signature blinding factor which is retained. The holder sends the commitment
14//! to the signer who completes the signing process and sends the blinded signature back.
15//! The holder can then un-blind the signature finishing a 2-PC computation
16//!
17//! BBS+ signatures can be used for TPM DAA attestations or Verifiable Credentials.
18
19#![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
66/// Number of bytes in scalar compressed form
67pub const FR_COMPRESSED_SIZE: usize = 32;
68/// Number of bytes in scalar uncompressed form
69pub const FR_UNCOMPRESSED_SIZE: usize = 48;
70/// Number of bytes in G1 X coordinate
71pub const G1_COMPRESSED_SIZE: usize = 48;
72/// Number of bytes in G1 X and Y coordinates
73pub const G1_UNCOMPRESSED_SIZE: usize = 96;
74/// Number of bytes in G2 X (a, b) coordinate
75pub const G2_COMPRESSED_SIZE: usize = 96;
76/// Number of bytes in G2 X(a, b) and Y(a, b) coordinates
77pub const G2_UNCOMPRESSED_SIZE: usize = 192;
78
79#[macro_use]
80mod macros;
81/// Proof messages
82#[macro_use]
83pub mod messages;
84/// Macros and classes used for creating proofs of knowledge
85#[macro_use]
86pub mod pok_vc;
87/// The errors that BBS+ throws
88pub mod errors;
89/// Represents steps taken by the issuer to create a BBS+ signature
90/// whether its 2PC or all in one
91pub mod issuer;
92/// BBS+ key classes
93pub mod keys;
94/// Methods and structs for creating signature proofs of knowledge
95pub mod pok_sig;
96/// Represents steps taken by the prover to receive a BBS+ signature
97/// and generate ZKPs
98pub mod prover;
99/// Methods and structs for creating signatures
100pub mod signature;
101/// Represents steps taken by the verifier to request signature proofs of knowledge
102/// and selective disclosure proofs
103pub mod verifier;
104
105/// Trait for structs that have variable length bytes but use compressed Bls12 elements
106pub trait ToVariableLengthBytes {
107    /// The type that implements this trait
108    type Output;
109    /// The type of error to return
110    type Error;
111
112    /// Convert to raw compressed bytes
113    fn to_bytes_compressed_form(&self) -> Vec<u8>;
114
115    /// Convert from raw compressed bytes
116    fn from_bytes_compressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error>;
117
118    /// Convert to raw bytes
119    fn to_bytes_uncompressed_form(&self) -> Vec<u8>;
120
121    /// Convert from raw bytes
122    fn from_bytes_uncompressed_form<I: AsRef<[u8]>>(data: I) -> Result<Self::Output, Self::Error>;
123}
124
125/// Struct can be generated randomly
126pub trait RandomElem {
127    /// The type that implements this trait
128    type Output;
129
130    /// Return a randomly generated type
131    fn random() -> Self::Output;
132}
133
134/// Struct can be generated from hashing
135pub trait HashElem {
136    /// The type that implements this trait
137    type Output;
138
139    /// Return a type from hashing `data`
140    fn hash<I: AsRef<[u8]>>(data: I) -> Self;
141}
142
143/// The type for creating commitments to messages that are hidden during issuance.
144#[derive(Copy, Clone, Debug, Eq, PartialEq)]
145pub struct Commitment(pub(crate) G1);
146
147impl Commitment {
148    /// Compute a new commitment from multiple points and scalars
149    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/// Wrapper for G1
167#[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/// Wrapper for G2
185#[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/// Convenience wrapper for creating commitments
202#[derive(Clone, Debug, Default)]
203pub struct CommitmentBuilder {
204    bases: Vec<G1>,
205    scalars: Vec<Fr>,
206}
207
208impl CommitmentBuilder {
209    /// Initialize a new builder
210    pub fn new() -> Self {
211        Self {
212            bases: Vec::new(),
213            scalars: Vec::new(),
214        }
215    }
216
217    /// Add a new base and scalar to the commitment
218    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    /// Convert to commitment
224    pub fn finalize(self) -> Commitment {
225        Commitment(multi_scalar_mul_const_time_g1(&self.bases, &self.scalars))
226    }
227}
228
229/// The type for messages
230#[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/// The type for nonces
250#[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/// The Fiat-Shamir Challenge in proofs
268#[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/// The type for blinding factors
286#[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    // Annoying step to keep the borrow checker happy
345    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/// Contains the data used for computing a blind signature and verifying
388/// proof of hidden messages from a prover
389#[derive(Debug, Clone)]
390pub struct BlindSignatureContext {
391    /// The blinded signature commitment
392    pub commitment: Commitment,
393    /// The challenge hash for the Fiat-Shamir heuristic
394    pub challenge_hash: ProofChallenge,
395    /// The proof for the hidden messages
396    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    /// Assumes the proof of hidden messages
439    /// If other proofs were included, those will need to be verified another
440    /// way
441    pub fn verify(
442        &self,
443        revealed_messages: &BTreeSet<usize>,
444        verkey: &PublicKey,
445        nonce: &ProofNonce,
446    ) -> Result<bool, BBSError> {
447        // Verify the proof
448        // First get the generators used to create the commitment
449        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/// Contains the data from a verifier to a prover
522#[derive(Debug, Clone)]
523pub struct ProofRequest {
524    /// Allow the prover to retrieve which messages should be revealed.
525    /// Might be prompted in a GUI or CLI
526    pub revealed_messages: BTreeSet<usize>,
527    /// Allow the prover to know which public key for which the signature must
528    /// be valid.
529    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/// Contains the data from a prover to a verifier
606#[derive(Debug, Clone)]
607pub struct SignatureProof {
608    /// The revealed messages as field elements
609    pub revealed_messages: BTreeMap<usize, SignatureMessage>,
610    /// The signature proof of knowledge
611    pub proof: PoKOfSignatureProof,
612}
613
614impl SignatureProof {
615    /// Convert to raw bytes
616    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    /// Convert from raw bytes
637    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    /// Convert to raw bytes using compressed form for each element.
684    fn to_bytes_compressed_form(&self) -> Vec<u8> {
685        self.to_bytes(true)
686    }
687
688    /// Convert from compressed form raw bytes.
689    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
716/// Expects `revealed` to be sorted
717fn 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    // Convert to big endian
727    bytes.reverse();
728    bytes
729}
730
731/// Convert big-endian vector to u32
732fn 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
764/// Convenience importer
765pub 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 bases = Vec::new();
793        let mut scalars = Vec::new();
794        let mut rng = thread_rng();
795        //
796        for _ in 0..count {
797            //     bases.push(G1::random(&mut rng));
798            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        // No revealed messages
872        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}