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.5.0", 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.5.0", 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}
194
195#[cfg(test)]
196mod tests {
197    mod golden {
198        use blake2::{Blake2b, digest::consts::U32};
199        use rand_chacha::ChaCha20Rng;
200        use rand_core::SeedableRng;
201
202        use crate::bls_multi_signature::{BlsSigningKey, BlsVerificationKeyProofOfPossession};
203        use crate::{ClosedKeyRegistration, KeyRegistration, Parameters, Signer, SingleSignature};
204
205        type D = Blake2b<U32>;
206
207        const GOLDEN_JSON: &str = r#"
208        {
209            "sigma": [
210                149, 157, 201, 187, 140, 54, 0, 128, 209, 88, 16, 203, 61, 78, 77, 98, 161,
211                133, 58, 152, 29, 74, 217, 113, 64, 100, 10, 161, 186, 167, 133, 114, 211,
212                153, 218, 56, 223, 84, 105, 242, 41, 54, 224, 170, 208, 185, 126, 83
213            ],
214            "indexes": [1, 4, 5, 8],
215            "signer_index": 1
216        }"#;
217
218        fn golden_value() -> SingleSignature {
219            let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
220            let msg = [0u8; 16];
221            let params = Parameters {
222                m: 10,
223                k: 5,
224                phi_f: 0.8,
225            };
226            let sk_1 = BlsSigningKey::generate(&mut rng);
227            let sk_2 = BlsSigningKey::generate(&mut rng);
228            let pk_1 = BlsVerificationKeyProofOfPossession::from(&sk_1);
229            let pk_2 = BlsVerificationKeyProofOfPossession::from(&sk_2);
230            let mut key_reg = KeyRegistration::init();
231            key_reg.register(1, pk_1).unwrap();
232            key_reg.register(1, pk_2).unwrap();
233            let closed_key_reg: ClosedKeyRegistration<D> = key_reg.close();
234            let signer = Signer::set_signer(1, 1, params, sk_1, pk_1.vk, closed_key_reg);
235            signer.sign(&msg).unwrap()
236        }
237
238        #[test]
239        fn golden_conversions() {
240            let value = serde_json::from_str(GOLDEN_JSON)
241                .expect("This JSON deserialization should not fail");
242            assert_eq!(golden_value(), value);
243
244            let serialized =
245                serde_json::to_string(&value).expect("This JSON serialization should not fail");
246            let golden_serialized = serde_json::to_string(&golden_value())
247                .expect("This JSON serialization should not fail");
248            assert_eq!(golden_serialized, serialized);
249        }
250    }
251}