aven-protocol 0.1.0

Storage-independent encrypted sync protocol for Aven
Documentation
//! Canonical bounded framing shared by membership actions.
use super::*;

pub(super) type Components<'a> = (&'a [u8], &'a [u8], &'a [u8], &'a [u8]);
pub(super) fn blob<'a>(r: &mut Reader<'a>, limit: usize) -> Result<&'a [u8]> {
    let n = u32::from_be_bytes(r.array()?) as usize;
    check(n <= limit)?;
    r.take(n)
}
pub(super) fn components(raw: &[u8]) -> Result<Components<'_>> {
    check(raw.len() <= MAX_RECORD_BYTES)?;
    let mut r = Reader(raw);
    check(r.take(1)? == [1])?;
    let parts = (
        blob(&mut r, MAX_RECORD_BYTES)?,
        blob(&mut r, MAX_RECORD_BYTES)?,
        blob(&mut r, MAX_RECORD_BYTES)?,
        r.blob(64)?,
    );
    r.end()?;
    Ok(parts)
}
pub(super) fn signer_action(core: &[u8]) -> Result<(Hash, u8)> {
    let mut r = Reader(core);
    check(r.take(1)? == [1])?;
    r.blob(32)?;
    r.take(8)?;
    r.blob(32)?;
    check(r.take(1)? == [1])?;
    let signer = r.blob(32)?.try_into()?;
    Ok((signer, r.take(1)?[0]))
}
pub(super) fn state(m: &Membership) -> Vec<u8> {
    let mut out = b"AVGS\0\x05\x01".to_vec();
    out.extend(m.genesis.context().vault_id);
    out.push(1);
    out.extend(m.publication.binding().tuple());
    out.extend([u8::from(m.pending), 0]);
    out.extend((m.members.len() as u16).to_be_bytes());
    for member in &m.members {
        member.write(&mut out);
    }
    out.extend((m.generations.len() as u16).to_be_bytes());
    for g in &m.generations {
        out.extend(g.id);
        out.extend(g.commitment);
        out.extend(g.starts_after.to_be_bytes());
    }
    out
}
pub(super) fn core(m: &Membership, signer: Hash, action: u8, body: &[u8], state: &[u8]) -> Vec<u8> {
    membership_core(
        &m.genesis.context().vault_id,
        m.sequence() + 1,
        &m.head(),
        &signer,
        action,
        body,
        state,
    )
}
pub(super) fn packages(count: usize) -> Vec<u8> {
    let mut out = b"AVGA\0\x05".to_vec();
    out.extend((count as u16).to_be_bytes());
    out
}
pub(super) fn package(
    out: &mut Vec<u8>,
    mode: u8,
    device: &Hash,
    public: &Hash,
    enc: &[u8],
    cipher: &[u8],
) {
    out.extend([1, mode]);
    for field in [device.as_slice(), public, enc, cipher] {
        bytes(out, field);
    }
}
pub(super) struct Package<'a> {
    pub device: Hash,
    pub public: Hash,
    pub enc: &'a [u8],
    pub cipher: &'a [u8],
}
pub(super) fn read_packages(
    raw: &[u8],
    mode: u8,
    count: usize,
    plaintext_len: usize,
) -> Result<Vec<Package<'_>>> {
    check(count <= MAX_DEVICES && plaintext_len <= MAX_KEY_PLAINTEXT_BYTES)?;
    let mut r = Reader(raw);
    check(r.take(6)? == b"AVGA\0\x05" && u16::from_be_bytes(r.array()?) as usize == count)?;
    let mut result = Vec::with_capacity(count);
    let mut previous = None;
    for _ in 0..count {
        check(r.take(2)? == [1, mode])?;
        let device: Hash = r.blob(32)?.try_into()?;
        check(previous.is_none_or(|p| p < device))?;
        previous = Some(device);
        result.push(Package {
            device,
            public: r.blob(32)?.try_into()?,
            enc: r.blob(32)?,
            cipher: r.blob(plaintext_len + 16)?,
        });
    }
    r.end()?;
    Ok(result)
}