#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[cfg(feature = "noise_sv2")]
use alloc::boxed::Box;
#[cfg(feature = "noise_sv2")]
use framing_sv2::framing::{handshake_message_to_frame as h2f, HandShakeFrame};
#[cfg(feature = "noise_sv2")]
use noise_sv2::NoiseCodec;
mod decoder;
mod encoder;
pub mod error;
pub use error::{Error, Result};
pub use decoder::{StandardEitherFrame, StandardSv2Frame};
pub use decoder::StandardDecoder;
#[cfg(feature = "noise_sv2")]
pub use decoder::StandardNoiseDecoder;
pub use encoder::Encoder;
#[cfg(feature = "noise_sv2")]
pub use encoder::NoiseEncoder;
#[allow(clippy::large_enum_variant)]
#[cfg(feature = "noise_sv2")]
#[derive(Debug, Clone)]
pub enum HandshakeRole {
Initiator(Box<noise_sv2::Initiator>),
Responder(Box<noise_sv2::Responder>),
}
#[cfg(feature = "noise_sv2")]
#[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)]
pub enum State {
NotInitialized(usize),
HandShake(HandshakeRole),
Transport(NoiseCodec),
}
#[cfg(feature = "noise_sv2")]
impl State {
pub fn step_0(&mut self) -> core::result::Result<HandShakeFrame, Error> {
match self {
Self::HandShake(h) => match h {
HandshakeRole::Initiator(i) => i.step_0().map_err(|e| e.into()).map(h2f),
HandshakeRole::Responder(_) => Err(Error::InvalidStepForResponder),
},
_ => Err(Error::NotInHandShakeState),
}
}
#[cfg(feature = "std")]
pub fn step_1(
&mut self,
re_pub: [u8; noise_sv2::ELLSWIFT_ENCODING_SIZE],
) -> core::result::Result<(HandShakeFrame, Self), Error> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
self.step_1_with_now_rng(re_pub, now, &mut rand::thread_rng())
}
#[inline]
pub fn step_1_with_now_rng<R: rand::Rng + rand::CryptoRng>(
&mut self,
re_pub: [u8; noise_sv2::ELLSWIFT_ENCODING_SIZE],
now: u32,
rng: &mut R,
) -> core::result::Result<(HandShakeFrame, Self), Error> {
match self {
Self::HandShake(h) => match h {
HandshakeRole::Responder(r) => {
let (message, codec) = r.step_1_with_now_rng(re_pub, now, rng)?;
Ok((h2f(message), Self::Transport(codec)))
}
HandshakeRole::Initiator(_) => Err(Error::InvalidStepForInitiator),
},
_ => Err(Error::NotInHandShakeState),
}
}
#[cfg(feature = "std")]
pub fn step_2(
&mut self,
message: [u8; noise_sv2::INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE],
) -> core::result::Result<Self, Error> {
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs() as u32;
self.step_2_with_now(message, now)
}
#[inline]
pub fn step_2_with_now(
&mut self,
message: [u8; noise_sv2::INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE],
now: u32,
) -> core::result::Result<Self, Error> {
match self {
Self::HandShake(h) => match h {
HandshakeRole::Initiator(i) => i
.step_2_with_now(message, now)
.map_err(|e| e.into())
.map(Self::Transport),
HandshakeRole::Responder(_) => Err(Error::InvalidStepForResponder),
},
_ => Err(Error::NotInHandShakeState),
}
}
}
#[cfg(feature = "noise_sv2")]
impl State {
pub fn not_initialized(role: &HandshakeRole) -> Self {
match role {
HandshakeRole::Initiator(_) => {
Self::NotInitialized(noise_sv2::INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE)
}
HandshakeRole::Responder(_) => Self::NotInitialized(noise_sv2::ELLSWIFT_ENCODING_SIZE),
}
}
pub fn initialized(inner: HandshakeRole) -> Self {
Self::HandShake(inner)
}
pub fn with_transport_mode(tm: NoiseCodec) -> Self {
Self::Transport(tm)
}
}
#[cfg(test)]
#[cfg(feature = "noise_sv2")]
mod tests {
use super::*;
#[test]
fn handshake_step_fails_if_state_is_not_initialized() {
let mut state = State::NotInitialized(32);
let actual = state.step_0().unwrap_err();
let expect = Error::NotInHandShakeState;
assert_eq!(actual, expect);
}
#[test]
fn handshake_step_fails_if_state_is_in_transport_mode() {
let mut state = State::NotInitialized(32);
let actual = state.step_0().unwrap_err();
let expect = Error::NotInHandShakeState;
assert_eq!(actual, expect);
}
}