Skip to main content

vitaminc_aead/plaintext/
mod.rs

1//! The plaintext data model: a source describes itself once ([`Encrypt`])
2//! to a consumer ([`Sink`]), the way serde splits `Serialize` from
3//! `Serializer`.
4//!
5//! - **Containers are push-style.** [`SeqSink::element`] returns a sink for
6//!   the next element rather than taking the element as a value, so the
7//!   source drives the whole walk and any number of sinks can share it
8//!   (see [`Tee`]).
9//! - **Sources can fail.** Every sink error implements [`Error`], so a
10//!   source can stop the walk with [`Error::source`] without knowing which
11//!   sink it is feeding. That is what lets a native binding walk a live host
12//!   object, where a getter can throw, without taking a snapshot first.
13//! - **Lengths are optional,** for host iterables that do not know their
14//!   size.
15//! - **A scalar is a physical value plus an optional logical type.** One
16//!   [`Sink::scalar`] method takes a [`Physical`] value and an optional
17//!   [`Logical`] type, rather than a method per kind. See [`kinds`].
18//!
19//! `Sink` is implemented inside vitaminc and its host bindings. Application
20//! code implements `Encrypt`, usually by derive.
21
22pub mod depth;
23pub mod kinds;
24mod path;
25mod sources;
26mod tee;
27
28pub use kinds::{
29    FixedType, Float, Int, Kind, KnownLogical, Logical, Physical, TimeUnit, UnknownLogical,
30    UnknownLogicalId, Width,
31};
32#[cfg(any(test, feature = "test-support"))]
33#[doc(hidden)]
34pub use path::render;
35pub use path::{Path, Step};
36pub use sources::{Bytes, Raw};
37
38/// What `#[derive(Encrypt)]`'s expansion needs by path. Not an API.
39#[doc(hidden)]
40pub mod __private {
41    pub use super::sources::discard_one;
42}
43pub use tee::Tee;
44
45/// A value that can describe itself to a [`Sink`].
46///
47/// Implemented by Rust primitives and containers, by the optional chrono,
48/// `rust_decimal` and uuid types, and by host bindings for their own values.
49/// A struct implements it by walking its fields into a map, which is what
50/// `#[derive(Encrypt)]` generates.
51///
52/// `Encrypt` and [`Decrypt`](crate::Decrypt) are the pair a type implements
53/// to say how it is encrypted and decrypted. Neither does any cryptography:
54/// that is the [`Cipher`](crate::Cipher)'s job, and the same walk also
55/// feeds sinks that are not ciphers, such as equality terms and the
56/// transport frame. This trait replaces the visitor-based `Encrypt` of
57/// vitaminc 0.5, which drove a cipher directly.
58///
59/// # Owned values and `Protected`
60///
61/// A source implements `Encrypt` for `T` and for `&T`. The by-value walk
62/// consumes the value; the borrowed walk hands the sink borrows of what
63/// the value holds and leaves it where it is. `Protected<T>` walks as a
64/// borrow of what it wraps, so nothing leaves the wrapper during the walk
65/// and everything in it, visited or not, is zeroized when it drops. That
66/// is why a type that is to sit inside a `Protected`, a derived struct
67/// included, needs the borrowed impl; the derive generates it.
68///
69/// An owned byte or text leaf (`String`, `Vec<u8>`, `[u8; N]`) wraps itself
70/// in a `Protected` before the sink sees it, so its buffer is wiped however
71/// it arrives. A bare container that is walked by value and stops part way
72/// discards the children it did not reach through their own walks, so
73/// their owned leaves are wiped too rather than dropped bare. A
74/// hand-written leaf that owns a secret buffer should wrap itself the same
75/// way, and a hand-written container should not drop unvisited children
76/// bare.
77pub trait Encrypt {
78    /// How deep a value of this type can nest below its own root, when the
79    /// type alone fixes it: `Some(0)` for a scalar, one more than its
80    /// deepest child for a sequence or map (see [`depth`]). `None`, the
81    /// default, when it depends on the value: a recursive type, a frame, a
82    /// live host value.
83    ///
84    /// `#[derive(Encrypt)]` works this out from the fields' depths and fails
85    /// to compile a type deeper than [`MAX_DEPTH`](crate::frame::MAX_DEPTH),
86    /// whose fully populated values the encrypting sink would always
87    /// refuse. A hand-written impl may leave it `None`, which skips the
88    /// check for every type that contains it; the walk still refuses a
89    /// value that is too deep. It must never be more than the deepest a
90    /// value of the type can nest, or a type that is fine fails to compile.
91    const DEPTH: Option<usize> = None;
92
93    /// The fixed-width scalar type every value of this type has, if it has
94    /// one: an int, a float, a date, a timestamp, a decimal. `None`, the
95    /// default, for everything else: a bool (whose leaf is already as short
96    /// as a null's), text, bytes, a container, a value whose type depends
97    /// on the value.
98    ///
99    /// `Option<Self>` walks its `None` as a [`Sink::typed_null`] of this
100    /// type, so the encrypting sink seals it padded to the length of a
101    /// `Some`, and [`Decrypt`](crate::Decrypt) reads that typed null back
102    /// only into an `Option` of the same type. It must be the type
103    /// [`visit`](Encrypt::visit) always walks, normalised as
104    /// [`FixedType`] normalises it, or a `None` and a `Some` seal at
105    /// different lengths.
106    const FIXED: Option<FixedType> = None;
107
108    /// Describe `self` to `sink`, consuming it.
109    fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error>;
110}
111
112/// Every sink's error type.
113///
114/// A source reports its own failure through [`source`](Error::source),
115/// without knowing which sink it is feeding.
116pub trait Error: Sized {
117    /// Wrap a failure that came from the source, not the sink.
118    fn source(error: SourceError) -> Self;
119}
120
121/// A failure reading the source: a host getter threw, a string had an
122/// unpaired surrogate, a big integer was out of range, a timestamp was a
123/// leap second.
124///
125/// Transparent: it displays as the wrapped error, and its `source()` is the
126/// wrapped error's, so a reporter that walks the chain sees what lies behind
127/// a failed getter.
128#[derive(Debug, thiserror::Error)]
129#[error(transparent)]
130pub struct SourceError(Box<dyn core::error::Error + Send + Sync>);
131
132impl SourceError {
133    /// A source error from any error type.
134    pub fn new(error: impl core::error::Error + Send + Sync + 'static) -> Self {
135        Self(Box::new(error))
136    }
137
138    /// A source error from a message.
139    pub fn msg(msg: impl Into<String>) -> Self {
140        Self(msg.into().into())
141    }
142
143    /// The underlying error, which can be downcast to its concrete type.
144    pub fn inner(&self) -> &(dyn core::error::Error + Send + Sync + 'static) {
145        &*self.0
146    }
147}
148
149/// A consumer of one value's description.
150///
151/// A sink is used once: each method takes `self`. Containers hand back a
152/// [`SeqSink`] or [`MapSink`] that produces one child sink per element or
153/// entry.
154pub trait Sink: Sized {
155    /// What the sink produces when the walk ends.
156    type Ok;
157    /// The sink's error, which can also carry a [`SourceError`].
158    type Error: Error;
159    /// The sink for a sequence's elements.
160    type Seq: SeqSink<Ok = Self::Ok, Error = Self::Error>;
161    /// The sink for a map's entries.
162    type Map: MapSink<Ok = Self::Ok, Error = Self::Error>;
163
164    /// One scalar: a physical value, and the logical type it represents,
165    /// if any. See [`kinds`].
166    ///
167    /// # Examples
168    ///
169    /// A plain value has no logical type. A value that means something
170    /// more names the type it is stored as, and the sink checks that the
171    /// physical value fits it ([`Logical::admits`]).
172    ///
173    /// ```
174    /// use vitaminc_aead::plaintext::{Int, Logical, Physical, Encrypt, Sink};
175    ///
176    /// struct Celsius(i32);
177    ///
178    /// impl Encrypt for Celsius {
179    ///     fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
180    ///         sink.scalar(None, Physical::Int(Int::I32(self.0)))
181    ///     }
182    /// }
183    ///
184    /// /// Days since 1970-01-01.
185    /// struct Day(i32);
186    ///
187    /// impl Encrypt for Day {
188    ///     fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
189    ///         sink.scalar(Some(Logical::Date), Physical::Int(Int::I32(self.0)))
190    ///     }
191    /// }
192    /// ```
193    fn scalar(self, ty: Option<Logical>, value: Physical<'_>) -> Result<Self::Ok, Self::Error>;
194
195    /// An absent value of a fixed-width type: a null that says what it
196    /// stands in for. `Option<T>` walks its `None` here when `T` has a
197    /// [`FIXED`](Encrypt::FIXED) type, and a host that knows a missing
198    /// value's type does the same.
199    ///
200    /// It means what `scalar(None, Physical::Null)` means; the type is
201    /// there so its length can be hidden. The encrypting sink seals it as a
202    /// typed null padded to the type's leaf length (see
203    /// [`tags::TYPED_NULL`](crate::tags::TYPED_NULL)), the frame carries
204    /// it, and a typed decode target reads it only as an `Option` of the
205    /// same type. A sink that only needs to know a value is absent treats
206    /// it as a null. A sink that forwards to other sinks must forward it as
207    /// it is, or the padding is lost and absent values show again.
208    fn typed_null(self, ty: FixedType) -> Result<Self::Ok, Self::Error>;
209
210    /// Start a sequence. `len` is a hint; a source that does not know its
211    /// length passes `None`.
212    fn seq(self, len: Option<usize>) -> Result<Self::Seq, Self::Error>;
213
214    /// Start a map with string keys. `len` is a hint.
215    fn map(self, len: Option<usize>) -> Result<Self::Map, Self::Error>;
216
217    /// A subtree that travels in the clear. It is walked like anything
218    /// else; the sink decides what "in the clear" means for it.
219    ///
220    /// The value is `Clone` so that a sink which is really several sinks
221    /// (see [`Tee`]) can give the subtree to each of them. Passthrough is
222    /// non-sensitive by contract, so the copy carries no secret.
223    fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, Self::Error>;
224}
225
226/// The sink for a sequence's elements.
227pub trait SeqSink: Sized {
228    type Ok;
229    type Error: Error;
230    /// A sink for one element. It borrows the sequence sink and writes
231    /// into it; its own `Ok` is incidental.
232    type Element<'s>: Sink<Error = Self::Error>
233    where
234        Self: 's;
235
236    /// A sink for the next element.
237    fn element(&mut self) -> Result<Self::Element<'_>, Self::Error>;
238
239    /// Finish the sequence.
240    fn end(self) -> Result<Self::Ok, Self::Error>;
241}
242
243/// The sink for a map's entries. Keys are strings and travel in the clear.
244pub trait MapSink: Sized {
245    type Ok;
246    type Error: Error;
247    /// A sink for one entry's value.
248    type Entry<'s>: Sink<Error = Self::Error>
249    where
250        Self: 's;
251
252    /// A sink for the value under `key`.
253    fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, Self::Error>;
254
255    /// Finish the map.
256    fn end(self) -> Result<Self::Ok, Self::Error>;
257}
258
259/// Walk each item into its own element sink: the loop every sequence
260/// source writes.
261pub fn visit_seq<S, I>(sink: S, len: Option<usize>, items: I) -> Result<S::Ok, S::Error>
262where
263    S: Sink,
264    I: IntoIterator,
265    I::Item: Encrypt,
266{
267    let mut seq = sink.seq(len)?;
268    for item in items {
269        item.visit(seq.element()?)?;
270    }
271    seq.end()
272}
273
274/// Walk each `(key, value)` into its own entry sink: the loop every map
275/// source writes.
276///
277/// # Examples
278///
279/// ```
280/// use std::collections::BTreeMap;
281/// use vitaminc_aead::plaintext::{visit_map, Encrypt, Sink};
282///
283/// struct Scores(BTreeMap<String, u32>);
284///
285/// impl Encrypt for Scores {
286///     fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
287///         let len = Some(self.0.len());
288///         visit_map(sink, len, self.0.iter().map(|(name, score)| (name.as_str(), *score)))
289///     }
290/// }
291/// ```
292pub fn visit_map<'k, S, I, P>(sink: S, len: Option<usize>, entries: I) -> Result<S::Ok, S::Error>
293where
294    S: Sink,
295    I: IntoIterator<Item = (&'k str, P)>,
296    P: Encrypt,
297{
298    let mut map = sink.map(len)?;
299    for (key, value) in entries {
300        value.visit(map.entry(key)?)?;
301    }
302    map.end()
303}
304
305#[cfg(test)]
306pub(crate) mod record {
307    //! A sink that records every call, for tests of sources and of sinks
308    //! that forward to other sinks.
309
310    use super::*;
311
312    #[derive(Debug, Clone, PartialEq)]
313    pub enum Event {
314        Scalar(Option<Logical>, Owned),
315        TypedNull(FixedType),
316        Seq(Option<usize>),
317        Element,
318        EndSeq,
319        Map(Option<usize>),
320        Entry(String),
321        EndMap,
322        Passthrough,
323    }
324
325    /// An owned copy of a physical value, so a recording can outlive the
326    /// borrow a source handed over.
327    #[derive(Debug, Clone, PartialEq)]
328    pub enum Owned {
329        Null,
330        Bool(bool),
331        Int(Int),
332        Float(Float),
333        Text(String),
334        Bytes(Vec<u8>),
335    }
336
337    impl From<Physical<'_>> for Owned {
338        fn from(v: Physical<'_>) -> Self {
339            match v {
340                Physical::Null => Owned::Null,
341                Physical::Bool(b) => Owned::Bool(b),
342                Physical::Int(i) => Owned::Int(i),
343                Physical::Float(f) => Owned::Float(f),
344                Physical::Text(s) => Owned::Text(s.to_owned()),
345                Physical::Bytes(b) => Owned::Bytes(b.to_vec()),
346            }
347        }
348    }
349
350    #[derive(Debug)]
351    pub struct RecordError(pub String);
352
353    impl Error for RecordError {
354        fn source(error: SourceError) -> Self {
355            Self(error.to_string())
356        }
357    }
358
359    /// Records into a shared log. `Ok` is `()`.
360    pub struct Record<'l>(pub &'l mut Vec<Event>);
361
362    impl Sink for Record<'_> {
363        type Ok = ();
364        type Error = RecordError;
365        type Seq = Self;
366        type Map = Self;
367
368        fn scalar(self, ty: Option<Logical>, value: Physical<'_>) -> Result<(), RecordError> {
369            self.0.push(Event::Scalar(ty, value.into()));
370            Ok(())
371        }
372
373        fn typed_null(self, ty: FixedType) -> Result<(), RecordError> {
374            self.0.push(Event::TypedNull(ty));
375            Ok(())
376        }
377
378        fn seq(self, len: Option<usize>) -> Result<Self, RecordError> {
379            self.0.push(Event::Seq(len));
380            Ok(self)
381        }
382
383        fn map(self, len: Option<usize>) -> Result<Self, RecordError> {
384            self.0.push(Event::Map(len));
385            Ok(self)
386        }
387
388        fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<(), RecordError> {
389            self.0.push(Event::Passthrough);
390            value.visit(Record(self.0))
391        }
392    }
393
394    impl SeqSink for Record<'_> {
395        type Ok = ();
396        type Error = RecordError;
397        type Element<'s>
398            = Record<'s>
399        where
400            Self: 's;
401
402        fn element(&mut self) -> Result<Record<'_>, RecordError> {
403            self.0.push(Event::Element);
404            Ok(Record(self.0))
405        }
406
407        fn end(self) -> Result<(), RecordError> {
408            self.0.push(Event::EndSeq);
409            Ok(())
410        }
411    }
412
413    impl MapSink for Record<'_> {
414        type Ok = ();
415        type Error = RecordError;
416        type Entry<'s>
417            = Record<'s>
418        where
419            Self: 's;
420
421        fn entry(&mut self, key: &str) -> Result<Record<'_>, RecordError> {
422            self.0.push(Event::Entry(key.to_owned()));
423            Ok(Record(self.0))
424        }
425
426        fn end(self) -> Result<(), RecordError> {
427            self.0.push(Event::EndMap);
428            Ok(())
429        }
430    }
431
432    /// Walk `p` and return what a sink would have seen.
433    pub fn record<P: Encrypt>(p: P) -> Result<Vec<Event>, RecordError> {
434        let mut log = Vec::new();
435        p.visit(Record(&mut log))?;
436        Ok(log)
437    }
438}