Skip to main content

aven_protocol/
artifact.rs

1//! Descriptor, catalog and ordered whole-artifact verification.
2//! Structural verification does not authorize membership or publication.
3
4pub mod catalog;
5pub mod codec;
6pub mod staging;
7
8use crate::context::LocalSharedStatePackageContext;
9use catalog::{Artifact, Declaration};
10use codec::*;
11
12/// Privacy-safe failures. Resource refusal says nothing about domain validity.
13#[derive(Clone, Copy, Debug, PartialEq, Eq)]
14pub enum Error {
15    Invalid,
16    ResourceLimit,
17    Authentication,
18    Unsupported,
19}
20impl std::fmt::Display for Error {
21    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22        f.write_str(match self {
23            Self::Invalid => "invalid bootstrap representation",
24            Self::ResourceLimit => "bootstrap codec resource limit exceeded",
25            Self::Authentication => "bootstrap authentication failed",
26            Self::Unsupported => "unsupported bootstrap format version",
27        })
28    }
29}
30impl std::error::Error for Error {}
31pub type Result<T> = std::result::Result<T, Error>;
32
33/// Encrypted records that are either freshly owned or borrowed from a package.
34#[derive(Clone, Debug, PartialEq, Eq)]
35pub struct EncryptedArtifact<'a> {
36    pub total_plaintext_bytes: u64,
37    pub aggregate_commitment: [u8; 32],
38    pub chunks: Vec<EncryptedChunk<'a>>,
39}
40
41#[derive(Clone, Debug, PartialEq, Eq)]
42pub struct EncryptedChunk<'a> {
43    pub record_commitment: [u8; 32],
44    pub record: std::borrow::Cow<'a, [u8]>,
45}
46
47impl EncryptedArtifact<'_> {
48    /// Moves the records out without copying owned bytes.
49    pub fn into_records(self) -> Vec<Vec<u8>> {
50        self.chunks
51            .into_iter()
52            .map(|chunk| chunk.record.into_owned())
53            .collect()
54    }
55}
56
57#[derive(Clone, PartialEq, Eq)]
58pub struct Descriptor {
59    pub vault: [u8; 32],
60    pub stream: [u8; 32],
61    pub generation: [u8; 32],
62    pub bootstrap: [u8; 32],
63    // An already-known predecessor/genesis commitment, never PublishBootstrap.
64    pub membership: [u8; 32],
65    pub prefix: u64,
66    pub catalogs: [Declaration; 3],
67    pub manifest: Artifact,
68}
69
70impl Descriptor {
71    pub fn context(&self) -> LocalSharedStatePackageContext {
72        LocalSharedStatePackageContext {
73            vault_id: self.vault,
74            generation_id: self.generation,
75        }
76    }
77    pub fn binding(&self) -> Vec<u8> {
78        let mut out = b"AVBP\0\x02\x01".to_vec();
79        for id in [
80            self.vault,
81            self.stream,
82            self.generation,
83            self.bootstrap,
84            self.membership,
85        ] {
86            out.extend_from_slice(&id);
87        }
88        u64_bytes(&mut out, self.prefix);
89        for (index, declaration) in self.catalogs.iter().enumerate() {
90            out.push(index as u8 + 1);
91            declaration.write(&mut out);
92        }
93        out
94    }
95    pub fn encode(&self) -> Result<Vec<u8>> {
96        let mut out = self.binding();
97        self.manifest.write(&mut out)?;
98        Ok(out)
99    }
100    pub fn decode(bytes: &[u8]) -> Result<Self> {
101        bound(number(bytes.len())?, MAX_DESCRIPTOR_BYTES as u64)?;
102        let mut r = Reader(bytes);
103        valid(r.take(4)? == b"AVBP")?;
104        if r.take(2)? != [0, 2] {
105            return Err(Error::Unsupported);
106        }
107        valid(r.byte()? == 1)?;
108        let vault = r.array()?;
109        let stream = r.array()?;
110        let generation = r.array()?;
111        let bootstrap = r.array()?;
112        let membership = r.array()?;
113        let prefix = r.u64()?;
114        valid(prefix < i64::MAX as u64)?;
115        bound(prefix, RECORD_LIMIT)?;
116        valid(r.byte()? == 1)?;
117        let data = Declaration::read(&mut r)?;
118        valid(r.byte()? == 2)?;
119        let ids = Declaration::read(&mut r)?;
120        valid(r.byte()? == 3)?;
121        let images = Declaration::read(&mut r)?;
122        let manifest = Artifact::read(&mut r, CHUNK, false)?;
123        r.end()?;
124        Ok(Self {
125            vault,
126            stream,
127            generation,
128            bootstrap,
129            membership,
130            prefix,
131            catalogs: [data, ids, images],
132            manifest,
133        })
134    }
135}
136
137pub fn state_catalog(state: &Artifact) -> Result<Vec<u8>> {
138    let mut row = vec![1];
139    state.write(&mut row)?;
140    stream(1, &[row])
141}
142
143pub fn decode_state_catalog(bytes: &[u8]) -> Result<Artifact> {
144    let records = read_stream(bytes, 1)?;
145    valid(records.len() == 1)?;
146    let mut r = Reader(records[0]);
147    valid(r.byte()? == 1)?;
148    let state = Artifact::read(&mut r, STATE_LIMIT, false)?;
149    r.end()?;
150    Ok(state)
151}
152
153#[cfg(test)]
154mod tests;