1use std::{
2 cmp::Ordering,
3 hash::{Hash, Hasher},
4};
5
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 AggregateVerificationKey, Index, MembershipDigest, Parameters, Stake, StmResult,
10 VerificationKey, proof_system::SingleSignatureForConcatenation, signature_scheme::BlsSignature,
11};
12
13use super::SignatureError;
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct SingleSignature {
19 #[serde(flatten)]
21 pub(crate) concatenation_signature: SingleSignatureForConcatenation,
22 pub signer_index: Index,
24}
25
26impl SingleSignature {
27 pub fn verify<D: MembershipDigest>(
29 &self,
30 params: &Parameters,
31 pk: &VerificationKey,
32 stake: &Stake,
33 avk: &AggregateVerificationKey<D>,
34 msg: &[u8],
35 ) -> StmResult<()> {
36 self.concatenation_signature.verify(params, pk, stake, avk, msg)
37 }
38
39 pub(crate) fn check_indices(
41 &self,
42 params: &Parameters,
43 stake: &Stake,
44 msg: &[u8],
45 total_stake: &Stake,
46 ) -> StmResult<()> {
47 self.concatenation_signature
48 .check_indices(params, stake, msg, total_stake)
49 }
50
51 pub fn to_bytes(&self) -> Vec<u8> {
60 let mut output = Vec::new();
61 let indices = self.get_concatenation_signature_indices();
62 output.extend_from_slice(&(indices.len() as u64).to_be_bytes());
63
64 for index in indices {
65 output.extend_from_slice(&index.to_be_bytes());
66 }
67
68 output.extend_from_slice(&self.get_concatenation_signature_sigma().to_bytes());
69
70 output.extend_from_slice(&self.signer_index.to_be_bytes());
71 output
72 }
73
74 pub fn from_bytes<D: MembershipDigest>(bytes: &[u8]) -> StmResult<SingleSignature> {
76 let mut u64_bytes = [0u8; 8];
77
78 u64_bytes.copy_from_slice(bytes.get(0..8).ok_or(SignatureError::SerializationError)?);
79 let nr_indexes = u64::from_be_bytes(u64_bytes) as usize;
80
81 let mut indexes = Vec::new();
82 for i in 0..nr_indexes {
83 u64_bytes.copy_from_slice(
84 bytes
85 .get(8 + i * 8..16 + i * 8)
86 .ok_or(SignatureError::SerializationError)?,
87 );
88 indexes.push(u64::from_be_bytes(u64_bytes));
89 }
90
91 let offset = 8 + nr_indexes * 8;
92 let sigma = BlsSignature::from_bytes(
93 bytes
94 .get(offset..offset + 48)
95 .ok_or(SignatureError::SerializationError)?,
96 )?;
97
98 u64_bytes.copy_from_slice(
99 bytes
100 .get(offset + 48..offset + 56)
101 .ok_or(SignatureError::SerializationError)?,
102 );
103 let signer_index = u64::from_be_bytes(u64_bytes);
104
105 Ok(SingleSignature {
106 concatenation_signature: SingleSignatureForConcatenation::new(sigma, indexes),
107 signer_index,
108 })
109 }
110
111 pub fn get_concatenation_signature_indices(&self) -> Vec<Index> {
113 self.concatenation_signature.get_indices().to_vec()
114 }
115
116 pub fn get_concatenation_signature_sigma(&self) -> BlsSignature {
118 self.concatenation_signature.get_sigma()
119 }
120
121 pub fn set_concatenation_signature_indices(&mut self, indices: &[Index]) {
123 self.concatenation_signature.set_indices(indices)
124 }
125}
126
127impl Hash for SingleSignature {
128 fn hash<H: Hasher>(&self, state: &mut H) {
129 Hash::hash_slice(&self.concatenation_signature.get_sigma().to_bytes(), state)
130 }
131}
132
133impl PartialEq for SingleSignature {
134 fn eq(&self, other: &Self) -> bool {
135 self.concatenation_signature == other.concatenation_signature
136 }
137}
138
139impl Eq for SingleSignature {}
140
141impl PartialOrd for SingleSignature {
142 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
143 Some(std::cmp::Ord::cmp(self, other))
144 }
145}
146
147impl Ord for SingleSignature {
148 fn cmp(&self, other: &Self) -> Ordering {
149 self.signer_index.cmp(&other.signer_index)
150 }
151}
152
153#[cfg(test)]
154mod tests {
155
156 use rand_chacha::ChaCha20Rng;
157 use rand_core::SeedableRng;
158
159 use crate::{
160 ClosedKeyRegistration, KeyRegistration, MithrilMembershipDigest, Parameters, Signer,
161 SingleSignature,
162 signature_scheme::{BlsSigningKey, BlsVerificationKeyProofOfPossession},
163 };
164
165 mod golden {
166 use super::*;
167
168 type D = MithrilMembershipDigest;
169
170 const GOLDEN_BYTES: &[u8; 96] = &[
171 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0,
172 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 8, 149, 157, 201, 187, 140, 54, 0, 128, 209, 88, 16, 203,
173 61, 78, 77, 98, 161, 133, 58, 152, 29, 74, 217, 113, 64, 100, 10, 161, 186, 167, 133,
174 114, 211, 153, 218, 56, 223, 84, 105, 242, 41, 54, 224, 170, 208, 185, 126, 83, 0, 0,
175 0, 0, 0, 0, 0, 1,
176 ];
177
178 fn golden_value() -> SingleSignature {
179 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
180 let msg = [0u8; 16];
181 let params = Parameters {
182 m: 10,
183 k: 5,
184 phi_f: 0.8,
185 };
186 let sk_1 = BlsSigningKey::generate(&mut rng);
187 let sk_2 = BlsSigningKey::generate(&mut rng);
188 let pk_1 = BlsVerificationKeyProofOfPossession::from(&sk_1);
189 let pk_2 = BlsVerificationKeyProofOfPossession::from(&sk_2);
190 let mut key_reg = KeyRegistration::init();
191 key_reg.register(1, pk_1).unwrap();
192 key_reg.register(1, pk_2).unwrap();
193 let closed_key_reg: ClosedKeyRegistration<MithrilMembershipDigest> = key_reg.close();
194 let signer = Signer::set_signer(1, 1, params, sk_1, pk_1.vk, closed_key_reg);
195 signer.sign(&msg).unwrap()
196 }
197
198 #[test]
199 fn golden_conversions() {
200 let value = SingleSignature::from_bytes::<D>(GOLDEN_BYTES)
201 .expect("This from bytes should not fail");
202 assert_eq!(golden_value(), value);
203
204 let serialized = SingleSignature::to_bytes(&value);
205 let golden_serialized = SingleSignature::to_bytes(&golden_value());
206 assert_eq!(golden_serialized, serialized);
207 }
208 }
209
210 mod golden_json {
211 use super::*;
212
213 const GOLDEN_JSON: &str = r#"
214 {
215 "sigma": [
216 149, 157, 201, 187, 140, 54, 0, 128, 209, 88, 16, 203, 61, 78, 77, 98, 161,
217 133, 58, 152, 29, 74, 217, 113, 64, 100, 10, 161, 186, 167, 133, 114, 211,
218 153, 218, 56, 223, 84, 105, 242, 41, 54, 224, 170, 208, 185, 126, 83
219 ],
220 "indexes": [1, 4, 5, 8],
221 "signer_index": 1
222 }"#;
223
224 fn golden_value() -> SingleSignature {
225 let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
226 let msg = [0u8; 16];
227 let params = Parameters {
228 m: 10,
229 k: 5,
230 phi_f: 0.8,
231 };
232 let sk_1 = BlsSigningKey::generate(&mut rng);
233 let sk_2 = BlsSigningKey::generate(&mut rng);
234 let pk_1 = BlsVerificationKeyProofOfPossession::from(&sk_1);
235 let pk_2 = BlsVerificationKeyProofOfPossession::from(&sk_2);
236 let mut key_reg = KeyRegistration::init();
237 key_reg.register(1, pk_1).unwrap();
238 key_reg.register(1, pk_2).unwrap();
239 let closed_key_reg: ClosedKeyRegistration<MithrilMembershipDigest> = key_reg.close();
240 let signer = Signer::set_signer(1, 1, params, sk_1, pk_1.vk, closed_key_reg);
241 signer.sign(&msg).unwrap()
242 }
243
244 #[test]
245 fn golden_conversions() {
246 let value = serde_json::from_str(GOLDEN_JSON)
247 .expect("This JSON deserialization should not fail");
248 assert_eq!(golden_value(), value);
249
250 let serialized =
251 serde_json::to_string(&value).expect("This JSON serialization should not fail");
252 let golden_serialized = serde_json::to_string(&golden_value())
253 .expect("This JSON serialization should not fail");
254 assert_eq!(golden_serialized, serialized);
255 }
256 }
257}