mithril_stm/single_signature/
signature.rs1use 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#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct SingleSignature {
18 pub sigma: BlsSignature,
20 pub indexes: Vec<Index>,
22 pub signer_index: Index,
24}
25
26impl SingleSignature {
27 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 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 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 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 fn compare_signer_index(&self, other: &Self) -> Ordering {
130 self.signer_index.cmp(&other.signer_index)
131 }
132
133 #[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 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 #[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}