use core::ops::{Deref, DerefMut};
use super::common::*;
use super::error::Error;
use super::field25519::*;
const POINT_BYTES: usize = 32;
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct DHOutput([u8; DHOutput::BYTES]);
impl DHOutput {
pub const BYTES: usize = 32;
}
impl Deref for DHOutput {
type Target = [u8; DHOutput::BYTES];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for DHOutput {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl From<DHOutput> for PublicKey {
fn from(dh: DHOutput) -> Self {
PublicKey(dh.0)
}
}
impl From<DHOutput> for SecretKey {
fn from(dh: DHOutput) -> Self {
SecretKey(dh.0)
}
}
impl Drop for DHOutput {
fn drop(&mut self) {
Mem::wipe(self.0)
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
pub struct PublicKey([u8; POINT_BYTES]);
impl PublicKey {
pub const BYTES: usize = POINT_BYTES;
pub fn new(pk: [u8; PublicKey::BYTES]) -> Self {
PublicKey(pk)
}
pub fn from_slice(pk: &[u8]) -> Result<Self, Error> {
let mut pk_ = [0u8; PublicKey::BYTES];
if pk.len() != pk_.len() {
return Err(Error::InvalidPublicKey);
}
Fe::reject_noncanonical(pk)?;
pk_.copy_from_slice(pk);
Ok(PublicKey::new(pk_))
}
pub fn clear_cofactor(&self) -> Result<[u8; PublicKey::BYTES], Error> {
let cofactor = [
8u8, 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,
];
self.ladder(&cofactor, 4)
}
pub fn dh(&self, sk: &SecretKey) -> Result<DHOutput, Error> {
let sk = sk.clamped();
Ok(DHOutput(self.ladder(&sk.0, 255)?))
}
pub fn unclamped_mul(&self, sk: &SecretKey) -> Result<DHOutput, Error> {
self.clear_cofactor()?;
Ok(DHOutput(self.ladder(&sk.0, 256)?))
}
fn ladder(&self, s: &[u8], bits: usize) -> Result<[u8; POINT_BYTES], Error> {
let x1 = Fe::from_bytes(&self.0);
let mut x2 = FE_ONE;
let mut z2 = FE_ZERO;
let mut x3 = x1;
let mut z3 = FE_ONE;
let mut swap: u8 = 0;
let mut pos = bits - 1;
loop {
let bit = (s[pos >> 3] >> (pos & 7)) & 1;
swap ^= bit;
Fe::cswap2(&mut x2, &mut x3, &mut z2, &mut z3, swap);
swap = bit;
let a = x2 + z2;
let b = x2 - z2;
let aa = a.square();
let bb = b.square();
x2 = aa * bb;
let e = aa - bb;
let da = (x3 - z3) * a;
let cb = (x3 + z3) * b;
x3 = (da + cb).square();
z3 = x1 * ((da - cb).square());
z2 = e * (bb + (e.mul32(121666)));
if pos == 0 {
break;
}
pos -= 1;
}
Fe::cswap2(&mut x2, &mut x3, &mut z2, &mut z3, swap);
z2 = z2.invert();
x2 = x2 * z2;
if x2.is_zero() {
return Err(Error::WeakPublicKey);
}
Ok(x2.to_bytes())
}
#[inline]
pub fn base_point() -> PublicKey {
PublicKey(FE_CURVE25519_BASEPOINT.to_bytes())
}
}
impl Deref for PublicKey {
type Target = [u8; PublicKey::BYTES];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PublicKey {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct SecretKey([u8; SecretKey::BYTES]);
impl SecretKey {
pub const BYTES: usize = 32;
pub fn new(sk: [u8; SecretKey::BYTES]) -> Self {
SecretKey(sk)
}
pub fn from_slice(sk: &[u8]) -> Result<Self, Error> {
let mut sk_ = [0u8; SecretKey::BYTES];
if sk.len() != sk_.len() {
return Err(Error::InvalidSecretKey);
}
sk_.copy_from_slice(sk);
Ok(SecretKey::new(sk_))
}
pub fn clamped(&self) -> SecretKey {
let mut clamped = self.clone();
clamped[0] &= 248;
clamped[31] &= 63;
clamped[31] |= 64;
clamped
}
pub fn recover_public_key(&self) -> Result<PublicKey, Error> {
let sk = self.clamped();
Ok(PublicKey(PublicKey::base_point().ladder(&sk.0, 255)?))
}
pub fn validate_public_key(&self, pk: &PublicKey) -> Result<(), Error> {
let recovered_pk = self.recover_public_key()?;
if recovered_pk != *pk {
return Err(Error::InvalidPublicKey);
}
Ok(())
}
}
impl Drop for SecretKey {
fn drop(&mut self) {
Mem::wipe(self.0)
}
}
impl Deref for SecretKey {
type Target = [u8; SecretKey::BYTES];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SecretKey {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct KeyPair {
pub pk: PublicKey,
pub sk: SecretKey,
}
impl KeyPair {
#[cfg(feature = "random")]
pub fn generate() -> KeyPair {
let mut sk = [0u8; SecretKey::BYTES];
getrandom::getrandom(&mut sk).expect("getrandom");
if Fe::from_bytes(&sk).is_zero() {
panic!("All-zero secret key");
}
let sk = SecretKey(sk);
let pk = sk
.recover_public_key()
.expect("generated public key is weak");
KeyPair { pk, sk }
}
pub fn validate(&self) -> Result<(), Error> {
self.sk.validate_public_key(&self.pk)
}
}
#[cfg(not(feature = "disable-signatures"))]
mod from_ed25519 {
use super::super::{
edwards25519, sha512, KeyPair as EdKeyPair, PublicKey as EdPublicKey,
SecretKey as EdSecretKey,
};
use super::*;
impl SecretKey {
pub fn from_ed25519(edsk: &EdSecretKey) -> Result<SecretKey, Error> {
let seed = edsk.seed();
let az: [u8; 64] = {
let mut hash_output = sha512::Hash::hash(*seed);
hash_output[0] &= 248;
hash_output[31] &= 63;
hash_output[31] |= 64;
hash_output
};
SecretKey::from_slice(&az[..32])
}
}
impl PublicKey {
pub fn from_ed25519(edpk: &EdPublicKey) -> Result<PublicKey, Error> {
let pk = PublicKey::from_slice(
&edwards25519::ge_to_x25519_vartime(edpk).ok_or(Error::InvalidPublicKey)?,
)?;
pk.clear_cofactor()?;
Ok(pk)
}
}
impl KeyPair {
pub fn from_ed25519(edkp: &EdKeyPair) -> Result<KeyPair, Error> {
let pk = PublicKey::from_ed25519(&edkp.pk)?;
let sk = SecretKey::from_ed25519(&edkp.sk)?;
Ok(KeyPair { pk, sk })
}
}
}
#[cfg(not(feature = "disable-signatures"))]
pub use from_ed25519::*;
#[test]
fn test_x25519() {
let sk_1 = SecretKey::from_slice(&[
1u8, 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,
])
.unwrap();
let output = PublicKey::base_point().unclamped_mul(&sk_1).unwrap();
assert_eq!(PublicKey::from(output), PublicKey::base_point());
let kp_a = KeyPair::generate();
let kp_b = KeyPair::generate();
let output_a = kp_b.pk.dh(&kp_a.sk).unwrap();
let output_b = kp_a.pk.dh(&kp_b.sk).unwrap();
assert_eq!(output_a, output_b);
}
#[cfg(not(feature = "disable-signatures"))]
#[test]
fn test_x25519_map() {
use super::KeyPair as EdKeyPair;
let edkp_a = EdKeyPair::generate();
let edkp_b = EdKeyPair::generate();
let kp_a = KeyPair::from_ed25519(&edkp_a).unwrap();
let kp_b = KeyPair::from_ed25519(&edkp_b).unwrap();
let output_a = kp_b.pk.dh(&kp_a.sk).unwrap();
let output_b = kp_a.pk.dh(&kp_b.sk).unwrap();
assert_eq!(output_a, output_b);
}
#[test]
#[cfg(all(not(feature = "disable-signatures"), feature = "random"))]
fn test_x25519_invalid_keypair() {
let kp1 = KeyPair::generate();
let kp2 = KeyPair::generate();
assert_eq!(
kp1.sk.validate_public_key(&kp2.pk).unwrap_err(),
Error::InvalidPublicKey
);
assert_eq!(
kp2.sk.validate_public_key(&kp1.pk).unwrap_err(),
Error::InvalidPublicKey
);
assert!(kp1.sk.validate_public_key(&kp1.pk).is_ok());
assert!(kp2.sk.validate_public_key(&kp2.pk).is_ok());
assert!(kp1.validate().is_ok());
}