use super::RosenpassError;
use crate::{pqkem::*, sodium};
#[macro_export]
macro_rules! data_lense(
(token_muncher_ref @ $offset:expr ; $( $attr:meta )* ; $field:ident : $len:expr $(, $( $tail:tt )+ )?) => {
::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
$( #[ $attr ] )*
#[doc = data_lense!(maybe_docstring_link $len)]
pub fn $field(&self) -> &__ContainerType::Output {
&self.0[$offset .. $offset + $len]
}
#[doc = data_lense!(maybe_docstring_link Self::$field)]
pub fn [< until_ $field >](&self) -> &__ContainerType::Output {
&self.0[0 .. $offset]
}
$(
data_lense!{token_muncher_ref @ $offset + $len ; $( $tail )+ }
)?
}
};
(token_muncher_mut @ $offset:expr ; $( $attr:meta )* ; $field:ident : $len:expr $(, $( $tail:tt )+ )?) => {
::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
$( #[ $attr ] )*
#[doc = data_lense!(maybe_docstring_link $len)]
pub fn [< $field _mut >](&mut self) -> &mut __ContainerType::Output {
&mut self.0[$offset .. $offset + $len]
}
$(
data_lense!{token_muncher_mut @ $offset + $len ; $( $tail )+ }
)?
}
};
(maybe_docstring_link $x:literal) => (stringify!($x));
(maybe_docstring_link $x:expr) => (stringify!([$x]));
($type:ident $( < $( $generic:ident ),+ > )? := $( $( #[ $attr:meta ] )* $field:ident : $len:expr ),+) => (::paste::paste!{
#[allow(rustdoc::broken_intra_doc_links)]
$(
#[doc = stringify!($field)]
#[doc = data_lense!(maybe_docstring_link $len)]
)+
pub struct $type<__ContainerType $(, $( $generic ),+ )? > (
__ContainerType,
$( $( ::core::marker::PhantomData<$generic> ),+ )?
);
impl<__ContainerType $(, $( $generic: LenseView ),+ )? > $type<__ContainerType $(, $( $generic ),+ )? >{
$(
pub const fn [< $field _len >]() -> usize{
$len
}
)+
pub fn check_size(len: usize) -> Result<(), RosenpassError>{
let required_size = $( $len + )+ 0;
let actual_size = len;
if required_size != actual_size {
Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
})
}else{
Ok(())
}
}
}
impl<'a, __ContainerType $(, $( $generic: LenseView ),+ )?> $type<&'a __ContainerType $(, $( $generic ),+ )?>
where
__ContainerType: std::ops::Index<std::ops::Range<usize>> + ?Sized,
{
data_lense!{token_muncher_ref @ 0 ; $( $( $attr )* ; $field : $len ),+ }
pub fn all_bytes(&self) -> &__ContainerType::Output {
&self.0[0..Self::LEN]
}
}
impl<'a, __ContainerType $(, $( $generic: LenseView ),+ )?> $type<&'a mut __ContainerType $(, $( $generic ),+ )?>
where
__ContainerType: std::ops::IndexMut<std::ops::Range<usize>> + ?Sized,
{
data_lense!{token_muncher_ref @ 0 ; $( $( $attr )* ; $field : $len ),+ }
data_lense!{token_muncher_mut @ 0 ; $( $( $attr )* ; $field : $len ),+ }
pub fn all_bytes(&self) -> &__ContainerType::Output {
&self.0[0..Self::LEN]
}
pub fn all_bytes_mut(&mut self) -> &mut __ContainerType::Output {
&mut self.0[0..Self::LEN]
}
}
impl<__ContainerType $(, $( $generic: LenseView ),+ )? > LenseView for $type<__ContainerType $(, $( $generic ),+ )? >{
const LEN: usize = $( $len + )+ 0;
}
#[doc = data_lense!(maybe_docstring_link $type)]
pub trait [< $type Ext >] {
type __ContainerType;
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError>;
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError>;
}
impl<'a> [< $type Ext >] for &'a [u8] {
type __ContainerType = &'a [u8];
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
let required_size = $( $len + )+ 0;
let actual_size = self.len();
if actual_size < required_size {
return Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
});
}
[< $type Ext >]::[< $type:snake >](&self[..required_size])
}
}
impl<'a> [< $type Ext >] for &'a mut [u8] {
type __ContainerType = &'a mut [u8];
fn [< $type:snake >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
$type::<Self::__ContainerType, $( $($generic),+ )? >::check_size(self.len())?;
Ok($type ( self, $( $( ::core::marker::PhantomData::<$generic> ),+ )? ))
}
fn [< $type:snake _ truncating >] $(< $($generic : LenseView),* >)? (self) -> Result< $type<Self::__ContainerType, $( $($generic),+ )? >, RosenpassError> {
let required_size = $( $len + )+ 0;
let actual_size = self.len();
if actual_size < required_size {
return Err(RosenpassError::BufferSizeMismatch {
required_size,
actual_size,
});
}
[< $type Ext >]::[< $type:snake >](&mut self[..required_size])
}
}
});
);
pub trait LenseView {
const LEN: usize;
}
data_lense! { Envelope<M> :=
msg_type: 1,
reserved: 3,
payload: M::LEN,
mac: sodium::MAC_SIZE,
cookie: sodium::MAC_SIZE
}
data_lense! { InitHello :=
sidi: 4,
epki: EphemeralKEM::PK_LEN,
sctr: StaticKEM::CT_LEN,
pidic: sodium::AEAD_TAG_LEN + 32,
auth: sodium::AEAD_TAG_LEN
}
data_lense! { RespHello :=
sidr: 4,
sidi: 4,
ecti: EphemeralKEM::CT_LEN,
scti: StaticKEM::CT_LEN,
auth: sodium::AEAD_TAG_LEN,
biscuit: BISCUIT_CT_LEN
}
data_lense! { InitConf :=
sidi: 4,
sidr: 4,
biscuit: BISCUIT_CT_LEN,
auth: sodium::AEAD_TAG_LEN
}
data_lense! { EmptyData :=
sid: 4,
ctr: 8,
auth: sodium::AEAD_TAG_LEN
}
data_lense! { Biscuit :=
pidi: sodium::KEY_SIZE,
biscuit_no: 12,
ck: sodium::KEY_SIZE
}
data_lense! { DataMsg :=
dummy: 4
}
data_lense! { CookieReply :=
dummy: 4
}
pub trait WireMsg: std::fmt::Debug {
const MSG_TYPE: MsgType;
const MSG_TYPE_U8: u8 = Self::MSG_TYPE as u8;
const BYTES: usize;
}
pub const SESSION_ID_LEN: usize = 4;
pub const BISCUIT_ID_LEN: usize = 12;
pub const WIRE_ENVELOPE_LEN: usize = 1 + 3 + 16 + 16;
pub const MAX_MESSAGE_LEN: usize = 2500;
#[repr(u8)]
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)]
pub enum MsgType {
InitHello = 0x81,
RespHello = 0x82,
InitConf = 0x83,
EmptyData = 0x84,
DataMsg = 0x85,
CookieReply = 0x86,
}
impl TryFrom<u8> for MsgType {
type Error = RosenpassError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0x81 => MsgType::InitHello,
0x82 => MsgType::RespHello,
0x83 => MsgType::InitConf,
0x84 => MsgType::EmptyData,
0x85 => MsgType::DataMsg,
0x86 => MsgType::CookieReply,
_ => return Err(RosenpassError::InvalidMessageType(value)),
})
}
}
pub const BISCUIT_PT_LEN: usize = Biscuit::<()>::LEN;
pub const BISCUIT_CT_LEN: usize = BISCUIT_PT_LEN + sodium::XAEAD_NONCE_LEN + sodium::XAEAD_TAG_LEN;
#[cfg(test)]
mod test_constants {
use crate::{
msgs::{BISCUIT_CT_LEN, BISCUIT_PT_LEN},
sodium,
};
#[test]
fn sodium_keysize() {
assert_eq!(sodium::KEY_SIZE, 32);
}
#[test]
fn biscuit_pt_len() {
assert_eq!(BISCUIT_PT_LEN, 2 * sodium::KEY_SIZE + 12);
}
#[test]
fn biscuit_ct_len() {
assert_eq!(
BISCUIT_CT_LEN,
BISCUIT_PT_LEN + sodium::XAEAD_NONCE_LEN + sodium::XAEAD_TAG_LEN
);
}
}