use crate::errors::{BottleError, Result};
use crate::signing::Sign;
use rand::RngCore;
use std::collections::HashMap;
pub struct Keychain {
keys: HashMap<Vec<u8>, Box<dyn SignerKey>>,
}
pub trait SignerKey: Sign + Send + Sync {
fn fingerprint(&self) -> Vec<u8>;
fn public_key(&self) -> Vec<u8>;
}
impl Keychain {
pub fn new() -> Self {
Self {
keys: HashMap::new(),
}
}
pub fn add_key<K: SignerKey + 'static>(&mut self, key: K) {
let fingerprint = key.fingerprint();
self.keys.insert(fingerprint, Box::new(key));
}
pub fn add_keys<K: SignerKey + 'static>(&mut self, keys: Vec<K>) {
for key in keys {
self.add_key(key);
}
}
pub fn get_key(&self, public_key: &[u8]) -> Result<&dyn SignerKey> {
let fingerprint = crate::hash::sha256(public_key);
self.keys
.get(&fingerprint)
.map(|k| k.as_ref())
.ok_or(BottleError::KeyNotFound)
}
pub fn get_signer(&self, public_key: &[u8]) -> Result<&dyn SignerKey> {
self.get_key(public_key)
}
pub fn sign<R: RngCore>(
&self,
rng: &mut R,
public_key: &[u8],
message: &[u8],
) -> Result<Vec<u8>> {
let signer = self.get_signer(public_key)?;
signer.sign(rng as &mut dyn RngCore, message)
}
pub fn signers(&self) -> impl Iterator<Item = &dyn SignerKey> {
self.keys.values().map(|k| k.as_ref())
}
}
impl Default for Keychain {
fn default() -> Self {
Self::new()
}
}