pub mod link;
pub mod link_map;
use ed25519_dalek::{Signature, SigningKey, VerifyingKey, SIGNATURE_LENGTH};
use rand_core::CryptoRngCore;
use x25519_dalek::PublicKey;
use core::{fmt, marker::PhantomData};
use crate::{
error::RnsError,
hash::{AddressHash, Hash},
identity::{EmptyIdentity, HashIdentity, Identity, PrivateIdentity, PUBLIC_KEY_LENGTH},
packet::{
self, DestinationType, Header, HeaderType, IfacFlag, Packet, PacketContext,
PacketDataBuffer, PacketType, PropagationType,
},
};
use sha2::Digest;
pub trait Direction {}
pub struct Input;
pub struct Output;
impl Direction for Input {}
impl Direction for Output {}
pub trait Type {
fn destination_type() -> DestinationType;
}
pub struct Single;
pub struct Plain;
pub struct Group;
impl Type for Single {
fn destination_type() -> DestinationType {
DestinationType::Single
}
}
impl Type for Plain {
fn destination_type() -> DestinationType {
DestinationType::Plain
}
}
impl Type for Group {
fn destination_type() -> DestinationType {
DestinationType::Group
}
}
pub const NAME_HASH_LENGTH: usize = 10;
pub const RAND_HASH_LENGTH: usize = 10;
pub const MIN_ANNOUNCE_DATA_LENGTH: usize =
PUBLIC_KEY_LENGTH * 2 + NAME_HASH_LENGTH + RAND_HASH_LENGTH + SIGNATURE_LENGTH;
#[derive(Copy, Clone)]
pub struct DestinationName {
pub hash: Hash,
}
impl DestinationName {
pub fn new(app_name: &str, aspects: &str) -> Self {
let hash = Hash::new(
Hash::generator()
.chain_update(app_name.as_bytes())
.chain_update(".".as_bytes())
.chain_update(aspects.as_bytes())
.finalize()
.into(),
);
Self { hash }
}
pub fn new_from_hash_slice(hash_slice: &[u8]) -> Self {
let mut hash = [0u8; 32];
hash[..hash_slice.len()].copy_from_slice(hash_slice);
Self {
hash: Hash::new(hash),
}
}
pub fn as_name_hash_slice(&self) -> &[u8] {
&self.hash.as_slice()[..NAME_HASH_LENGTH]
}
}
#[derive(Copy, Clone)]
pub struct DestinationDesc {
pub identity: Identity,
pub address_hash: AddressHash,
pub name: DestinationName,
}
impl fmt::Display for DestinationDesc {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.address_hash)?;
Ok(())
}
}
pub type DestinationAnnounce = Packet;
impl DestinationAnnounce {
pub fn validate(packet: &Packet) -> Result<(SingleOutputDestination, &[u8]), RnsError> {
if packet.header.packet_type != PacketType::Announce {
return Err(RnsError::PacketError);
}
let announce_data = packet.data.as_slice();
if announce_data.len() < MIN_ANNOUNCE_DATA_LENGTH {
return Err(RnsError::OutOfMemory);
}
let mut offset = 0usize;
let public_key = {
let mut key_data = [0u8; PUBLIC_KEY_LENGTH];
key_data.copy_from_slice(&announce_data[offset..(offset + PUBLIC_KEY_LENGTH)]);
offset += PUBLIC_KEY_LENGTH;
PublicKey::from(key_data)
};
let verifying_key = {
let mut key_data = [0u8; PUBLIC_KEY_LENGTH];
key_data.copy_from_slice(&announce_data[offset..(offset + PUBLIC_KEY_LENGTH)]);
offset += PUBLIC_KEY_LENGTH;
VerifyingKey::from_bytes(&key_data).map_err(|_| RnsError::CryptoError)?
};
let identity = Identity::new(public_key, verifying_key);
let name_hash = &announce_data[offset..(offset + NAME_HASH_LENGTH)];
offset += NAME_HASH_LENGTH;
let rand_hash = &announce_data[offset..(offset + RAND_HASH_LENGTH)];
offset += RAND_HASH_LENGTH;
let signature = &announce_data[offset..(offset + SIGNATURE_LENGTH)];
offset += SIGNATURE_LENGTH;
let app_data = &announce_data[offset..];
let destination = &packet.destination;
let signed_data = PacketDataBuffer::new()
.chain_write(destination.as_slice())?
.chain_write(public_key.as_bytes())?
.chain_write(verifying_key.as_bytes())?
.chain_write(name_hash)?
.chain_write(rand_hash)?
.chain_write(app_data)?
.finalize();
let signature = Signature::from_slice(signature).map_err(|_| RnsError::CryptoError)?;
identity.verify(signed_data.as_slice(), &signature)?;
Ok((
SingleOutputDestination::new(identity, DestinationName::new_from_hash_slice(name_hash)),
app_data,
))
}
}
pub struct Destination<I: HashIdentity, D: Direction, T: Type> {
pub direction: PhantomData<D>,
pub r#type: PhantomData<T>,
pub identity: I,
pub desc: DestinationDesc,
}
impl<I: HashIdentity, D: Direction, T: Type> Destination<I, D, T> {
pub fn destination_type(&self) -> packet::DestinationType {
<T as Type>::destination_type()
}
}
pub enum DestinationHandleStatus {
None,
LinkProof,
}
impl Destination<PrivateIdentity, Input, Single> {
pub fn new(identity: PrivateIdentity, name: DestinationName) -> Self {
let address_hash = create_address_hash(&identity, &name);
let pub_identity = identity.as_identity().clone();
Self {
direction: PhantomData,
r#type: PhantomData,
identity,
desc: DestinationDesc {
identity: pub_identity,
name,
address_hash,
},
}
}
pub fn announce<R: CryptoRngCore + Copy>(
&self,
rng: R,
app_data: Option<&[u8]>,
) -> Result<Packet, RnsError> {
let mut packet_data = PacketDataBuffer::new();
let rand_hash = Hash::new_from_rand(rng);
let rand_hash = &rand_hash.as_slice()[..RAND_HASH_LENGTH];
let pub_key = self.identity.as_identity().public_key_bytes();
let verifying_key = self.identity.as_identity().verifying_key_bytes();
packet_data
.chain_safe_write(self.desc.address_hash.as_slice())
.chain_safe_write(pub_key)
.chain_safe_write(verifying_key)
.chain_safe_write(self.desc.name.as_name_hash_slice())
.chain_safe_write(rand_hash);
if let Some(data) = app_data {
packet_data.write(data)?;
}
let signature = self.identity.sign(packet_data.as_slice());
packet_data.reset();
packet_data
.chain_safe_write(pub_key)
.chain_safe_write(verifying_key)
.chain_safe_write(self.desc.name.as_name_hash_slice())
.chain_safe_write(rand_hash)
.chain_safe_write(&signature.to_bytes());
if let Some(data) = app_data {
packet_data.write(data)?;
}
Ok(Packet {
header: Header {
ifac_flag: IfacFlag::Open,
header_type: HeaderType::Type1,
propagation_type: PropagationType::Broadcast,
destination_type: DestinationType::Single,
packet_type: PacketType::Announce,
hops: 0,
},
ifac: None,
destination: self.desc.address_hash,
transport: None,
context: PacketContext::None,
data: packet_data,
})
}
pub fn handle_packet(&mut self, packet: &Packet) -> DestinationHandleStatus {
if self.desc.address_hash != packet.destination {
return DestinationHandleStatus::None;
}
match packet.header.packet_type {
PacketType::LinkRequest => {
return DestinationHandleStatus::LinkProof;
}
_ => {}
}
DestinationHandleStatus::None
}
pub fn sign_key(&self) -> &SigningKey {
self.identity.sign_key()
}
}
impl Destination<Identity, Output, Single> {
pub fn new(identity: Identity, name: DestinationName) -> Self {
let address_hash = create_address_hash(&identity, &name);
Self {
direction: PhantomData,
r#type: PhantomData,
identity,
desc: DestinationDesc {
identity,
name,
address_hash,
},
}
}
}
impl<D: Direction> Destination<EmptyIdentity, D, Plain> {
pub fn new(identity: EmptyIdentity, name: DestinationName) -> Self {
let address_hash = create_address_hash(&identity, &name);
Self {
direction: PhantomData,
r#type: PhantomData,
identity,
desc: DestinationDesc {
identity: Default::default(),
name,
address_hash,
},
}
}
}
fn create_address_hash<I: HashIdentity>(identity: &I, name: &DestinationName) -> AddressHash {
AddressHash::new_from_hash(&Hash::new(
Hash::generator()
.chain_update(name.as_name_hash_slice())
.chain_update(identity.as_address_hash_slice())
.finalize()
.into(),
))
}
pub type SingleInputDestination = Destination<PrivateIdentity, Input, Single>;
pub type SingleOutputDestination = Destination<Identity, Output, Single>;
pub type PlainInputDestination = Destination<EmptyIdentity, Input, Plain>;
pub type PlainOutputDestination = Destination<EmptyIdentity, Output, Plain>;
#[cfg(test)]
mod tests {
use rand_core::OsRng;
use crate::buffer::OutputBuffer;
use crate::hash::Hash;
use crate::identity::PrivateIdentity;
use crate::serde::Serialize;
use super::DestinationAnnounce;
use super::DestinationName;
use super::SingleInputDestination;
#[test]
fn create_announce() {
let identity = PrivateIdentity::new_from_rand(OsRng);
let single_in_destination =
SingleInputDestination::new(identity, DestinationName::new("test", "in"));
let announce_packet = single_in_destination
.announce(OsRng, None)
.expect("valid announce packet");
println!("Announce packet {}", announce_packet);
}
#[test]
fn create_path_request_hash() {
let name = DestinationName::new("rnstransport", "path.request");
println!("PathRequest Name Hash {}", name.hash);
println!(
"PathRequest Destination Hash {}",
Hash::new_from_slice(name.as_name_hash_slice())
);
}
#[test]
fn compare_announce() {
let priv_key: [u8; 32] = [
0xf0, 0xec, 0xbb, 0xa4, 0x9e, 0x78, 0x3d, 0xee, 0x14, 0xff, 0xc6, 0xc9, 0xf1, 0xe1,
0x25, 0x1e, 0xfa, 0x7d, 0x76, 0x29, 0xe0, 0xfa, 0x32, 0x41, 0x3c, 0x5c, 0x59, 0xec,
0x2e, 0x0f, 0x6d, 0x6c,
];
let sign_priv_key: [u8; 32] = [
0xf0, 0xec, 0xbb, 0xa4, 0x9e, 0x78, 0x3d, 0xee, 0x14, 0xff, 0xc6, 0xc9, 0xf1, 0xe1,
0x25, 0x1e, 0xfa, 0x7d, 0x76, 0x29, 0xe0, 0xfa, 0x32, 0x41, 0x3c, 0x5c, 0x59, 0xec,
0x2e, 0x0f, 0x6d, 0x6c,
];
let priv_identity = PrivateIdentity::new(priv_key.into(), sign_priv_key.into());
println!("identity hash {}", priv_identity.as_identity().address_hash);
let destination = SingleInputDestination::new(
priv_identity,
DestinationName::new("example_utilities", "announcesample.fruits"),
);
println!("destination name hash {}", destination.desc.name.hash);
println!("destination hash {}", destination.desc.address_hash);
let announce = destination
.announce(OsRng, None)
.expect("valid announce packet");
let mut output_data = [0u8; 4096];
let mut buffer = OutputBuffer::new(&mut output_data);
let _ = announce.serialize(&mut buffer).expect("correct data");
println!("ANNOUNCE {}", buffer);
}
#[test]
fn check_announce() {
let priv_identity = PrivateIdentity::new_from_rand(OsRng);
let destination = SingleInputDestination::new(
priv_identity,
DestinationName::new("example_utilities", "announcesample.fruits"),
);
let announce = destination
.announce(OsRng, None)
.expect("valid announce packet");
DestinationAnnounce::validate(&announce).expect("valid announce");
}
}