use curve25519_dalek::{edwards::EdwardsPoint, montgomery::MontgomeryPoint, traits::IsIdentity};
use rand_core::CryptoRng;
#[cfg(feature = "zeroize")]
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct PublicKey(pub(crate) MontgomeryPoint);
impl From<[u8; 32]> for PublicKey {
fn from(bytes: [u8; 32]) -> PublicKey {
PublicKey(MontgomeryPoint(bytes))
}
}
impl PublicKey {
#[inline]
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
#[inline]
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
}
impl AsRef<[u8]> for PublicKey {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
#[cfg(feature = "zeroize")]
impl Zeroize for PublicKey {
fn zeroize(&mut self) {
self.0.zeroize();
}
}
pub struct EphemeralSecret(pub(crate) [u8; 32]);
impl EphemeralSecret {
pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret {
SharedSecret(their_public.0.mul_clamped(self.0))
}
pub fn random_from_rng<R: CryptoRng + ?Sized>(csprng: &mut R) -> Self {
let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes);
EphemeralSecret(bytes)
}
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
let mut bytes = [0u8; 32];
getrandom::fill(&mut bytes).expect("getrandom failure");
EphemeralSecret(bytes)
}
}
impl<'a> From<&'a EphemeralSecret> for PublicKey {
fn from(secret: &'a EphemeralSecret) -> PublicKey {
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
}
}
impl Drop for EphemeralSecret {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for EphemeralSecret {}
#[cfg(feature = "reusable_secrets")]
#[derive(Clone)]
pub struct ReusableSecret(pub(crate) [u8; 32]);
#[cfg(feature = "reusable_secrets")]
impl ReusableSecret {
pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
SharedSecret(their_public.0.mul_clamped(self.0))
}
pub fn random_from_rng<R: CryptoRng + ?Sized>(csprng: &mut R) -> Self {
let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes);
ReusableSecret(bytes)
}
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
let mut bytes = [0u8; 32];
getrandom::fill(&mut bytes).expect("getrandom failure");
ReusableSecret(bytes)
}
}
#[cfg(feature = "reusable_secrets")]
impl<'a> From<&'a ReusableSecret> for PublicKey {
fn from(secret: &'a ReusableSecret) -> PublicKey {
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
}
}
#[cfg(feature = "reusable_secrets")]
impl Drop for ReusableSecret {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
self.0.zeroize();
}
}
#[cfg(all(feature = "reusable_secrets", feature = "zeroize"))]
impl ZeroizeOnDrop for ReusableSecret {}
#[cfg(feature = "static_secrets")]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[derive(Clone)]
pub struct StaticSecret([u8; 32]);
#[cfg(feature = "static_secrets")]
impl StaticSecret {
pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret {
SharedSecret(their_public.0.mul_clamped(self.0))
}
pub fn random_from_rng<R: CryptoRng + ?Sized>(csprng: &mut R) -> Self {
let mut bytes = [0u8; 32];
csprng.fill_bytes(&mut bytes);
StaticSecret(bytes)
}
#[cfg(feature = "getrandom")]
pub fn random() -> Self {
let mut bytes = [0u8; 32];
getrandom::fill(&mut bytes).expect("getrandom failure");
StaticSecret(bytes)
}
#[inline]
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
#[inline]
pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
}
#[cfg(feature = "static_secrets")]
impl From<[u8; 32]> for StaticSecret {
fn from(bytes: [u8; 32]) -> StaticSecret {
StaticSecret(bytes)
}
}
#[cfg(feature = "static_secrets")]
impl<'a> From<&'a StaticSecret> for PublicKey {
fn from(secret: &'a StaticSecret) -> PublicKey {
PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery())
}
}
#[cfg(feature = "static_secrets")]
impl AsRef<[u8]> for StaticSecret {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
#[cfg(feature = "static_secrets")]
impl Drop for StaticSecret {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
self.0.zeroize();
}
}
#[cfg(all(feature = "static_secrets", feature = "zeroize"))]
impl ZeroizeOnDrop for StaticSecret {}
pub struct SharedSecret(pub(crate) MontgomeryPoint);
impl SharedSecret {
#[inline]
pub fn to_bytes(&self) -> [u8; 32] {
self.0.to_bytes()
}
#[inline]
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
#[must_use]
pub fn was_contributory(&self) -> bool {
!self.0.is_identity()
}
}
impl AsRef<[u8]> for SharedSecret {
#[inline]
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
impl Drop for SharedSecret {
fn drop(&mut self) {
#[cfg(feature = "zeroize")]
self.0.zeroize();
}
}
#[cfg(feature = "zeroize")]
impl ZeroizeOnDrop for SharedSecret {}
#[cfg_attr(feature = "static_secrets", doc = "```")]
#[cfg_attr(not(feature = "static_secrets"), doc = "```ignore")]
pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] {
MontgomeryPoint(u).mul_clamped(k).to_bytes()
}
pub const X25519_BASEPOINT_BYTES: [u8; 32] = [
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];