oqs_safe/
sig.rs

1//! Signature API with safe accessors and feature-gated RNG for the mock backend.
2
3use crate::OqsError;
4use zeroize::Zeroize;
5
6#[cfg(not(feature = "liboqs"))]
7use rand_core::{OsRng, RngCore};
8
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12#[derive(Clone, Debug)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub struct PublicKey(pub(crate) Vec<u8>);
15
16#[derive(Clone, Debug, Zeroize)]
17#[zeroize(drop)]
18#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
19pub struct SecretKey(pub(crate) Vec<u8>);
20
21#[derive(Clone, Debug)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct Signature(pub(crate) Vec<u8>);
24
25// ---- Read-only accessors ----
26impl PublicKey {
27    #[inline]
28    pub fn as_bytes(&self) -> &[u8] {
29        &self.0
30    }
31    #[inline]
32    pub fn len(&self) -> usize {
33        self.0.len()
34    }
35    #[inline]
36    pub fn is_empty(&self) -> bool {
37        self.0.is_empty()
38    }
39}
40impl SecretKey {
41    #[inline]
42    pub fn as_bytes(&self) -> &[u8] {
43        &self.0
44    }
45    #[inline]
46    pub fn len(&self) -> usize {
47        self.0.len()
48    }
49    #[inline]
50    pub fn is_empty(&self) -> bool {
51        self.0.is_empty()
52    }
53}
54impl Signature {
55    #[inline]
56    pub fn as_bytes(&self) -> &[u8] {
57        &self.0
58    }
59    #[inline]
60    pub fn len(&self) -> usize {
61        self.0.len()
62    }
63    #[inline]
64    pub fn is_empty(&self) -> bool {
65        self.0.is_empty()
66    }
67}
68
69pub trait SignatureScheme {
70    fn keypair() -> Result<(PublicKey, SecretKey), OqsError>;
71    fn sign(sk: &SecretKey, msg: &[u8]) -> Result<Signature, OqsError>;
72    fn verify(pk: &PublicKey, msg: &[u8], sig: &Signature) -> Result<(), OqsError>;
73}
74
75pub struct Dilithium2;
76
77impl SignatureScheme for Dilithium2 {
78    fn keypair() -> Result<(PublicKey, SecretKey), OqsError> {
79        #[cfg(feature = "liboqs")]
80        {
81            let (pk, sk) = crate::ffi::dilithium2_keypair()?;
82            Ok((PublicKey(pk), SecretKey(sk)))
83        }
84        #[cfg(not(feature = "liboqs"))]
85        {
86            // Mock path: size-faithful random buffers for CI / no-liboqs environments.
87            let mut pk = vec![0u8; 1312];
88            let mut sk = vec![0u8; 2528];
89            OsRng.fill_bytes(&mut pk);
90            OsRng.fill_bytes(&mut sk);
91            Ok((PublicKey(pk), SecretKey(sk)))
92        }
93    }
94
95    fn sign(sk: &SecretKey, msg: &[u8]) -> Result<Signature, OqsError> {
96        #[cfg(feature = "liboqs")]
97        {
98            crate::ffi::dilithium2_sign(sk.as_bytes(), msg).map(Signature)
99        }
100        #[cfg(not(feature = "liboqs"))]
101        {
102            // Silence unused warnings on mock path
103            let _ = (sk, msg);
104            let mut sig = vec![0u8; 2420];
105            OsRng.fill_bytes(&mut sig);
106            Ok(Signature(sig))
107        }
108    }
109
110    fn verify(pk: &PublicKey, msg: &[u8], sig: &Signature) -> Result<(), OqsError> {
111        #[cfg(feature = "liboqs")]
112        {
113            crate::ffi::dilithium2_verify(pk.as_bytes(), msg, sig.as_bytes())
114        }
115        #[cfg(not(feature = "liboqs"))]
116        {
117            // Silence unused warnings on mock path
118            let _ = (pk, msg);
119            if sig.len() != 2420 {
120                return Err(OqsError::InvalidLength);
121            }
122            Ok(())
123        }
124    }
125}