use super::LocalCipherText;
use crate::Nonce;
use bytes::BytesMut;
use vitaminc_protected::{Controlled, Protected};
#[derive(Default)]
pub struct CipherTextBuilder();
impl CipherTextBuilder {
pub fn new() -> Self {
Default::default()
}
pub fn append_nonce<const N: usize>(self, nonce: Nonce<N>) -> NonceWritten<N> {
NonceWritten(nonce)
}
}
pub struct NonceWritten<const N: usize>(Nonce<N>);
impl<const N: usize> NonceWritten<N> {
pub fn append_target_plaintext(
self,
plaintext: impl Into<Protected<Vec<u8>>>,
) -> PlaintextWritten<N> {
PlaintextWritten::new(self.0, plaintext.into())
}
pub fn append_target_plaintext_array<const M: usize>(
self,
plaintext: Protected<[u8; M]>,
reserve: usize,
) -> PlaintextWritten<N> {
let src = plaintext.risky_ref();
let mut buf = Vec::with_capacity(M + reserve);
buf.extend_from_slice(src);
PlaintextWritten::new(self.0, Protected::new(buf))
}
}
pub struct PlaintextWritten<const N: usize>(Nonce<N>, Protected<Vec<u8>>);
impl<const N: usize> PlaintextWritten<N> {
fn new(nonce: Nonce<N>, plaintext: Protected<Vec<u8>>) -> Self {
Self(nonce, plaintext)
}
pub fn accepts_ciphertext_and_tag_ok<E>(
self,
f: impl FnOnce(Vec<u8>) -> Result<Vec<u8>, E>,
) -> EncryptedWithTag<N, E> {
EncryptedWithTag::new(self.0, self.1.map_ok(f))
}
}
pub struct EncryptedWithTag<const N: usize, E> {
nonce: Nonce<N>,
bytes: Result<Protected<Vec<u8>>, E>,
}
impl<const N: usize, E> EncryptedWithTag<N, E> {
fn new(nonce: Nonce<N>, bytes: Result<Protected<Vec<u8>>, E>) -> Self {
Self { bytes, nonce }
}
pub fn build(self) -> Result<LocalCipherText, E> {
let inner = self.bytes?.risky_unwrap();
let mut bytes = BytesMut::with_capacity(1 + N + inner.len());
bytes.extend([super::WIRE_VERSION]);
bytes.extend(self.nonce.into_inner());
bytes.extend(inner);
Ok(LocalCipherText(bytes.freeze()))
}
}