rust_bottle/
keychain.rs

1use crate::errors::{BottleError, Result};
2use crate::signing::Sign;
3use rand::RngCore;
4use std::collections::HashMap;
5
6/// A keychain provides secure storage for private keys.
7///
8/// Keychains store private keys indexed by their public key fingerprints,
9/// allowing easy lookup and signing operations. Keys must implement the
10/// `SignerKey` trait, which includes both `Sign` and key identification
11/// methods.
12///
13/// # Example
14///
15/// ```rust
16/// use rust_bottle::*;
17/// use rand::rngs::OsRng;
18///
19/// let mut keychain = Keychain::new();
20/// let rng = &mut OsRng;
21///
22/// let key1 = Ed25519Key::generate(rng);
23/// let key2 = EcdsaP256Key::generate(rng);
24///
25/// keychain.add_key(key1);
26/// keychain.add_key(key2);
27///
28/// let pub_key = keychain.signers().next().unwrap().public_key();
29/// let signature = keychain.sign(rng, &pub_key, b"Message").unwrap();
30/// ```
31pub struct Keychain {
32    /// Keys indexed by their public key fingerprint (SHA-256 hash)
33    keys: HashMap<Vec<u8>, Box<dyn SignerKey>>,
34}
35
36/// Trait for keys that can be stored in a keychain.
37///
38/// This trait extends `Sign` with methods for key identification. All key
39/// types in rust-bottle implement this trait, allowing them to be stored in
40/// keychains.
41///
42/// # Requirements
43///
44/// * `Sign`: Must be able to sign messages
45/// * `Send + Sync`: Must be safe to send across threads
46pub trait SignerKey: Sign + Send + Sync {
47    /// Get the public key fingerprint (SHA-256 hash of public key).
48    ///
49    /// The fingerprint is used as the key in the keychain's internal
50    /// HashMap for fast lookup.
51    ///
52    /// # Returns
53    ///
54    /// SHA-256 hash of the public key bytes
55    fn fingerprint(&self) -> Vec<u8>;
56    /// Get the public key bytes.
57    ///
58    /// # Returns
59    ///
60    /// Public key bytes in the key's native format
61    fn public_key(&self) -> Vec<u8>;
62}
63
64impl Keychain {
65    /// Create a new empty keychain.
66    ///
67    /// # Returns
68    ///
69    /// A new `Keychain` instance with no keys
70    ///
71    /// # Example
72    ///
73    /// ```rust
74    /// use rust_bottle::Keychain;
75    ///
76    /// let keychain = Keychain::new();
77    /// ```
78    pub fn new() -> Self {
79        Self {
80            keys: HashMap::new(),
81        }
82    }
83
84    /// Add a key to the keychain.
85    ///
86    /// The key is indexed by its public key fingerprint. If a key with the
87    /// same fingerprint already exists, it will be replaced.
88    ///
89    /// # Arguments
90    ///
91    /// * `key` - A key implementing `SignerKey` (e.g., `Ed25519Key`, `EcdsaP256Key`)
92    ///
93    /// # Example
94    ///
95    /// ```rust
96    /// use rust_bottle::*;
97    /// use rand::rngs::OsRng;
98    ///
99    /// let mut keychain = Keychain::new();
100    /// let rng = &mut OsRng;
101    /// let key = Ed25519Key::generate(rng);
102    ///
103    /// keychain.add_key(key);
104    /// ```
105    pub fn add_key<K: SignerKey + 'static>(&mut self, key: K) {
106        let fingerprint = key.fingerprint();
107        self.keys.insert(fingerprint, Box::new(key));
108    }
109
110    /// Add multiple keys to the keychain at once.
111    ///
112    /// # Arguments
113    ///
114    /// * `keys` - A vector of keys to add
115    ///
116    /// # Example
117    ///
118    /// ```rust
119    /// use rust_bottle::*;
120    /// use rand::rngs::OsRng;
121    ///
122    /// let mut keychain = Keychain::new();
123    /// let rng = &mut OsRng;
124    /// let key1 = Ed25519Key::generate(rng);
125    /// let key2 = Ed25519Key::generate(rng);
126    ///
127    /// keychain.add_keys(vec![key1, key2]);
128    /// ```
129    pub fn add_keys<K: SignerKey + 'static>(&mut self, keys: Vec<K>) {
130        for key in keys {
131            self.add_key(key);
132        }
133    }
134
135    /// Get a key by its public key.
136    ///
137    /// The public key is hashed to find the corresponding private key in
138    /// the keychain.
139    ///
140    /// # Arguments
141    ///
142    /// * `public_key` - The public key to look up
143    ///
144    /// # Returns
145    ///
146    /// * `Ok(&dyn SignerKey)` - Reference to the key
147    /// * `Err(BottleError::KeyNotFound)` - If the key is not in the keychain
148    ///
149    /// # Example
150    ///
151    /// ```rust
152    /// use rust_bottle::*;
153    /// use rand::rngs::OsRng;
154    ///
155    /// let mut keychain = Keychain::new();
156    /// let rng = &mut OsRng;
157    /// let key = Ed25519Key::generate(rng);
158    /// let pub_key = key.public_key_bytes();
159    ///
160    /// keychain.add_key(key);
161    /// let retrieved = keychain.get_key(&pub_key).unwrap();
162    /// ```
163    pub fn get_key(&self, public_key: &[u8]) -> Result<&dyn SignerKey> {
164        let fingerprint = crate::hash::sha256(public_key);
165        self.keys
166            .get(&fingerprint)
167            .map(|k| k.as_ref())
168            .ok_or(BottleError::KeyNotFound)
169    }
170
171    /// Get a signer by its public key (alias for `get_key`).
172    ///
173    /// # Arguments
174    ///
175    /// * `public_key` - The public key to look up
176    ///
177    /// # Returns
178    ///
179    /// * `Ok(&dyn SignerKey)` - Reference to the signer
180    /// * `Err(BottleError::KeyNotFound)` - If the key is not in the keychain
181    pub fn get_signer(&self, public_key: &[u8]) -> Result<&dyn SignerKey> {
182        self.get_key(public_key)
183    }
184
185    /// Sign a message with a specific key from the keychain.
186    ///
187    /// This is a convenience method that looks up the key and signs the
188    /// message in one operation.
189    ///
190    /// # Arguments
191    ///
192    /// * `rng` - A random number generator
193    /// * `public_key` - The public key of the key to use for signing
194    /// * `message` - The message to sign
195    ///
196    /// # Returns
197    ///
198    /// * `Ok(Vec<u8>)` - Signature bytes
199    /// * `Err(BottleError::KeyNotFound)` - If the key is not in the keychain
200    /// * `Err(BottleError::VerifyFailed)` - If signing fails
201    ///
202    /// # Example
203    ///
204    /// ```rust
205    /// use rust_bottle::*;
206    /// use rand::rngs::OsRng;
207    ///
208    /// let mut keychain = Keychain::new();
209    /// let rng = &mut OsRng;
210    /// let key = Ed25519Key::generate(rng);
211    /// let pub_key = key.public_key_bytes();
212    ///
213    /// keychain.add_key(key);
214    /// let signature = keychain.sign(rng, &pub_key, b"Message").unwrap();
215    /// ```
216    pub fn sign<R: RngCore>(
217        &self,
218        rng: &mut R,
219        public_key: &[u8],
220        message: &[u8],
221    ) -> Result<Vec<u8>> {
222        let signer = self.get_signer(public_key)?;
223        signer.sign(rng as &mut dyn RngCore, message)
224    }
225
226    /// Iterate over all signers in the keychain.
227    ///
228    /// # Returns
229    ///
230    /// An iterator over all stored keys (as `&dyn SignerKey`)
231    ///
232    /// # Example
233    ///
234    /// ```rust
235    /// use rust_bottle::*;
236    /// use rand::rngs::OsRng;
237    ///
238    /// let mut keychain = Keychain::new();
239    /// let rng = &mut OsRng;
240    /// let key1 = Ed25519Key::generate(rng);
241    /// let key2 = EcdsaP256Key::generate(rng);
242    ///
243    /// keychain.add_key(key1);
244    /// keychain.add_key(key2);
245    ///
246    /// for signer in keychain.signers() {
247    ///     let pub_key = signer.public_key();
248    ///     println!("Key: {:?}", pub_key);
249    /// }
250    /// ```
251    pub fn signers(&self) -> impl Iterator<Item = &dyn SignerKey> {
252        self.keys.values().map(|k| k.as_ref())
253    }
254}
255
256impl Default for Keychain {
257    fn default() -> Self {
258        Self::new()
259    }
260}