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::BlsSignature;
10use crate::eligibility_check::is_lottery_won;
11use crate::{
12    AggregateVerificationKey, Index, Parameters, Stake, StmSignatureError, VerificationKey,
13};
14
15/// Signature created by a single party who has won the lottery.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct SingleSignature {
18    /// The signature from the underlying MSP scheme.
19    pub sigma: BlsSignature,
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 SingleSignature {
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: &Parameters,
32        pk: &VerificationKey,
33        stake: &Stake,
34        avk: &AggregateVerificationKey<D>,
35        msg: &[u8],
36    ) -> Result<(), StmSignatureError> {
37        let msgp = avk.get_merkle_tree_batch_commitment().concatenate_with_message(msg);
38        self.basic_verify(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: &Parameters,
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.evaluate_dense_mapping(msg, index);
56
57            if !is_lottery_won(params.phi_f, ev, *stake, *total_stake) {
58                return Err(StmSignatureError::LotteryLost);
59            }
60        }
61
62        Ok(())
63    }
64
65    /// Convert an `SingleSignature` 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 `SingleSignature` from a byte slice.
89    pub fn from_bytes<D: Clone + Digest + FixedOutput>(
90        bytes: &[u8],
91    ) -> Result<SingleSignature, StmSignatureError> {
92        let mut u64_bytes = [0u8; 8];
93
94        u64_bytes.copy_from_slice(bytes.get(0..8).ok_or(StmSignatureError::SerializationError)?);
95        let nr_indexes = u64::from_be_bytes(u64_bytes) as usize;
96
97        let mut indexes = Vec::new();
98        for i in 0..nr_indexes {
99            u64_bytes.copy_from_slice(
100                bytes
101                    .get(8 + i * 8..16 + i * 8)
102                    .ok_or(StmSignatureError::SerializationError)?,
103            );
104            indexes.push(u64::from_be_bytes(u64_bytes));
105        }
106
107        let offset = 8 + nr_indexes * 8;
108        let sigma = BlsSignature::from_bytes(
109            bytes
110                .get(offset..offset + 48)
111                .ok_or(StmSignatureError::SerializationError)?,
112        )?;
113
114        u64_bytes.copy_from_slice(
115            bytes
116                .get(offset + 48..offset + 56)
117                .ok_or(StmSignatureError::SerializationError)?,
118        );
119        let signer_index = u64::from_be_bytes(u64_bytes);
120
121        Ok(SingleSignature {
122            sigma,
123            indexes,
124            signer_index,
125        })
126    }
127
128    /// Compare two `SingleSignature` by their signers' merkle tree indexes.
129    fn compare_signer_index(&self, other: &Self) -> Ordering {
130        self.signer_index.cmp(&other.signer_index)
131    }
132
133    /// Compare two `SingleSignature` by their signers' merkle tree indexes.
134    #[deprecated(since = "0.4.9", note = "This function will be removed")]
135    pub fn cmp_stm_sig(&self, other: &Self) -> Ordering {
136        Self::compare_signer_index(self, other)
137    }
138
139    /// Verify a basic signature by checking that the lottery was won,
140    /// the indexes are in the desired range and the underlying multi signature validates.
141    pub(crate) fn basic_verify(
142        &self,
143        params: &Parameters,
144        pk: &VerificationKey,
145        stake: &Stake,
146        msg: &[u8],
147        total_stake: &Stake,
148    ) -> Result<(), StmSignatureError> {
149        self.sigma.verify(msg, pk)?;
150        self.check_indices(params, stake, msg, total_stake)?;
151
152        Ok(())
153    }
154
155    /// Will be deprecated. Use `basic_verify` instead.
156    #[deprecated(since = "0.4.9", note = "Use `basic_verify` instead")]
157    pub fn core_verify(
158        &self,
159        params: &Parameters,
160        pk: &VerificationKey,
161        stake: &Stake,
162        msg: &[u8],
163        total_stake: &Stake,
164    ) -> Result<(), StmSignatureError> {
165        Self::basic_verify(self, params, pk, stake, msg, total_stake)
166    }
167}
168
169impl Hash for SingleSignature {
170    fn hash<H: Hasher>(&self, state: &mut H) {
171        Hash::hash_slice(&self.sigma.to_bytes(), state)
172    }
173}
174
175impl PartialEq for SingleSignature {
176    fn eq(&self, other: &Self) -> bool {
177        self.sigma == other.sigma
178    }
179}
180
181impl Eq for SingleSignature {}
182
183impl PartialOrd for SingleSignature {
184    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
185        Some(std::cmp::Ord::cmp(self, other))
186    }
187}
188
189impl Ord for SingleSignature {
190    fn cmp(&self, other: &Self) -> Ordering {
191        self.signer_index.cmp(&other.signer_index)
192    }
193}