pub use hkdf::hmac::EagerHash;
use crate::{
AffinePoint, Curve, CurveArithmetic, CurveGroup, FieldBytes, NonZeroScalar, ProjectivePoint,
PublicKey, point::AffineCoordinates,
};
use common::Generate;
use core::{borrow::Borrow, fmt};
use hkdf::Hkdf;
use rand_core::{CryptoRng, TryCryptoRng};
use zeroize::{Zeroize, ZeroizeOnDrop};
pub fn diffie_hellman<C>(
secret_key: impl Borrow<NonZeroScalar<C>>,
public_key: impl Borrow<AffinePoint<C>>,
) -> SharedSecret<C>
where
C: CurveArithmetic,
{
let public_point = ProjectivePoint::<C>::from(*public_key.borrow());
let secret_point = (public_point * secret_key.borrow().as_ref()).to_affine();
SharedSecret::new(secret_point)
}
pub struct EphemeralSecret<C>
where
C: CurveArithmetic,
{
scalar: NonZeroScalar<C>,
}
impl<C: CurveArithmetic> fmt::Debug for EphemeralSecret<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("EphemeralSecret").finish_non_exhaustive()
}
}
impl<C> Generate for EphemeralSecret<C>
where
C: CurveArithmetic,
{
fn try_generate_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
Ok(Self {
scalar: NonZeroScalar::try_generate_from_rng(rng)?,
})
}
}
impl<C> EphemeralSecret<C>
where
C: CurveArithmetic,
{
pub fn public_key(&self) -> PublicKey<C> {
PublicKey::from_secret_scalar(&self.scalar)
}
pub fn diffie_hellman(&self, public_key: &PublicKey<C>) -> SharedSecret<C> {
diffie_hellman(self.scalar, public_key.as_affine())
}
#[deprecated(since = "0.14.0", note = "use the `Generate` trait instead")]
pub fn random<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
Self::generate_from_rng(rng)
}
}
impl<C> From<&EphemeralSecret<C>> for PublicKey<C>
where
C: CurveArithmetic,
{
fn from(ephemeral_secret: &EphemeralSecret<C>) -> Self {
ephemeral_secret.public_key()
}
}
impl<C> Zeroize for EphemeralSecret<C>
where
C: CurveArithmetic,
{
fn zeroize(&mut self) {
self.scalar.zeroize();
}
}
impl<C> ZeroizeOnDrop for EphemeralSecret<C> where C: CurveArithmetic {}
impl<C> Drop for EphemeralSecret<C>
where
C: CurveArithmetic,
{
fn drop(&mut self) {
self.zeroize();
}
}
pub struct SharedSecret<C: Curve> {
secret_bytes: FieldBytes<C>,
}
impl<C: Curve> fmt::Debug for SharedSecret<C> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SharedSecret").finish_non_exhaustive()
}
}
impl<C: Curve> SharedSecret<C> {
#[inline]
fn new(point: AffinePoint<C>) -> Self
where
C: CurveArithmetic,
{
Self {
secret_bytes: point.x(),
}
}
pub fn extract<D>(&self, salt: Option<&[u8]>) -> Hkdf<D>
where
D: EagerHash,
{
Hkdf::new(salt, &self.secret_bytes)
}
pub fn raw_secret_bytes(&self) -> &FieldBytes<C> {
&self.secret_bytes
}
}
impl<C: Curve> From<FieldBytes<C>> for SharedSecret<C> {
fn from(secret_bytes: FieldBytes<C>) -> Self {
Self { secret_bytes }
}
}
impl<C: Curve> ZeroizeOnDrop for SharedSecret<C> {}
impl<C: Curve> Drop for SharedSecret<C> {
fn drop(&mut self) {
self.secret_bytes.zeroize();
}
}