use crate::error::{Error, Result};
use std::collections::VecDeque;
#[derive(Debug)]
pub struct SectionKeyShare {
pub public_key_set: bls::PublicKeySet,
pub index: usize,
pub secret_key_share: bls::SecretKeyShare,
}
#[derive(Debug)]
pub struct SectionKeysProvider {
cache: MiniKeyCache,
pending: Option<SectionKeyShare>,
}
impl SectionKeysProvider {
pub fn new(cache_size: u8, current: Option<SectionKeyShare>) -> Self {
let mut provider = Self {
pending: None,
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) {
self.pending = Some(share);
}
pub fn finalise_dkg(&mut self, public_key: &bls::PublicKey) {
if let Some(share) = &self.pending {
if *public_key != share.public_key_set.public_key() {
return;
}
}
if let Some(share) = self.pending.take() {
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
}
}