use libcrux_ecdh::{secret_to_public, Algorithm};
use rand::CryptoRng;
use tls_codec::{TlsDeserialize, TlsDeserializeBytes, TlsSerialize, TlsSerializeBytes, TlsSize};
use crate::handshake::{
types::{Authenticator, ProvideAuthenticator},
HandshakeError as Error,
};
#[derive(TlsSerializeBytes, TlsSize)]
pub struct DHSharedSecret(Vec<u8>);
impl AsRef<[u8]> for DHSharedSecret {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
#[derive(
Eq,
Debug,
Hash,
PartialEq,
Clone,
Copy,
TlsDeserializeBytes,
TlsSerializeBytes,
TlsSize,
TlsSerialize,
TlsDeserialize,
)]
pub struct DHPublicKey([u8; 32]);
impl ProvideAuthenticator for DHPublicKey {
fn authenticator(&self) -> super::types::Authenticator {
Authenticator::Dh(*self)
}
}
impl AsRef<[u8]> for DHPublicKey {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl DHPublicKey {
pub fn from_bytes(value: &[u8; 32]) -> Self {
Self(*value)
}
}
pub struct DHPrivateKey(Vec<u8>);
impl AsRef<[u8]> for DHPrivateKey {
fn as_ref(&self) -> &[u8] {
self.0.as_slice()
}
}
impl DHSharedSecret {
pub(crate) fn derive(sk: &DHPrivateKey, pk: &DHPublicKey) -> Result<DHSharedSecret, Error> {
Ok(DHSharedSecret(
libcrux_ecdh::derive(Algorithm::X25519, pk.0, &sk.0).map_err(|_| Error::CryptoError)?,
))
}
}
impl DHPrivateKey {
pub fn new(rng: &mut impl CryptoRng) -> Self {
Self(
libcrux_ecdh::generate_secret(libcrux_ecdh::Algorithm::X25519, rng)
.expect("Insufficient Randomness"),
)
}
pub fn to_public(&self) -> DHPublicKey {
DHPublicKey(
secret_to_public(libcrux_ecdh::Algorithm::X25519, &self.0)
.expect("secret key is honestly generated X25519 key")
.try_into()
.expect("secret key is honestly generated X25519 key"),
)
}
pub fn from_bytes(value: &[u8; 32]) -> Result<Self, Error> {
if libcrux_ecdh::validate_scalar(libcrux_ecdh::Algorithm::X25519, value).is_err() {
Err(Error::InvalidDHSecret)
} else {
Ok(Self(Vec::from(value)))
}
}
pub fn diffie_hellman(&self, remote_public_key: &DHPublicKey) -> Result<DHSharedSecret, Error> {
DHSharedSecret::derive(self, remote_public_key)
}
}
pub struct DHKeyPair {
pub(crate) sk: DHPrivateKey,
pub pk: DHPublicKey,
}
impl ProvideAuthenticator for DHKeyPair {
fn authenticator(&self) -> super::types::Authenticator {
self.pk.authenticator()
}
}
impl DHKeyPair {
pub fn new(rng: &mut impl CryptoRng) -> Self {
let sk = DHPrivateKey::new(rng);
let pk = sk.to_public();
Self { sk, pk }
}
pub fn sk(&self) -> &DHPrivateKey {
&self.sk
}
}
impl From<DHPrivateKey> for DHKeyPair {
fn from(sk: DHPrivateKey) -> Self {
Self {
pk: sk.to_public(),
sk,
}
}
}