use crate::{
crypto::{
base64_decode, base64_encode, sha256::Sha256, SigningPrivateKey, SigningPublicKey,
StaticPrivateKey, StaticPublicKey,
},
error::parser::RouterIdentityParseError,
runtime::Runtime,
};
use bytes::{BufMut, Bytes, BytesMut};
use nom::{
bytes::complete::take,
number::complete::{be_u16, be_u8},
sequence::tuple,
Err, IResult,
};
use rand::Rng;
use alloc::{string::String, sync::Arc, vec::Vec};
use core::fmt;
const SERIALIZED_LEN: usize = 391usize;
const KEY_CERTIFICATE: u8 = 0x05;
const KEY_CERTIFICATE_LEN: u16 = 0x04;
const KEY_KIND_EDDSA_SHA512_ED25519: u16 = 0x0007;
const KEY_KIND_X25519: u16 = 0x0004;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct RouterId(Arc<String>);
impl RouterId {
#[cfg(test)]
pub fn random() -> RouterId {
use crate::runtime::mock::MockRuntime;
use rand::RngExt;
let bytes = MockRuntime::rng().random::<[u8; 32]>();
RouterId::from(bytes)
}
pub fn to_vec(&self) -> Vec<u8> {
base64_decode(self.0.as_bytes()).expect("to succeed")
}
}
impl fmt::Display for RouterId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", &self.0[..8])
}
}
impl<T: AsRef<[u8]>> From<T> for RouterId {
fn from(value: T) -> Self {
RouterId(Arc::new(base64_encode(value)))
}
}
impl From<RouterId> for Vec<u8> {
fn from(value: RouterId) -> Self {
base64_decode(value.0.as_bytes()).expect("to succeed")
}
}
#[derive(Debug, Clone)]
pub struct RouterIdentity {
identity_hash: Bytes,
padding: Bytes,
router: RouterId,
signing_key: SigningPublicKey,
static_key: StaticPublicKey,
}
impl RouterIdentity {
pub fn from_keys<R: Runtime>(
static_key: &StaticPrivateKey,
signing_key: &SigningPrivateKey,
) -> crate::Result<Self> {
let padding = {
let mut padding = [0u8; 320];
R::rng().fill_bytes(&mut padding);
padding
};
let identity_hash = {
let mut out = BytesMut::with_capacity(SERIALIZED_LEN);
out.put_slice(static_key.public().as_ref());
out.put_slice(&padding);
out.put_slice(signing_key.public().as_ref());
out.put_u8(KEY_CERTIFICATE);
out.put_u16(KEY_CERTIFICATE_LEN);
out.put_u16(KEY_KIND_EDDSA_SHA512_ED25519);
out.put_u16(KEY_KIND_X25519);
Sha256::new().update(&out).finalize()
};
Ok(Self {
identity_hash: Bytes::from(identity_hash.clone()),
padding: Bytes::from(padding.to_vec()),
router: RouterId::from(identity_hash),
signing_key: signing_key.public(),
static_key: static_key.public(),
})
}
pub fn parse_frame(input: &[u8]) -> IResult<&[u8], RouterIdentity, RouterIdentityParseError> {
if input.len() < SERIALIZED_LEN {
return Err(Err::Error(RouterIdentityParseError::InvalidLength(
input.len(),
)));
}
let (_, (initial_bytes, rest)) = tuple((take(384usize), take(input.len() - 384)))(input)?;
let (rest, cert_type) = be_u8(rest)?;
let (rest, cert_len) = be_u16(rest)?;
let (rest, sig_key_type) = be_u16(rest)?;
let (rest, pub_key_type) = be_u16(rest)?;
let (KEY_CERTIFICATE, KEY_CERTIFICATE_LEN) = (cert_type, cert_len) else {
return Err(Err::Error(RouterIdentityParseError::InvalidCertificate((
cert_type, cert_len,
))));
};
let static_key = match pub_key_type {
KEY_KIND_X25519 => StaticPublicKey::try_from_bytes(&initial_bytes[..32])
.ok_or(Err::Error(RouterIdentityParseError::InvalidBitstream)),
kind => Err(Err::Error(RouterIdentityParseError::InvalidPublicKey(kind))),
}?;
let signing_key = match sig_key_type {
KEY_KIND_EDDSA_SHA512_ED25519 => Some({
let public_key =
TryInto::<[u8; 32]>::try_into(initial_bytes[384 - 32..384].to_vec())
.expect("to succeed");
SigningPublicKey::from_bytes(&public_key)
.ok_or(Err::Error(RouterIdentityParseError::InvalidBitstream))?
}),
_ => None,
}
.ok_or(Err::Error(RouterIdentityParseError::InvalidSigningKey(
sig_key_type,
)))?;
let identity_hash = Bytes::from(Sha256::new().update(&input[..391]).finalize());
Ok((
rest,
RouterIdentity {
static_key,
padding: Bytes::from(initial_bytes[32..352].to_vec()),
signing_key,
identity_hash: identity_hash.clone(),
router: RouterId::from(identity_hash),
},
))
}
#[allow(unused)]
pub fn parse(bytes: impl AsRef<[u8]>) -> Result<Self, RouterIdentityParseError> {
Ok(Self::parse_frame(bytes.as_ref())?.1)
}
pub fn serialize(&self) -> BytesMut {
let mut out = BytesMut::with_capacity(SERIALIZED_LEN);
out.put_slice(self.static_key.as_ref());
out.put_slice(&self.padding);
out.put_slice(self.signing_key.as_ref());
out.put_u8(KEY_CERTIFICATE);
out.put_u16(KEY_CERTIFICATE_LEN);
out.put_u16(KEY_KIND_EDDSA_SHA512_ED25519);
out.put_u16(KEY_KIND_X25519);
out
}
pub fn static_key(&self) -> &StaticPublicKey {
&self.static_key
}
pub fn signing_key(&self) -> &SigningPublicKey {
&self.signing_key
}
pub fn hash(&self) -> Bytes {
self.identity_hash.clone()
}
pub fn id(&self) -> RouterId {
self.router.clone()
}
pub fn serialized_len(&self) -> usize {
SERIALIZED_LEN
}
#[cfg(test)]
pub fn random() -> (Self, StaticPrivateKey, SigningPrivateKey) {
use crate::runtime::mock::MockRuntime;
let sk = {
let mut out = [0u8; 32];
MockRuntime::rng().fill_bytes(&mut out);
StaticPrivateKey::from_bytes(out)
};
let sgk = {
let mut out = [0u8; 32];
MockRuntime::rng().fill_bytes(&mut out);
SigningPrivateKey::from(out)
};
let identity = RouterIdentity::from_keys::<MockRuntime>(&sk, &sgk).unwrap();
(identity, sk, sgk)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::crypto::base64_encode;
#[test]
fn expected_router_hash() {
let router = include_bytes!("../../test-vectors/router5.dat");
let identity = RouterIdentity::parse(router).unwrap();
assert_eq!(
base64_encode(&identity.identity_hash),
"u9QdTy~qBwh8Mrcfrcqvea8MOiNmavLv8Io4XQsMDHg="
);
let serialized = identity.serialize();
let parsed = RouterIdentity::parse(&serialized).unwrap();
assert_eq!(
base64_encode(&parsed.identity_hash),
"u9QdTy~qBwh8Mrcfrcqvea8MOiNmavLv8Io4XQsMDHg="
);
}
#[test]
fn too_short_router_identity() {
assert_eq!(
RouterIdentity::parse(vec![1, 2, 3, 4]).unwrap_err(),
RouterIdentityParseError::InvalidLength(4)
);
}
#[test]
fn serialize_deserialize() {
let (identity, _, _) = RouterIdentity::random();
let id = identity.id();
let serialized = identity.serialize();
let parsed = RouterIdentity::parse(&serialized).unwrap();
assert_eq!(parsed.id(), id);
}
}