use core::ops::{Deref, DerefMut}; use super::common::*; use super::error::Error; use super::field25519::*; const POINT_BYTES: usize = 32; /// Non-uniform output of a scalar multiplication. /// This represents a point on the curve, and should not be used directly as a /// cipher key. #[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]; /// Returns the output of the scalar multiplication as bytes. /// The output is not uniform, and should be hashed before use. fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for DHOutput { /// Returns the output of the scalar multiplication as bytes. /// The output is not uniform, and should be hashed before use. fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } impl From for PublicKey { fn from(dh: DHOutput) -> Self { PublicKey(dh.0) } } impl From for SecretKey { fn from(dh: DHOutput) -> Self { SecretKey(dh.0) } } impl Drop for DHOutput { fn drop(&mut self) { Mem::wipe(self.0) } } /// A public key. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub struct PublicKey([u8; POINT_BYTES]); impl PublicKey { /// Number of raw bytes in a public key. pub const BYTES: usize = POINT_BYTES; /// Creates a public key from raw bytes. pub fn new(pk: [u8; PublicKey::BYTES]) -> Self { PublicKey(pk) } /// Creates a public key from a slice. pub fn from_slice(pk: &[u8]) -> Result { 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_)) } /// Multiply a point by the cofactor, returning an error if the element is /// in a small-order group. 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) } /// Multiply the point represented by the public key by the scalar after /// clamping it pub fn dh(&self, sk: &SecretKey) -> Result { let sk = sk.clamped(); Ok(DHOutput(self.ladder(&sk.0, 255)?)) } /// Multiply the point represented by the public key by the scalar WITHOUT /// CLAMPING pub fn unclamped_mul(&self, sk: &SecretKey) -> Result { 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()) } /// The Curve25519 base point #[inline] pub fn base_point() -> PublicKey { PublicKey(FE_CURVE25519_BASEPOINT.to_bytes()) } } impl Deref for PublicKey { type Target = [u8; PublicKey::BYTES]; /// Returns a public key as bytes. fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for PublicKey { /// Returns a public key as mutable bytes. fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } /// A secret key. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct SecretKey([u8; SecretKey::BYTES]); impl SecretKey { /// Number of bytes in a secret key. pub const BYTES: usize = 32; /// Creates a secret key from raw bytes. pub fn new(sk: [u8; SecretKey::BYTES]) -> Self { SecretKey(sk) } /// Creates a secret key from a slice. pub fn from_slice(sk: &[u8]) -> Result { let mut sk_ = [0u8; SecretKey::BYTES]; if sk.len() != sk_.len() { return Err(Error::InvalidSecretKey); } sk_.copy_from_slice(sk); Ok(SecretKey::new(sk_)) } /// Perform the X25519 clamping magic pub fn clamped(&self) -> SecretKey { let mut clamped = self.clone(); clamped[0] &= 248; clamped[31] &= 63; clamped[31] |= 64; clamped } /// Recover the public key pub fn recover_public_key(&self) -> Result { let sk = self.clamped(); Ok(PublicKey(PublicKey::base_point().ladder(&sk.0, 255)?)) } /// Returns `Ok(())` if the given public key is the public counterpart of /// this secret key. /// Returns `Err(Error::InvalidPublicKey)` otherwise. 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]; /// Returns a secret key as bytes. fn deref(&self) -> &Self::Target { &self.0 } } impl DerefMut for SecretKey { /// Returns a secret key as mutable bytes. fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 } } /// A key pair. #[derive(Clone, Debug, Eq, PartialEq, Hash)] pub struct KeyPair { /// Public key part of the key pair. pub pk: PublicKey, /// Secret key part of the key pair. pub sk: SecretKey, } impl KeyPair { /// Generates a new key pair. #[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 } } /// Check that the public key is valid for the secret key. 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 { /// Convert an Ed25519 secret key to a X25519 secret key. pub fn from_ed25519(edsk: &EdSecretKey) -> Result { 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 { /// Convert an Ed25519 public key to a X25519 public key. pub fn from_ed25519(edpk: &EdPublicKey) -> Result { let pk = PublicKey::from_slice( &edwards25519::ge_to_x25519_vartime(edpk).ok_or(Error::InvalidPublicKey)?, )?; pk.clear_cofactor()?; Ok(pk) } } impl KeyPair { /// Convert an Ed25519 key pair to a X25519 key pair. pub fn from_ed25519(edkp: &EdKeyPair) -> Result { 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()); }