summaryrefslogtreecommitdiffstats
path: root/vendor/ed25519-compact/src/x25519.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/ed25519-compact/src/x25519.rs')
-rw-r--r--vendor/ed25519-compact/src/x25519.rs360
1 files changed, 360 insertions, 0 deletions
diff --git a/vendor/ed25519-compact/src/x25519.rs b/vendor/ed25519-compact/src/x25519.rs
new file mode 100644
index 000000000..c43bc8bce
--- /dev/null
+++ b/vendor/ed25519-compact/src/x25519.rs
@@ -0,0 +1,360 @@
+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<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)
+ }
+}
+
+/// 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<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_))
+ }
+
+ /// 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<DHOutput, Error> {
+ 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<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())
+ }
+
+ /// 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<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_))
+ }
+
+ /// 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<PublicKey, Error> {
+ 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<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 {
+ /// Convert an Ed25519 public key to a X25519 public key.
+ 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 {
+ /// Convert an Ed25519 key pair to a X25519 key pair.
+ 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());
+}