use crate::error::{Code, Error};
use chain_crypto::{Ed25519, KeyPair, PublicKey, SecretKey, Signature, Verification};
use rand_core::{CryptoRng, RngCore};
use std::fmt;
use std::net::SocketAddr;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Peer {
addr: SocketAddr,
}
impl Peer {
#[inline]
pub fn addr(&self) -> SocketAddr {
self.addr
}
}
impl From<SocketAddr> for Peer {
#[inline]
fn from(addr: SocketAddr) -> Self {
Peer { addr }
}
}
impl fmt::Display for Peer {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.addr)
}
}
#[derive(Clone, Debug)]
pub struct NodeKeyPair(KeyPair<Ed25519>);
impl NodeKeyPair {
pub fn generate<R: RngCore + CryptoRng>(rng: R) -> Self {
NodeKeyPair(KeyPair::generate(rng))
}
pub fn sign(&self, nonce: &[u8]) -> AuthenticatedNodeId {
let signature = self.0.private_key().sign(nonce);
AuthenticatedNodeId {
id: NodeId(self.0.public_key().clone()),
signature,
}
}
}
impl From<SecretKey<Ed25519>> for NodeKeyPair {
fn from(key: SecretKey<Ed25519>) -> Self {
Self(key.into())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct NodeId(PublicKey<Ed25519>);
impl NodeId {
#[inline]
pub fn as_bytes(&self) -> &[u8] {
self.0.as_ref()
}
pub fn authenticated(self, signature: &[u8]) -> Result<AuthenticatedNodeId, Error> {
let signature =
Signature::from_binary(signature).map_err(|e| Error::new(Code::InvalidArgument, e))?;
Ok(AuthenticatedNodeId {
id: self,
signature,
})
}
}
impl TryFrom<&[u8]> for NodeId {
type Error = Error;
fn try_from(src: &[u8]) -> Result<Self, Error> {
match PublicKey::from_binary(src) {
Ok(data) => Ok(NodeId(data)),
Err(e) => Err(Error::new(Code::InvalidArgument, e)),
}
}
}
pub struct AuthenticatedNodeId {
id: NodeId,
signature: Signature<[u8], Ed25519>,
}
impl AuthenticatedNodeId {
pub fn id(&self) -> &NodeId {
&self.id
}
pub fn signature(&self) -> &[u8] {
self.signature.as_ref()
}
pub fn verify(&self, nonce: &[u8]) -> Result<(), Error> {
match self.signature.verify(&self.id.0, nonce) {
Verification::Success => Ok(()),
Verification::Failed => Err(Error::new(
Code::InvalidArgument,
"invalid node ID signature",
)),
}
}
}
impl From<AuthenticatedNodeId> for NodeId {
fn from(auth: AuthenticatedNodeId) -> Self {
auth.id
}
}