use crate::prelude::*;
use std::sync::Arc;
use rand::prelude::*;
#[derive(Debug, PartialEq)]
enum InputChunk {
Message(Vec<u8>, Option<u8>),
Transport(String),
}
impl InputChunk {
fn serialize(self) -> Vec<u8> {
match self {
InputChunk::Message(mut m, reply_to) => {
let mut b = vec![0];
let reply_to = match reply_to {
None => 0,
Some(idx) => idx + 1,
};
b.push(reply_to);
b.append(&mut m);
b
}
InputChunk::Transport(t) => {
let mut b = vec![1];
b.append(&mut t.into_bytes());
b
}
}
}
}
#[derive(Debug, PartialEq)]
pub(crate) enum Chunk {
Message(Vec<u8>, Option<Arc<Vec<Vec<u8>>>>),
Transport(String),
}
impl Chunk {
fn deserialize(mut from: Vec<u8>, replies: &[Arc<Vec<Vec<u8>>>]) -> Result<Chunk, ()> {
match from.get(0) {
Some(0) => {
let reply = match from[1] {
0 => None,
i => Some(replies.get(i as usize - 1).expect("Should be valid index").clone()),
};
Ok(Chunk::Message(from.drain(2..).collect(), reply))
}
Some(1) => Ok(Chunk::Transport(
String::from_utf8(from.drain(1..).collect()).map_err(|_| ())?,
)),
_ => Err(()),
}
}
}
pub struct ReplyPathHandle<'packet>(u8, &'packet mut Packet);
impl<'packet> ReplyPathHandle<'packet> {
pub fn add_message<'handle>(
&'handle mut self,
data: &[u8],
node_pkey: &encrypt::PublicKey,
reply: Option<ReplyPathHandle<'handle>>,
) {
self.1.add_instruction(
Some(self.0),
InputChunk::Message(data.to_vec(), reply.map(|h| h.0)),
node_pkey,
)
}
pub fn add_hop(&mut self, path: String, node_pkey: &encrypt::PublicKey) {
self
.1
.add_instruction(Some(self.0), InputChunk::Transport(path), node_pkey)
}
pub fn use_for_message(&mut self, data: &[u8], node_pkey: &encrypt::PublicKey) {
self
.1
.add_instruction(None, InputChunk::Message(data.to_vec(), Some(self.0)), node_pkey)
}
}
#[derive(Clone)]
pub struct Packet {
pub(crate) main_path: Vec<Vec<u8>>,
pub(crate) reply_paths: Vec<Vec<Vec<u8>>>,
pub(crate) signing_key: Option<sign::SecretKey>,
}
impl Packet {
pub fn unsigned() -> Packet {
Packet {
main_path: vec![],
reply_paths: vec![],
signing_key: None,
}
}
pub fn signed(skey: sign::SecretKey) -> Packet {
Packet {
signing_key: Some(skey),
..Packet::unsigned()
}
}
pub fn reply_to(&mut self, msg: &Message) -> fail::Result<()> {
match &msg.reply_path {
None => Err(fail::MesherFail::NoReplyBlock),
Some(path) => {
self.main_path.append(&mut path.as_ref().clone());
Ok(())
}
}
}
fn add_instruction(&mut self, block: Option<u8>, instruct: InputChunk, target_pkey: &encrypt::PublicKey) {
let bytes = instruct.serialize();
let bytes = encrypt::seal(&bytes, &target_pkey);
let bytes = match &self.signing_key {
Some(key) => sign::sign(&bytes, key),
None => bytes,
};
match block {
None => &mut self.main_path,
Some(idx) => &mut self.reply_paths[idx as usize],
}
.push(bytes);
}
pub fn add_message(&mut self, data: &[u8], node_pkey: &encrypt::PublicKey) {
self.add_instruction(None, InputChunk::Message(data.to_vec(), None), node_pkey)
}
pub fn add_hop(&mut self, path: String, node_pkey: &encrypt::PublicKey) {
self.add_instruction(None, InputChunk::Transport(path), node_pkey)
}
pub fn add_reply_path(&mut self) -> Option<ReplyPathHandle> {
if self.reply_paths.len() == u8::max_value() as usize {
return None;
}
self.reply_paths.push(vec![]);
Some(ReplyPathHandle(self.reply_paths.len() as u8 - 1, self))
}
pub(crate) fn serialize(mut self) -> fail::Result<Vec<u8>> {
let mut rng = thread_rng();
let mut paths = Vec::with_capacity(self.reply_paths.len() + 1);
self.main_path.shuffle(&mut rng);
paths.push(self.main_path);
for mut path in self.reply_paths {
path.shuffle(&mut rng);
paths.push(path);
}
bincode::serialize(&paths).map_err(|e| fail::MesherFail::Other(Box::new(e)))
}
pub(crate) fn deserialize(packet: &[u8], keys: &[encrypt::SecretKey]) -> fail::Result<Vec<Chunk>> {
let blocks = bincode::deserialize::<Vec<Vec<Vec<u8>>>>(packet);
let mut blocks = match blocks {
Ok(blocks) if !blocks.is_empty() => blocks,
_ => return Err(fail::MesherFail::InvalidPacket),
};
let reply_blocks: Vec<_> = blocks.split_off(1).into_iter().map(Arc::new).collect();
let main = blocks.pop().expect("Already validated length before");
let main = main
.into_iter()
.filter_map(|b| keys.iter().find_map(|k| encrypt::open(&b, k).ok()))
.filter_map(|c| Chunk::deserialize(c, &reply_blocks).ok())
.collect();
Ok(main)
}
pub(crate) fn deserialize_signed(
packet: &[u8],
keys: &[encrypt::SecretKey],
sender_keys: &[sign::PublicKey],
) -> fail::Result<Vec<Chunk>> {
let blocks = bincode::deserialize::<Vec<Vec<Vec<u8>>>>(packet);
let mut blocks = match blocks {
Ok(blocks) if !blocks.is_empty() => blocks,
_ => return Err(fail::MesherFail::InvalidPacket),
};
let reply_blocks: Vec<_> = blocks.split_off(1).into_iter().map(Arc::new).collect();
let main = blocks.pop().expect("Already validated length before");
let main = main
.into_iter()
.filter_map(|b| sender_keys.iter().find_map(|k| sign::verify(&b, k).ok()))
.filter_map(|b| keys.iter().find_map(|k| encrypt::open(&b, k).ok()))
.filter_map(|c| Chunk::deserialize(c, &reply_blocks).ok())
.collect();
Ok(main)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unsigned_serialized_deserializable() {
let (pk1, sk1) = encrypt::gen_keypair();
let (pk2, sk2) = encrypt::gen_keypair();
let mut packet = Packet::unsigned();
packet.add_hop("hello".to_owned(), &pk1);
packet.add_message(&[1, 2, 3], &pk2);
let packet = packet.serialize().expect("Failed to serialize packet");
let dec1 = Packet::deserialize(&packet, &[sk1]).expect("Failed to deserialize packets");
assert!(dec1.contains(&Chunk::Transport("hello".to_owned())));
let dec2 = Packet::deserialize(&packet, &[sk2]).expect("Failed to deserialize packets");
assert!(dec2.contains(&Chunk::Message(vec![1, 2, 3], None)));
}
#[test]
fn signed_serialized_deserializable() {
let (pks, sks) = sign::gen_keypair();
let (pk1, sk1) = encrypt::gen_keypair();
let (pk2, sk2) = encrypt::gen_keypair();
let mut packet = Packet::signed(sks);
packet.add_hop("hello".to_owned(), &pk1);
packet.add_message(&[1, 2, 3], &pk2);
let packet = packet.serialize().expect("Failed to serialize packet");
let dec1 = Packet::deserialize_signed(&packet, &[sk1], &[pks]).expect("Failed to deserialize packets");
assert!(dec1.contains(&Chunk::Transport("hello".to_owned())));
let dec2 = Packet::deserialize_signed(&packet, &[sk2], &[pks]).expect("Failed to deserialize packets");
assert!(dec2.contains(&Chunk::Message(vec![1, 2, 3], None)));
}
#[test]
fn all_functions_compile() {
let (pk, _) = encrypt::gen_keypair();
let mut packet = Packet::unsigned();
packet.add_hop("foo1".to_owned(), &pk);
packet.add_message(&[1], &pk);
let mut rh1 = packet.add_reply_path().expect("Failed to add reply handle 1");
rh1.add_hop("foo2".to_owned(), &pk);
rh1.use_for_message(&[2], &pk);
let mut rh2 = packet.add_reply_path().expect("Failed to add reply handle 2");
rh2.add_hop("foo4".to_owned(), &pk);
rh2.use_for_message(&[4], &pk);
}
#[test]
fn replies_match() {
use std::collections::HashMap;
let (pk, sk) = encrypt::gen_keypair();
let (tpk, _) = encrypt::gen_keypair();
let bytes = {
let mut packet = Packet::unsigned();
packet.add_hop("foo1".to_owned(), &tpk);
packet.add_message(&[1], &pk);
let mut rh1 = packet.add_reply_path().expect("Failed to add reply handle 1");
rh1.add_hop("foo2".to_owned(), &tpk);
rh1.use_for_message(&[2], &pk);
rh1.use_for_message(&[3], &pk);
let mut rh2 = packet.add_reply_path().expect("Failed to add reply handle 2");
rh2.add_hop("foo4".to_owned(), &tpk);
rh2.use_for_message(&[4], &pk);
rh2.use_for_message(&[5], &pk);
packet.serialize().expect("Failed to serialize packet")
};
let deser = Packet::deserialize(&bytes, &[sk]).expect("Failed to deserialize");
let mut messages = HashMap::new();
for chunk in deser {
if let Chunk::Message(data, rep) = chunk {
messages.insert(data[0], rep);
}
}
assert_eq!(messages[&1], None);
assert_eq!(messages[&2], messages[&3]);
assert_eq!(messages[&4], messages[&5]);
assert_ne!(messages[&2], None);
assert_ne!(messages[&4], None);
assert_ne!(messages[&3], messages[&4]);
}
#[test]
fn signed_replies_match() {
use std::collections::HashMap;
let (rpk, rsk) = encrypt::gen_keypair();
let (spk, ssk) = sign::gen_keypair();
let (tpk, _) = encrypt::gen_keypair();
let bytes = {
let mut packet = Packet::signed(ssk);
packet.add_hop("foo1".to_owned(), &tpk);
packet.add_message(&[1], &rpk);
let mut rh1 = packet.add_reply_path().expect("Failed to add reply handle 1");
rh1.add_hop("foo2".to_owned(), &tpk);
rh1.use_for_message(&[2], &rpk);
rh1.use_for_message(&[3], &rpk);
let mut rh2 = packet.add_reply_path().expect("Failed to add reply handle 2");
rh2.add_hop("foo4".to_owned(), &tpk);
rh2.use_for_message(&[4], &rpk);
rh2.use_for_message(&[5], &rpk);
packet.serialize().expect("Failed to serialize packet")
};
let deser = Packet::deserialize_signed(&bytes, &[rsk], &[spk]).expect("Failed to deserialize");
let mut messages = HashMap::new();
for chunk in deser {
if let Chunk::Message(data, rep) = chunk {
messages.insert(data[0], rep);
}
}
assert_eq!(messages[&1], None);
assert_eq!(messages[&2], messages[&3]);
assert_eq!(messages[&4], messages[&5]);
assert_ne!(messages[&2], None);
assert_ne!(messages[&4], None);
assert_ne!(messages[&3], messages[&4]);
}
}