Skip to main content

superfluid_executor/
envelope.rs

1//! The state envelope.
2
3use superfluid_abi::{checksum_kind, StateEnvelope, TokenRange, Status, STATE_ENVELOPE_MAGIC};
4
5pub const ENVELOPE_VERSION: u32 = 1;
6pub const ENVELOPE_BYTES: usize = std::mem::size_of::<StateEnvelope>();
7
8pub fn compat_identity(kind: u32, version_tag: u64, runtime: &str, version: &str, weights: &[u8; 32]) -> [u8; 32] {
9    let mut input = Vec::with_capacity(64 + runtime.len() + version.len());
10    input.extend_from_slice(&kind.to_le_bytes());
11    input.extend_from_slice(&version_tag.to_le_bytes());
12    input.extend_from_slice(runtime.as_bytes());
13    input.push(0);
14    input.extend_from_slice(version.as_bytes());
15    input.push(0);
16    input.extend_from_slice(weights);
17    let h = superfluid_fingerprint::fnv1a64(&input, 0xCBF2_9CE4_8422_2325);
18    let mut out = [0u8; 32];
19    out[..8].copy_from_slice(&h.to_le_bytes());
20    out[8..16].copy_from_slice(&superfluid_fingerprint::fnv1a64(&input, h).to_le_bytes());
21    out
22}
23
24pub struct SealArgs<'a> {
25    pub kind: u32,
26    pub version_tag: u64,
27    pub compat: [u8; 32],
28    pub provenance: [u8; 32],
29    pub taint_bits: u32,
30    pub range: TokenRange,
31    pub encoding: u8,
32    pub payload: &'a [u8],
33}
34
35pub fn seal(a: SealArgs<'_>) -> Vec<u8> {
36    let env = StateEnvelope {
37        magic: STATE_ENVELOPE_MAGIC,
38        envelope_version: ENVELOPE_VERSION,
39        space_kind: a.kind,
40        compat_identity: a.compat,
41        version_tag: a.version_tag,
42        provenance_digest: a.provenance,
43        taint_bits: a.taint_bits,
44        _pad0: 0,
45        range: a.range,
46        encoding: a.encoding,
47        _pad1: [0; 3],
48        checksum_kind: checksum_kind::FNV1A64,
49        payload_len: a.payload.len() as u64,
50        content_checksum: superfluid_fingerprint::fnv1a64(a.payload, 0xCBF2_9CE4_8422_2325),
51    };
52    let mut out = Vec::with_capacity(ENVELOPE_BYTES + a.payload.len());
53    // SAFETY: StateEnvelope is #[repr(C)] with explicit padding;
54    // viewing it as bytes is well-defined.
55    let env_bytes = unsafe { std::slice::from_raw_parts(&env as *const _ as *const u8, ENVELOPE_BYTES) };
56    out.extend_from_slice(env_bytes);
57    out.extend_from_slice(a.payload);
58    out
59}
60
61pub fn open<'a>(
62    bytes: &'a [u8],
63    kind: u32,
64    version_tag: u64,
65    compat: &[u8; 32],
66) -> Result<(StateEnvelope, &'a [u8]), Status> {
67    if bytes.len() < ENVELOPE_BYTES {
68        return Err(Status::EnvelopeMismatch);
69    }
70    let mut env = StateEnvelope::default();
71    // SAFETY: the source holds >= ENVELOPE_BYTES; the type accepts any bit
72    // pattern.
73    unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), &mut env as *mut _ as *mut u8, ENVELOPE_BYTES) };
74    if env.magic != STATE_ENVELOPE_MAGIC || env.envelope_version != ENVELOPE_VERSION {
75        return Err(Status::EnvelopeMismatch);
76    }
77    if env.space_kind != kind {
78        return Err(Status::EnvelopeMismatch);
79    }
80    if env.compat_identity != *compat || env.version_tag != version_tag {
81        return Err(Status::IdentityMismatch);
82    }
83    let payload = &bytes[ENVELOPE_BYTES..];
84    if payload.len() as u64 != env.payload_len {
85        return Err(Status::EnvelopeMismatch);
86    }
87    match env.checksum_kind {
88        checksum_kind::FNV1A64 => {
89            if superfluid_fingerprint::fnv1a64(payload, 0xCBF2_9CE4_8422_2325) != env.content_checksum {
90                return Err(Status::Checksum);
91            }
92        }
93        _ => return Err(Status::EnvelopeMismatch),
94    }
95    Ok((env, payload))
96}