use crate::network_knowledge::{Error, Result, SectionAuthorityProvider};
use crate::types::log_markers::LogMarker;
use sn_dbc::{
Commitment, Hash, IndexedSignatureShare, RingCtTransaction, SpentProofContent, SpentProofShare,
};
use uluru::LRUCache;
const KEY_CACHE_SIZE: usize = 50;
#[derive(custom_debug::Debug, Clone)]
pub struct SectionKeyShare {
pub public_key_set: bls::PublicKeySet,
pub index: usize,
#[debug(skip)]
pub secret_key_share: bls::SecretKeyShare,
}
#[derive(Debug, Clone)]
pub struct SectionKeysProvider {
cache: Box<LRUCache<SectionKeyShare, KEY_CACHE_SIZE>>,
}
impl SectionKeysProvider {
pub fn new(current: Option<SectionKeyShare>) -> Self {
let mut section_keys_provider = Self {
cache: Box::default(),
};
if let Some(share) = current {
section_keys_provider.insert(share);
}
section_keys_provider
}
pub fn wipe(&mut self) {
self.cache.clear();
}
pub fn key_share(&self, public_key: &bls::PublicKey) -> Result<SectionKeyShare> {
match self
.cache
.iter()
.find(|share| public_key == &share.public_key_set.public_key())
{
Some(key_share) => Ok(key_share.clone()),
None => Err(Error::MissingSecretKeyShare(*public_key)),
}
}
pub fn sign_with(
&self,
data: &[u8],
public_key: &bls::PublicKey,
) -> Result<(usize, bls::SignatureShare)> {
let key_share = self.key_share(public_key)?;
Ok((key_share.index, key_share.secret_key_share.sign(data)))
}
pub fn is_empty(&self) -> bool {
self.cache.is_empty()
}
pub fn insert(&mut self, share: SectionKeyShare) {
let public_key = share.public_key_set.public_key();
if let Some(evicted) = self.cache.insert(share) {
trace!("evicted old key share from cache: {:?}", evicted);
}
let cache_len = self.cache.len();
trace!(
"{} in cache (total {cache_len}): {public_key:?}",
LogMarker::NewKeyShareStored,
);
}
}
pub fn build_spent_proof_share(
key_image: &bls::PublicKey,
tx: &RingCtTransaction,
sap: &SectionAuthorityProvider,
skp: &SectionKeysProvider,
public_commitments: Vec<Commitment>,
) -> Result<SpentProofShare> {
let content = SpentProofContent {
key_image: *key_image,
transaction_hash: Hash::from(tx.hash()),
public_commitments,
};
let (index, sig_share) = skp.sign_with(content.hash().as_ref(), &sap.section_key())?;
Ok(SpentProofShare {
content,
spentbook_pks: sap.public_key_set(),
spentbook_sig_share: IndexedSignatureShare::new(index as u64, sig_share),
})
}