mithril_stm/protocol/single_signature/
signature.rs1use std::{
2 cmp::Ordering,
3 hash::{Hash, Hasher},
4};
5
6use anyhow::{Context, anyhow};
7use blake2::digest::{Digest, FixedOutput};
8use serde::{Deserialize, Serialize};
9
10use crate::{
11 AggregateVerificationKey, Index, Parameters, SignatureError, Stake, StmResult, VerificationKey,
12 is_lottery_won, signature_scheme::BlsSignature,
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 ) -> StmResult<()> {
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 .with_context(|| {
40 format!(
41 "Single signature verification failed for signer index {}.",
42 self.signer_index
43 )
44 })?;
45 Ok(())
46 }
47
48 pub(crate) fn check_indices(
50 &self,
51 params: &Parameters,
52 stake: &Stake,
53 msg: &[u8],
54 total_stake: &Stake,
55 ) -> StmResult<()> {
56 for &index in &self.indexes {
57 if index > params.m {
58 return Err(anyhow!(SignatureError::IndexBoundFailed(index, params.m)));
59 }
60
61 let ev = self.sigma.evaluate_dense_mapping(msg, index);
62
63 if !is_lottery_won(params.phi_f, ev, *stake, *total_stake) {
64 return Err(anyhow!(SignatureError::LotteryLost));
65 }
66 }
67
68 Ok(())
69 }
70
71 pub fn to_bytes(&self) -> Vec<u8> {
81 let mut output = Vec::new();
82 output.extend_from_slice(&(self.indexes.len() as u64).to_be_bytes());
83
84 for index in &self.indexes {
85 output.extend_from_slice(&index.to_be_bytes());
86 }
87
88 output.extend_from_slice(&self.sigma.to_bytes());
89
90 output.extend_from_slice(&self.signer_index.to_be_bytes());
91 output
92 }
93
94 pub fn from_bytes<D: Clone + Digest + FixedOutput>(bytes: &[u8]) -> StmResult<SingleSignature> {
96 let mut u64_bytes = [0u8; 8];
97
98 u64_bytes.copy_from_slice(bytes.get(0..8).ok_or(SignatureError::SerializationError)?);
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(SignatureError::SerializationError)?,
107 );
108 indexes.push(u64::from_be_bytes(u64_bytes));
109 }
110
111 let offset = 8 + nr_indexes * 8;
112 let sigma = BlsSignature::from_bytes(
113 bytes
114 .get(offset..offset + 48)
115 .ok_or(SignatureError::SerializationError)?,
116 )?;
117
118 u64_bytes.copy_from_slice(
119 bytes
120 .get(offset + 48..offset + 56)
121 .ok_or(SignatureError::SerializationError)?,
122 );
123 let signer_index = u64::from_be_bytes(u64_bytes);
124
125 Ok(SingleSignature {
126 sigma,
127 indexes,
128 signer_index,
129 })
130 }
131
132 fn compare_signer_index(&self, other: &Self) -> Ordering {
134 self.signer_index.cmp(&other.signer_index)
135 }
136
137 #[deprecated(since = "0.5.0", note = "This function will be removed")]
139 pub fn cmp_stm_sig(&self, other: &Self) -> Ordering {
140 Self::compare_signer_index(self, other)
141 }
142
143 pub(crate) fn basic_verify(
146 &self,
147 params: &Parameters,
148 pk: &VerificationKey,
149 stake: &Stake,
150 msg: &[u8],
151 total_stake: &Stake,
152 ) -> StmResult<()> {
153 self.sigma
154 .verify(msg, pk)
155 .with_context(|| "Basic verification of single signature failed.")?;
156 self.check_indices(params, stake, msg, total_stake)
157 .with_context(|| "Basic verification of single signature failed.")?;
158
159 Ok(())
160 }
161
162 #[deprecated(since = "0.5.0", note = "Use `basic_verify` instead")]
164 pub fn core_verify(
165 &self,
166 params: &Parameters,
167 pk: &VerificationKey,
168 stake: &Stake,
169 msg: &[u8],
170 total_stake: &Stake,
171 ) -> StmResult<()> {
172 Self::basic_verify(self, params, pk, stake, msg, total_stake)
173 }
174}
175
176impl Hash for SingleSignature {
177 fn hash<H: Hasher>(&self, state: &mut H) {
178 Hash::hash_slice(&self.sigma.to_bytes(), state)
179 }
180}
181
182impl PartialEq for SingleSignature {
183 fn eq(&self, other: &Self) -> bool {
184 self.sigma == other.sigma
185 }
186}
187
188impl Eq for SingleSignature {}
189
190impl PartialOrd for SingleSignature {
191 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
192 Some(std::cmp::Ord::cmp(self, other))
193 }
194}
195
196impl Ord for SingleSignature {
197 fn cmp(&self, other: &Self) -> Ordering {
198 self.signer_index.cmp(&other.signer_index)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 mod golden {
205 use blake2::{Blake2b, digest::consts::U32};
206 use rand_chacha::ChaCha20Rng;
207 use rand_core::SeedableRng;
208
209 use crate::{
210 ClosedKeyRegistration, KeyRegistration, Parameters, Signer, SingleSignature,
211 signature_scheme::{BlsSigningKey, BlsVerificationKeyProofOfPossession},
212 };
213
214 type D = Blake2b<U32>;
215
216 const GOLDEN_JSON: &str = r#"
217 {
218 "sigma": [
219 149, 157, 201, 187, 140, 54, 0, 128, 209, 88, 16, 203, 61, 78, 77, 98, 161,
220 133, 58, 152, 29, 74, 217, 113, 64, 100, 10, 161, 186, 167, 133, 114, 211,
221 153, 218, 56, 223, 84, 105, 242, 41, 54, 224, 170, 208, 185, 126, 83
222 ],
223 "indexes": [1, 4, 5, 8],
224 "signer_index": 1
225 }"#;
226
227 fn golden_value() -> SingleSignature {
228 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
229 let msg = [0u8; 16];
230 let params = Parameters {
231 m: 10,
232 k: 5,
233 phi_f: 0.8,
234 };
235 let sk_1 = BlsSigningKey::generate(&mut rng);
236 let sk_2 = BlsSigningKey::generate(&mut rng);
237 let pk_1 = BlsVerificationKeyProofOfPossession::from(&sk_1);
238 let pk_2 = BlsVerificationKeyProofOfPossession::from(&sk_2);
239 let mut key_reg = KeyRegistration::init();
240 key_reg.register(1, pk_1).unwrap();
241 key_reg.register(1, pk_2).unwrap();
242 let closed_key_reg: ClosedKeyRegistration<D> = key_reg.close();
243 let signer = Signer::set_signer(1, 1, params, sk_1, pk_1.vk, closed_key_reg);
244 signer.sign(&msg).unwrap()
245 }
246
247 #[test]
248 fn golden_conversions() {
249 let value = serde_json::from_str(GOLDEN_JSON)
250 .expect("This JSON deserialization should not fail");
251 assert_eq!(golden_value(), value);
252
253 let serialized =
254 serde_json::to_string(&value).expect("This JSON serialization should not fail");
255 let golden_serialized = serde_json::to_string(&golden_value())
256 .expect("This JSON serialization should not fail");
257 assert_eq!(golden_serialized, serialized);
258 }
259 }
260}