use super::*;
#[derive(Clone)]
pub struct VerifiedKeys {
vault: Hash,
generations: Vec<Generation>,
keys: Vec<LocalSharedStatePackageKey>,
}
impl VerifiedKeys {
pub fn key(&self, generation: Hash) -> Result<&LocalSharedStatePackageKey> {
let index = self
.generations
.iter()
.position(|g| g.id == generation)
.context("error membership-key-missing")?;
Ok(&self.keys[index])
}
pub fn validate(&self, m: &Membership) -> Result<()> {
check(self.vault == m.genesis.context().vault_id && self.generations == m.generations)
}
pub(super) fn write(&self, out: &mut Vec<u8>) {
out.extend((self.keys.len() as u16).to_be_bytes());
for (g, key) in self.generations.iter().zip(&self.keys) {
out.extend(g.id);
out.extend(key.protected_storage_bytes());
out.extend(g.starts_after.to_be_bytes());
}
}
pub(super) fn read(m: &Membership, r: &mut Reader<'_>) -> Result<Self> {
check(u16::from_be_bytes(r.array()?) as usize == m.generations.len())?;
let mut keys = Vec::with_capacity(m.generations.len());
for g in &m.generations {
check(r.array::<32>()? == g.id)?;
let key = LocalSharedStatePackageKey::new(r.array()?);
check(r.array::<8>()? == g.starts_after.to_be_bytes())?;
check(
generation_commitment(
LocalSharedStatePackageContext {
vault_id: m.genesis.context().vault_id,
generation_id: g.id,
},
key.protected_storage_bytes(),
) == g.commitment,
)?;
keys.push(key);
}
check(r.0.is_empty())?;
Ok(Self {
vault: m.genesis.context().vault_id,
generations: m.generations.clone(),
keys,
})
}
pub(super) fn extended(&self, m: &Membership, key: LocalSharedStatePackageKey) -> Result<Self> {
check(
self.vault == m.genesis.context().vault_id
&& m.generations.len() == self.generations.len() + 1
&& m.generations.starts_with(&self.generations),
)?;
let mut bytes = Zeroizing::new(Vec::new());
bytes.extend((m.generations.len() as u16).to_be_bytes());
for (g, key) in self
.generations
.iter()
.zip(&self.keys)
.chain(std::iter::once((m.current_generation(), &key)))
{
bytes.extend(g.id);
bytes.extend(key.protected_storage_bytes());
bytes.extend(g.starts_after.to_be_bytes());
}
Self::read(m, &mut Reader(&bytes))
}
}
impl Membership {
pub fn verify_initial_key(&self, key: &LocalSharedStatePackageKey) -> Result<VerifiedKeys> {
self.validate_key(key)?;
Ok(VerifiedKeys {
vault: self.genesis.context().vault_id,
generations: self.generations.clone(),
keys: vec![key.clone()],
})
}
}
pub const MAX_COVERAGE_BYTES: usize = 40 + GENERATION_BYTES * MAX_GENERATIONS;
impl VerifiedKeys {
pub fn protected_storage_bytes(&self) -> Zeroizing<Vec<u8>> {
let mut out = Zeroizing::new(b"AVKC\0\x01".to_vec());
out.extend(self.vault);
self.write(&mut out);
out
}
pub fn from_protected_storage(m: &Membership, bytes: &[u8]) -> Result<Self> {
check(bytes.len() <= MAX_COVERAGE_BYTES)?;
let mut r = Reader(bytes);
check(r.take(6)? == b"AVKC\0\x01" && r.array::<32>()? == m.genesis.context().vault_id)?;
Self::read(m, &mut r)
}
}