use binary_sv2::{GetSize, Serialize};
use core::marker::PhantomData;
use framing_sv2::framing::Sv2Frame;
#[cfg(feature = "noise_sv2")]
use buffer_sv2::AeadBuffer;
#[cfg(feature = "noise_sv2")]
use core::convert::TryInto;
#[cfg(feature = "noise_sv2")]
use framing_sv2::framing::{Frame, HandShakeFrame};
#[cfg(feature = "noise_sv2")]
use framing_sv2::{ENCRYPTED_SV2_FRAME_HEADER_SIZE, SV2_FRAME_CHUNK_SIZE, SV2_FRAME_HEADER_SIZE};
#[cfg(feature = "noise_sv2")]
use noise_sv2::AEAD_MAC_LEN;
#[cfg(feature = "tracing")]
use tracing::error;
#[cfg(feature = "noise_sv2")]
use crate::{Error, Result, State};
#[cfg(not(feature = "with_buffer_pool"))]
use buffer_sv2::{Buffer as IsBuffer, BufferFromSystemMemory as Buffer};
#[cfg(feature = "with_buffer_pool")]
use buffer_sv2::{Buffer as IsBuffer, BufferFromSystemMemory, BufferPool};
#[cfg(feature = "with_buffer_pool")]
type Buffer = BufferPool<BufferFromSystemMemory>;
#[cfg(feature = "noise_sv2")]
pub type NoiseEncoder<T> = WithNoise<Buffer, T>;
pub type Encoder<T> = WithoutNoise<Buffer, T>;
#[cfg(feature = "noise_sv2")]
pub struct WithNoise<B: IsBuffer, T: Serialize + binary_sv2::GetSize> {
noise_buffer: B,
sv2_buffer: B,
frame: PhantomData<T>,
}
#[cfg(feature = "noise_sv2")]
type Item<T, B> = Frame<T, <B as IsBuffer>::Slice>;
#[cfg(feature = "noise_sv2")]
impl<B: IsBuffer + AeadBuffer, T: Serialize + GetSize> WithNoise<B, T> {
#[inline]
pub fn encode(&mut self, item: Item<T, B>, state: &mut State) -> Result<B::Slice> {
match state {
State::Transport(noise_codec) => {
let len = item.encoded_length();
let writable = self.sv2_buffer.get_writable(len);
let i: Sv2Frame<T, B::Slice> = item.try_into().map_err(|e| {
#[cfg(feature = "tracing")]
error!("Error while encoding 1 frame: {:?}", e);
Error::FramingError(e)
})?;
i.serialize(writable)?;
let sv2 = self.sv2_buffer.get_data_owned();
let sv2: &[u8] = sv2.as_ref();
let to_encrypt = self.noise_buffer.get_writable(SV2_FRAME_HEADER_SIZE);
to_encrypt.copy_from_slice(&sv2[..SV2_FRAME_HEADER_SIZE]);
noise_codec.encrypt(&mut self.noise_buffer)?;
let mut start = SV2_FRAME_HEADER_SIZE;
let mut end = if sv2.len() - start < (SV2_FRAME_CHUNK_SIZE - AEAD_MAC_LEN) {
sv2.len()
} else {
SV2_FRAME_CHUNK_SIZE + start - AEAD_MAC_LEN
};
let mut encrypted_len = ENCRYPTED_SV2_FRAME_HEADER_SIZE;
while start < sv2.len() {
let to_encrypt = self.noise_buffer.get_writable(end - start);
to_encrypt.copy_from_slice(&sv2[start..end]);
self.noise_buffer.danger_set_start(encrypted_len);
noise_codec.encrypt(&mut self.noise_buffer)?;
encrypted_len += self.noise_buffer.as_ref().len();
start = end;
end = (start + SV2_FRAME_CHUNK_SIZE - AEAD_MAC_LEN).min(sv2.len());
}
self.noise_buffer.danger_set_start(0);
}
State::HandShake(_) => self.while_handshaking(item)?,
State::NotInitialized(_) => self.while_handshaking(item)?,
};
self.sv2_buffer.get_data_owned();
Ok(self.noise_buffer.get_data_owned())
}
#[inline(never)]
fn while_handshaking(&mut self, item: Item<T, B>) -> Result<()> {
let i: HandShakeFrame = item.try_into().map_err(|e| {
#[cfg(feature = "tracing")]
error!("Error while encoding 2 frame - while_handshaking: {:?}", e);
Error::FramingError(e)
})?;
let payload = i.get_payload_when_handshaking();
let wrtbl = self.noise_buffer.get_writable(payload.len());
for (i, b) in payload.iter().enumerate() {
wrtbl[i] = *b;
}
Ok(())
}
pub fn droppable(&self) -> bool {
self.noise_buffer.is_droppable() && self.sv2_buffer.is_droppable()
}
}
#[cfg(feature = "noise_sv2")]
impl<T: Serialize + binary_sv2::GetSize> WithNoise<Buffer, T> {
pub fn new() -> Self {
#[cfg(not(feature = "with_buffer_pool"))]
let size = 512;
#[cfg(feature = "with_buffer_pool")]
let size = 2_usize.pow(16) * 5;
Self {
sv2_buffer: Buffer::new(size),
noise_buffer: Buffer::new(size),
frame: core::marker::PhantomData,
}
}
}
#[cfg(feature = "noise_sv2")]
impl<T: Serialize + GetSize> Default for WithNoise<Buffer, T> {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
pub struct WithoutNoise<B: IsBuffer, T> {
buffer: B,
frame: PhantomData<T>,
}
impl<B: IsBuffer, T: Serialize + GetSize> WithoutNoise<B, T> {
pub fn encode(
&mut self,
item: Sv2Frame<T, B::Slice>,
) -> core::result::Result<B::Slice, crate::Error> {
let len = item.encoded_length();
let writable = self.buffer.get_writable(len);
item.serialize(writable)?;
Ok(self.buffer.get_data_owned())
}
}
impl<T: Serialize + GetSize> Default for WithoutNoise<Buffer, T> {
fn default() -> Self {
Self::new()
}
}
impl<T: Serialize + GetSize> WithoutNoise<Buffer, T> {
pub fn new() -> Self {
Self {
buffer: Buffer::new(512),
frame: core::marker::PhantomData,
}
}
}
#[cfg(test)]
mod prop_tests {
use super::*;
#[cfg(feature = "noise_sv2")]
use crate::{HandshakeRole, State};
use binary_sv2::{self, Serialize};
#[cfg(feature = "noise_sv2")]
use framing_sv2::framing::Frame;
use framing_sv2::framing::Sv2Frame;
#[cfg(feature = "noise_sv2")]
use key_utils::{Secp256k1PublicKey, Secp256k1SecretKey};
#[cfg(feature = "noise_sv2")]
use noise_sv2::{ELLSWIFT_ENCODING_SIZE, INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE};
use quickcheck::{Arbitrary, Gen, TestResult};
use quickcheck_macros::quickcheck;
#[cfg(feature = "noise_sv2")]
use std::convert::TryInto;
#[cfg(feature = "noise_sv2")]
use std::time::Duration;
#[cfg(feature = "noise_sv2")]
const AUTHORITY_PUBLIC_K: &str = "9auqWEzQDVyd2oe1JVGFLMLHZtCo2FFqZwtKA5gd9xbuEu7PH72";
#[cfg(feature = "noise_sv2")]
const AUTHORITY_PRIVATE_K: &str = "mkDLTBBRxdBv998612qipDYoTK3YUrqLe8uWw7gu3iXbSrn2n";
type Slice = <Buffer as IsBuffer>::Slice;
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
struct TestMessage {
value: u16,
}
impl Arbitrary for TestMessage {
fn arbitrary(g: &mut Gen) -> Self {
TestMessage {
value: u16::arbitrary(g),
}
}
}
#[quickcheck]
fn prop_encoder_encode(
msg: TestMessage,
msg_type: u8,
ext_type: u16,
channel_msg: bool,
) -> TestResult {
let frame = match Sv2Frame::<TestMessage, Slice>::from_message(
msg,
msg_type,
ext_type,
channel_msg,
) {
Some(f) => f,
None => return TestResult::discard(),
};
let mut encoder = Encoder::<TestMessage>::new();
match encoder.encode(frame.clone()) {
Ok(data) => {
let bytes: &[u8] = data.as_ref();
TestResult::from_bool(!bytes.is_empty() && bytes.len() <= frame.encoded_length())
}
Err(_) => TestResult::failed(),
}
}
#[quickcheck]
fn prop_encoder_reusable(msg1: TestMessage, msg2: TestMessage, msg_type: u8) -> TestResult {
let frame1 = match Sv2Frame::<TestMessage, Slice>::from_message(msg1, msg_type, 0, false) {
Some(f) => f,
None => return TestResult::discard(),
};
let frame2 = match Sv2Frame::<TestMessage, Slice>::from_message(msg2, msg_type, 0, false) {
Some(f) => f,
None => return TestResult::discard(),
};
let mut encoder = Encoder::<TestMessage>::new();
let ok1 = encoder.encode(frame1).is_ok();
let ok2 = encoder.encode(frame2).is_ok();
TestResult::from_bool(ok1 && ok2)
}
#[cfg(feature = "noise_sv2")]
fn make_transport_state_pair() -> (State, State) {
let pub_k: Secp256k1PublicKey = AUTHORITY_PUBLIC_K.to_string().try_into().unwrap();
let pub_k_bytes = pub_k.into_bytes();
let priv_k: Secp256k1SecretKey = AUTHORITY_PRIVATE_K.to_string().try_into().unwrap();
let priv_k_bytes = priv_k.into_bytes();
let initiator = noise_sv2::Initiator::from_raw_k(pub_k_bytes).unwrap();
let responder = noise_sv2::Responder::from_authority_kp(
&pub_k_bytes,
&priv_k_bytes,
Duration::from_secs(3600),
)
.unwrap();
let mut sender_state = State::initialized(HandshakeRole::Initiator(initiator));
let mut receiver_state = State::initialized(HandshakeRole::Responder(responder));
let msg0 = sender_state.step_0().unwrap();
let msg0: [u8; ELLSWIFT_ENCODING_SIZE] =
msg0.get_payload_when_handshaking().try_into().unwrap();
let (msg1, receiver_transport) = receiver_state.step_1(msg0).unwrap();
let msg1: [u8; INITIATOR_EXPECTED_HANDSHAKE_MESSAGE_SIZE] =
msg1.get_payload_when_handshaking().try_into().unwrap();
let sender_transport = sender_state.step_2(msg1).unwrap();
let sender_state = match sender_transport {
State::Transport(c) => State::with_transport_mode(c),
_ => unreachable!(),
};
let receiver_state = match receiver_transport {
State::Transport(c) => State::with_transport_mode(c),
_ => unreachable!(),
};
(sender_state, receiver_state)
}
#[cfg(feature = "noise_sv2")]
#[quickcheck]
fn prop_noise_encoder_encode(
msg: TestMessage,
msg_type: u8,
ext_type: u16,
channel_msg: bool,
) -> TestResult {
let frame = match Sv2Frame::<TestMessage, Slice>::from_message(
msg,
msg_type,
ext_type,
channel_msg,
) {
Some(f) => Frame::Sv2(f),
None => return TestResult::discard(),
};
let (mut sender_state, _) = make_transport_state_pair();
let mut encoder = NoiseEncoder::<TestMessage>::new();
match encoder.encode(frame, &mut sender_state) {
Ok(data) => {
let bytes: &[u8] = data.as_ref();
TestResult::from_bool(!bytes.is_empty())
}
Err(_) => TestResult::failed(),
}
}
#[cfg(feature = "noise_sv2")]
#[quickcheck]
fn prop_noise_encoder_reusable(
msg1: TestMessage,
msg2: TestMessage,
msg_type: u8,
) -> TestResult {
let frame1 = match Sv2Frame::<TestMessage, Slice>::from_message(msg1, msg_type, 0, false) {
Some(f) => Frame::Sv2(f),
None => return TestResult::discard(),
};
let frame2 = match Sv2Frame::<TestMessage, Slice>::from_message(msg2, msg_type, 0, false) {
Some(f) => Frame::Sv2(f),
None => return TestResult::discard(),
};
let (mut sender_state, _) = make_transport_state_pair();
let mut encoder = NoiseEncoder::<TestMessage>::new();
let ok1 = encoder.encode(frame1, &mut sender_state).is_ok();
let ok2 = encoder.encode(frame2, &mut sender_state).is_ok();
TestResult::from_bool(ok1 && ok2)
}
}