aven-protocol 0.1.0

Storage-independent encrypted sync protocol for Aven
Documentation
use super::*;

pub(super) fn state_core(
    m: &Membership,
    d: &Declaration,
    request: &[u8],
    recipient: &Recipient,
) -> (Vec<u8>, Vec<u8>) {
    let mut next = m.clone();
    next.members.push(Member {
        device: recipient.device,
        sign: recipient.sign,
        hpke: recipient.hpke,
        verifier: recipient.verifier,
        admission: d.handle,
        admitted_at: m.sequence() + 1,
    });
    next.members.sort_by_key(|member| member.device);
    let state = encoding::state(&next);
    let mut action = b"AVAD\0\x02".to_vec();
    for field in [
        d.handle,
        d.commitment(),
        hash(request),
        recipient.device,
        recipient.sign,
        recipient.hpke,
        recipient.verifier,
    ] {
        action.extend(field);
    }
    action.extend(1_u32.to_be_bytes());
    action.extend(DOMAIN_VERSION.to_be_bytes());
    action.extend(recipient.pop);
    let core = encoding::core(m, d.inviter, 3, &action, &state);
    (state, core)
}

pub(super) fn grant_parts<'a>(
    attachments: &'a [u8],
    recipient: &Recipient,
    count: usize,
) -> Result<(&'a [u8], &'a [u8])> {
    let packages = encoding::read_packages(attachments, 1, 1, GRANT_PREFIX_BYTES + 2 + 72 * count)?;
    let p = &packages[0];
    check(p.device == recipient.device && p.public == recipient.hpke)?;
    Ok((p.enc, p.cipher))
}

pub(super) fn validate(
    m: &Membership,
    d: &Declaration,
    request: &[u8],
    raw: &[u8],
) -> Result<Recipient> {
    super::super::peer::request_parts(request, &d.handle)?;
    let (core, state, attachments, signature) = encoding::components(raw)?;
    check(core.len() == CORE_BYTES)?;
    let mut r = Reader(core);
    check(r.take(1)? == [1] && r.blob(32)? == m.genesis.context().vault_id)?;
    check(u64::from_be_bytes(r.array()?) == m.sequence() + 1 && r.blob(32)? == m.head())?;
    check(r.take(1)? == [1] && r.blob(32)? == d.inviter && r.take(1)? == [3])?;
    let mut a = Reader(r.blob(302)?);
    check(a.take(6)? == b"AVAD\0\x02")?;
    check(
        a.array::<32>()? == d.handle
            && a.array::<32>()? == d.commitment()
            && a.array::<32>()? == hash(request),
    )?;
    let device = a.array()?;
    let sign = a.array()?;
    let hpke = a.array()?;
    let verifier = a.array()?;
    check(u32::from_be_bytes(a.array()?) == 1 && u32::from_be_bytes(a.array()?) == DOMAIN_VERSION)?;
    let pop = a.array()?;
    a.end()?;
    r.blob(32)?;
    r.end()?;
    let recipient = Recipient {
        device,
        sign,
        hpke,
        verifier,
        pop,
    };
    m.unique(&recipient, &d.handle)?;
    recipient.verify(&m.genesis.context().vault_id, &d.handle, &d.hpke)?;
    let (expected_state, expected_core) = state_core(m, d, request, &recipient);
    check(state == expected_state && core == expected_core)?;
    grant_parts(attachments, &recipient, m.generations.len())?;
    verify(
        &m.member(&d.inviter)?.sign,
        MEMBERSHIP_SIGN,
        &[core, attachments],
        signature,
    )?;
    Ok(recipient)
}

pub(super) fn grant_plaintext(
    m: &Membership,
    d: &Declaration,
    request: &[u8],
    recipient: &Recipient,
    keys: &VerifiedKeys,
) -> Zeroizing<Vec<u8>> {
    let b = m.publication.binding();
    let mut out = Zeroizing::new(vec![3]);
    for field in [
        m.genesis.context().vault_id,
        d.handle,
        d.commitment(),
        hash(request),
        recipient.device,
        m.genesis.commitment(),
        m.publication.commitment(),
        m.head(),
        b.bootstrap_id,
        b.stream_id,
        b.descriptor_commitment,
        b.manifest_commitment,
    ] {
        out.extend(field);
    }
    out.extend(b.prefix_count.to_be_bytes());
    keys.write(&mut out);
    out
}

pub(super) fn signed(signing: &Secret, core: &[u8], state: &[u8], attachments: &[u8]) -> Vec<u8> {
    let sig =
        SigningKey::from_bytes(signing.expose()).sign(&cce(MEMBERSHIP_SIGN, &[core, attachments]));
    let mut raw = vec![1];
    for part in [core, state, attachments, &sig.to_bytes()] {
        bytes(&mut raw, part);
    }
    raw
}