1use crate::admin::StoreChange;
4use crate::error::{bound, exact_length, require, Error, Rule};
5use crate::sealed;
6use crate::sealed_key::{CopyBox, KeyCopyPrefix};
7use crate::sequence::{SlotFrame, MAX_BOUNDED_SLOT};
8use crate::wire::{Decoder, Encoder, Wire};
9use coven_crypto::{
10 CircleKey, Signature, StoreKey, KEY_BOX_HEAD_LEN, KEY_BOX_TAG_LEN,
11 SEALED_OBJECT_CHUNK_OVERHEAD, SIGNATURE_LEN,
12};
13use coven_foundation::id_source::KeyId;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum BoxPlace {
19 KeyCopy,
21 Admission(u32),
23}
24
25#[derive(Clone, Debug, PartialEq, Eq)]
28pub enum SlotKind {
29 Admin,
31 Writes,
33 KeyCopy(CopyBox),
35 Announcement,
37 Admission(Vec<CopyBox>),
41}
42impl SlotKind {
43 pub fn tag(&self) -> u8 {
45 match self {
46 Self::Admin => 0,
47 Self::Writes => 1,
48 Self::KeyCopy(_) => 2,
49 Self::Announcement => 3,
50 Self::Admission(_) => 4,
51 }
52 }
53 pub fn boxes(&self) -> impl Iterator<Item = (BoxPlace, &CopyBox)> {
55 let (single, many) = match self {
56 Self::KeyCopy(copy) => (Some(copy), &[][..]),
57 Self::Admission(copies) => (None, &copies[..]),
58 Self::Admin | Self::Writes | Self::Announcement => (None, &[][..]),
59 };
60 single.map(|copy| (BoxPlace::KeyCopy, copy)).into_iter().chain(
61 many.iter().enumerate().map(|(index, copy)| (BoxPlace::Admission(index as u32), copy)),
62 )
63 }
64 pub fn check_frame(&self, frame: &SlotFrame) -> Result<(), Error> {
68 let admits = matches!(
69 frame,
70 SlotFrame::Admin(StoreChange::AdmitMember { .. } | StoreChange::RecoverMember { .. })
71 );
72 require(
73 match (self, frame) {
74 (Self::Admin, SlotFrame::Admin(_)) => !admits,
75 (Self::Admission(_), SlotFrame::Admin(_)) => admits,
76 (Self::KeyCopy(_), SlotFrame::KeyCopy)
77 | (Self::Announcement, SlotFrame::Announcement(_)) => true,
78 _ => false,
79 },
80 "slot kind",
81 Rule::Kind,
82 )
83 }
84}
85
86fn check_copies(copies: &[CopyBox]) -> Result<(), Error> {
89 require(!copies.is_empty(), "admission copies", Rule::Required)?;
90 let first = &copies[0];
91 require(
92 copies.iter().all(|copy| {
93 copy.routing.member == first.routing.member
94 && copy.routing.sealing == first.routing.sealing
95 }),
96 "admission copy recipient",
97 Rule::Recipient,
98 )?;
99 require(
100 copies.windows(2).all(|pair| {
101 (&pair[0].routing.audience, pair[0].routing.key)
102 < (&pair[1].routing.audience, pair[1].routing.key)
103 }),
104 "admission copy order",
105 Rule::Order,
106 )
107}
108
109#[derive(Clone, Debug, PartialEq, Eq)]
111pub struct SlotObjectPrefix {
112 pub format: crate::FormatVersion,
114 pub key: KeyId,
116 pub kind: SlotKind,
118}
119impl SlotObjectPrefix {
120 pub const MAX_LENGTH: usize = Self::FIXED_LEN
123 + KeyCopyPrefix::CIRCLE_LEN
124 + KEY_BOX_HEAD_LEN
125 + 4
126 + CircleKey::ENCODED_LEN
127 + KEY_BOX_TAG_LEN;
128 const FIXED_LEN: usize = 1 + 2 + 1 + 16 + 1;
130 pub fn encode(&self) -> Result<Vec<u8>, Error> {
132 let mut out = self.start()?;
133 match &self.kind {
134 SlotKind::KeyCopy(copy) => {
135 1u8.put(&mut out)?;
136 copy.put(&mut out)?;
137 }
138 SlotKind::Admission(copies) => {
139 check_copies(copies)?;
140 copies.put(&mut out)?;
141 }
142 SlotKind::Admin | SlotKind::Writes | SlotKind::Announcement => 0u8.put(&mut out)?,
143 }
144 Ok(out.bytes)
145 }
146 fn start(&self) -> Result<Encoder, Error> {
147 let mut out = Encoder::new();
148 out.bytes(&self.format.prefix(crate::kinds::SEQUENCE_SLOT))?;
149 self.kind.tag().put(&mut out)?;
150 self.key.put(&mut out)?;
151 Ok(out)
152 }
153 pub fn copy_context(
157 format: crate::FormatVersion,
158 key: KeyId,
159 place: BoxPlace,
160 routing: &KeyCopyPrefix,
161 ) -> Result<Vec<u8>, Error> {
162 let mut out = Encoder::new();
163 out.bytes(&format.prefix(crate::kinds::SEQUENCE_SLOT))?;
164 match place {
165 BoxPlace::KeyCopy => {
166 2u8.put(&mut out)?;
167 key.put(&mut out)?;
168 1u8.put(&mut out)?;
169 }
170 BoxPlace::Admission(index) => {
171 4u8.put(&mut out)?;
172 key.put(&mut out)?;
173 index.put(&mut out)?;
174 }
175 }
176 routing.put(&mut out)?;
177 Ok(out.bytes)
178 }
179 pub fn admission(bytes: &[u8]) -> Result<bool, Error> {
182 sealed::prefix(bytes, crate::kinds::SEQUENCE_SLOT)?;
183 Ok(*bytes.get(3).ok_or(Error::Truncated)? == 4)
184 }
185 pub fn length(bytes: &[u8]) -> Result<usize, Error> {
188 sealed::prefix(bytes, crate::kinds::SEQUENCE_SLOT)?;
189 let kind = *bytes.get(3).ok_or(Error::Truncated)?;
190 require(kind <= 4, "slot kind", Rule::Kind)?;
191 if kind == 4 {
192 let start = Self::FIXED_LEN - 1;
193 let count = bytes.get(start..start + 4).ok_or(Error::Truncated)?;
194 let count = u32::from_be_bytes(count.try_into().expect("four bytes")) as usize;
195 require(count > 0, "admission copies", Rule::Required)?;
196 bound(count, crate::wire::MAX_ITEMS, "admission copies")?;
197 let mut end = start + 4;
198 for _ in 0..count {
199 end = box_end(bytes, end)?;
200 }
201 return Ok(end);
202 }
203 let copy = *bytes.get(Self::FIXED_LEN - 1).ok_or(Error::Truncated)?;
204 require(copy == u8::from(kind == 2), "slot copy routing", Rule::Kind)?;
205 if kind != 2 {
206 return Ok(Self::FIXED_LEN);
207 }
208 box_end(bytes, Self::FIXED_LEN)
209 }
210 pub fn decode(bytes: &[u8]) -> Result<Self, Error> {
212 exact_length(bytes.len(), Self::length(bytes)?)?;
213 let mut input = Decoder::new(&bytes[4..])?;
214 let key = KeyId::get(&mut input)?;
215 let kind = match bytes[3] {
216 4 => {
217 let copies = Vec::<CopyBox>::get(&mut input)?;
218 check_copies(&copies)?;
219 SlotKind::Admission(copies)
220 }
221 tag => {
222 let copy = Option::<CopyBox>::get(&mut input)?;
223 match tag {
224 0 => SlotKind::Admin,
225 1 => SlotKind::Writes,
226 2 => SlotKind::KeyCopy(copy.expect("copy tag checked")),
227 3 => SlotKind::Announcement,
228 _ => unreachable!("kind checked"),
229 }
230 }
231 };
232 input.finish()?;
233 Ok(Self { format: crate::FormatVersion::decode(bytes)?, key, kind })
234 }
235 pub fn fits(&self, plaintext: usize) -> Result<bool, Error> {
239 Ok(bound(
240 Self::bounded_size(self.encode()?.len(), plaintext + SEALED_OBJECT_CHUNK_OVERHEAD),
241 MAX_BOUNDED_SLOT,
242 "slot object",
243 )
244 .is_ok())
245 }
246 fn bounded_size(prefix: usize, chunk: usize) -> usize {
249 prefix + 4 + chunk + SIGNATURE_LEN
250 }
251 pub fn encode_chunk(&self, chunk: &[u8]) -> Result<Vec<u8>, Error> {
255 require(!matches!(self.kind, SlotKind::Writes), "bounded slot kind", Rule::Kind)?;
256 let mut bytes = self.encode()?;
257 let length =
258 chunk.len().checked_sub(SEALED_OBJECT_CHUNK_OVERHEAD).ok_or(Error::Truncated)?;
259 require(length >= 2 * crate::FRAME_PREFIX_LEN, "slot frames", Rule::Chunk)?;
260 bound(Self::bounded_size(bytes.len(), chunk.len()), MAX_BOUNDED_SLOT, "slot object")?;
261 bytes.extend_from_slice(&sealed::encode_chunk(chunk)?);
262 Ok(bytes)
263 }
264}
265
266fn box_end(bytes: &[u8], start: usize) -> Result<usize, Error> {
270 let (routing, ciphertext) = match *bytes.get(start).ok_or(Error::Truncated)? {
271 0 => (KeyCopyPrefix::STORE_LEN, StoreKey::ENCODED_LEN),
272 1 => (KeyCopyPrefix::CIRCLE_LEN, CircleKey::ENCODED_LEN),
273 tag => return Err(Error::UnknownTag { field: "audience", tag }),
274 };
275 let offset = start + routing + KEY_BOX_HEAD_LEN;
276 let declared = bytes.get(offset..offset + 4).ok_or(Error::Truncated)?;
277 require(
278 u32::from_be_bytes(declared.try_into().expect("four bytes")) as usize == ciphertext,
279 "key box ciphertext",
280 Rule::StreamLength,
281 )?;
282 Ok(offset + 4 + ciphertext + KEY_BOX_TAG_LEN)
283}
284
285#[derive(Debug)]
287pub struct BoundedSlot<'a> {
288 pub prefix: SlotObjectPrefix,
290 pub chunk: &'a [u8],
292 pub signature: Signature,
294}
295impl<'a> BoundedSlot<'a> {
296 pub fn decode(bytes: &'a [u8]) -> Result<Self, Error> {
298 bound(bytes.len(), MAX_BOUNDED_SLOT, "slot object")?;
299 let prefix_length = SlotObjectPrefix::length(bytes)?;
300 let prefix = SlotObjectPrefix::decode(bytes.get(..prefix_length).ok_or(Error::Truncated)?)?;
301 require(!matches!(prefix.kind, SlotKind::Writes), "bounded slot kind", Rule::Kind)?;
302 let body = &bytes[prefix_length..];
303 let length = sealed::chunk_length(body, MAX_BOUNDED_SLOT)?;
304 let chunk = body.get(4..length).ok_or(Error::Truncated)?;
305 require(
306 chunk.len() >= SEALED_OBJECT_CHUNK_OVERHEAD + 2 * crate::FRAME_PREFIX_LEN,
307 "slot frames",
308 Rule::Chunk,
309 )?;
310 let signature = sealed::signature(body.get(length..).ok_or(Error::Truncated)?)?;
311 Ok(Self { prefix, chunk, signature })
312 }
313 pub fn encode(&self) -> Result<Vec<u8>, Error> {
315 let mut bytes = self.prefix.encode_chunk(self.chunk)?;
316 bytes.extend_from_slice(self.signature.as_bytes());
317 Ok(bytes)
318 }
319}
320
321#[cfg(test)]
322#[path = "sealed_slot_tests.rs"]
323mod tests;