use crate::{Error, NoiseConfig, Protocol, ProtocolParams};
use libp2p_core::UpgradeInfo;
use libp2p_identity as identity;
use rand::Rng;
use x25519_dalek::{x25519, X25519_BASEPOINT_BYTES};
use zeroize::Zeroize;
use super::*;
const STATIC_KEY_DOMAIN: &str = "noise-libp2p-static-key:";
#[derive(Clone)]
pub struct X25519Spec([u8; 32]);
impl AsRef<[u8]> for X25519Spec {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Zeroize for X25519Spec {
fn zeroize(&mut self) {
self.0.zeroize()
}
}
impl Keypair<X25519Spec> {
pub(super) fn default() -> Self {
Keypair {
secret: SecretKey(X25519Spec([0u8; 32])),
public: PublicKey(X25519Spec([0u8; 32])),
}
}
pub fn new() -> Keypair<X25519Spec> {
let mut sk_bytes = [0u8; 32];
rand::thread_rng().fill(&mut sk_bytes);
let sk = SecretKey(X25519Spec(sk_bytes)); sk_bytes.zeroize();
Self::from(sk)
}
}
impl Default for Keypair<X25519Spec> {
fn default() -> Self {
Self::new()
}
}
impl From<SecretKey<X25519Spec>> for Keypair<X25519Spec> {
fn from(secret: SecretKey<X25519Spec>) -> Keypair<X25519Spec> {
let public = PublicKey(X25519Spec(x25519((secret.0).0, X25519_BASEPOINT_BYTES)));
Keypair { secret, public }
}
}
impl UpgradeInfo for NoiseConfig<XX, X25519Spec> {
type Info = &'static [u8];
type InfoIter = std::iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
std::iter::once(b"/noise")
}
}
impl UpgradeInfo for NoiseConfig<IX, X25519Spec> {
type Info = &'static [u8];
type InfoIter = std::iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
std::iter::once(b"/noise/ix/25519/chachapoly/sha256/0.1.0")
}
}
impl<R> UpgradeInfo for NoiseConfig<IK, X25519Spec, R> {
type Info = &'static [u8];
type InfoIter = std::iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
std::iter::once(b"/noise/ik/25519/chachapoly/sha256/0.1.0")
}
}
impl Protocol<X25519Spec> for X25519Spec {
fn params_ik() -> ProtocolParams {
x25519::X25519::params_ik()
}
fn params_ix() -> ProtocolParams {
x25519::X25519::params_ix()
}
fn params_xx() -> ProtocolParams {
x25519::X25519::params_xx()
}
fn public_from_bytes(bytes: &[u8]) -> Result<PublicKey<X25519Spec>, Error> {
if bytes.len() != 32 {
return Err(Error::InvalidLength);
}
let mut pk = [0u8; 32];
pk.copy_from_slice(bytes);
Ok(PublicKey(X25519Spec(pk)))
}
fn verify(
id_pk: &identity::PublicKey,
dh_pk: &PublicKey<X25519Spec>,
sig: &Option<Vec<u8>>,
) -> bool {
sig.as_ref().map_or(false, |s| {
id_pk.verify(&[STATIC_KEY_DOMAIN.as_bytes(), dh_pk.as_ref()].concat(), s)
})
}
fn sign(id_keys: &identity::Keypair, dh_pk: &PublicKey<X25519Spec>) -> Result<Vec<u8>, Error> {
Ok(id_keys.sign(&[STATIC_KEY_DOMAIN.as_bytes(), dh_pk.as_ref()].concat())?)
}
}
#[doc(hidden)]
impl snow::types::Dh for Keypair<X25519Spec> {
fn name(&self) -> &'static str {
"25519"
}
fn pub_len(&self) -> usize {
32
}
fn priv_len(&self) -> usize {
32
}
fn pubkey(&self) -> &[u8] {
self.public.as_ref()
}
fn privkey(&self) -> &[u8] {
self.secret.as_ref()
}
fn set(&mut self, sk: &[u8]) {
let mut secret = [0u8; 32];
secret.copy_from_slice(sk);
self.secret = SecretKey(X25519Spec(secret)); self.public = PublicKey(X25519Spec(x25519(secret, X25519_BASEPOINT_BYTES)));
secret.zeroize();
}
fn generate(&mut self, rng: &mut dyn snow::types::Random) {
let mut secret = [0u8; 32];
rng.fill_bytes(&mut secret);
self.secret = SecretKey(X25519Spec(secret)); self.public = PublicKey(X25519Spec(x25519(secret, X25519_BASEPOINT_BYTES)));
secret.zeroize();
}
fn dh(&self, pk: &[u8], shared_secret: &mut [u8]) -> Result<(), snow::Error> {
let mut p = [0; 32];
p.copy_from_slice(&pk[..32]);
let ss = x25519((self.secret.0).0, p);
shared_secret[..32].copy_from_slice(&ss[..]);
Ok(())
}
}