1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use crate::errors::prelude::*;
use crate::keys::prelude::*;
use crate::messages::*;
use crate::pok_sig::prelude::*;
use crate::pok_vc::prelude::*;
use crate::signature::prelude::*;
/// The prover of a signature or credential receives it from an
/// issuer and later proves to a verifier.
/// The prover can either have the issuer sign all messages
/// or can have some (0 to all) messages blindly signed by the issuer.
use crate::{
    BlindSignatureContext, CommitmentBuilder, HashElem, ProofChallenge, ProofNonce, ProofRequest,
    RandomElem, SignatureBlinding, SignatureMessage, SignatureProof,
};
use std::collections::BTreeMap;

/// This struct represents a Prover who receives signatures or proves with them.
/// Provided are methods for 2PC where some are only known to the prover and a blind signature
/// is created, unblinding signatures, verifying signatures, and creating signature proofs of knowledge
/// with selective disclosure proofs
pub struct Prover {}

impl Prover {
    /// Generate a unique message that will be used across multiple signatures.
    /// This `link_secret` is the same in all signatures and allows a prover to demonstrate
    /// that signatures were issued to the same identity. This value should be a blinded
    /// message in all signatures and never revealed to anyone.
    pub fn new_link_secret() -> SignatureMessage {
        SignatureMessage::random()
    }

    /// Create the structures need to send to an issuer to complete a blinded signature
    pub fn new_blind_signature_context(
        verkey: &PublicKey,
        messages: &BTreeMap<usize, SignatureMessage>,
        nonce: &ProofNonce,
    ) -> Result<(BlindSignatureContext, SignatureBlinding), BBSError> {
        let blinding_factor = Signature::generate_blinding();
        let mut builder = CommitmentBuilder::new();

        // h0^blinding_factor*hi^mi.....
        builder.add(&verkey.h0, &blinding_factor);

        let mut committing = ProverCommittingG1::new();
        committing.commit(&verkey.h0);
        let mut secrets = Vec::new();
        secrets.push(SignatureMessage(blinding_factor.0));
        for (i, m) in messages {
            if *i > verkey.h.len() {
                return Err(BBSErrorKind::PublicKeyGeneratorMessageCountMismatch(
                    *i,
                    verkey.h.len(),
                )
                .into());
            }
            secrets.push(m.clone());
            builder.add(&verkey.h[*i], &m);
            committing.commit(&verkey.h[*i]);
        }

        // Create a random commitment, compute challenges and response.
        // The proof of knowledge consists of a commitment and responses
        // Prover and issuer engage in a proof of knowledge for `commitment`
        let commitment = builder.finalize();
        let committed = committing.finish();

        let mut extra = Vec::new();
        extra.extend_from_slice(&commitment.to_bytes_uncompressed_form()[..]);
        extra.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]);
        let challenge_hash = committed.gen_challenge(extra);
        let proof_of_hidden_messages = committed
            .gen_proof(&challenge_hash, secrets.as_slice())
            .unwrap();

        Ok((
            BlindSignatureContext {
                challenge_hash,
                commitment,
                proof_of_hidden_messages,
            },
            blinding_factor,
        ))
    }

    /// Unblinds and verifies a signature received from an issuer
    pub fn complete_signature(
        verkey: &PublicKey,
        messages: &[SignatureMessage],
        blind_signature: &BlindSignature,
        blinding_factor: &SignatureBlinding,
    ) -> Result<Signature, BBSError> {
        let signature = blind_signature.to_unblinded(blinding_factor);
        if signature.verify(messages, verkey)? {
            Ok(signature)
        } else {
            Err(BBSErrorKind::GeneralError {
                msg: "Invalid signature.".to_string(),
            }
            .into())
        }
    }

    /// Create a new signature proof of knowledge and selective disclosure proof
    /// from a verifier's request
    ///
    /// # Arguments
    /// * `request` - Proof request from verifier
    /// * `proof_messages` -
    /// If blinding_factor is Some(Nonce) then it will use that.
    /// If None, a blinding factor will be generated at random.
    pub fn commit_signature_pok(
        request: &ProofRequest,
        proof_messages: &[ProofMessage],
        signature: &Signature,
    ) -> Result<PoKOfSignature, BBSError> {
        PoKOfSignature::init(&signature, &request.verification_key, proof_messages)
    }

    /// Create the challenge hash for a set of proofs
    ///
    /// # Arguments
    /// * `poks` - a vec of PoKOfSignature objects
    /// * `nonce` - a SignatureNonce
    /// * `claims` - an optional slice of bytes the prover wishes to include in the challenge
    pub fn create_challenge_hash(
        pok_sigs: &[PoKOfSignature],
        claims: Option<&[&[u8]]>,
        nonce: &ProofNonce,
    ) -> Result<ProofChallenge, BBSError> {
        let mut bytes = Vec::new();

        for p in pok_sigs {
            bytes.extend_from_slice(p.to_bytes().as_slice());
        }
        bytes.extend_from_slice(&nonce.to_bytes_uncompressed_form()[..]);
        if let Some(add_claims) = claims {
            for c in add_claims {
                bytes.extend_from_slice(c);
            }
        }

        let challenge = ProofChallenge::hash(&bytes);
        Ok(challenge)
    }

    /// Convert the a committed proof of signature knowledge to the proof
    pub fn generate_signature_pok(
        pok_sig: PoKOfSignature,
        challenge: &ProofChallenge,
    ) -> Result<SignatureProof, BBSError> {
        let revealed_messages = (&pok_sig.revealed_messages).clone();
        let proof = pok_sig.gen_proof(challenge)?;

        Ok(SignatureProof {
            revealed_messages,
            proof,
        })
    }
}