use core::marker::PhantomData;
use std::collections::{BTreeMap, HashMap};
use vitaminc_protected::{Controlled, Protected};
use zeroize::Zeroize;
use crate::plaintext::{
Encrypt, Error, Float, Logical, MapSink, Physical, SeqSink, Sink, SourceError,
};
use crate::seal::{AsyncCipher, Cipher, Node};
use crate::walk::{decrypt_into, decrypt_into_async, DecryptError};
use crate::IntoAad;
#[doc(inline)]
pub use vitaminc_aead_derive::Decrypt;
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum DecodeError {
#[error("expected {0}")]
Expected(&'static str),
#[error("unknown key {0:?}")]
UnknownKey(String),
#[error("duplicate key {0:?}")]
DuplicateKey(String),
#[error("missing field {0:?}")]
MissingField(&'static str),
#[error("source failed: {0}")]
Source(#[source] SourceError),
}
impl DecodeError {
pub fn unknown_key(key: &str) -> Self {
Self::UnknownKey(key.to_owned())
}
pub fn duplicate_key(key: &str) -> Self {
Self::DuplicateKey(key.to_owned())
}
}
impl Error for DecodeError {
fn source(error: SourceError) -> Self {
Self::Source(error)
}
}
pub trait Decrypt: Sized {
type Sink: Sink<Ok = Self, Error = DecodeError>;
fn sink() -> Self::Sink;
}
pub fn decrypt<'a, T, C, A>(
cipher: &C,
node: Node<C::Leaf>,
aad: A,
) -> Result<T, DecryptError<DecodeError, C::Error>>
where
T: Decrypt,
C: Cipher,
A: IntoAad<'a>,
{
decrypt_into(cipher, node, aad, T::sink())
}
pub async fn decrypt_async<'a, T, C, A>(
cipher: &C,
node: Node<C::Leaf>,
aad: A,
) -> Result<T, DecryptError<DecodeError, C::Error>>
where
T: Decrypt,
C: AsyncCipher,
A: IntoAad<'a>,
{
decrypt_into_async(cipher, node, aad, T::sink()).await
}
pub trait FromScalar: Sized {
const EXPECTED: &'static str;
fn from_scalar(ty: Option<Logical>, value: Physical<'_>) -> Option<Self>;
fn from_scalar_protected(ty: Option<Logical>, value: Physical<'_>) -> Option<Protected<Self>>
where
Self: Zeroize,
{
Self::from_scalar(ty, value).map(Protected::new)
}
}
pub struct ScalarSink<T>(PhantomData<T>);
impl<T: FromScalar> Sink for ScalarSink<T> {
type Ok = T;
type Error = DecodeError;
type Seq = Never<T>;
type Map = Never<T>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<T, DecodeError> {
T::from_scalar(ty, v).ok_or(DecodeError::Expected(T::EXPECTED))
}
fn seq(self, _: Option<usize>) -> Result<Never<T>, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
fn map(self, _: Option<usize>) -> Result<Never<T>, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<T, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
}
impl<T: FromScalar> Decrypt for T {
type Sink = ScalarSink<T>;
fn sink() -> ScalarSink<T> {
ScalarSink(PhantomData)
}
}
pub enum Nothing {}
impl Sink for Nothing {
type Ok = ();
type Error = DecodeError;
type Seq = Never<()>;
type Map = Never<()>;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<(), DecodeError> {
match self {}
}
fn seq(self, _: Option<usize>) -> Result<Never<()>, DecodeError> {
match self {}
}
fn map(self, _: Option<usize>) -> Result<Never<()>, DecodeError> {
match self {}
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<(), DecodeError> {
match self {}
}
}
pub enum Never<T> {
#[doc(hidden)]
_Never(core::convert::Infallible, PhantomData<T>),
}
impl<T> Never<T> {
fn absurd<R>(&self) -> R {
match *self {
Never::_Never(never, _) => match never {},
}
}
}
impl<T> SeqSink for Never<T> {
type Ok = T;
type Error = DecodeError;
type Element<'s>
= Nothing
where
Self: 's;
fn element(&mut self) -> Result<Nothing, DecodeError> {
self.absurd()
}
fn end(self) -> Result<T, DecodeError> {
self.absurd()
}
}
impl<T> MapSink for Never<T> {
type Ok = T;
type Error = DecodeError;
type Entry<'s>
= Nothing
where
Self: 's;
fn entry(&mut self, _: &str) -> Result<Nothing, DecodeError> {
self.absurd()
}
fn end(self) -> Result<T, DecodeError> {
self.absurd()
}
}
macro_rules! int_target {
($($ty:ty),* $(,)?) => {
$(
impl FromScalar for $ty {
const EXPECTED: &'static str = stringify!($ty);
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Int(i)) => i
.to_i128()
.and_then(|v| Self::try_from(v).ok())
.or_else(|| i.to_u128().and_then(|v| Self::try_from(v).ok())),
_ => None,
}
}
}
)*
};
}
int_target!(i8, i16, i32, i64, i128, u16, u32, u64, u128);
impl FromScalar for bool {
const EXPECTED: &'static str = "bool";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Bool(b)) => Some(b),
_ => None,
}
}
}
impl FromScalar for f32 {
const EXPECTED: &'static str = "f32";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Float(Float::F32(f))) => Some(f),
_ => None,
}
}
}
impl FromScalar for f64 {
const EXPECTED: &'static str = "f64";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Float(Float::F64(f))) => Some(f),
(None, Physical::Float(Float::F32(f))) => Some(f.into()),
_ => None,
}
}
}
impl FromScalar for String {
const EXPECTED: &'static str = "string";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Text(s)) => Some(s.to_owned()),
_ => None,
}
}
}
impl FromScalar for Vec<u8> {
const EXPECTED: &'static str = "bytes";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Bytes(b)) => Some(b.to_vec()),
_ => None,
}
}
}
impl<const N: usize> FromScalar for [u8; N] {
const EXPECTED: &'static str = "byte array";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(None, Physical::Bytes(b)) => b.try_into().ok(),
_ => None,
}
}
fn from_scalar_protected(ty: Option<Logical>, v: Physical<'_>) -> Option<Protected<Self>> {
match (ty, v) {
(None, Physical::Bytes(b)) if b.len() == N => {
let mut out = Protected::new([0u8; N]);
out.risky_inner_mut().copy_from_slice(b);
Some(out)
}
_ => None,
}
}
}
#[cfg(feature = "chrono")]
mod chrono_targets {
use super::*;
use crate::plaintext::kinds::chrono as conv;
use ::chrono::{DateTime, NaiveDate, Utc};
impl FromScalar for NaiveDate {
const EXPECTED: &'static str = "date";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(Some(Logical::Date), Physical::Int(days)) => conv::date(days),
_ => None,
}
}
}
impl FromScalar for DateTime<Utc> {
const EXPECTED: &'static str = "timestamp";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(Some(Logical::Timestamp(unit)), Physical::Int(count)) => {
conv::timestamp(unit, count)
}
_ => None,
}
}
}
}
#[cfg(feature = "rust_decimal")]
impl FromScalar for rust_decimal::Decimal {
const EXPECTED: &'static str = "decimal";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(Some(Logical::Decimal { scale }), Physical::Int(mantissa)) => {
crate::plaintext::kinds::decimal::decimal(scale, mantissa)
}
_ => None,
}
}
}
#[cfg(feature = "uuid")]
impl FromScalar for uuid::Uuid {
const EXPECTED: &'static str = "uuid";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
match (ty, v) {
(Some(Logical::Uuid), Physical::Bytes(b)) => uuid::Uuid::from_slice(b).ok(),
_ => None,
}
}
}
pub trait Put<T> {
fn put(self, value: T);
}
pub struct Push<'s, T>(pub &'s mut Vec<T>);
impl<T> Put<T> for Push<'_, T> {
fn put(self, value: T) {
self.0.push(value);
}
}
pub struct Insert<'s, M>(pub &'s mut M, pub String);
impl<T> Put<T> for Insert<'_, HashMap<String, T>> {
fn put(self, value: T) {
self.0.insert(self.1, value);
}
}
impl<T> Put<T> for Insert<'_, BTreeMap<String, T>> {
fn put(self, value: T) {
self.0.insert(self.1, value);
}
}
pub struct Slot<'s, T>(pub &'s mut Option<T>);
impl<T> Put<T> for Slot<'_, T> {
fn put(self, value: T) {
*self.0 = Some(value);
}
}
pub struct Forward<T: Decrypt, O>(pub T::Sink, pub O);
impl<T: Decrypt, O: Put<T>> Sink for Forward<T, O> {
type Ok = ();
type Error = DecodeError;
type Seq = ForwardEnd<T, <T::Sink as Sink>::Seq, O>;
type Map = ForwardEnd<T, <T::Sink as Sink>::Map, O>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<(), DecodeError> {
self.1.put(self.0.scalar(ty, v)?);
Ok(())
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, DecodeError> {
Ok(ForwardEnd(self.0.seq(len)?, self.1, PhantomData))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(ForwardEnd(self.0.map(len)?, self.1, PhantomData))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<(), DecodeError> {
self.1.put(self.0.passthrough(value)?);
Ok(())
}
}
pub struct ForwardEnd<T, Q, O>(Q, O, PhantomData<T>);
impl<T, Q: SeqSink<Ok = T, Error = DecodeError>, O: Put<T>> SeqSink for ForwardEnd<T, Q, O> {
type Ok = ();
type Error = DecodeError;
type Element<'e>
= Q::Element<'e>
where
Self: 'e;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
self.0.element()
}
fn end(self) -> Result<(), DecodeError> {
self.1.put(self.0.end()?);
Ok(())
}
}
impl<T, Q: MapSink<Ok = T, Error = DecodeError>, O: Put<T>> MapSink for ForwardEnd<T, Q, O> {
type Ok = ();
type Error = DecodeError;
type Entry<'e>
= Q::Entry<'e>
where
Self: 'e;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
self.0.entry(key)
}
fn end(self) -> Result<(), DecodeError> {
self.1.put(self.0.end()?);
Ok(())
}
}
pub enum Either<L, R> {
Left(L),
Right(R),
}
impl<L: Sink, R: Sink<Error = L::Error>> Sink for Either<L, R> {
type Ok = Either<L::Ok, R::Ok>;
type Error = L::Error;
type Seq = Either<L::Seq, R::Seq>;
type Map = Either<L::Map, R::Map>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<Self::Ok, Self::Error> {
match self {
Either::Left(l) => l.scalar(ty, v).map(Either::Left),
Either::Right(r) => r.scalar(ty, v).map(Either::Right),
}
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, Self::Error> {
match self {
Either::Left(l) => l.seq(len).map(Either::Left),
Either::Right(r) => r.seq(len).map(Either::Right),
}
}
fn map(self, len: Option<usize>) -> Result<Self::Map, Self::Error> {
match self {
Either::Left(l) => l.map(len).map(Either::Left),
Either::Right(r) => r.map(len).map(Either::Right),
}
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, Self::Error> {
match self {
Either::Left(l) => l.passthrough(value).map(Either::Left),
Either::Right(r) => r.passthrough(value).map(Either::Right),
}
}
}
impl<L: SeqSink, R: SeqSink<Error = L::Error>> SeqSink for Either<L, R> {
type Ok = Either<L::Ok, R::Ok>;
type Error = L::Error;
type Element<'s>
= Either<L::Element<'s>, R::Element<'s>>
where
Self: 's;
fn element(&mut self) -> Result<Self::Element<'_>, Self::Error> {
match self {
Either::Left(l) => l.element().map(Either::Left),
Either::Right(r) => r.element().map(Either::Right),
}
}
fn end(self) -> Result<Self::Ok, Self::Error> {
match self {
Either::Left(l) => l.end().map(Either::Left),
Either::Right(r) => r.end().map(Either::Right),
}
}
}
impl<L: MapSink, R: MapSink<Error = L::Error>> MapSink for Either<L, R> {
type Ok = Either<L::Ok, R::Ok>;
type Error = L::Error;
type Entry<'s>
= Either<L::Entry<'s>, R::Entry<'s>>
where
Self: 's;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, Self::Error> {
match self {
Either::Left(l) => l.entry(key).map(Either::Left),
Either::Right(r) => r.entry(key).map(Either::Right),
}
}
fn end(self) -> Result<Self::Ok, Self::Error> {
match self {
Either::Left(l) => l.end().map(Either::Left),
Either::Right(r) => r.end().map(Either::Right),
}
}
}
pub struct Clear<T: Decrypt, O>(O, PhantomData<T>);
impl<T: Decrypt, O: Put<T>> Clear<T, O> {
pub fn new(out: O) -> Self {
Self(out, PhantomData)
}
}
impl<T: Decrypt, O: Put<T>> Sink for Clear<T, O> {
type Ok = ();
type Error = DecodeError;
type Seq = Never<()>;
type Map = Never<()>;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<(), DecodeError> {
Err(DecodeError::Expected("passthrough"))
}
fn seq(self, _: Option<usize>) -> Result<Never<()>, DecodeError> {
Err(DecodeError::Expected("passthrough"))
}
fn map(self, _: Option<usize>) -> Result<Never<()>, DecodeError> {
Err(DecodeError::Expected("passthrough"))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<(), DecodeError> {
self.0.put(value.visit(T::sink())?);
Ok(())
}
}
pub trait Rewrap<T> {
type Output;
fn rewrap(value: T) -> Result<Self::Output, DecodeError>;
}
pub struct Wrapped<S, W>(S, PhantomData<W>);
impl<S, W> Wrapped<S, W> {
pub fn new(sink: S) -> Self {
Self(sink, PhantomData)
}
}
impl<S: Sink<Error = DecodeError>, W: Rewrap<S::Ok>> Sink for Wrapped<S, W> {
type Ok = W::Output;
type Error = DecodeError;
type Seq = WrappedEnd<S::Seq, W>;
type Map = WrappedEnd<S::Map, W>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<W::Output, DecodeError> {
self.0.scalar(ty, v).and_then(W::rewrap)
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, DecodeError> {
Ok(WrappedEnd(self.0.seq(len)?, PhantomData))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(WrappedEnd(self.0.map(len)?, PhantomData))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<W::Output, DecodeError> {
self.0.passthrough(value).and_then(W::rewrap)
}
}
pub struct WrappedEnd<Q, W>(Q, PhantomData<W>);
impl<Q: SeqSink<Error = DecodeError>, W: Rewrap<Q::Ok>> SeqSink for WrappedEnd<Q, W> {
type Ok = W::Output;
type Error = DecodeError;
type Element<'e>
= Q::Element<'e>
where
Self: 'e;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
self.0.element()
}
fn end(self) -> Result<W::Output, DecodeError> {
self.0.end().and_then(W::rewrap)
}
}
impl<Q: MapSink<Error = DecodeError>, W: Rewrap<Q::Ok>> MapSink for WrappedEnd<Q, W> {
type Ok = W::Output;
type Error = DecodeError;
type Entry<'e>
= Q::Entry<'e>
where
Self: 'e;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
self.0.entry(key)
}
fn end(self) -> Result<W::Output, DecodeError> {
self.0.end().and_then(W::rewrap)
}
}
pub struct List<T>(PhantomData<T>);
impl<T: Decrypt> Sink for List<T> {
type Ok = Vec<T>;
type Error = DecodeError;
type Seq = ListSeq<T>;
type Map = Never<Vec<T>>;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<Vec<T>, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
fn seq(self, len: Option<usize>) -> Result<ListSeq<T>, DecodeError> {
Ok(ListSeq(Vec::with_capacity(len.unwrap_or(0).min(1024))))
}
fn map(self, _: Option<usize>) -> Result<Never<Vec<T>>, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<Vec<T>, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
}
pub struct ListSeq<T>(Vec<T>);
impl<T: Decrypt> SeqSink for ListSeq<T> {
type Ok = Vec<T>;
type Error = DecodeError;
type Element<'s>
= Forward<T, Push<'s, T>>
where
Self: 's;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
Ok(Forward(T::sink(), Push(&mut self.0)))
}
fn end(self) -> Result<Vec<T>, DecodeError> {
Ok(self.0)
}
}
impl<T: Decrypt> Decrypt for Vec<T> {
type Sink = List<T>;
fn sink() -> List<T> {
List(PhantomData)
}
}
pub struct Dict<M>(PhantomData<M>);
pub struct DictEntries<M>(M);
macro_rules! dict_target {
($($map:ident),*) => {
$(
impl<T: Decrypt> Sink for Dict<$map<String, T>> {
type Ok = $map<String, T>;
type Error = DecodeError;
type Seq = Never<$map<String, T>>;
type Map = DictEntries<$map<String, T>>;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<Self::Ok, DecodeError> {
Err(DecodeError::Expected("map"))
}
fn seq(self, _: Option<usize>) -> Result<Self::Seq, DecodeError> {
Err(DecodeError::Expected("map"))
}
fn map(self, _: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(DictEntries($map::new()))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<Self::Ok, DecodeError> {
Err(DecodeError::Expected("map"))
}
}
impl<T: Decrypt> MapSink for DictEntries<$map<String, T>> {
type Ok = $map<String, T>;
type Error = DecodeError;
type Entry<'s>
= Forward<T, Insert<'s, $map<String, T>>>
where
Self: 's;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
Ok(Forward(T::sink(), Insert(&mut self.0, key.to_owned())))
}
fn end(self) -> Result<Self::Ok, DecodeError> {
Ok(self.0)
}
}
impl<T: Decrypt> Decrypt for $map<String, T> {
type Sink = Dict<$map<String, T>>;
fn sink() -> Self::Sink {
Dict(PhantomData)
}
}
)*
};
}
dict_target!(HashMap, BTreeMap);
pub struct Optional<T: Decrypt>(T::Sink);
impl<T: Decrypt> Sink for Optional<T> {
type Ok = Option<T>;
type Error = DecodeError;
type Seq = Some_<T, <T::Sink as Sink>::Seq>;
type Map = Some_<T, <T::Sink as Sink>::Map>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<Option<T>, DecodeError> {
match (ty, v) {
(None | Some(Logical::Undefined), Physical::Null) => Ok(None),
_ => self.0.scalar(ty, v).map(Some),
}
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, DecodeError> {
Ok(Some_(self.0.seq(len)?, PhantomData))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(Some_(self.0.map(len)?, PhantomData))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Option<T>, DecodeError> {
self.0.passthrough(value).map(Some)
}
}
pub struct Some_<T, Q>(Q, PhantomData<T>);
impl<T, Q: SeqSink<Ok = T, Error = DecodeError>> SeqSink for Some_<T, Q> {
type Ok = Option<T>;
type Error = DecodeError;
type Element<'e>
= Q::Element<'e>
where
Self: 'e;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
self.0.element()
}
fn end(self) -> Result<Option<T>, DecodeError> {
self.0.end().map(Some)
}
}
impl<T, Q: MapSink<Ok = T, Error = DecodeError>> MapSink for Some_<T, Q> {
type Ok = Option<T>;
type Error = DecodeError;
type Entry<'e>
= Q::Entry<'e>
where
Self: 'e;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
self.0.entry(key)
}
fn end(self) -> Result<Option<T>, DecodeError> {
self.0.end().map(Some)
}
}
impl<T: Decrypt> Decrypt for Option<T> {
type Sink = Optional<T>;
fn sink() -> Optional<T> {
Optional(T::sink())
}
}
pub trait DecryptProtected: Decrypt + Zeroize {
type ProtectedSink: Sink<Ok = Protected<Self>, Error = DecodeError>;
fn protected_sink() -> Self::ProtectedSink;
}
impl<T: DecryptProtected> Decrypt for Protected<T> {
type Sink = T::ProtectedSink;
fn sink() -> T::ProtectedSink {
T::protected_sink()
}
}
impl<T: FromScalar + Zeroize> DecryptProtected for T {
type ProtectedSink = ScalarProtected<T>;
fn protected_sink() -> ScalarProtected<T> {
ScalarProtected(PhantomData)
}
}
pub struct ScalarProtected<T>(PhantomData<T>);
impl<T: FromScalar + Zeroize> Sink for ScalarProtected<T> {
type Ok = Protected<T>;
type Error = DecodeError;
type Seq = Never<Protected<T>>;
type Map = Never<Protected<T>>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<Protected<T>, DecodeError> {
T::from_scalar_protected(ty, v).ok_or(DecodeError::Expected(T::EXPECTED))
}
fn seq(self, _: Option<usize>) -> Result<Self::Seq, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
fn map(self, _: Option<usize>) -> Result<Self::Map, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<Protected<T>, DecodeError> {
Err(DecodeError::Expected(T::EXPECTED))
}
}
impl<T: DecryptProtected> DecryptProtected for Vec<T> {
type ProtectedSink = ProtectedList<T>;
fn protected_sink() -> ProtectedList<T> {
ProtectedList(PhantomData)
}
}
pub struct ProtectedList<T>(PhantomData<T>);
impl<T: DecryptProtected> Sink for ProtectedList<T> {
type Ok = Protected<Vec<T>>;
type Error = DecodeError;
type Seq = ProtectedListSeq<T>;
type Map = Never<Protected<Vec<T>>>;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<Self::Ok, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
fn seq(self, len: Option<usize>) -> Result<ProtectedListSeq<T>, DecodeError> {
let items = Vec::with_capacity(len.unwrap_or(0).min(1024));
Ok(ProtectedListSeq(Protected::new(items)))
}
fn map(self, _: Option<usize>) -> Result<Self::Map, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<Self::Ok, DecodeError> {
Err(DecodeError::Expected("sequence"))
}
}
pub struct ProtectedListSeq<T: Zeroize>(Protected<Vec<T>>);
impl<T: DecryptProtected> SeqSink for ProtectedListSeq<T> {
type Ok = Protected<Vec<T>>;
type Error = DecodeError;
type Element<'s>
= Forward<Protected<T>, ProtectedPush<'s, T>>
where
Self: 's;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
Ok(Forward(
T::protected_sink(),
ProtectedPush(self.0.risky_inner_mut()),
))
}
fn end(self) -> Result<Protected<Vec<T>>, DecodeError> {
Ok(self.0)
}
}
pub struct ProtectedPush<'s, T: Zeroize>(&'s mut Vec<T>);
impl<T: Zeroize> Put<Protected<T>> for ProtectedPush<'_, T> {
fn put(self, value: Protected<T>) {
if self.0.len() == self.0.capacity() {
let mut grown = Vec::with_capacity(self.0.capacity().max(4) * 2);
grown.append(self.0);
self.0.zeroize();
*self.0 = grown;
}
self.0.push(value.risky_unwrap());
}
}
impl<T: DecryptProtected> DecryptProtected for Option<T> {
type ProtectedSink = ProtectedOptional<T>;
fn protected_sink() -> ProtectedOptional<T> {
ProtectedOptional(T::protected_sink())
}
}
pub struct ProtectedOptional<T: DecryptProtected>(T::ProtectedSink);
impl<T: DecryptProtected> Sink for ProtectedOptional<T> {
type Ok = Protected<Option<T>>;
type Error = DecodeError;
type Seq = SomeProtected<T, <T::ProtectedSink as Sink>::Seq>;
type Map = SomeProtected<T, <T::ProtectedSink as Sink>::Map>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<Self::Ok, DecodeError> {
match (ty, v) {
(None | Some(Logical::Undefined), Physical::Null) => Ok(Protected::new(None)),
_ => self.0.scalar(ty, v).map(some),
}
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, DecodeError> {
Ok(SomeProtected(self.0.seq(len)?, PhantomData))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(SomeProtected(self.0.map(len)?, PhantomData))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, DecodeError> {
self.0.passthrough(value).map(some)
}
}
fn some<T: Zeroize>(value: Protected<T>) -> Protected<Option<T>> {
value.map(Some)
}
pub struct Wrap<S>(pub S);
impl<S> Sink for Wrap<S>
where
S: Sink<Error = DecodeError>,
S::Ok: Zeroize,
{
type Ok = Protected<S::Ok>;
type Error = DecodeError;
type Seq = WrapEnd<S::Seq>;
type Map = WrapEnd<S::Map>;
fn scalar(self, ty: Option<Logical>, v: Physical<'_>) -> Result<Self::Ok, DecodeError> {
self.0.scalar(ty, v).map(Protected::new)
}
fn seq(self, len: Option<usize>) -> Result<Self::Seq, DecodeError> {
Ok(WrapEnd(self.0.seq(len)?))
}
fn map(self, len: Option<usize>) -> Result<Self::Map, DecodeError> {
Ok(WrapEnd(self.0.map(len)?))
}
fn passthrough<P: Encrypt + Clone>(self, value: P) -> Result<Self::Ok, DecodeError> {
self.0.passthrough(value).map(Protected::new)
}
}
pub struct WrapEnd<Q>(Q);
impl<Q> SeqSink for WrapEnd<Q>
where
Q: SeqSink<Error = DecodeError>,
Q::Ok: Zeroize,
{
type Ok = Protected<Q::Ok>;
type Error = DecodeError;
type Element<'e>
= Q::Element<'e>
where
Self: 'e;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
self.0.element()
}
fn end(self) -> Result<Self::Ok, DecodeError> {
self.0.end().map(Protected::new)
}
}
impl<Q> MapSink for WrapEnd<Q>
where
Q: MapSink<Error = DecodeError>,
Q::Ok: Zeroize,
{
type Ok = Protected<Q::Ok>;
type Error = DecodeError;
type Entry<'e>
= Q::Entry<'e>
where
Self: 'e;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
self.0.entry(key)
}
fn end(self) -> Result<Self::Ok, DecodeError> {
self.0.end().map(Protected::new)
}
}
pub struct SomeProtected<T, Q>(Q, PhantomData<T>);
impl<T, Q> SeqSink for SomeProtected<T, Q>
where
T: Zeroize,
Q: SeqSink<Ok = Protected<T>, Error = DecodeError>,
{
type Ok = Protected<Option<T>>;
type Error = DecodeError;
type Element<'e>
= Q::Element<'e>
where
Self: 'e;
fn element(&mut self) -> Result<Self::Element<'_>, DecodeError> {
self.0.element()
}
fn end(self) -> Result<Protected<Option<T>>, DecodeError> {
self.0.end().map(some)
}
}
impl<T, Q> MapSink for SomeProtected<T, Q>
where
T: Zeroize,
Q: MapSink<Ok = Protected<T>, Error = DecodeError>,
{
type Ok = Protected<Option<T>>;
type Error = DecodeError;
type Entry<'e>
= Q::Entry<'e>
where
Self: 'e;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
self.0.entry(key)
}
fn end(self) -> Result<Protected<Option<T>>, DecodeError> {
self.0.end().map(some)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::plaintext::{Int, Raw};
use crate::seal::mock::{Mock, Remote};
use crate::{encrypt, encrypt_async};
use futures_executor::block_on;
fn round_trip<T: Decrypt>(
p: impl Encrypt,
) -> Result<T, DecryptError<DecodeError, crate::seal::mock::Refused>> {
decrypt(&Mock, encrypt(p, &Mock, "ctx").expect("encrypts"), "ctx")
}
fn expected<T>(
r: Result<T, DecryptError<DecodeError, crate::seal::mock::Refused>>,
) -> &'static str {
match r {
Err(DecryptError::Sink(DecodeError::Expected(what))) => what,
Err(other) => panic!("{other:?}"),
Ok(_) => panic!("decoded"),
}
}
#[test]
fn scalars_round_trip() {
assert_eq!(round_trip::<u32>(34u32).expect("u32"), 34);
assert_eq!(round_trip::<i128>(-5i64).expect("i128"), -5);
assert!(round_trip::<bool>(true).expect("bool"));
assert_eq!(round_trip::<f64>(2.5f64).expect("f64"), 2.5);
assert_eq!(round_trip::<f64>(2.5f32).expect("f64 from f32"), 2.5);
assert_eq!(round_trip::<String>("Ada").expect("string"), "Ada");
assert_eq!(round_trip::<Vec<u8>>(vec![1u8, 2]).expect("bytes"), [1, 2]);
assert_eq!(round_trip::<[u8; 2]>(vec![1u8, 2]).expect("array"), [1, 2]);
assert_eq!(
round_trip::<Protected<String>>(Protected::new(String::from("pw")))
.expect("protected")
.risky_ref(),
"pw"
);
assert_eq!(
round_trip::<Protected<Vec<u8>>>(vec![9u8])
.expect("protected")
.risky_ref(),
&[9]
);
}
#[test]
fn integer_targets_read_the_value_not_the_width() {
assert_eq!(round_trip::<u32>(34i8).expect("widens"), 34);
assert_eq!(round_trip::<i8>(34u64).expect("narrows"), 34);
assert_eq!(
round_trip::<u128>(Raw(None, Physical::Int(Int::U128(u128::MAX)))).expect("u128"),
u128::MAX
);
assert_eq!(expected(round_trip::<u32>(-1i8)), "u32");
assert_eq!(expected(round_trip::<i8>(300u16)), "i8");
assert_eq!(
expected(round_trip::<i128>(Raw(
None,
Physical::Int(Int::U128(u128::MAX))
))),
"i128"
);
}
#[test]
fn the_wrong_kind_is_refused_by_name() {
assert_eq!(expected(round_trip::<String>(34u32)), "string");
assert_eq!(expected(round_trip::<u32>("34")), "u32");
assert_eq!(expected(round_trip::<f32>(2.5f64)), "f32");
assert_eq!(expected(round_trip::<bool>(vec![true])), "bool");
assert_eq!(expected(round_trip::<Vec<u32>>(34u32)), "sequence");
assert_eq!(expected(round_trip::<[u8; 4]>(vec![1u8, 2])), "byte array");
assert_eq!(
expected(round_trip::<i32>(Raw(
Some(Logical::Date),
Physical::Int(Int::I32(0))
))),
"i32"
);
}
#[test]
fn containers_round_trip() {
assert_eq!(
round_trip::<Vec<String>>(vec!["Ada", "Grace"]).expect("strings"),
["Ada", "Grace"]
);
assert_eq!(
round_trip::<Vec<Vec<u32>>>(vec![vec![1u32, 2], vec![], vec![3]]).expect("nested"),
[vec![1, 2], vec![], vec![3]]
);
assert_eq!(
round_trip::<Vec<u32>>(Vec::<u32>::new()).expect("empty"),
Vec::<u32>::new()
);
}
#[test]
fn option_reads_null_and_undefined_as_none() {
assert_eq!(round_trip::<Option<u32>>(None::<u32>).expect("none"), None);
assert_eq!(
round_trip::<Option<u32>>(Some(7u32)).expect("some"),
Some(7)
);
assert_eq!(
round_trip::<Option<u32>>(Raw(Some(Logical::Undefined), Physical::Null))
.expect("undefined"),
None
);
assert_eq!(
round_trip::<Option<Vec<u32>>>(Some(vec![1u32])).expect("some seq"),
Some(vec![1])
);
assert_eq!(
round_trip::<Vec<Option<u32>>>(vec![Some(1u32), None]).expect("options"),
[Some(1), None]
);
assert_eq!(expected(round_trip::<Option<u32>>("x")), "u32");
}
#[test]
fn a_typed_target_works_through_an_async_cipher() {
let remote = Remote::new(true);
let sealed = block_on(encrypt_async(vec![1u32, 2], &remote, ())).expect("encrypts");
let out: Vec<u32> = block_on(decrypt_async(&remote, sealed, ())).expect("decrypts");
assert_eq!(out, [1, 2]);
assert_eq!(remote.calls(), 2);
}
#[test]
fn sync_and_async_decrypt_agree() {
let mut value = BTreeMap::new();
value.insert(String::from("a"), vec![Some(1u32), None]);
value.insert(String::from("b"), vec![]);
let sealed = || encrypt(value.clone(), &Mock, "ctx").expect("encrypts");
let sync: BTreeMap<String, Vec<Option<u32>>> =
decrypt(&Mock, sealed(), "ctx").expect("sync");
let remote = Remote::new(true);
let async_: BTreeMap<String, Vec<Option<u32>>> =
block_on(decrypt_async(&remote, sealed(), "ctx")).expect("async");
assert_eq!(sync, async_);
assert_eq!(sync, value);
}
#[test]
fn maps_round_trip() {
let mut hash = HashMap::new();
hash.insert(String::from("a"), 1u32);
hash.insert(String::from("b"), 2u32);
assert_eq!(
round_trip::<HashMap<String, u32>>(hash.clone()).expect("hash"),
hash
);
let mut tree = BTreeMap::new();
tree.insert("xs", vec![String::from("Ada")]);
tree.insert("ys", vec![]);
let back = round_trip::<BTreeMap<String, Vec<String>>>(tree).expect("tree");
assert_eq!(back["xs"], ["Ada"]);
assert!(back["ys"].is_empty());
assert!(
round_trip::<HashMap<String, u32>>(HashMap::<String, u32>::new())
.expect("empty")
.is_empty()
);
assert_eq!(
expected(round_trip::<HashMap<String, u32>>(vec![1u32])),
"map"
);
assert_eq!(expected(round_trip::<BTreeMap<String, u32>>(1u32)), "map");
let mut bad = BTreeMap::new();
bad.insert("a", "x");
assert_eq!(expected(round_trip::<BTreeMap<String, u32>>(bad)), "u32");
}
#[test]
fn any_wipeable_scalar_reads_into_protected() {
assert_eq!(
*round_trip::<Protected<u64>>(34u64)
.expect("u64")
.risky_ref(),
34
);
assert_eq!(
round_trip::<Protected<[u8; 32]>>([7u8; 32])
.expect("array")
.risky_ref(),
&[7; 32]
);
assert_eq!(
expected(round_trip::<Protected<[u8; 4]>>(vec![1u8, 2])),
"byte array"
);
assert_eq!(expected(round_trip::<Protected<u64>>("x")), "u64");
}
#[test]
fn a_scalar_target_refuses_a_map_and_a_passthrough() {
let mut map = BTreeMap::new();
map.insert("a", 1u32);
assert_eq!(expected(round_trip::<u32>(map)), "u32");
#[derive(Clone)]
struct Clear;
impl Encrypt for Clear {
fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
let mut seq = sink.seq(Some(2))?;
seq.element()?.passthrough(7u16)?;
8u16.visit(seq.element()?)?;
seq.end()
}
}
assert_eq!(expected(round_trip::<Vec<u16>>(Clear)), "u16");
assert_eq!(expected(round_trip::<Vec<Option<u16>>>(Clear)), "u16");
}
#[test]
fn nested_maps_are_handed_up_to_their_container() {
let mut row = BTreeMap::new();
row.insert(String::from("a"), 1u32);
let rows = vec![row.clone(), row.clone()];
assert_eq!(
round_trip::<Vec<BTreeMap<String, u32>>>(rows.clone()).expect("decodes"),
rows
);
assert_eq!(
round_trip::<Option<BTreeMap<String, u32>>>(Some(row.clone())).expect("decodes"),
Some(row)
);
}
#[test]
fn a_list_target_refuses_a_passthrough() {
struct Clear;
impl Encrypt for Clear {
fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
sink.passthrough(vec![1u16])
}
}
assert_eq!(expected(round_trip::<Vec<u16>>(Clear)), "sequence");
}
#[test]
fn f32_reads_only_an_f32() {
assert_eq!(round_trip::<f32>(1.5f32).expect("decodes"), 1.5);
assert_eq!(expected(round_trip::<f32>(1.5f64)), "f32");
}
#[test]
fn clear_decodes_a_passthrough_and_nothing_else() {
let mut held = None;
Clear::<Vec<u16>, _>::new(Slot(&mut held))
.passthrough(vec![1u16, 2])
.expect("decodes");
assert_eq!(held, Some(vec![1, 2]));
let refused = |r: Result<(), DecodeError>| {
assert!(matches!(r, Err(DecodeError::Expected("passthrough"))))
};
let mut held: Option<u16> = None;
refused(Clear::<u16, _>::new(Slot(&mut held)).scalar(None, Physical::Null));
refused(Clear::<u16, _>::new(Slot(&mut held)).seq(None).map(|_| ()));
refused(Clear::<u16, _>::new(Slot(&mut held)).map(None).map(|_| ()));
assert!(matches!(
Clear::<u16, _>::new(Slot(&mut held)).passthrough("x"),
Err(DecodeError::Expected("u16"))
));
}
#[test]
fn a_wrap_can_refuse_what_it_is_handed() {
struct AtMostTwo;
impl Rewrap<Vec<u16>> for AtMostTwo {
type Output = Vec<u16>;
fn rewrap(v: Vec<u16>) -> Result<Vec<u16>, DecodeError> {
(v.len() <= 2)
.then_some(v)
.ok_or(DecodeError::Expected("at most two"))
}
}
struct Even;
impl Rewrap<u16> for Even {
type Output = u16;
fn rewrap(v: u16) -> Result<u16, DecodeError> {
v.is_multiple_of(2)
.then_some(v)
.ok_or(DecodeError::Expected("even"))
}
}
let short = vec![1u16, 2].visit(Wrapped::<_, AtMostTwo>::new(Vec::<u16>::sink()));
assert_eq!(short.expect("two"), [1, 2]);
let long = vec![1u16, 2, 3].visit(Wrapped::<_, AtMostTwo>::new(Vec::<u16>::sink()));
assert!(matches!(long, Err(DecodeError::Expected("at most two"))));
assert_eq!(
4u16.visit(Wrapped::<_, Even>::new(u16::sink()))
.expect("even"),
4
);
assert!(matches!(
5u16.visit(Wrapped::<_, Even>::new(u16::sink())),
Err(DecodeError::Expected("even"))
));
assert!(matches!(
DecodeError::unknown_key("k"),
DecodeError::UnknownKey(k) if k == "k"
));
assert!(matches!(
DecodeError::duplicate_key("k"),
DecodeError::DuplicateKey(k) if k == "k"
));
}
#[test]
fn a_slot_holds_what_is_put() {
let mut held = None;
Slot(&mut held).put(3u8);
assert_eq!(held, Some(3));
}
#[test]
fn some_none_reads_back_as_none() {
assert_eq!(
round_trip::<Option<Option<u32>>>(Some(None::<u32>)).expect("decodes"),
None
);
assert_eq!(
round_trip::<Option<Option<u32>>>(Some(Some(1u32))).expect("decodes"),
Some(Some(1))
);
}
#[test]
fn decode_errors_are_std_errors() {
let e: Box<dyn core::error::Error> = Box::new(DecodeError::Expected("u32"));
assert_eq!(e.to_string(), "expected u32");
assert!(core::error::Error::source(&DecodeError::Expected("u32")).is_none());
let source = DecodeError::Source(SourceError::new(core::fmt::Error));
assert!(core::error::Error::source(&source).is_some());
}
#[cfg(feature = "chrono")]
#[test]
fn chrono_targets_accept_any_unit() {
use crate::plaintext::TimeUnit;
use ::chrono::{DateTime, NaiveDate};
let date = NaiveDate::from_ymd_opt(2024, 2, 29).expect("date");
assert_eq!(round_trip::<NaiveDate>(date).expect("date"), date);
let ts = DateTime::from_timestamp(1_700_000_000, 123_456_789).expect("ts");
assert_eq!(round_trip::<DateTime<_>>(ts).expect("ts"), ts);
let js = Raw(
Some(Logical::Timestamp(TimeUnit::Millis)),
Physical::Int(Int::I64(1_700_000_000_123)),
);
assert_eq!(
round_trip::<DateTime<_>>(js).expect("ms"),
DateTime::from_timestamp(1_700_000_000, 123_000_000).expect("ts")
);
assert_eq!(expected(round_trip::<NaiveDate>(0i32)), "date");
}
#[cfg(feature = "rust_decimal")]
#[test]
fn decimal_round_trips_with_its_scale() {
let d: rust_decimal::Decimal = "1.50".parse().expect("decimal");
let back = round_trip::<rust_decimal::Decimal>(d).expect("decimal");
assert_eq!(back, d);
assert_eq!(back.scale(), 2);
assert_eq!(
expected(round_trip::<rust_decimal::Decimal>(150u32)),
"decimal"
);
}
#[cfg(feature = "uuid")]
#[test]
fn uuid_round_trips() {
let id = uuid::Uuid::from_bytes([5; 16]);
assert_eq!(round_trip::<uuid::Uuid>(id).expect("uuid"), id);
assert_eq!(expected(round_trip::<uuid::Uuid>(vec![5u8; 16])), "uuid");
}
#[test]
fn a_map_target_refuses_a_passthrough() {
struct Clear;
impl Encrypt for Clear {
fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
let mut map = BTreeMap::new();
map.insert("a", 1u16);
sink.passthrough(map)
}
}
assert_eq!(expected(round_trip::<HashMap<String, u16>>(Clear)), "map");
assert_eq!(expected(round_trip::<BTreeMap<String, u16>>(Clear)), "map");
}
#[test]
fn byte_targets_refuse_a_uuid_leaf() {
let uuid = || Raw(Some(Logical::Uuid), Physical::Bytes(&[5; 16]));
assert_eq!(expected(round_trip::<Vec<u8>>(uuid())), "bytes");
assert_eq!(expected(round_trip::<[u8; 16]>(uuid())), "byte array");
assert_eq!(
expected(round_trip::<Protected<[u8; 16]>>(uuid())),
"byte array"
);
}
#[cfg(feature = "chrono")]
#[test]
fn chrono_targets_refuse_the_other_logical_types() {
use crate::plaintext::TimeUnit;
use ::chrono::{DateTime, NaiveDate, Utc};
let date = NaiveDate::from_ymd_opt(2024, 2, 29).expect("date");
let ts = DateTime::from_timestamp(1_700_000_000, 0).expect("ts");
assert_eq!(expected(round_trip::<DateTime<Utc>>(date)), "timestamp");
assert_eq!(
expected(round_trip::<DateTime<Utc>>(1_700_000_000i64)),
"timestamp"
);
assert_eq!(expected(round_trip::<NaiveDate>(ts)), "date");
let instant = DateTime::from_timestamp(2, 0).expect("timestamp");
for (unit, count) in [
(TimeUnit::Seconds, 2),
(TimeUnit::Millis, 2_000),
(TimeUnit::Micros, 2_000_000),
(TimeUnit::Nanos, 2_000_000_000),
] {
let raw = Raw(
Some(Logical::Timestamp(unit)),
Physical::Int(Int::I64(count)),
);
assert_eq!(round_trip::<DateTime<Utc>>(raw).expect("unit"), instant);
}
}
#[test]
fn a_wrong_aad_fails_before_the_target_is_checked() {
let sealed = || encrypt(34u32, &Mock, "ctx").expect("encrypts");
assert!(matches!(
decrypt::<String, _, _>(&Mock, sealed(), "other"),
Err(DecryptError::Cipher(_))
));
assert!(matches!(
decrypt::<Vec<u32>, _, _>(&Mock, sealed(), "other"),
Err(DecryptError::Cipher(_))
));
let remote = Remote::new(true);
assert_eq!(
block_on(decrypt_async::<u32, _, _>(&remote, sealed(), "ctx")).expect("decrypts"),
34
);
assert!(matches!(
block_on(decrypt_async::<String, _, _>(&remote, sealed(), "other")),
Err(DecryptError::Cipher(_))
));
}
#[test]
fn a_null_is_refused_where_no_option_is_expected() {
assert_eq!(expected(round_trip::<u32>(None::<u32>)), "u32");
assert_eq!(expected(round_trip::<String>(None::<String>)), "string");
assert_eq!(
expected(round_trip::<Vec<u32>>(None::<Vec<u32>>)),
"sequence"
);
assert_eq!(
expected(round_trip::<Vec<u32>>(vec![Some(1u32), None])),
"u32"
);
assert_eq!(
expected(round_trip::<u32>(Raw(
Some(Logical::Undefined),
Physical::Null
))),
"u32"
);
}
#[test]
fn a_list_target_refuses_a_map() {
let mut map = BTreeMap::new();
map.insert("a", 1u32);
assert_eq!(expected(round_trip::<Vec<u32>>(map)), "sequence");
}
#[test]
fn number_targets_refuse_the_other_number_kinds() {
assert_eq!(expected(round_trip::<u32>(true)), "u32");
assert_eq!(expected(round_trip::<i64>(1.0f64)), "i64");
assert_eq!(expected(round_trip::<i64>(1.0f32)), "i64");
assert_eq!(expected(round_trip::<f64>(1i64)), "f64");
assert_eq!(expected(round_trip::<f32>(1u32)), "f32");
}
#[test]
fn integer_targets_accept_their_limits_and_nothing_past_them() {
assert_eq!(round_trip::<i8>(i8::MIN).expect("i8"), i8::MIN);
assert_eq!(round_trip::<i8>(127i32).expect("i8"), i8::MAX);
assert_eq!(expected(round_trip::<i8>(-129i32)), "i8");
assert_eq!(expected(round_trip::<i8>(128i32)), "i8");
assert_eq!(round_trip::<u64>(u64::MAX).expect("u64"), u64::MAX);
assert_eq!(expected(round_trip::<u64>(u128::from(u64::MAX) + 1)), "u64");
assert_eq!(round_trip::<u128>(u128::MAX).expect("u128"), u128::MAX);
assert_eq!(expected(round_trip::<u128>(-1i8)), "u128");
assert_eq!(round_trip::<i128>(i128::MIN).expect("i128"), i128::MIN);
assert_eq!(expected(round_trip::<i128>(u128::MAX)), "i128");
}
#[test]
fn a_source_error_displays_its_message() {
assert_eq!(
DecodeError::Source(SourceError::msg("getter threw")).to_string(),
"source failed: getter threw"
);
assert_eq!(DecodeError::Expected("u32").to_string(), "expected u32");
}
#[test]
fn protected_containers_round_trip() {
let ints = round_trip::<Protected<Vec<u32>>>(vec![1u32, 2, 3]).expect("decrypts");
assert_eq!(ints.risky_ref(), &[1, 2, 3]);
let some = round_trip::<Protected<Option<String>>>(Some("pw")).expect("decrypts");
assert_eq!(some.risky_ref().as_deref(), Some("pw"));
let none = round_trip::<Protected<Option<String>>>(None::<&str>).expect("decrypts");
assert_eq!(none.risky_ref(), &None);
let undefined =
round_trip::<Protected<Option<u32>>>(Raw(Some(Logical::Undefined), Physical::Null))
.expect("decrypts");
assert_eq!(undefined.risky_ref(), &None);
let nested = round_trip::<Protected<Vec<Vec<String>>>>(vec![vec!["a", "b"], vec![]])
.expect("decrypts");
assert_eq!(
nested.risky_ref(),
&[vec![String::from("a"), String::from("b")], vec![]]
);
let list = round_trip::<Protected<Option<Vec<u32>>>>(Some(vec![7u32])).expect("decrypts");
assert_eq!(list.risky_ref(), &Some(vec![7]));
let arrays = round_trip::<Protected<Vec<Option<[u8; 2]>>>>(vec![Some([1u8, 2]), None])
.expect("decrypts");
assert_eq!(arrays.risky_ref(), &[Some([1, 2]), None]);
let bytes = round_trip::<Protected<Vec<u8>>>(vec![9u8, 8]).expect("decrypts");
assert_eq!(bytes.risky_ref(), &[9, 8]);
}
#[test]
fn protected_containers_refuse_what_their_bare_forms_refuse() {
let mut map = BTreeMap::new();
map.insert("a", 1u32);
assert_eq!(expected(round_trip::<Protected<Vec<u32>>>(map)), "sequence");
assert_eq!(
expected(round_trip::<Protected<Vec<u32>>>(1u32)),
"sequence"
);
assert_eq!(
expected(round_trip::<Protected<Vec<u32>>>(vec!["x"])),
"u32"
);
assert_eq!(expected(round_trip::<Protected<Option<u32>>>("x")), "u32");
assert_eq!(
expected(round_trip::<Protected<Option<Vec<u32>>>>(1u32)),
"sequence"
);
struct Clear;
impl Encrypt for Clear {
fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
sink.passthrough(vec![1u32])
}
}
assert_eq!(
expected(round_trip::<Protected<Vec<u32>>>(Clear)),
"sequence"
);
assert_eq!(expected(round_trip::<Protected<Option<u32>>>(Clear)), "u32");
assert_eq!(expected(round_trip::<Protected<u32>>(Clear)), "u32");
assert_eq!(expected(round_trip::<Protected<u32>>(vec![1u32])), "u32");
let mut map = BTreeMap::new();
map.insert("a", 1u32);
assert_eq!(expected(round_trip::<Protected<u32>>(map)), "u32");
}
std::thread_local! {
static WIPES: core::cell::Cell<usize> = const { core::cell::Cell::new(0) };
}
struct Wiped(u32);
impl Zeroize for Wiped {
fn zeroize(&mut self) {
self.0 = 0;
WIPES.with(|w| w.set(w.get() + 1));
}
}
impl FromScalar for Wiped {
const EXPECTED: &'static str = "wiped";
fn from_scalar(ty: Option<Logical>, v: Physical<'_>) -> Option<Self> {
u32::from_scalar(ty, v).map(Wiped)
}
}
#[test]
fn a_protected_list_that_fails_part_way_wipes_what_it_decoded() {
let source = vec![
Raw(None, Physical::Int(Int::U32(1))),
Raw(None, Physical::Int(Int::U32(2))),
Raw(None, Physical::Text("x")),
];
WIPES.with(|w| w.set(0));
let result = round_trip::<Protected<Vec<Wiped>>>(source);
assert_eq!(expected(result), "wiped");
assert_eq!(WIPES.with(|w| w.get()), 2);
}
struct Unsized(u32);
impl Encrypt for Unsized {
fn visit<S: Sink>(self, sink: S) -> Result<S::Ok, S::Error> {
let mut seq = sink.seq(None)?;
for i in 0..self.0 {
i.visit(seq.element()?)?;
}
seq.end()
}
}
#[test]
fn a_protected_list_grows_by_doubling_into_a_fresh_buffer() {
let decode = |n| {
Unsized(n)
.visit(<Protected<Vec<u32>> as Decrypt>::sink())
.expect("decodes")
};
let five = decode(5);
assert_eq!(five.risky_ref(), &[0, 1, 2, 3, 4]);
assert_eq!(five.risky_ref().capacity(), 8);
let nine = decode(9);
assert_eq!(nine.risky_ref(), &(0..9).collect::<Vec<_>>());
assert_eq!(nine.risky_ref().capacity(), 16);
}
#[derive(Debug, PartialEq)]
struct Point {
x: u32,
}
impl Zeroize for Point {
fn zeroize(&mut self) {
self.x.zeroize();
}
}
struct PointSink;
struct PointFields(Option<u32>);
impl Sink for PointSink {
type Ok = Point;
type Error = DecodeError;
type Seq = Never<Point>;
type Map = PointFields;
fn scalar(self, _: Option<Logical>, _: Physical<'_>) -> Result<Point, DecodeError> {
Err(DecodeError::Expected("point"))
}
fn seq(self, _: Option<usize>) -> Result<Never<Point>, DecodeError> {
Err(DecodeError::Expected("point"))
}
fn map(self, _: Option<usize>) -> Result<PointFields, DecodeError> {
Ok(PointFields(None))
}
fn passthrough<P: Encrypt + Clone>(self, _: P) -> Result<Point, DecodeError> {
Err(DecodeError::Expected("point"))
}
}
impl MapSink for PointFields {
type Ok = Point;
type Error = DecodeError;
type Entry<'s> = Forward<u32, Slot<'s, u32>>;
fn entry(&mut self, key: &str) -> Result<Self::Entry<'_>, DecodeError> {
match key {
"x" => Ok(Forward(u32::sink(), Slot(&mut self.0))),
_ => Err(DecodeError::Expected("point")),
}
}
fn end(self) -> Result<Point, DecodeError> {
self.0
.map(|x| Point { x })
.ok_or(DecodeError::Expected("point"))
}
}
impl Decrypt for Point {
type Sink = PointSink;
fn sink() -> PointSink {
PointSink
}
}
impl DecryptProtected for Point {
type ProtectedSink = Wrap<PointSink>;
fn protected_sink() -> Wrap<PointSink> {
Wrap(PointSink)
}
}
#[test]
fn a_struct_target_opts_into_protected_through_wrap() {
let point = || {
let mut map = BTreeMap::new();
map.insert("x", 3u32);
map
};
let p = round_trip::<Protected<Point>>(point()).expect("decrypts");
assert_eq!(p.risky_ref(), &Point { x: 3 });
let some = round_trip::<Protected<Option<Point>>>(Some(point())).expect("decrypts");
assert_eq!(some.risky_ref(), &Some(Point { x: 3 }));
let list = round_trip::<Protected<Vec<Point>>>(vec![point()]).expect("decrypts");
assert_eq!(list.risky_ref(), &[Point { x: 3 }]);
assert_eq!(expected(round_trip::<Protected<Point>>(1u32)), "point");
assert_eq!(
expected(round_trip::<Protected<Point>>(vec![1u32])),
"point"
);
let mut extra = point();
extra.insert("y", 4u32);
assert_eq!(expected(round_trip::<Protected<Point>>(extra)), "point");
}
#[test]
fn wrap_moves_any_sink_result_into_protected() {
let n = Wrap(u32::sink())
.scalar(None, Physical::Int(Int::U32(5)))
.expect("decodes");
assert_eq!(n.risky_ref(), &5);
assert!(matches!(
Wrap(u32::sink()).passthrough(5u32),
Err(DecodeError::Expected("u32"))
));
let list = vec![1u32, 2]
.visit(Wrap(<Vec<u32>>::sink()))
.expect("decodes");
assert_eq!(list.risky_ref(), &[1, 2]);
}
}