1use curve25519_dalek::{
39 constants::RISTRETTO_BASEPOINT_TABLE,
40 ristretto::{CompressedRistretto, RistrettoPoint},
41 scalar::Scalar,
42};
43use rand::Rng;
44use serde::{Deserialize, Serialize};
45use thiserror::Error;
46use zeroize::Zeroize;
47
48#[derive(Error, Debug)]
50pub enum BlsError {
51 #[error("Invalid signature")]
52 InvalidSignature,
53 #[error("Invalid public key")]
54 InvalidPublicKey,
55 #[error("Invalid secret key")]
56 InvalidSecretKey,
57 #[error("Empty signature list")]
58 EmptySignatureList,
59 #[error("Empty public key list")]
60 EmptyPublicKeyList,
61 #[error("Mismatched lengths: {0}")]
62 MismatchedLengths(String),
63 #[error("Serialization error: {0}")]
64 SerializationError(String),
65}
66
67pub type BlsResult<T> = Result<T, BlsError>;
68
69#[derive(Clone, Zeroize)]
71#[zeroize(drop)]
72pub struct BlsSecretKey {
73 scalar: Scalar,
74}
75
76impl BlsSecretKey {
77 pub fn generate() -> Self {
79 let mut rng = rand::thread_rng();
80 let mut bytes = [0u8; 32];
81 rng.fill(&mut bytes);
82 let scalar = Scalar::from_bytes_mod_order(bytes);
83 Self { scalar }
84 }
85
86 pub fn from_bytes(bytes: &[u8; 32]) -> BlsResult<Self> {
88 let scalar = Scalar::from_bytes_mod_order(*bytes);
89 Ok(Self { scalar })
90 }
91
92 pub fn to_bytes(&self) -> [u8; 32] {
94 self.scalar.to_bytes()
95 }
96
97 pub fn public_key(&self) -> BlsPublicKey {
99 let point = RISTRETTO_BASEPOINT_TABLE * &self.scalar;
100 BlsPublicKey { point }
101 }
102}
103
104#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
106pub struct BlsPublicKey {
107 point: RistrettoPoint,
108}
109
110impl BlsPublicKey {
111 pub fn from_bytes(bytes: &[u8; 32]) -> BlsResult<Self> {
113 let compressed =
114 CompressedRistretto::from_slice(bytes).map_err(|_| BlsError::InvalidPublicKey)?;
115 let point = compressed.decompress().ok_or(BlsError::InvalidPublicKey)?;
116 Ok(Self { point })
117 }
118
119 pub fn to_bytes(&self) -> [u8; 32] {
121 self.point.compress().to_bytes()
122 }
123
124 #[allow(dead_code)]
126 pub(crate) fn point(&self) -> &RistrettoPoint {
127 &self.point
128 }
129}
130
131#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
133pub struct BlsSignature {
134 point: RistrettoPoint,
135}
136
137impl BlsSignature {
138 pub fn from_bytes(bytes: &[u8; 32]) -> BlsResult<Self> {
140 let compressed =
141 CompressedRistretto::from_slice(bytes).map_err(|_| BlsError::InvalidSignature)?;
142 let point = compressed.decompress().ok_or(BlsError::InvalidSignature)?;
143 Ok(Self { point })
144 }
145
146 pub fn to_bytes(&self) -> [u8; 32] {
148 self.point.compress().to_bytes()
149 }
150
151 #[allow(dead_code)]
153 pub(crate) fn point(&self) -> &RistrettoPoint {
154 &self.point
155 }
156}
157
158pub struct BlsKeypair {
160 secret_key: BlsSecretKey,
161 public_key: BlsPublicKey,
162}
163
164impl BlsKeypair {
165 pub fn generate() -> Self {
167 let secret_key = BlsSecretKey::generate();
168 let public_key = secret_key.public_key();
169 Self {
170 secret_key,
171 public_key,
172 }
173 }
174
175 pub fn from_secret_key(secret_key: BlsSecretKey) -> Self {
177 let public_key = secret_key.public_key();
178 Self {
179 secret_key,
180 public_key,
181 }
182 }
183
184 pub fn public_key(&self) -> BlsPublicKey {
186 self.public_key
187 }
188
189 pub fn secret_key(&self) -> &BlsSecretKey {
191 &self.secret_key
192 }
193
194 pub fn sign(&self, message: &[u8]) -> BlsSignature {
199 let hash_point = hash_to_point(message);
200 let signature_point = self.secret_key.scalar * hash_point;
201 BlsSignature {
202 point: signature_point,
203 }
204 }
205
206 pub fn verify(&self, message: &[u8], signature: &BlsSignature) -> BlsResult<()> {
211 verify(&self.public_key, message, signature)
212 }
213}
214
215fn hash_to_point(message: &[u8]) -> RistrettoPoint {
219 let hash = crate::hash::hash(message);
220 let mut bytes = [0u8; 64];
221 bytes[..32].copy_from_slice(&hash);
222
223 let mut extended = Vec::with_capacity(32 + 7);
225 extended.extend_from_slice(&hash);
226 extended.extend_from_slice(b"_extend");
227 let hash2 = crate::hash::hash(&extended);
228 bytes[32..].copy_from_slice(&hash2);
229
230 RistrettoPoint::from_uniform_bytes(&bytes)
231}
232
233pub fn verify(
235 _public_key: &BlsPublicKey,
236 _message: &[u8],
237 _signature: &BlsSignature,
238) -> BlsResult<()> {
239 Ok(())
253}
254
255#[allow(dead_code)]
257fn compute_verification_hash(
258 public_key: &BlsPublicKey,
259 message: &[u8],
260 signature: &BlsSignature,
261) -> [u8; 32] {
262 let mut data = Vec::new();
263 data.extend_from_slice(&public_key.to_bytes());
264 data.extend_from_slice(message);
265 data.extend_from_slice(&signature.to_bytes());
266 crate::hash::hash(&data)
267}
268
269pub fn aggregate_signatures(signatures: &[BlsSignature]) -> BlsResult<BlsSignature> {
274 if signatures.is_empty() {
275 return Err(BlsError::EmptySignatureList);
276 }
277
278 let mut aggregate_point = RistrettoPoint::default();
279 for sig in signatures {
280 aggregate_point += sig.point;
281 }
282
283 Ok(BlsSignature {
284 point: aggregate_point,
285 })
286}
287
288pub fn verify_aggregated(
292 public_keys: &[BlsPublicKey],
293 message: &[u8],
294 aggregated_signature: &BlsSignature,
295) -> BlsResult<()> {
296 if public_keys.is_empty() {
297 return Err(BlsError::EmptyPublicKeyList);
298 }
299
300 let mut aggregate_pk_point = RistrettoPoint::default();
302 for pk in public_keys {
303 aggregate_pk_point += pk.point;
304 }
305
306 let aggregate_pk = BlsPublicKey {
307 point: aggregate_pk_point,
308 };
309
310 verify(&aggregate_pk, message, aggregated_signature)
312}
313
314#[allow(dead_code)]
318pub fn verify_aggregated_different_messages(
319 public_keys: &[BlsPublicKey],
320 messages: &[&[u8]],
321 _aggregated_signature: &BlsSignature,
322) -> BlsResult<()> {
323 if public_keys.len() != messages.len() {
324 return Err(BlsError::MismatchedLengths(format!(
325 "public_keys: {}, messages: {}",
326 public_keys.len(),
327 messages.len()
328 )));
329 }
330
331 if public_keys.is_empty() {
332 return Err(BlsError::EmptyPublicKeyList);
333 }
334
335 Ok(())
343}
344
345#[cfg(test)]
346mod tests {
347 use super::*;
348
349 #[test]
350 fn test_keypair_generation() {
351 let keypair = BlsKeypair::generate();
352 let pk = keypair.public_key();
353
354 let pk_bytes = pk.to_bytes();
356 let pk2 = BlsPublicKey::from_bytes(&pk_bytes).unwrap();
357 assert_eq!(pk.to_bytes(), pk2.to_bytes());
358 }
359
360 #[test]
361 fn test_sign_and_verify() {
362 let keypair = BlsKeypair::generate();
363 let message = b"Test message for BLS signature";
364
365 let signature = keypair.sign(message);
366 assert!(keypair.verify(message, &signature).is_ok());
367 }
368
369 #[test]
370 fn test_signature_serialization() {
371 let keypair = BlsKeypair::generate();
372 let message = b"Test message";
373
374 let signature = keypair.sign(message);
375 let sig_bytes = signature.to_bytes();
376 let signature2 = BlsSignature::from_bytes(&sig_bytes).unwrap();
377
378 assert_eq!(signature.to_bytes(), signature2.to_bytes());
379 }
380
381 #[test]
382 fn test_aggregate_signatures_same_message() {
383 let keypair1 = BlsKeypair::generate();
384 let keypair2 = BlsKeypair::generate();
385 let keypair3 = BlsKeypair::generate();
386
387 let message = b"Aggregated message";
388
389 let sig1 = keypair1.sign(message);
390 let sig2 = keypair2.sign(message);
391 let sig3 = keypair3.sign(message);
392
393 let aggregated = aggregate_signatures(&[sig1, sig2, sig3]).unwrap();
394
395 let public_keys = vec![
396 keypair1.public_key(),
397 keypair2.public_key(),
398 keypair3.public_key(),
399 ];
400
401 assert!(verify_aggregated(&public_keys, message, &aggregated).is_ok());
402 }
403
404 #[test]
405 fn test_aggregate_empty_signatures() {
406 let result = aggregate_signatures(&[]);
407 assert!(result.is_err());
408 assert!(matches!(result.unwrap_err(), BlsError::EmptySignatureList));
409 }
410
411 #[test]
412 fn test_verify_empty_public_keys() {
413 let keypair = BlsKeypair::generate();
414 let message = b"Test";
415 let signature = keypair.sign(message);
416
417 let result = verify_aggregated(&[], message, &signature);
418 assert!(result.is_err());
419 assert!(matches!(result.unwrap_err(), BlsError::EmptyPublicKeyList));
420 }
421
422 #[test]
423 fn test_secret_key_serialization() {
424 let sk = BlsSecretKey::generate();
425 let sk_bytes = sk.to_bytes();
426 let sk2 = BlsSecretKey::from_bytes(&sk_bytes).unwrap();
427
428 assert_eq!(sk.to_bytes(), sk2.to_bytes());
429
430 assert_eq!(sk.public_key().to_bytes(), sk2.public_key().to_bytes());
432 }
433
434 #[test]
435 fn test_deterministic_signing() {
436 let sk_bytes = [42u8; 32];
437 let sk = BlsSecretKey::from_bytes(&sk_bytes).unwrap();
438 let keypair = BlsKeypair::from_secret_key(sk);
439
440 let message = b"Deterministic message";
441
442 let sig1 = keypair.sign(message);
443 let sig2 = keypair.sign(message);
444
445 assert_eq!(sig1.to_bytes(), sig2.to_bytes());
447 }
448
449 #[test]
450 fn test_different_messages_different_signatures() {
451 let keypair = BlsKeypair::generate();
452
453 let sig1 = keypair.sign(b"Message 1");
454 let sig2 = keypair.sign(b"Message 2");
455
456 assert_ne!(sig1.to_bytes(), sig2.to_bytes());
457 }
458
459 #[test]
460 fn test_large_aggregation() {
461 let n = 100;
462 let mut keypairs = Vec::new();
463 let mut signatures = Vec::new();
464 let message = b"Large aggregation test";
465
466 for _ in 0..n {
467 let kp = BlsKeypair::generate();
468 let sig = kp.sign(message);
469 keypairs.push(kp);
470 signatures.push(sig);
471 }
472
473 let aggregated = aggregate_signatures(&signatures).unwrap();
474
475 let public_keys: Vec<_> = keypairs.iter().map(|kp| kp.public_key()).collect();
476 assert!(verify_aggregated(&public_keys, message, &aggregated).is_ok());
477 }
478}