mithril_stm/single_signature/
signature.rs

1use std::{
2    cmp::Ordering,
3    hash::{Hash, Hasher},
4};
5
6use blake2::digest::{Digest, FixedOutput};
7use serde::{Deserialize, Serialize};
8
9use crate::bls_multi_signature::Signature;
10use crate::eligibility_check::ev_lt_phi;
11use crate::{
12    Index, Stake, StmAggrVerificationKey, StmParameters, StmSignatureError, StmVerificationKey,
13};
14
15/// Signature created by a single party who has won the lottery.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct StmSig {
18    /// The signature from the underlying MSP scheme.
19    pub sigma: Signature,
20    /// The index(es) for which the signature is valid
21    pub indexes: Vec<Index>,
22    /// Merkle tree index of the signer.
23    pub signer_index: Index,
24}
25
26impl StmSig {
27    /// Verify an stm signature by checking that the lottery was won, the merkle path is correct,
28    /// the indexes are in the desired range and the underlying multi signature validates.
29    pub fn verify<D: Clone + Digest + FixedOutput>(
30        &self,
31        params: &StmParameters,
32        pk: &StmVerificationKey,
33        stake: &Stake,
34        avk: &StmAggrVerificationKey<D>,
35        msg: &[u8],
36    ) -> Result<(), StmSignatureError> {
37        let msgp = avk.get_mt_commitment().concat_with_msg(msg);
38        self.verify_core(params, pk, stake, &msgp, &avk.get_total_stake())?;
39        Ok(())
40    }
41
42    /// Verify that all indices of a signature are valid.
43    pub(crate) fn check_indices(
44        &self,
45        params: &StmParameters,
46        stake: &Stake,
47        msg: &[u8],
48        total_stake: &Stake,
49    ) -> Result<(), StmSignatureError> {
50        for &index in &self.indexes {
51            if index > params.m {
52                return Err(StmSignatureError::IndexBoundFailed(index, params.m));
53            }
54
55            let ev = self.sigma.eval(msg, index);
56
57            if !ev_lt_phi(params.phi_f, ev, *stake, *total_stake) {
58                return Err(StmSignatureError::LotteryLost);
59            }
60        }
61
62        Ok(())
63    }
64
65    /// Convert an `StmSig` into bytes
66    ///
67    /// # Layout
68    /// * Stake
69    /// * Number of valid indexes (as u64)
70    /// * Indexes of the signature
71    /// * Public Key
72    /// * Signature
73    /// * Merkle index of the signer.
74    pub fn to_bytes(&self) -> Vec<u8> {
75        let mut output = Vec::new();
76        output.extend_from_slice(&(self.indexes.len() as u64).to_be_bytes());
77
78        for index in &self.indexes {
79            output.extend_from_slice(&index.to_be_bytes());
80        }
81
82        output.extend_from_slice(&self.sigma.to_bytes());
83
84        output.extend_from_slice(&self.signer_index.to_be_bytes());
85        output
86    }
87
88    /// Extract a batch compatible `StmSig` from a byte slice.
89    pub fn from_bytes<D: Clone + Digest + FixedOutput>(
90        bytes: &[u8],
91    ) -> Result<StmSig, StmSignatureError> {
92        let mut u64_bytes = [0u8; 8];
93
94        u64_bytes.copy_from_slice(
95            bytes
96                .get(0..8)
97                .ok_or(StmSignatureError::SerializationError)?,
98        );
99        let nr_indexes = u64::from_be_bytes(u64_bytes) as usize;
100
101        let mut indexes = Vec::new();
102        for i in 0..nr_indexes {
103            u64_bytes.copy_from_slice(
104                bytes
105                    .get(8 + i * 8..16 + i * 8)
106                    .ok_or(StmSignatureError::SerializationError)?,
107            );
108            indexes.push(u64::from_be_bytes(u64_bytes));
109        }
110
111        let offset = 8 + nr_indexes * 8;
112        let sigma = Signature::from_bytes(
113            bytes
114                .get(offset..offset + 48)
115                .ok_or(StmSignatureError::SerializationError)?,
116        )?;
117
118        u64_bytes.copy_from_slice(
119            bytes
120                .get(offset + 48..offset + 56)
121                .ok_or(StmSignatureError::SerializationError)?,
122        );
123        let signer_index = u64::from_be_bytes(u64_bytes);
124
125        Ok(StmSig {
126            sigma,
127            indexes,
128            signer_index,
129        })
130    }
131
132    /// Compare two `StmSig` by their signers' merkle tree indexes.
133    pub fn cmp_stm_sig(&self, other: &Self) -> Ordering {
134        self.signer_index.cmp(&other.signer_index)
135    }
136
137    /// Verify a core signature by checking that the lottery was won,
138    /// the indexes are in the desired range and the underlying multi signature validates.
139    pub fn verify_core(
140        &self,
141        params: &StmParameters,
142        pk: &StmVerificationKey,
143        stake: &Stake,
144        msg: &[u8],
145        total_stake: &Stake,
146    ) -> Result<(), StmSignatureError> {
147        self.sigma.verify(msg, pk)?;
148        self.check_indices(params, stake, msg, total_stake)?;
149
150        Ok(())
151    }
152}
153
154impl Hash for StmSig {
155    fn hash<H: Hasher>(&self, state: &mut H) {
156        Hash::hash_slice(&self.sigma.to_bytes(), state)
157    }
158}
159
160impl PartialEq for StmSig {
161    fn eq(&self, other: &Self) -> bool {
162        self.sigma == other.sigma
163    }
164}
165
166impl Eq for StmSig {}
167
168impl PartialOrd for StmSig {
169    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
170        Some(std::cmp::Ord::cmp(self, other))
171    }
172}
173
174impl Ord for StmSig {
175    fn cmp(&self, other: &Self) -> Ordering {
176        self.cmp_stm_sig(other)
177    }
178}