use crate::error::{Error, Result};
use std::{
collections::{HashMap, VecDeque},
fmt::{self, Debug, Formatter},
};
pub struct SectionKeyShare {
pub public_key_set: bls::PublicKeySet,
pub index: usize,
pub secret_key_share: bls::SecretKeyShare,
}
impl Debug for SectionKeyShare {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(
f,
"SectionKeyShare {{ public_key: {:?}, index: {}, .. }}",
self.public_key_set.public_key(),
self.index
)
}
}
#[derive(Debug)]
pub struct SectionKeysProvider {
cache: MiniKeyCache,
pending: HashMap<bls::PublicKey, SectionKeyShare>,
}
impl SectionKeysProvider {
pub fn new(cache_size: u8, current: Option<SectionKeyShare>) -> Self {
let mut provider = Self {
pending: HashMap::new(),
cache: MiniKeyCache::with_capacity(cache_size as usize),
};
if let Some(share) = current {
let public_key = share.public_key_set.public_key();
provider.insert_dkg_outcome(share);
provider.finalise_dkg(&public_key);
}
provider
}
pub fn key_share(&self) -> Result<&SectionKeyShare> {
self.cache.get_most_recent()
}
pub fn sign_with(
&self,
data: &[u8],
public_key: &bls::PublicKey,
) -> Result<bls::SignatureShare> {
self.cache.sign_with(data, public_key)
}
pub fn has_key_share(&self) -> bool {
self.cache.has_key_share()
}
pub fn insert_dkg_outcome(&mut self, share: SectionKeyShare) {
let public_key = share.public_key_set.public_key();
let _ = self.pending.insert(public_key, share);
}
pub fn finalise_dkg(&mut self, public_key: &bls::PublicKey) {
if let Some(share) = self.pending.remove(public_key) {
if let Some(evicted) = self.cache.add(public_key, share) {
trace!("evicted old key from cache: {:?}", evicted);
}
trace!("finalised DKG: {:?}", public_key);
}
}
}
#[derive(Debug)]
pub struct MiniKeyCache {
list: VecDeque<(bls::PublicKey, SectionKeyShare)>,
}
impl MiniKeyCache {
pub fn with_capacity(capacity: usize) -> MiniKeyCache {
MiniKeyCache {
list: VecDeque::with_capacity(capacity),
}
}
pub fn has_key_share(&self) -> bool {
!self.list.is_empty()
}
pub fn get_most_recent(&self) -> Result<&SectionKeyShare> {
if let Some((_, share)) = self.list.back() {
return Ok(share);
}
Err(Error::MissingSecretKeyShare)
}
pub fn sign_with(
&self,
data: &[u8],
public_key: &bls::PublicKey,
) -> Result<bls::SignatureShare> {
for (cached_public, section_key_share) in &self.list {
if public_key == cached_public {
return Ok(section_key_share.secret_key_share.sign(data));
}
}
Err(Error::MissingSecretKeyShare)
}
pub fn add(
&mut self,
public_key: &bls::PublicKey,
section_key_share: SectionKeyShare,
) -> Option<bls::PublicKey> {
for (cached_public, _) in &self.list {
if public_key == cached_public {
return None;
}
}
let mut evicted = None;
if self.list.capacity() == self.list.len() {
if let Some((cached_public, _)) = self.list.pop_front() {
evicted = Some(cached_public);
}
}
self.list.push_back((*public_key, section_key_share));
evicted
}
}