baseid_crypto/
signer.rs

1//! Signer and Verifier traits for cryptographic agility.
2//!
3//! All signature operations go through these traits so that the underlying
4//! algorithm can be swapped (e.g., for post-quantum migration) without
5//! changing calling code.
6
7use baseid_core::error::CryptoError;
8use baseid_core::types::{KeyType, SignatureAlgorithm};
9
10use crate::key::{KeyPair, PublicKey};
11
12/// Trait for signing data.
13pub trait Signer: Send + Sync {
14    /// The signature algorithm used by this signer.
15    fn algorithm(&self) -> SignatureAlgorithm;
16
17    /// Sign the provided payload, returning the raw signature bytes.
18    fn sign(&self, payload: &[u8]) -> baseid_core::Result<Vec<u8>>;
19}
20
21/// Trait for verifying signatures.
22pub trait Verifier: Send + Sync {
23    /// The signature algorithm expected by this verifier.
24    fn algorithm(&self) -> SignatureAlgorithm;
25
26    /// Verify a signature over the given payload.
27    fn verify(&self, payload: &[u8], signature: &[u8]) -> baseid_core::Result<bool>;
28}
29
30/// Sign multiple messages as a single BBS+ signature.
31pub trait MultiMessageSigner: Send + Sync {
32    fn sign_messages(&self, messages: &[Vec<u8>]) -> baseid_core::Result<Vec<u8>>;
33}
34
35/// Derive a zero-knowledge proof from a multi-message signature.
36pub trait ProofDeriver {
37    fn derive_proof(
38        &self,
39        signature: &[u8],
40        messages: &[Vec<u8>],
41        disclosed_indices: &[usize],
42    ) -> baseid_core::Result<Vec<u8>>;
43}
44
45/// Verify a derived zero-knowledge proof.
46pub trait ProofVerifier {
47    fn verify_proof(
48        &self,
49        proof: &[u8],
50        disclosed_messages: &[(usize, Vec<u8>)],
51        total_message_count: usize,
52    ) -> baseid_core::Result<bool>;
53}
54
55impl Signer for KeyPair {
56    fn algorithm(&self) -> SignatureAlgorithm {
57        self.public.algorithm()
58    }
59
60    fn sign(&self, payload: &[u8]) -> baseid_core::Result<Vec<u8>> {
61        match self.public.key_type {
62            KeyType::Ed25519 => sign_ed25519(self.secret_bytes(), payload),
63            KeyType::P256 => sign_p256(self.secret_bytes(), payload),
64            KeyType::P384 => sign_p384(self.secret_bytes(), payload),
65            KeyType::Secp256k1 => sign_secp256k1(self.secret_bytes(), payload),
66            KeyType::Bls12381G2 => Err(CryptoError::UnsupportedAlgorithm.into()),
67        }
68    }
69}
70
71impl Verifier for PublicKey {
72    fn algorithm(&self) -> SignatureAlgorithm {
73        self.algorithm()
74    }
75
76    fn verify(&self, payload: &[u8], signature: &[u8]) -> baseid_core::Result<bool> {
77        match self.key_type {
78            KeyType::Ed25519 => verify_ed25519(&self.bytes, payload, signature),
79            KeyType::P256 => verify_p256(&self.bytes, payload, signature),
80            KeyType::P384 => verify_p384(&self.bytes, payload, signature),
81            KeyType::Secp256k1 => verify_secp256k1(&self.bytes, payload, signature),
82            KeyType::Bls12381G2 => Err(CryptoError::UnsupportedAlgorithm.into()),
83        }
84    }
85}
86
87fn sign_ed25519(secret: &[u8], payload: &[u8]) -> baseid_core::Result<Vec<u8>> {
88    use ed25519_dalek::Signer as _;
89    let bytes: [u8; 32] = secret
90        .try_into()
91        .map_err(|_| CryptoError::InvalidKeyMaterial)?;
92    let signing_key = ed25519_dalek::SigningKey::from_bytes(&bytes);
93    let sig = signing_key.sign(payload);
94    Ok(sig.to_bytes().to_vec())
95}
96
97fn sign_p256(secret: &[u8], payload: &[u8]) -> baseid_core::Result<Vec<u8>> {
98    use p256::ecdsa::{signature::Signer as _, Signature, SigningKey};
99    let signing_key =
100        SigningKey::from_bytes(secret.into()).map_err(|_| CryptoError::InvalidKeyMaterial)?;
101    let sig: Signature = signing_key.sign(payload);
102    Ok(sig.to_bytes().to_vec())
103}
104
105fn sign_p384(secret: &[u8], payload: &[u8]) -> baseid_core::Result<Vec<u8>> {
106    use p384::ecdsa::{signature::Signer as _, Signature, SigningKey};
107    let signing_key =
108        SigningKey::from_bytes(secret.into()).map_err(|_| CryptoError::InvalidKeyMaterial)?;
109    let sig: Signature = signing_key.sign(payload);
110    Ok(sig.to_bytes().to_vec())
111}
112
113fn sign_secp256k1(secret: &[u8], payload: &[u8]) -> baseid_core::Result<Vec<u8>> {
114    use k256::ecdsa::{signature::Signer as _, Signature, SigningKey};
115    let signing_key =
116        SigningKey::from_bytes(secret.into()).map_err(|_| CryptoError::InvalidKeyMaterial)?;
117    let sig: Signature = signing_key.sign(payload);
118    Ok(sig.to_bytes().to_vec())
119}
120
121fn verify_ed25519(
122    public_bytes: &[u8],
123    payload: &[u8],
124    signature: &[u8],
125) -> baseid_core::Result<bool> {
126    use ed25519_dalek::Verifier as _;
127    let bytes: [u8; 32] = public_bytes
128        .try_into()
129        .map_err(|_| CryptoError::InvalidKeyMaterial)?;
130    let verifying_key = ed25519_dalek::VerifyingKey::from_bytes(&bytes)
131        .map_err(|_| CryptoError::InvalidKeyMaterial)?;
132    let sig_bytes: [u8; 64] = signature
133        .try_into()
134        .map_err(|_| CryptoError::VerificationFailed)?;
135    let sig = ed25519_dalek::Signature::from_bytes(&sig_bytes);
136    Ok(verifying_key.verify(payload, &sig).is_ok())
137}
138
139fn verify_p256(public_bytes: &[u8], payload: &[u8], signature: &[u8]) -> baseid_core::Result<bool> {
140    use p256::ecdsa::{signature::Verifier as _, Signature, VerifyingKey};
141    let verifying_key =
142        VerifyingKey::from_sec1_bytes(public_bytes).map_err(|_| CryptoError::InvalidKeyMaterial)?;
143    let sig =
144        Signature::from_bytes(signature.into()).map_err(|_| CryptoError::VerificationFailed)?;
145    Ok(verifying_key.verify(payload, &sig).is_ok())
146}
147
148fn verify_p384(public_bytes: &[u8], payload: &[u8], signature: &[u8]) -> baseid_core::Result<bool> {
149    use p384::ecdsa::{signature::Verifier as _, Signature, VerifyingKey};
150    let verifying_key =
151        VerifyingKey::from_sec1_bytes(public_bytes).map_err(|_| CryptoError::InvalidKeyMaterial)?;
152    let sig =
153        Signature::from_bytes(signature.into()).map_err(|_| CryptoError::VerificationFailed)?;
154    Ok(verifying_key.verify(payload, &sig).is_ok())
155}
156
157fn verify_secp256k1(
158    public_bytes: &[u8],
159    payload: &[u8],
160    signature: &[u8],
161) -> baseid_core::Result<bool> {
162    use k256::ecdsa::{signature::Verifier as _, Signature, VerifyingKey};
163    let verifying_key =
164        VerifyingKey::from_sec1_bytes(public_bytes).map_err(|_| CryptoError::InvalidKeyMaterial)?;
165    let sig =
166        Signature::from_bytes(signature.into()).map_err(|_| CryptoError::VerificationFailed)?;
167    Ok(verifying_key.verify(payload, &sig).is_ok())
168}
169
170#[cfg(test)]
171mod tests {
172    use super::*;
173
174    fn sign_verify_roundtrip(key_type: KeyType) {
175        let kp = KeyPair::generate(key_type).unwrap();
176        let payload = b"test message for signing";
177        let sig = kp.sign(payload).unwrap();
178        let valid = kp.public.verify(payload, &sig).unwrap();
179        assert!(valid);
180    }
181
182    #[test]
183    fn roundtrip_ed25519() {
184        sign_verify_roundtrip(KeyType::Ed25519);
185    }
186
187    #[test]
188    fn roundtrip_p256() {
189        sign_verify_roundtrip(KeyType::P256);
190    }
191
192    #[test]
193    fn roundtrip_p384() {
194        sign_verify_roundtrip(KeyType::P384);
195    }
196
197    #[test]
198    fn roundtrip_secp256k1() {
199        sign_verify_roundtrip(KeyType::Secp256k1);
200    }
201
202    #[test]
203    fn verify_rejects_wrong_payload() {
204        let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
205        let sig = kp.sign(b"correct payload").unwrap();
206        let valid = kp.public.verify(b"wrong payload", &sig).unwrap();
207        assert!(!valid);
208    }
209
210    #[test]
211    fn verify_rejects_wrong_key() {
212        let kp1 = KeyPair::generate(KeyType::Ed25519).unwrap();
213        let kp2 = KeyPair::generate(KeyType::Ed25519).unwrap();
214        let payload = b"test";
215        let sig = kp1.sign(payload).unwrap();
216        let valid = kp2.public.verify(payload, &sig).unwrap();
217        assert!(!valid);
218    }
219
220    #[test]
221    fn verify_rejects_wrong_key_ec() {
222        let kp1 = KeyPair::generate(KeyType::P256).unwrap();
223        let kp2 = KeyPair::generate(KeyType::P256).unwrap();
224        let payload = b"test";
225        let sig = kp1.sign(payload).unwrap();
226        let valid = kp2.public.verify(payload, &sig).unwrap();
227        assert!(!valid);
228    }
229
230    #[test]
231    fn algorithm_matches_key_type() {
232        assert_eq!(
233            <KeyPair as Signer>::algorithm(&KeyPair::generate(KeyType::Ed25519).unwrap()),
234            SignatureAlgorithm::EdDsa
235        );
236        assert_eq!(
237            <KeyPair as Signer>::algorithm(&KeyPair::generate(KeyType::P256).unwrap()),
238            SignatureAlgorithm::Es256
239        );
240        assert_eq!(
241            <KeyPair as Signer>::algorithm(&KeyPair::generate(KeyType::P384).unwrap()),
242            SignatureAlgorithm::Es384
243        );
244        assert_eq!(
245            <KeyPair as Signer>::algorithm(&KeyPair::generate(KeyType::Secp256k1).unwrap()),
246            SignatureAlgorithm::Es256k
247        );
248    }
249}