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
// Copyright (c) 2021-2024 Espresso Systems (espressosys.com)
// This file is part of the HotShot repository.

// You should have received a copy of the MIT License
// along with the HotShot repository. If not, see <https://mit-license.org/>.

//! The quorum certificate (QC) trait is a certificate of a sufficient quorum of distinct
//! parties voted for a message or statement.

use ark_std::{
    rand::{CryptoRng, RngCore},
    vec::Vec,
};
use bitvec::prelude::*;
use generic_array::{ArrayLength, GenericArray};
use jf_signature::{AggregateableSignatureSchemes, SignatureError};
use serde::{Deserialize, Serialize};

/// Trait for validating a QC built from different signatures on the same message
pub trait QuorumCertificateScheme<
    A: AggregateableSignatureSchemes + Serialize + for<'a> Deserialize<'a>,
>
{
    /// Public parameters for generating the QC
    /// E.g: snark proving/verifying keys, list of (or pointer to) public keys stored in the smart contract.
    type QcProverParams: Serialize + for<'a> Deserialize<'a>;

    /// Public parameters for validating the QC
    /// E.g: verifying keys, stake table commitment
    type QcVerifierParams: Serialize + for<'a> Deserialize<'a>;

    /// Allows to fix the size of the message at compilation time.
    type MessageLength: ArrayLength<A::MessageUnit>;

    /// Type of the actual quorum certificate object
    type Qc;

    /// Type of the quorum size (e.g. number of votes or accumulated weight of signatures)
    type QuorumSize;

    /// Produces a partial signature on a message with a single user signing key
    /// NOTE: the original message (vote) should be prefixed with the hash of the stake table.
    /// * `agg_sig_pp` - public parameters for aggregate signature
    /// * `message` - message to be signed
    /// * `sk` - user signing key
    /// * `returns` - a "simple" signature
    ///
    /// # Errors
    ///
    /// Should return error if the underlying signature scheme fail to sign.
    fn sign<R: CryptoRng + RngCore, M: AsRef<[A::MessageUnit]>>(
        pp: &A::PublicParameter,
        sk: &A::SigningKey,
        msg: M,
        prng: &mut R,
    ) -> Result<A::Signature, SignatureError> {
        A::sign(pp, sk, msg, prng)
    }

    /// Computes an aggregated signature from a set of partial signatures and the verification keys involved
    /// * `qc_pp` - public parameters for generating the QC
    /// * `signers` - a bool vector indicating the list of verification keys corresponding to the set of partial signatures
    /// * `sigs` - partial signatures on the same message
    ///
    /// # Errors
    ///
    /// Will return error if some of the partial signatures provided are invalid or the number of
    /// partial signatures / verifications keys are different.
    fn assemble(
        qc_pp: &Self::QcProverParams,
        signers: &BitSlice,
        sigs: &[A::Signature],
    ) -> Result<Self::Qc, SignatureError>;

    /// Checks an aggregated signature over some message provided as input
    /// * `qc_vp` - public parameters for validating the QC
    /// * `message` - message to check the aggregated signature against
    /// * `qc` - quorum certificate
    /// * `returns` - the quorum size if the qc is valid, an error otherwise.
    ///
    /// # Errors
    ///
    /// Return error if the QC is invalid, either because accumulated weight didn't exceed threshold,
    /// or some partial signatures are invalid.
    fn check(
        qc_vp: &Self::QcVerifierParams,
        message: &GenericArray<A::MessageUnit, Self::MessageLength>,
        qc: &Self::Qc,
    ) -> Result<Self::QuorumSize, SignatureError>;

    /// Trace the list of signers given a qc.
    ///
    /// # Errors
    ///
    /// Return error if the inputs mismatch (e.g. wrong verifier parameter or original message).
    fn trace(
        qc_vp: &Self::QcVerifierParams,
        message: &GenericArray<A::MessageUnit, Self::MessageLength>,
        qc: &Self::Qc,
    ) -> Result<Vec<A::VerificationKey>, SignatureError>;
}