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}