baseid_crypto/
key.rs

1//! Key types and generation.
2
3use baseid_core::error::CryptoError;
4use baseid_core::types::{KeyType, SignatureAlgorithm};
5use serde::{Deserialize, Serialize};
6use zeroize::Zeroize;
7
8/// A public key with its type metadata.
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct PublicKey {
11    pub key_type: KeyType,
12    pub bytes: Vec<u8>,
13}
14
15/// A key pair consisting of a public key and secret key material.
16///
17/// Secret key bytes are zeroized on drop.
18pub struct KeyPair {
19    pub public: PublicKey,
20    secret: SecretKey,
21}
22
23/// Secret key material. Zeroized on drop.
24struct SecretKey {
25    bytes: Vec<u8>,
26}
27
28impl Drop for SecretKey {
29    fn drop(&mut self) {
30        self.bytes.zeroize();
31    }
32}
33
34impl std::fmt::Debug for KeyPair {
35    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36        f.debug_struct("KeyPair")
37            .field("public", &self.public)
38            .field("secret", &"[REDACTED]")
39            .finish()
40    }
41}
42
43impl KeyPair {
44    /// Generate a new key pair for the given key type.
45    pub fn generate(key_type: KeyType) -> baseid_core::Result<Self> {
46        use rand::rngs::OsRng;
47
48        match key_type {
49            KeyType::Bls12381G2 => Err(CryptoError::UnsupportedAlgorithm.into()),
50            KeyType::Ed25519 => {
51                let signing_key = ed25519_dalek::SigningKey::generate(&mut OsRng);
52                let verifying_key = signing_key.verifying_key();
53                Ok(Self {
54                    public: PublicKey {
55                        key_type,
56                        bytes: verifying_key.as_bytes().to_vec(),
57                    },
58                    secret: SecretKey {
59                        bytes: signing_key.to_bytes().to_vec(),
60                    },
61                })
62            }
63            KeyType::P256 => {
64                let signing_key = p256::ecdsa::SigningKey::random(&mut OsRng);
65                let verifying_key = signing_key.verifying_key();
66                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
67                let secret_bytes = signing_key.to_bytes().to_vec();
68                Ok(Self {
69                    public: PublicKey {
70                        key_type,
71                        bytes: public_bytes,
72                    },
73                    secret: SecretKey {
74                        bytes: secret_bytes,
75                    },
76                })
77            }
78            KeyType::P384 => {
79                let signing_key = p384::ecdsa::SigningKey::random(&mut OsRng);
80                let verifying_key = signing_key.verifying_key();
81                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
82                let secret_bytes = signing_key.to_bytes().to_vec();
83                Ok(Self {
84                    public: PublicKey {
85                        key_type,
86                        bytes: public_bytes,
87                    },
88                    secret: SecretKey {
89                        bytes: secret_bytes,
90                    },
91                })
92            }
93            KeyType::Secp256k1 => {
94                let signing_key = k256::ecdsa::SigningKey::random(&mut OsRng);
95                let verifying_key = signing_key.verifying_key();
96                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
97                let secret_bytes = signing_key.to_bytes().to_vec();
98                Ok(Self {
99                    public: PublicKey {
100                        key_type,
101                        bytes: public_bytes,
102                    },
103                    secret: SecretKey {
104                        bytes: secret_bytes,
105                    },
106                })
107            }
108        }
109    }
110
111    /// Return the signature algorithm this key pair uses.
112    pub fn algorithm(&self) -> SignatureAlgorithm {
113        self.public.algorithm()
114    }
115
116    /// Expose the secret key bytes.
117    pub fn secret_bytes(&self) -> &[u8] {
118        &self.secret.bytes
119    }
120
121    /// Reconstruct a key pair from secret key bytes (derives the public key).
122    pub fn from_bytes(key_type: KeyType, secret_bytes: &[u8]) -> baseid_core::Result<Self> {
123        match key_type {
124            KeyType::Bls12381G2 => Err(CryptoError::UnsupportedAlgorithm.into()),
125            KeyType::Ed25519 => {
126                let bytes: [u8; 32] = secret_bytes
127                    .try_into()
128                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
129                let signing_key = ed25519_dalek::SigningKey::from_bytes(&bytes);
130                let verifying_key = signing_key.verifying_key();
131                Ok(Self {
132                    public: PublicKey {
133                        key_type,
134                        bytes: verifying_key.as_bytes().to_vec(),
135                    },
136                    secret: SecretKey {
137                        bytes: secret_bytes.to_vec(),
138                    },
139                })
140            }
141            KeyType::P256 => {
142                if secret_bytes.len() != 32 {
143                    return Err(CryptoError::InvalidKeyMaterial.into());
144                }
145                let signing_key = p256::ecdsa::SigningKey::from_bytes(secret_bytes.into())
146                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
147                let verifying_key = signing_key.verifying_key();
148                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
149                Ok(Self {
150                    public: PublicKey {
151                        key_type,
152                        bytes: public_bytes,
153                    },
154                    secret: SecretKey {
155                        bytes: secret_bytes.to_vec(),
156                    },
157                })
158            }
159            KeyType::P384 => {
160                if secret_bytes.len() != 48 {
161                    return Err(CryptoError::InvalidKeyMaterial.into());
162                }
163                let signing_key = p384::ecdsa::SigningKey::from_bytes(secret_bytes.into())
164                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
165                let verifying_key = signing_key.verifying_key();
166                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
167                Ok(Self {
168                    public: PublicKey {
169                        key_type,
170                        bytes: public_bytes,
171                    },
172                    secret: SecretKey {
173                        bytes: secret_bytes.to_vec(),
174                    },
175                })
176            }
177            KeyType::Secp256k1 => {
178                if secret_bytes.len() != 32 {
179                    return Err(CryptoError::InvalidKeyMaterial.into());
180                }
181                let signing_key = k256::ecdsa::SigningKey::from_bytes(secret_bytes.into())
182                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
183                let verifying_key = signing_key.verifying_key();
184                let public_bytes = verifying_key.to_encoded_point(true).as_bytes().to_vec();
185                Ok(Self {
186                    public: PublicKey {
187                        key_type,
188                        bytes: public_bytes,
189                    },
190                    secret: SecretKey {
191                        bytes: secret_bytes.to_vec(),
192                    },
193                })
194            }
195        }
196    }
197}
198
199impl PublicKey {
200    /// Construct a public key from raw bytes with validation.
201    pub fn from_bytes(key_type: KeyType, public_bytes: &[u8]) -> baseid_core::Result<Self> {
202        if key_type == KeyType::Bls12381G2 {
203            return Err(CryptoError::UnsupportedAlgorithm.into());
204        }
205        // Validate the bytes by attempting to parse them
206        match key_type {
207            KeyType::Bls12381G2 => unreachable!(),
208            KeyType::Ed25519 => {
209                let bytes: [u8; 32] = public_bytes
210                    .try_into()
211                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
212                ed25519_dalek::VerifyingKey::from_bytes(&bytes)
213                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
214            }
215            KeyType::P256 => {
216                use p256::elliptic_curve::sec1::FromEncodedPoint;
217                let point = p256::EncodedPoint::from_bytes(public_bytes)
218                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
219                let maybe = p256::PublicKey::from_encoded_point(&point);
220                if maybe.is_none().into() {
221                    return Err(CryptoError::InvalidKeyMaterial.into());
222                }
223            }
224            KeyType::P384 => {
225                use p384::elliptic_curve::sec1::FromEncodedPoint;
226                let point = p384::EncodedPoint::from_bytes(public_bytes)
227                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
228                let maybe = p384::PublicKey::from_encoded_point(&point);
229                if maybe.is_none().into() {
230                    return Err(CryptoError::InvalidKeyMaterial.into());
231                }
232            }
233            KeyType::Secp256k1 => {
234                use k256::elliptic_curve::sec1::FromEncodedPoint;
235                let point = k256::EncodedPoint::from_bytes(public_bytes)
236                    .map_err(|_| CryptoError::InvalidKeyMaterial)?;
237                let maybe = k256::PublicKey::from_encoded_point(&point);
238                if maybe.is_none().into() {
239                    return Err(CryptoError::InvalidKeyMaterial.into());
240                }
241            }
242        }
243        Ok(Self {
244            key_type,
245            bytes: public_bytes.to_vec(),
246        })
247    }
248
249    /// Return the default signature algorithm for this key type.
250    pub fn algorithm(&self) -> SignatureAlgorithm {
251        match self.key_type {
252            KeyType::Ed25519 => SignatureAlgorithm::EdDsa,
253            KeyType::P256 => SignatureAlgorithm::Es256,
254            KeyType::P384 => SignatureAlgorithm::Es384,
255            KeyType::Secp256k1 => SignatureAlgorithm::Es256k,
256            KeyType::Bls12381G2 => SignatureAlgorithm::BbsPlus,
257        }
258    }
259}
260
261#[cfg(test)]
262mod tests {
263    use super::*;
264
265    #[test]
266    fn generate_ed25519() {
267        let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
268        assert_eq!(kp.public.key_type, KeyType::Ed25519);
269        assert_eq!(kp.public.bytes.len(), 32);
270        assert_eq!(kp.secret_bytes().len(), 32);
271    }
272
273    #[test]
274    fn generate_p256() {
275        let kp = KeyPair::generate(KeyType::P256).unwrap();
276        assert_eq!(kp.public.key_type, KeyType::P256);
277        assert_eq!(kp.public.bytes.len(), 33); // compressed
278        assert_eq!(kp.secret_bytes().len(), 32);
279    }
280
281    #[test]
282    fn generate_p384() {
283        let kp = KeyPair::generate(KeyType::P384).unwrap();
284        assert_eq!(kp.public.key_type, KeyType::P384);
285        assert_eq!(kp.public.bytes.len(), 49); // compressed
286        assert_eq!(kp.secret_bytes().len(), 48);
287    }
288
289    #[test]
290    fn generate_secp256k1() {
291        let kp = KeyPair::generate(KeyType::Secp256k1).unwrap();
292        assert_eq!(kp.public.key_type, KeyType::Secp256k1);
293        assert_eq!(kp.public.bytes.len(), 33); // compressed
294        assert_eq!(kp.secret_bytes().len(), 32);
295    }
296
297    #[test]
298    fn roundtrip_from_bytes_ed25519() {
299        let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
300        let restored = KeyPair::from_bytes(KeyType::Ed25519, kp.secret_bytes()).unwrap();
301        assert_eq!(kp.public.bytes, restored.public.bytes);
302    }
303
304    #[test]
305    fn roundtrip_from_bytes_p256() {
306        let kp = KeyPair::generate(KeyType::P256).unwrap();
307        let restored = KeyPair::from_bytes(KeyType::P256, kp.secret_bytes()).unwrap();
308        assert_eq!(kp.public.bytes, restored.public.bytes);
309    }
310
311    #[test]
312    fn roundtrip_from_bytes_p384() {
313        let kp = KeyPair::generate(KeyType::P384).unwrap();
314        let restored = KeyPair::from_bytes(KeyType::P384, kp.secret_bytes()).unwrap();
315        assert_eq!(kp.public.bytes, restored.public.bytes);
316    }
317
318    #[test]
319    fn roundtrip_from_bytes_secp256k1() {
320        let kp = KeyPair::generate(KeyType::Secp256k1).unwrap();
321        let restored = KeyPair::from_bytes(KeyType::Secp256k1, kp.secret_bytes()).unwrap();
322        assert_eq!(kp.public.bytes, restored.public.bytes);
323    }
324
325    #[test]
326    fn public_key_from_bytes_validates() {
327        let kp = KeyPair::generate(KeyType::Ed25519).unwrap();
328        let pk = PublicKey::from_bytes(KeyType::Ed25519, &kp.public.bytes).unwrap();
329        assert_eq!(pk.bytes, kp.public.bytes);
330    }
331
332    #[test]
333    fn public_key_rejects_invalid_bytes() {
334        assert!(PublicKey::from_bytes(KeyType::Ed25519, &[0u8; 31]).is_err());
335        assert!(PublicKey::from_bytes(KeyType::P256, &[0u8; 10]).is_err());
336        assert!(PublicKey::from_bytes(KeyType::P384, &[0u8; 10]).is_err());
337        assert!(PublicKey::from_bytes(KeyType::Secp256k1, &[0u8; 10]).is_err());
338    }
339
340    #[test]
341    fn keypair_from_bytes_rejects_invalid() {
342        assert!(KeyPair::from_bytes(KeyType::Ed25519, &[0u8; 10]).is_err());
343        assert!(KeyPair::from_bytes(KeyType::P256, &[0u8; 10]).is_err());
344        assert!(KeyPair::from_bytes(KeyType::P384, &[0u8; 10]).is_err());
345        assert!(KeyPair::from_bytes(KeyType::Secp256k1, &[0u8; 10]).is_err());
346    }
347
348    #[test]
349    fn algorithm_mapping() {
350        assert_eq!(
351            KeyPair::generate(KeyType::Ed25519).unwrap().algorithm(),
352            SignatureAlgorithm::EdDsa
353        );
354        assert_eq!(
355            KeyPair::generate(KeyType::P256).unwrap().algorithm(),
356            SignatureAlgorithm::Es256
357        );
358        assert_eq!(
359            KeyPair::generate(KeyType::P384).unwrap().algorithm(),
360            SignatureAlgorithm::Es384
361        );
362        assert_eq!(
363            KeyPair::generate(KeyType::Secp256k1).unwrap().algorithm(),
364            SignatureAlgorithm::Es256k
365        );
366    }
367}