Skip to main content

claw_crypto/
keypair.rs

1use ed25519_dalek::{SigningKey, VerifyingKey};
2use rand::rngs::OsRng;
3
4use crate::CryptoError;
5
6/// Ed25519 keypair used to sign capsules and related provenance claims.
7pub struct KeyPair {
8    signing_key: SigningKey,
9}
10
11impl KeyPair {
12    /// Generates a new Ed25519 keypair with operating-system randomness.
13    pub fn generate() -> Self {
14        let signing_key = SigningKey::generate(&mut OsRng);
15        Self { signing_key }
16    }
17
18    /// Constructs a keypair from a 32-byte Ed25519 secret key seed.
19    pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, CryptoError> {
20        let signing_key = SigningKey::from_bytes(bytes);
21        Ok(Self { signing_key })
22    }
23
24    /// Returns the underlying Ed25519 signing key.
25    pub fn signing_key(&self) -> &SigningKey {
26        &self.signing_key
27    }
28
29    /// Returns the corresponding Ed25519 verifying key.
30    pub fn verifying_key(&self) -> VerifyingKey {
31        self.signing_key.verifying_key()
32    }
33
34    /// Serializes the secret key seed.
35    pub fn to_bytes(&self) -> [u8; 32] {
36        self.signing_key.to_bytes()
37    }
38
39    /// Returns the public verifying key bytes.
40    pub fn public_key_bytes(&self) -> [u8; 32] {
41        self.verifying_key().to_bytes()
42    }
43
44    /// Writes the secret key seed to `path`.
45    pub fn save_to_file(&self, path: &std::path::Path) -> Result<(), CryptoError> {
46        std::fs::write(path, self.to_bytes())?;
47        Ok(())
48    }
49
50    /// Loads a keypair from a file containing exactly 32 secret-key bytes.
51    pub fn load_from_file(path: &std::path::Path) -> Result<Self, CryptoError> {
52        let bytes = std::fs::read(path)?;
53        let arr: [u8; 32] = bytes
54            .try_into()
55            .map_err(|_| CryptoError::InvalidKey("expected 32 bytes".into()))?;
56        Self::from_bytes(&arr)
57    }
58}