1use serde::{
2 de::Error as DeError, ser::Error as SerError, Deserialize, Deserializer, Serialize, Serializer,
3};
4use std::collections::HashMap;
5use std::fmt::Display;
6
7use pqcrypto_dilithium::dilithium2;
8use pqcrypto_falcon::falcon512;
9use pqcrypto_traits::sign::{
10 DetachedSignature, PublicKey as PqPublicKeyTrait, SecretKey as PqSecretKeyTrait,
11};
12use zeroize::Zeroizing;
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15pub enum SignatureSchemeId {
16 Dilithium2,
17 Falcon512,
18 Unknown(u16),
19}
20
21#[derive(Debug, thiserror::Error, PartialEq, Eq)]
22pub enum CryptoError {
23 #[error("signature scheme mismatch")]
24 WrongScheme,
25 #[error("invalid public key")]
26 InvalidPublicKey,
27 #[error("invalid secret key")]
28 InvalidSecretKey,
29 #[error("invalid signature")]
30 InvalidSignature,
31 #[error("unsupported scheme {0}")]
32 UnsupportedScheme(SignatureSchemeId),
33}
34
35impl SignatureSchemeId {
36 pub const DILITHIUM2_ID: u16 = 0x01;
37 pub const FALCON512_ID: u16 = 0x02;
38
39 pub fn from_u16(id: u16) -> Self {
40 match id {
41 Self::DILITHIUM2_ID => SignatureSchemeId::Dilithium2,
42 Self::FALCON512_ID => SignatureSchemeId::Falcon512,
43 other => SignatureSchemeId::Unknown(other),
44 }
45 }
46
47 pub fn to_u16(self) -> u16 {
48 match self {
49 SignatureSchemeId::Dilithium2 => Self::DILITHIUM2_ID,
50 SignatureSchemeId::Falcon512 => Self::FALCON512_ID,
51 SignatureSchemeId::Unknown(value) => value,
52 }
53 }
54}
55
56impl Display for SignatureSchemeId {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 match self {
59 SignatureSchemeId::Dilithium2 => write!(f, "dilithium2"),
60 SignatureSchemeId::Falcon512 => write!(f, "falcon512"),
61 SignatureSchemeId::Unknown(value) => write!(f, "unknown-{}", value),
62 }
63 }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67pub struct PublicKey {
68 pub scheme: SignatureSchemeId,
69 pub bytes: Vec<u8>,
70}
71
72#[derive(Debug, PartialEq, Eq)]
73pub struct PrivateKey {
74 pub scheme: SignatureSchemeId,
75 pub bytes: Zeroizing<Vec<u8>>,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq)]
79pub struct Signature {
80 pub scheme: SignatureSchemeId,
81 pub bytes: Vec<u8>,
82}
83
84impl PublicKey {
85 pub fn new(scheme: SignatureSchemeId, bytes: Vec<u8>) -> Result<Self, CryptoError> {
86 validate_key_size(
87 public_key_size,
88 scheme,
89 bytes.len(),
90 false,
91 CryptoError::InvalidPublicKey,
92 )?;
93 Ok(Self { scheme, bytes })
94 }
95
96 pub fn to_bytes(&self) -> Result<Vec<u8>, CryptoError> {
97 encode_with_scheme(
98 self.scheme,
99 public_key_size,
100 &self.bytes,
101 false,
102 CryptoError::InvalidPublicKey,
103 )
104 }
105
106 pub fn from_bytes(encoded: &[u8]) -> Result<Self, CryptoError> {
107 let (scheme, payload) = decode_with_scheme(encoded, CryptoError::InvalidPublicKey)?;
108 validate_key_size(
109 public_key_size,
110 scheme,
111 payload.len(),
112 false,
113 CryptoError::InvalidPublicKey,
114 )?;
115 Ok(Self {
116 scheme,
117 bytes: payload,
118 })
119 }
120}
121
122impl PrivateKey {
123 pub fn new(scheme: SignatureSchemeId, bytes: Vec<u8>) -> Result<Self, CryptoError> {
124 validate_key_size(
125 secret_key_size,
126 scheme,
127 bytes.len(),
128 false,
129 CryptoError::InvalidSecretKey,
130 )?;
131 Ok(Self {
132 scheme,
133 bytes: Zeroizing::new(bytes),
134 })
135 }
136
137 pub fn to_bytes(&self) -> Result<Vec<u8>, CryptoError> {
138 encode_with_scheme(
139 self.scheme,
140 secret_key_size,
141 &self.bytes,
142 false,
143 CryptoError::InvalidSecretKey,
144 )
145 }
146
147 pub fn from_bytes(encoded: &[u8]) -> Result<Self, CryptoError> {
148 let (scheme, payload) = decode_with_scheme(encoded, CryptoError::InvalidSecretKey)?;
149 validate_key_size(
150 secret_key_size,
151 scheme,
152 payload.len(),
153 false,
154 CryptoError::InvalidSecretKey,
155 )?;
156 Ok(Self {
157 scheme,
158 bytes: Zeroizing::new(payload),
159 })
160 }
161}
162
163impl Signature {
164 pub fn new(scheme: SignatureSchemeId, bytes: Vec<u8>) -> Result<Self, CryptoError> {
165 validate_key_size(
166 signature_size,
167 scheme,
168 bytes.len(),
169 true,
170 CryptoError::InvalidSignature,
171 )?;
172 Ok(Self { scheme, bytes })
173 }
174
175 pub fn to_bytes(&self) -> Result<Vec<u8>, CryptoError> {
176 encode_with_scheme(
177 self.scheme,
178 signature_size,
179 &self.bytes,
180 true,
181 CryptoError::InvalidSignature,
182 )
183 }
184
185 pub fn from_bytes(encoded: &[u8]) -> Result<Self, CryptoError> {
186 let (scheme, payload) = decode_with_scheme(encoded, CryptoError::InvalidSignature)?;
187 validate_key_size(
188 signature_size,
189 scheme,
190 payload.len(),
191 true,
192 CryptoError::InvalidSignature,
193 )?;
194 Ok(Self {
195 scheme,
196 bytes: payload,
197 })
198 }
199}
200
201impl Serialize for PublicKey {
202 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
203 where
204 S: Serializer,
205 {
206 let bytes = self.to_bytes().map_err(SerError::custom)?;
207 serializer.serialize_bytes(&bytes)
208 }
209}
210
211impl<'de> Deserialize<'de> for PublicKey {
212 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
213 where
214 D: Deserializer<'de>,
215 {
216 struct PublicKeyVisitor;
217
218 impl<'de> serde::de::Visitor<'de> for PublicKeyVisitor {
219 type Value = PublicKey;
220
221 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
222 write!(f, "byte-encoded public key")
223 }
224
225 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
226 where
227 E: DeError,
228 {
229 PublicKey::from_bytes(v).map_err(DeError::custom)
230 }
231 }
232
233 deserializer.deserialize_bytes(PublicKeyVisitor)
234 }
235}
236
237impl Serialize for PrivateKey {
238 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239 where
240 S: Serializer,
241 {
242 let bytes = self.to_bytes().map_err(SerError::custom)?;
243 serializer.serialize_bytes(&bytes)
244 }
245}
246
247impl<'de> Deserialize<'de> for PrivateKey {
248 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
249 where
250 D: Deserializer<'de>,
251 {
252 struct PrivateKeyVisitor;
253
254 impl<'de> serde::de::Visitor<'de> for PrivateKeyVisitor {
255 type Value = PrivateKey;
256
257 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
258 write!(f, "byte-encoded private key")
259 }
260
261 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
262 where
263 E: DeError,
264 {
265 PrivateKey::from_bytes(v).map_err(DeError::custom)
266 }
267 }
268
269 deserializer.deserialize_bytes(PrivateKeyVisitor)
270 }
271}
272
273impl Serialize for Signature {
274 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
275 where
276 S: Serializer,
277 {
278 let bytes = self.to_bytes().map_err(SerError::custom)?;
279 serializer.serialize_bytes(&bytes)
280 }
281}
282
283impl<'de> Deserialize<'de> for Signature {
284 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
285 where
286 D: Deserializer<'de>,
287 {
288 struct SignatureVisitor;
289
290 impl<'de> serde::de::Visitor<'de> for SignatureVisitor {
291 type Value = Signature;
292
293 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
294 write!(f, "byte-encoded signature")
295 }
296
297 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
298 where
299 E: DeError,
300 {
301 Signature::from_bytes(v).map_err(DeError::custom)
302 }
303 }
304
305 deserializer.deserialize_bytes(SignatureVisitor)
306 }
307}
308
309fn validate_key_size(
310 size_fn: fn(SignatureSchemeId) -> Option<usize>,
311 scheme: SignatureSchemeId,
312 len: usize,
313 allow_shorter: bool,
314 mismatch_error: CryptoError,
315) -> Result<(), CryptoError> {
316 match size_fn(scheme) {
317 Some(expected)
318 if (!allow_shorter && expected == len) || (allow_shorter && len <= expected) =>
319 {
320 Ok(())
321 }
322 Some(_) => Err(mismatch_error),
323 None => Err(CryptoError::UnsupportedScheme(scheme)),
324 }
325}
326
327fn encode_with_scheme(
328 scheme: SignatureSchemeId,
329 size_fn: fn(SignatureSchemeId) -> Option<usize>,
330 bytes: &[u8],
331 allow_shorter: bool,
332 mismatch_error: CryptoError,
333) -> Result<Vec<u8>, CryptoError> {
334 validate_key_size(size_fn, scheme, bytes.len(), allow_shorter, mismatch_error)?;
335
336 let len = bytes.len() as u32;
337 let mut encoded = Vec::with_capacity(2 + 4 + bytes.len());
338 encoded.extend_from_slice(&scheme.to_u16().to_le_bytes());
339 encoded.extend_from_slice(&len.to_le_bytes());
340 encoded.extend_from_slice(bytes);
341 Ok(encoded)
342}
343
344fn decode_with_scheme(
345 encoded: &[u8],
346 mismatch_error: CryptoError,
347) -> Result<(SignatureSchemeId, Vec<u8>), CryptoError> {
348 const PREFIX_LEN: usize = 2 + 4;
349 if encoded.len() < PREFIX_LEN {
350 return Err(mismatch_error);
351 }
352
353 let scheme = SignatureSchemeId::from_u16(u16::from_le_bytes([encoded[0], encoded[1]]));
354 let len = u32::from_le_bytes([encoded[2], encoded[3], encoded[4], encoded[5]]) as usize;
355
356 if encoded.len() != PREFIX_LEN + len {
357 return Err(mismatch_error);
358 }
359
360 let payload = encoded[PREFIX_LEN..].to_vec();
361 Ok((scheme, payload))
362}
363
364fn public_key_size(scheme: SignatureSchemeId) -> Option<usize> {
365 match scheme {
366 SignatureSchemeId::Dilithium2 => Some(dilithium2::public_key_bytes()),
367 SignatureSchemeId::Falcon512 => Some(falcon512::public_key_bytes()),
368 SignatureSchemeId::Unknown(_) => None,
369 }
370}
371
372fn secret_key_size(scheme: SignatureSchemeId) -> Option<usize> {
373 match scheme {
374 SignatureSchemeId::Dilithium2 => Some(dilithium2::secret_key_bytes()),
375 SignatureSchemeId::Falcon512 => Some(falcon512::secret_key_bytes()),
376 SignatureSchemeId::Unknown(_) => None,
377 }
378}
379
380fn signature_size(scheme: SignatureSchemeId) -> Option<usize> {
381 match scheme {
382 SignatureSchemeId::Dilithium2 => Some(dilithium2::signature_bytes()),
383 SignatureSchemeId::Falcon512 => Some(falcon512::signature_bytes()),
384 SignatureSchemeId::Unknown(_) => None,
385 }
386}
387
388pub trait PqSignatureScheme: Send + Sync {
389 fn id(&self) -> SignatureSchemeId;
390 fn keygen(&self) -> Result<(PublicKey, PrivateKey), CryptoError>;
391 fn sign(&self, sk: &PrivateKey, msg: &[u8]) -> Result<Signature, CryptoError>;
392 fn verify(&self, pk: &PublicKey, msg: &[u8], sig: &Signature) -> Result<(), CryptoError>;
393}
394
395pub trait PqSchemeRegistry {
396 fn get(&self, id: &SignatureSchemeId) -> Option<&dyn PqSignatureScheme>;
397}
398
399pub struct InMemoryRegistry {
400 schemes: HashMap<SignatureSchemeId, Box<dyn PqSignatureScheme>>,
401}
402
403impl InMemoryRegistry {
404 pub fn new() -> Self {
405 Self {
406 schemes: HashMap::new(),
407 }
408 }
409
410 pub fn with_scheme(mut self, scheme: Box<dyn PqSignatureScheme>) -> Self {
411 let id = scheme.id();
412 self.schemes.insert(id, scheme);
413 self
414 }
415
416 pub fn add_scheme(&mut self, scheme: Box<dyn PqSignatureScheme>) {
417 let id = scheme.id();
418 self.schemes.insert(id, scheme);
419 }
420}
421
422impl PqSchemeRegistry for InMemoryRegistry {
423 fn get(&self, id: &SignatureSchemeId) -> Option<&dyn PqSignatureScheme> {
424 self.schemes.get(id).map(|boxed| boxed.as_ref())
425 }
426}
427
428pub struct Dilithium2Scheme;
429
430impl PqSignatureScheme for Dilithium2Scheme {
431 fn id(&self) -> SignatureSchemeId {
432 SignatureSchemeId::Dilithium2
433 }
434
435 fn keygen(&self) -> Result<(PublicKey, PrivateKey), CryptoError> {
436 let (pk, sk) = dilithium2::keypair();
437 Ok((
438 PublicKey::new(self.id(), pk.as_bytes().to_vec())?,
439 PrivateKey::new(self.id(), sk.as_bytes().to_vec())?,
440 ))
441 }
442
443 fn sign(&self, sk: &PrivateKey, msg: &[u8]) -> Result<Signature, CryptoError> {
444 if sk.scheme != self.id() {
445 return Err(CryptoError::WrongScheme);
446 }
447
448 let sk = dilithium2::SecretKey::from_bytes(&sk.bytes)
449 .map_err(|_| CryptoError::InvalidSecretKey)?;
450
451 let signature = dilithium2::detached_sign(msg, &sk);
452 Signature::new(self.id(), signature.as_bytes().to_vec())
453 }
454
455 fn verify(&self, pk: &PublicKey, msg: &[u8], sig: &Signature) -> Result<(), CryptoError> {
456 if pk.scheme != self.id() || sig.scheme != self.id() {
457 return Err(CryptoError::WrongScheme);
458 }
459
460 let pk = dilithium2::PublicKey::from_bytes(&pk.bytes)
461 .map_err(|_| CryptoError::InvalidPublicKey)?;
462 let sig = dilithium2::DetachedSignature::from_bytes(&sig.bytes)
463 .map_err(|_| CryptoError::InvalidSignature)?;
464
465 dilithium2::verify_detached_signature(&sig, msg, &pk)
466 .map_err(|_| CryptoError::InvalidSignature)
467 }
468}
469
470pub struct Falcon512Scheme;
471
472impl PqSignatureScheme for Falcon512Scheme {
473 fn id(&self) -> SignatureSchemeId {
474 SignatureSchemeId::Falcon512
475 }
476
477 fn keygen(&self) -> Result<(PublicKey, PrivateKey), CryptoError> {
478 let (pk, sk) = falcon512::keypair();
479 Ok((
480 PublicKey::new(self.id(), pk.as_bytes().to_vec())?,
481 PrivateKey::new(self.id(), sk.as_bytes().to_vec())?,
482 ))
483 }
484
485 fn sign(&self, sk: &PrivateKey, msg: &[u8]) -> Result<Signature, CryptoError> {
486 if sk.scheme != self.id() {
487 return Err(CryptoError::WrongScheme);
488 }
489
490 let sk = falcon512::SecretKey::from_bytes(&sk.bytes)
491 .map_err(|_| CryptoError::InvalidSecretKey)?;
492
493 let signature = falcon512::detached_sign(msg, &sk);
494 Signature::new(self.id(), signature.as_bytes().to_vec())
495 }
496
497 fn verify(&self, pk: &PublicKey, msg: &[u8], sig: &Signature) -> Result<(), CryptoError> {
498 if pk.scheme != self.id() || sig.scheme != self.id() {
499 return Err(CryptoError::WrongScheme);
500 }
501
502 let pk = falcon512::PublicKey::from_bytes(&pk.bytes)
503 .map_err(|_| CryptoError::InvalidPublicKey)?;
504 let sig = falcon512::DetachedSignature::from_bytes(&sig.bytes)
505 .map_err(|_| CryptoError::InvalidSignature)?;
506
507 falcon512::verify_detached_signature(&sig, msg, &pk)
508 .map_err(|_| CryptoError::InvalidSignature)
509 }
510}
511
512pub fn default_registry() -> InMemoryRegistry {
513 InMemoryRegistry::new()
514 .with_scheme(Box::new(Dilithium2Scheme))
515 .with_scheme(Box::new(Falcon512Scheme))
516}
517
518#[cfg(test)]
519mod tests {
520 use super::*;
521
522 const MESSAGE: &[u8] = b"qcoin-pq-test";
523
524 #[test]
525 fn dilithium_roundtrip() {
526 let scheme = Dilithium2Scheme;
527 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
528 let sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
529
530 assert!(scheme.verify(&pk, MESSAGE, &sig).is_ok());
531 }
532
533 #[test]
534 fn falcon_roundtrip() {
535 let scheme = Falcon512Scheme;
536 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
537 let sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
538
539 assert!(scheme.verify(&pk, MESSAGE, &sig).is_ok());
540 }
541
542 #[test]
543 fn signing_rejects_wrong_scheme_key() {
544 let dilithium = Dilithium2Scheme;
545 let falcon = Falcon512Scheme;
546
547 let (_, sk) = dilithium.keygen().expect("keygen should succeed");
548 let result = falcon.sign(&sk, MESSAGE);
549
550 assert!(matches!(result, Err(CryptoError::WrongScheme)));
551 }
552
553 #[test]
554 fn verify_rejects_wrong_scheme_signature() {
555 let dilithium = Dilithium2Scheme;
556 let falcon = Falcon512Scheme;
557
558 let (dili_pk, _dili_sk) = dilithium.keygen().expect("keygen should succeed");
559 let falcon_sig = falcon
560 .sign(
561 &falcon.keygen().expect("falcon keygen should succeed").1,
562 MESSAGE,
563 )
564 .expect("falcon signing should succeed");
565
566 let result = dilithium.verify(&dili_pk, MESSAGE, &falcon_sig);
567 assert!(matches!(result, Err(CryptoError::WrongScheme)));
568
569 let sig_from_wrong_scheme = Signature {
570 scheme: SignatureSchemeId::Dilithium2,
571 bytes: falcon_sig.bytes.clone(),
572 };
573 let result = dilithium.verify(&dili_pk, MESSAGE, &sig_from_wrong_scheme);
574 assert!(matches!(result, Err(CryptoError::InvalidSignature)));
575 }
576
577 #[test]
578 fn verify_rejects_corrupted_public_key() {
579 let scheme = Dilithium2Scheme;
580 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
581 let sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
582
583 let mut corrupted_bytes = pk.bytes.clone();
584 corrupted_bytes.push(0);
585 let corrupted_pk = PublicKey {
586 scheme: pk.scheme,
587 bytes: corrupted_bytes,
588 };
589
590 let result = scheme.verify(&corrupted_pk, MESSAGE, &sig);
591 assert!(matches!(result, Err(CryptoError::InvalidPublicKey)));
592 }
593
594 #[test]
595 fn verify_rejects_corrupted_signature() {
596 let scheme = Falcon512Scheme;
597 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
598 let mut sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
599 sig.bytes.push(1);
600
601 let result = scheme.verify(&pk, MESSAGE, &sig);
602 assert!(matches!(result, Err(CryptoError::InvalidSignature)));
603 }
604
605 #[test]
606 fn verify_rejects_corrupted_message() {
607 let scheme = Dilithium2Scheme;
608 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
609 let sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
610
611 let result = scheme.verify(&pk, b"tampered", &sig);
612 assert!(matches!(result, Err(CryptoError::InvalidSignature)));
613 }
614
615 #[test]
616 fn roundtrip_serialization_is_canonical() {
617 let scheme = Falcon512Scheme;
618 let (pk, sk) = scheme.keygen().expect("keygen should succeed");
619 let sig = scheme.sign(&sk, MESSAGE).expect("signing should succeed");
620
621 let encoded_pk = pk.to_bytes().expect("public key encoding");
622 let decoded_pk = PublicKey::from_bytes(&encoded_pk).expect("public key decoding");
623 assert_eq!(pk, decoded_pk);
624
625 let encoded_sig = sig.to_bytes().expect("signature encoding");
626 let decoded_sig = Signature::from_bytes(&encoded_sig).expect("signature decoding");
627 assert_eq!(sig, decoded_sig);
628 }
629}