mithril_stm/participant/
signer.rs

1use crate::bls_multi_signature::{Signature, SigningKey, VerificationKey};
2use crate::eligibility_check::ev_lt_phi;
3use crate::key_reg::ClosedKeyReg;
4use crate::stm::{Stake, StmParameters, StmSig};
5use blake2::digest::{Digest, FixedOutput};
6
7/// Wrapper of the MultiSignature Verification key
8pub type StmVerificationKey = VerificationKey;
9
10/// Participant in the protocol can sign messages.
11/// * If the signer has `closed_reg`, then it can generate Stm certificate.
12///     * This kind of signer can only be generated out of an `StmInitializer` and a `ClosedKeyReg`.
13///     * This ensures that a `MerkleTree` root is not computed before all participants have registered.
14/// * If the signer does not have `closed_reg`, then it is a core signer.
15///     * This kind of signer cannot participate certificate generation.
16///     * Signature generated can be verified by a full node verifier (core verifier).
17#[derive(Debug, Clone)]
18pub struct StmSigner<D: Digest> {
19    signer_index: u64,
20    stake: Stake,
21    params: StmParameters,
22    sk: SigningKey,
23    vk: StmVerificationKey,
24    closed_reg: Option<ClosedKeyReg<D>>,
25}
26
27impl<D: Clone + Digest + FixedOutput> StmSigner<D> {
28    /// Create an StmSigner for given input
29    pub fn set_stm_signer(
30        signer_index: u64,
31        stake: Stake,
32        params: StmParameters,
33        sk: SigningKey,
34        vk: StmVerificationKey,
35        closed_reg: ClosedKeyReg<D>,
36    ) -> StmSigner<D> {
37        Self {
38            signer_index,
39            stake,
40            params,
41            sk,
42            vk,
43            closed_reg: Some(closed_reg),
44        }
45    }
46
47    /// Create a core signer (no registration data) for given input
48    pub fn set_core_signer(
49        signer_index: u64,
50        stake: Stake,
51        params: StmParameters,
52        sk: SigningKey,
53        vk: StmVerificationKey,
54    ) -> StmSigner<D> {
55        Self {
56            signer_index,
57            stake,
58            params,
59            sk,
60            vk,
61            closed_reg: None,
62        }
63    }
64
65    /// This function produces a signature following the description of Section 2.4.
66    /// Once the signature is produced, this function checks whether any index in `[0,..,self.params.m]`
67    /// wins the lottery by evaluating the dense mapping.
68    /// It records all the winning indexes in `Self.indexes`.
69    /// If it wins at least one lottery, it stores the signer's merkle tree index. The proof of membership
70    /// will be handled by the aggregator.
71    pub fn sign(&self, msg: &[u8]) -> Option<StmSig> {
72        let closed_reg = self.closed_reg.as_ref().expect("Closed registration not found! Cannot produce StmSignatures. Use core_sign to produce core signatures (not valid for an StmCertificate).");
73        let msgp = closed_reg
74            .merkle_tree
75            .to_commitment_batch_compat()
76            .concat_with_msg(msg);
77        let signature = self.core_sign(&msgp, closed_reg.total_stake)?;
78
79        Some(StmSig {
80            sigma: signature.sigma,
81            signer_index: self.signer_index,
82            indexes: signature.indexes,
83        })
84    }
85
86    /// Extract the verification key.
87    pub fn verification_key(&self) -> StmVerificationKey {
88        self.vk
89    }
90
91    /// Extract stake from the signer.
92    pub fn get_stake(&self) -> Stake {
93        self.stake
94    }
95
96    /// A core signature generated without closed registration.
97    /// The core signature can be verified by core verifier.
98    /// Once the signature is produced, this function checks whether any index in `[0,..,self.params.m]`
99    /// wins the lottery by evaluating the dense mapping.
100    /// It records all the winning indexes in `Self.indexes`.
101    pub fn core_sign(&self, msg: &[u8], total_stake: Stake) -> Option<StmSig> {
102        let sigma = self.sk.sign(msg);
103
104        let indexes = self.check_lottery(msg, &sigma, total_stake);
105        if !indexes.is_empty() {
106            Some(StmSig {
107                sigma,
108                indexes,
109                signer_index: self.signer_index,
110            })
111        } else {
112            None
113        }
114    }
115
116    /// Collects and returns the winning indices.
117    pub fn check_lottery(&self, msg: &[u8], sigma: &Signature, total_stake: Stake) -> Vec<u64> {
118        let mut indexes = Vec::new();
119        for index in 0..self.params.m {
120            if ev_lt_phi(
121                self.params.phi_f,
122                sigma.eval(msg, index),
123                self.stake,
124                total_stake,
125            ) {
126                indexes.push(index);
127            }
128        }
129        indexes
130    }
131
132    /// Get StmParameters
133    pub fn get_params(&self) -> StmParameters {
134        self.params
135    }
136
137    /// Get closed key registration
138    pub fn get_closed_reg(&self) -> Option<ClosedKeyReg<D>> {
139        self.closed_reg.clone()
140    }
141
142    /// Get verification key
143    pub fn get_vk(&self) -> StmVerificationKey {
144        self.vk
145    }
146}