nym-sphinx-wasm: various cleanups on packet creation

This commit is contained in:
Dave Hrycyszyn
2020-04-16 18:26:12 +01:00
parent d7e4374054
commit fd874845cd
+62 -22
View File
@@ -14,15 +14,18 @@
use crypto::identity::MixIdentityPublicKey;
use curve25519_dalek::montgomery::MontgomeryPoint;
use nymsphinx::addressing::nodes::NymNodeRoutingAddress;
use nymsphinx::chunking::split_and_prepare_payloads;
use serde::{Deserialize, Serialize};
use serde_json;
use sphinx::header::delays;
use sphinx::route::DestinationAddressBytes;
use sphinx::route::NodeAddressBytes;
use sphinx::route::{Destination, Node};
use sphinx::SphinxPacket;
use std::convert::TryFrom;
use std::convert::TryInto;
use std::net::SocketAddr;
use std::time::Duration;
use wasm_bindgen::prelude::*;
mod utils;
@@ -36,12 +39,12 @@ const IDENTIFIER_LENGTH: usize = 16;
static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT;
#[derive(Serialize, Deserialize)]
pub struct Route {
pub struct JsonRoute {
nodes: Vec<NodeData>,
}
#[wasm_bindgen]
#[derive(Serialize, Deserialize)]
#[derive(Clone, Serialize, Deserialize)]
pub struct NodeData {
address: String,
public_key: String,
@@ -54,36 +57,73 @@ pub struct NodeData {
/// Message chunking is currently not implemented. If the message exceeds the
/// capacity of a single Sphinx packet, the extra information will be discarded.
#[wasm_bindgen]
pub fn create_sphinx_packet(rout: String, msg: &str, destination: &str) -> Vec<u8> {
pub fn create_sphinx_packet(raw_route: &str, msg: &str, destination: &str) -> Vec<u8> {
utils::set_panic_hook(); // nicer js errors.
let r: Route = serde_json::from_str(&rout).unwrap();
let mut route: Vec<Node> = vec![];
for node in r.nodes.iter() {
let address = node.address.parse().unwrap();
let public_key = public_key_from_str(&node.public_key);
let n = NymNodeRoutingAddress(address);
let x = Node::new(n.try_into().unwrap(), public_key);
route.push(x);
}
let route = sphinx_route_from(raw_route);
let average_delay = Duration::from_secs_f64(1.0);
let average_delay = Duration::from_secs_f64(0.1);
let delays = delays::generate_from_average_duration(route.len(), average_delay);
let dest_bytes = DestinationAddressBytes::from_base58_string(destination.to_owned());
let dest = Destination::new(dest_bytes, [4u8; IDENTIFIER_LENGTH]);
let message = split_and_prepare_payloads(&msg.as_bytes()).pop().unwrap();
let sphinx_packet = match SphinxPacket::new(message, &route, &dest, &delays).unwrap() {
SphinxPacket { header, payload } => SphinxPacket { header, payload },
};
let mut message = nymsphinx::chunking::split_and_prepare_payloads(&msg.as_bytes());
let sphinx_packet =
match SphinxPacket::new(message.pop().unwrap(), &route, &dest, &delays).unwrap() {
SphinxPacket { header, payload } => SphinxPacket { header, payload },
};
sphinx_packet.to_bytes()
payload(sphinx_packet, route)
}
fn public_key_from_str(s: &str) -> MontgomeryPoint {
/// Concatenate the first mix address bytes with the Sphinx packet.
///
/// The Nym gateway node has no idea what is inside the Sphinx packet, or where
/// it should send a packet it receives. So we prepend the packet with the
/// address bytes of the first mix inside the packet, so that the gateway can
/// forward the packet to it.
fn payload(sphinx_packet: SphinxPacket, route: Vec<Node>) -> Vec<u8> {
let mut packet = sphinx_packet.to_bytes();
let mut first_mix_address = route.first().unwrap().clone().address.to_bytes().to_vec();
let mut bytes: Vec<u8> = vec![];
bytes.append(&mut first_mix_address);
bytes.append(&mut packet);
bytes
}
fn sphinx_route_from(raw_route: &str) -> Vec<Node> {
let json_route: JsonRoute = serde_json::from_str(raw_route).unwrap();
assert!(
json_route.nodes.len() > 0,
"Sphinx packet must route to at least one mixnode."
);
let mut sphinx_route: Vec<Node> = vec![];
for node_data in json_route.nodes.iter() {
let x = Node::try_from(node_data.clone()).expect("Malformed NodeData");
sphinx_route.push(x);
}
sphinx_route
}
// Converts a base58 &str into a public key (MontgomeryPoint)
//
// A TryInto would be nice here but this crate doesn't own MontgomeryPoint.
fn public_key_from(s: &str) -> MontgomeryPoint {
let src = MixIdentityPublicKey::from_base58_string(s.to_owned()).to_bytes();
let mut dest: [u8; 32] = [0; 32];
dest.copy_from_slice(&src);
MontgomeryPoint(dest)
}
impl TryFrom<NodeData> for Node {
type Error = ();
fn try_from(node_data: NodeData) -> Result<Self, Self::Error> {
let parsed: SocketAddr = node_data.address.parse().unwrap();
let address: NodeAddressBytes = NymNodeRoutingAddress(parsed).try_into().unwrap();
let pub_key = public_key_from(&node_data.public_key);
Ok(Node { address, pub_key })
}
}