mithril_stm/participant/
signer.rs

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