Skip to main content

coven_format/
sealed_floor.rs

1//! Streamed floor routing: a key id, first kept slot and original key copies (D9).
2//! The clear prefix has no total-size bound. Each returned piece is bounded.
3
4use crate::error::{bound, exact_length, require, Error, Rule};
5use crate::floor::OriginalSlot;
6use crate::value::Slot;
7use crate::wire::{Decoder, Encoder, Wire, MAX_ITEMS};
8use coven_foundation::id_source::KeyId;
9
10/// Incremental clear-prefix encoder. Retains only the count and previous slot.
11pub struct FloorPrefixEncoder {
12    remaining: u32,
13    previous: Option<Slot>,
14}
15impl FloorPrefixEncoder {
16    /// Emit kind 39, format, store key, first kept slot and copy count.
17    pub fn start(key: KeyId, first: Slot, copies: u32) -> Result<(Self, Vec<u8>), Error> {
18        bound(copies as usize, MAX_ITEMS, "floor key copies")?;
19        let mut out = Encoder::new();
20        out.bytes(&crate::FormatVersion::CURRENT.prefix(crate::kinds::FLOOR))?;
21        key.put(&mut out)?;
22        first.put(&mut out)?;
23        copies.put(&mut out)?;
24        Ok((Self { remaining: copies, previous: None }, out.bytes))
25    }
26    /// Emit one exact original key-copy slot in increasing slot order.
27    pub fn copy(&mut self, copy: &OriginalSlot) -> Result<Vec<u8>, Error> {
28        check_copy(self.remaining, self.previous, copy)?;
29        let mut out = Encoder::new();
30        copy.put(&mut out)?;
31        self.remaining -= 1;
32        self.previous = Some(copy.slot);
33        Ok(out.bytes)
34    }
35    /// Require all declared copies before emitting encrypted floor chunks.
36    pub fn finish(self) -> Result<(), Error> {
37        require(self.remaining == 0, "floor key copies", Rule::StreamLength)
38    }
39}
40
41/// Incremental clear-prefix decoder. Supply one bounded copy piece at a time.
42pub struct FloorPrefixDecoder {
43    /// Store key sealing the floor stream.
44    pub key: KeyId,
45    /// First kept slot; guides key discovery until the floor authenticates.
46    pub first: Slot,
47    remaining: u32,
48    previous: Option<Slot>,
49}
50impl FloorPrefixDecoder {
51    /// Exact initial routing length, before copy pieces.
52    pub const HEADER_LENGTH: usize = 31;
53    /// Read exactly the initial routing and bounded copy count.
54    pub fn start(bytes: &[u8]) -> Result<Self, Error> {
55        crate::sealed::prefix(bytes, crate::kinds::FLOOR)?;
56        let mut input = Decoder::new(&bytes[3..])?;
57        let key = KeyId::get(&mut input)?;
58        let first = <Slot as Wire>::get(&mut input)?;
59        let remaining = u32::get(&mut input)?;
60        bound(remaining as usize, MAX_ITEMS, "floor key copies")?;
61        input.finish()?;
62        Ok(Self { key, first, remaining, previous: None })
63    }
64    /// Number of copy pieces still needed, before the encrypted body begins.
65    pub fn remaining(&self) -> u32 {
66        self.remaining
67    }
68    /// Bound one copy's slot and length fields before allocating its body.
69    pub fn copy_length(&self, bytes: &[u8]) -> Result<usize, Error> {
70        require(self.remaining > 0, "floor key copy count", Rule::StreamLength)?;
71        let length = bytes.get(8..12).ok_or(Error::Truncated)?;
72        let length = u32::from_be_bytes(length.try_into().expect("four bytes")) as usize;
73        bound(length, crate::sequence::MAX_BOUNDED_SLOT, "floor key copy")?;
74        Ok(12 + length)
75    }
76    /// Decode one complete original slot, keeping its signed bytes intact.
77    pub fn copy(&mut self, bytes: &[u8]) -> Result<OriginalSlot, Error> {
78        exact_length(bytes.len(), self.copy_length(bytes)?)?;
79        let mut input = Decoder::new(bytes)?;
80        let copy = OriginalSlot::get(&mut input)?;
81        input.finish()?;
82        check_copy(self.remaining, self.previous, &copy)?;
83        self.remaining -= 1;
84        self.previous = Some(copy.slot);
85        Ok(copy)
86    }
87    /// Refuse a prefix missing any declared copy.
88    pub fn finish(self) -> Result<(), Error> {
89        require(self.remaining == 0, "floor key copies", Rule::StreamLength)
90    }
91}
92fn check_copy(remaining: u32, previous: Option<Slot>, copy: &OriginalSlot) -> Result<(), Error> {
93    require(
94        remaining > 0 && previous.is_none_or(|slot| slot < copy.slot),
95        "floor key-copy order",
96        Rule::Order,
97    )?;
98    // Key-copy slots and admissions carry copies (D9).
99    copy.validate_kind(&[2, 4])
100}