pub use ed25519_dalek::Signature as Ed25519Signature;
use alloc::vec::Vec;
use core::fmt::{Debug, Formatter, Result as FmtResult};
use core::sync::atomic::{fence, Ordering};
use curve25519_dalek::edwards::CompressedEdwardsY;
use ed25519_dalek::{Signature, SigningKey, VerifyingKey};
use secrecy::{ExposeSecret, SecretBox};
use x25519_dalek::PublicKey as DalekX25519PublicKey;
use zeroize::{Zeroize, ZeroizeOnDrop};
#[cfg(feature = "signature")]
use ::signature::{Keypair, Signer, Verifier};
#[cfg(feature = "encryption")]
use crate::algorithms::ecies::{Ecies, EciesX25519};
#[cfg(feature = "encryption")]
use crate::operations::encryption::{AsymmetricEncryption, KeyGeneration};
#[cfg(feature = "encryption")]
use crate::utils::generate_random_seed;
#[cfg(feature = "signature")]
use crate::hash::hash_default;
#[cfg(feature = "signature")]
use crate::operations::signature::{
CryptoSigner, CryptoSignerWithOptions, CryptoVerifier, CryptoVerifierWithOptions, SigningOptions,
};
use crate::algorithms::{Algorithm, CryptoAlgorithm, KeyDerivation, PrivateKey, PublicKey};
use crate::error::{CryptoError, OrCryptoError};
use crate::hash::{hash_array, HashAlgorithm};
use crate::IntoSecret;
#[derive(Clone, ZeroizeOnDrop)]
pub struct Ed25519PrivateKey {
inner: SigningKey,
}
crate::impl_secure_zeroize!(Ed25519PrivateKey, SigningKey, inner);
impl Ed25519PrivateKey {
pub fn to_x25519(&self) -> Result<X25519PrivateKey, CryptoError> {
ed25519_to_x25519_private(self)
}
}
impl PrivateKey for Ed25519PrivateKey {
type PublicKey = Ed25519PublicKey;
type Signature = Signature;
fn as_public_key(&self) -> Self::PublicKey {
let bytes = self.inner.verifying_key().to_bytes().to_vec();
Ed25519PublicKey { inner: self.inner.verifying_key(), bytes }
}
}
impl CryptoAlgorithm for Ed25519PrivateKey {
fn to_algorithm(&self) -> Algorithm {
Algorithm::Ed25519
}
}
impl Debug for Ed25519PrivateKey {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("Ed25519PrivateKey")
.field("inner", &"[REDACTED]")
.finish()
}
}
impl From<Ed25519PrivateKey> for SecretBox<Vec<u8>> {
fn from(key: Ed25519PrivateKey) -> Self {
key.inner.to_bytes().to_vec().into_secret()
}
}
impl From<&Ed25519PrivateKey> for SecretBox<Vec<u8>> {
fn from(key: &Ed25519PrivateKey) -> Self {
key.inner.to_bytes().to_vec().into_secret()
}
}
impl TryFrom<&[u8]> for Ed25519PrivateKey {
type Error = CryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes_array: [u8; ed25519_dalek::SECRET_KEY_LENGTH] = bytes.try_into()?;
let signing_key = SigningKey::from_bytes(&bytes_array);
Ok(Ed25519PrivateKey { inner: signing_key })
}
}
#[cfg(any(feature = "der", feature = "rasn"))]
impl From<Ed25519PrivateKey> for keetanetwork_asn1::ObjectIdentifier {
fn from(_private_key: Ed25519PrivateKey) -> Self {
#[cfg(feature = "der")]
{
keetanetwork_asn1::oids::typed::ED25519
}
#[cfg(all(feature = "rasn", not(feature = "der")))]
{
keetanetwork_asn1::oids::typed::ED25519.clone()
}
}
}
#[cfg(feature = "encryption")]
impl AsymmetricEncryption for Ed25519PrivateKey {
fn encrypt<P: AsRef<[u8]>>(&self, plaintext: P) -> Result<Vec<u8>, CryptoError> {
let public_key = self.as_public_key();
public_key.encrypt(plaintext)
}
fn decrypt<C: AsRef<[u8]>>(&self, cipher_text: C) -> Result<Vec<u8>, CryptoError> {
let x25519_private = self.to_x25519()?;
EciesX25519::decrypt(&x25519_private, cipher_text.as_ref())
}
}
#[cfg(feature = "encryption")]
impl KeyGeneration for Ed25519PrivateKey {
type Error = CryptoError;
fn generate_random() -> Result<Self, Self::Error> {
let random_seed = generate_random_seed()?;
Ed25519Derivation::derive_from_seed(random_seed)
}
}
#[cfg(feature = "signature")]
impl Keypair for Ed25519PrivateKey {
type VerifyingKey = Ed25519PublicKey;
fn verifying_key(&self) -> Self::VerifyingKey {
let bytes = self.inner.verifying_key().to_bytes().to_vec();
Ed25519PublicKey { inner: self.inner.verifying_key(), bytes }
}
}
#[cfg(feature = "signature")]
impl Signer<Signature> for Ed25519PrivateKey {
fn try_sign(&self, msg: &[u8]) -> Result<Signature, ::signature::Error> {
self.inner.try_sign(msg)
}
}
#[cfg(feature = "signature")]
impl CryptoSigner<Signature> for Ed25519PrivateKey {
fn has_private_key(&self) -> bool {
true
}
}
#[cfg(feature = "signature")]
impl CryptoSignerWithOptions<Signature> for Ed25519PrivateKey {
fn sign_with_options<T: AsRef<[u8]>>(
&self,
message: T,
options: SigningOptions,
) -> Result<Signature, ::signature::Error> {
let message = message.as_ref();
let data = if options.raw {
message.to_vec()
} else {
hash_default(message).to_vec()
};
self.inner.try_sign(&data)
}
}
#[derive(Debug, Clone, Default, Eq, PartialEq)]
pub struct Ed25519PublicKey {
bytes: Vec<u8>,
inner: VerifyingKey,
}
impl Ed25519PublicKey {
pub fn to_x25519(&self) -> Result<X25519PublicKey, CryptoError> {
ed25519_to_x25519_public(self)
}
}
impl CryptoAlgorithm for Ed25519PublicKey {
fn to_algorithm(&self) -> Algorithm {
Algorithm::Ed25519
}
}
impl PublicKey for Ed25519PublicKey {
fn to_uncompressed_bytes(&self) -> Vec<u8> {
self.inner.to_bytes().to_vec()
}
}
impl From<Ed25519PublicKey> for Vec<u8> {
fn from(key: Ed25519PublicKey) -> Self {
(&key).into()
}
}
impl From<&Ed25519PublicKey> for Vec<u8> {
fn from(key: &Ed25519PublicKey) -> Self {
key.inner.to_bytes().to_vec()
}
}
impl TryFrom<&[u8]> for Ed25519PublicKey {
type Error = CryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes_array: [u8; ed25519_dalek::PUBLIC_KEY_LENGTH] = bytes.try_into()?;
let verifying_key = VerifyingKey::from_bytes(&bytes_array).or_invalid_public_key()?;
Ok(Ed25519PublicKey { inner: verifying_key, bytes: bytes.to_vec() })
}
}
impl AsRef<[u8]> for Ed25519PublicKey {
fn as_ref(&self) -> &[u8] {
self.bytes.as_ref()
}
}
#[cfg(any(feature = "der", feature = "rasn"))]
impl From<Ed25519PublicKey> for keetanetwork_asn1::ObjectIdentifier {
fn from(_public_key: Ed25519PublicKey) -> Self {
#[cfg(feature = "der")]
{
keetanetwork_asn1::oids::typed::ED25519
}
#[cfg(all(feature = "rasn", not(feature = "der")))]
{
keetanetwork_asn1::oids::typed::ED25519.clone()
}
}
}
#[cfg(feature = "signature")]
impl Verifier<Signature> for Ed25519PublicKey {
fn verify(&self, msg: &[u8], signature: &Signature) -> Result<(), ::signature::Error> {
self.inner.verify(msg, signature)
}
}
#[cfg(feature = "signature")]
impl CryptoVerifier<Signature> for Ed25519PublicKey {
fn public_key_bytes(&self) -> Vec<u8> {
self.into()
}
}
#[cfg(feature = "signature")]
impl CryptoVerifierWithOptions<Signature> for Ed25519PublicKey {
fn verify_with_options<T: AsRef<[u8]>>(
&self,
message: T,
signature: &Signature,
options: SigningOptions,
) -> Result<(), ::signature::Error> {
let message = message.as_ref();
let data = if options.raw {
message.to_vec()
} else {
hash_default(message).to_vec()
};
self.inner.verify(&data, signature)
}
}
#[cfg(feature = "encryption")]
impl AsymmetricEncryption for Ed25519PublicKey {
fn encrypt<P: AsRef<[u8]>>(&self, plaintext: P) -> Result<Vec<u8>, CryptoError> {
let x25519_public = self.to_x25519()?;
EciesX25519::encrypt(&x25519_public, plaintext.as_ref())
}
fn decrypt<C: AsRef<[u8]>>(&self, _cipher_text: C) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::InvalidOperation)
}
}
#[derive(Zeroize)]
pub struct X25519PrivateKey {
bytes: SecretBox<[u8; 32]>,
}
impl Debug for X25519PrivateKey {
fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
f.debug_struct("X25519PrivateKey")
.field("bytes", &"[REDACTED]")
.finish()
}
}
impl X25519PrivateKey {
pub fn derive_public_key(&self) -> X25519PublicKey {
let private_key_array: [u8; 32] = *self.bytes.expose_secret();
let public_key_bytes = x25519_dalek::x25519(private_key_array, x25519_dalek::X25519_BASEPOINT_BYTES);
let public_key = DalekX25519PublicKey::from(public_key_bytes);
X25519PublicKey::from(public_key)
}
pub fn diffie_hellman(&self, other_public: &X25519PublicKey) -> [u8; 32] {
let private_key_array: [u8; 32] = *self.bytes.expose_secret();
let shared_secret = x25519_dalek::x25519(private_key_array, *other_public.inner.as_bytes());
shared_secret
}
}
impl TryFrom<&[u8]> for X25519PrivateKey {
type Error = CryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes_array: [u8; 32] = bytes.try_into()?;
let bytes = bytes_array.into_secret();
Ok(X25519PrivateKey { bytes })
}
}
impl From<X25519PrivateKey> for SecretBox<Vec<u8>> {
fn from(key: X25519PrivateKey) -> Self {
key.bytes.expose_secret().to_vec().into_secret()
}
}
impl From<&X25519PrivateKey> for SecretBox<Vec<u8>> {
fn from(key: &X25519PrivateKey) -> Self {
key.bytes.expose_secret().to_vec().into_secret()
}
}
#[cfg(feature = "encryption")]
impl AsymmetricEncryption for X25519PrivateKey {
fn encrypt<P: AsRef<[u8]>>(&self, plaintext: P) -> Result<Vec<u8>, CryptoError> {
let public_key = self.derive_public_key();
EciesX25519::encrypt(&public_key, plaintext.as_ref())
}
fn decrypt<C: AsRef<[u8]>>(&self, cipher_text: C) -> Result<Vec<u8>, CryptoError> {
EciesX25519::decrypt(self, cipher_text.as_ref())
}
}
#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)]
pub struct X25519PublicKey {
inner: DalekX25519PublicKey,
}
impl TryFrom<&[u8]> for X25519PublicKey {
type Error = CryptoError;
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes_array: [u8; 32] = bytes.try_into().or_invalid_public_key()?;
let public_key = DalekX25519PublicKey::from(bytes_array);
Ok(X25519PublicKey { inner: public_key })
}
}
impl From<X25519PublicKey> for Vec<u8> {
fn from(key: X25519PublicKey) -> Self {
key.inner.as_bytes().to_vec()
}
}
impl From<&X25519PublicKey> for Vec<u8> {
fn from(key: &X25519PublicKey) -> Self {
key.inner.as_bytes().to_vec()
}
}
impl From<DalekX25519PublicKey> for X25519PublicKey {
fn from(public_key: DalekX25519PublicKey) -> Self {
X25519PublicKey { inner: public_key }
}
}
#[cfg(feature = "encryption")]
impl AsymmetricEncryption for X25519PublicKey {
fn encrypt<P: AsRef<[u8]>>(&self, plaintext: P) -> Result<Vec<u8>, CryptoError> {
EciesX25519::encrypt(self, plaintext.as_ref())
}
fn decrypt<C: AsRef<[u8]>>(&self, _cipher_text: C) -> Result<Vec<u8>, CryptoError> {
Err(CryptoError::InvalidOperation)
}
}
pub fn ed25519_to_x25519_private(ed25519_key: &Ed25519PrivateKey) -> Result<X25519PrivateKey, CryptoError> {
let key_bytes = SecretBox::<Vec<u8>>::from(ed25519_key);
let hash: [u8; 64] = hash_array(key_bytes.expose_secret(), Some(HashAlgorithm::Sha2_512))?;
let mut x25519_bytes = [0u8; 32];
x25519_bytes.copy_from_slice(&hash[..32]);
x25519_bytes[0] &= 248; x25519_bytes[31] &= 127; x25519_bytes[31] |= 64;
X25519PrivateKey::try_from(x25519_bytes.as_slice())
}
pub fn ed25519_to_x25519_public(ed25519_key: &Ed25519PublicKey) -> Result<X25519PublicKey, CryptoError> {
let ed25519_bytes: Vec<u8> = ed25519_key.into();
let compressed_edwards = CompressedEdwardsY::from_slice(&ed25519_bytes).or_invalid_public_key()?;
let edwards_point = compressed_edwards
.decompress()
.ok_or(CryptoError::InvalidPublicKey)?;
let montgomery_point = edwards_point.to_montgomery();
let montgomery_bytes = montgomery_point.as_bytes();
let x25519_public = DalekX25519PublicKey::from(*montgomery_bytes);
Ok(X25519PublicKey { inner: x25519_public })
}
pub struct Ed25519Derivation;
impl KeyDerivation for Ed25519Derivation {
type PrivateKey = Ed25519PrivateKey;
fn derive_from_seed<T>(seed: SecretBox<T>) -> Result<Self::PrivateKey, CryptoError>
where
T: IntoIterator<Item = u8> + AsRef<[u8]> + zeroize::Zeroize + Clone,
{
fence(Ordering::SeqCst);
let seed = seed.expose_secret();
let hash_result: [u8; 32] = hash_array(seed, None)?;
let mut private_key_bytes = hash_result.to_vec();
private_key_bytes[0] &= 248; private_key_bytes[31] &= 127; private_key_bytes[31] |= 64;
let mut key_bytes = [0u8; ed25519_dalek::SECRET_KEY_LENGTH];
key_bytes.copy_from_slice(&private_key_bytes[..ed25519_dalek::SECRET_KEY_LENGTH]);
let signing_key = SigningKey::from_bytes(&key_bytes);
fence(Ordering::SeqCst);
Ok(Ed25519PrivateKey { inner: signing_key })
}
fn is_valid_key_material<T: AsRef<[u8]>>(bytes: T) -> bool {
bytes.as_ref().len() == ed25519_dalek::SECRET_KEY_LENGTH
}
fn key_size() -> usize {
ed25519_dalek::SECRET_KEY_LENGTH
}
}
#[cfg(test)]
mod tests {
extern crate std;
use std::collections::HashMap;
use super::*;
use crate::error::CryptoError;
use x25519_dalek::PublicKey as DalekX25519PublicKey;
#[cfg(feature = "signature")]
use crate::operations::signature::{CryptoSignerWithOptions, CryptoVerifierWithOptions};
crate::test_utils::test_key_derivation!(
Ed25519Derivation,
Ed25519PrivateKey,
Ed25519PublicKey,
32, 64, "ed25519"
);
crate::test_utils::test_crypto_utils!(Ed25519Derivation, Ed25519PrivateKey, 32, "ed25519", "ed25519");
#[cfg(feature = "encryption")]
crate::test_utils::test_asymmetric_encryption!(Ed25519Derivation, "ed25519");
#[cfg(feature = "signature")]
crate::test_utils::test_signatures!(Ed25519Derivation, "ed25519");
#[cfg(any(feature = "der", feature = "rasn"))]
crate::test_utils::test_der!(Ed25519Derivation, keetanetwork_asn1::oids::ED25519, "ed25519");
#[test]
fn test_ed25519_to_x25519_conversion() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 conversion!!!!!!".into_secret();
let ed25519_key = Ed25519Derivation::derive_from_seed(seed)?;
let x25519_key = ed25519_key.to_x25519()?;
let x25519_public = x25519_key.derive_public_key();
let x25519_key2 = ed25519_key.to_x25519()?;
assert_eq!(
SecretBox::<Vec<u8>>::from(&x25519_key).expose_secret(),
SecretBox::<Vec<u8>>::from(&x25519_key2).expose_secret()
);
let x25519_bytes = SecretBox::<Vec<u8>>::from(&x25519_key);
let recovered_x25519 = X25519PrivateKey::try_from(x25519_bytes.expose_secret().as_slice())?;
assert_eq!(
SecretBox::<Vec<u8>>::from(&x25519_key).expose_secret(),
SecretBox::<Vec<u8>>::from(&recovered_x25519).expose_secret()
);
let x25519_pub_bytes = Vec::<u8>::from(&x25519_public);
let recovered_x25519_pub = X25519PublicKey::try_from(x25519_pub_bytes.as_slice())?;
assert_eq!(Vec::<u8>::from(&x25519_public), Vec::<u8>::from(&recovered_x25519_pub));
assert_ne!(
SecretBox::<Vec<u8>>::from(&x25519_key).expose_secret(),
SecretBox::<Vec<u8>>::from(&ed25519_key).expose_secret()
);
let ed25519_public_for_comparison = ed25519_key.as_public_key();
assert_ne!(Vec::<u8>::from(&x25519_public), Vec::<u8>::from(&ed25519_public_for_comparison));
Ok(())
}
#[test]
fn test_ed25519_public_to_x25519_conversion() -> Result<(), CryptoError> {
let seed = b"seed_for_testing_public_conversion!!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let ed25519_public = ed25519_key.as_public_key();
let x25519_public_direct = ed25519_public.to_x25519()?;
let x25519_private = ed25519_key.to_x25519()?;
let x25519_public_via_private = x25519_private.derive_public_key();
assert_eq!(Vec::<u8>::from(&x25519_public_direct).len(), 32);
assert_eq!(Vec::<u8>::from(&x25519_public_via_private).len(), 32);
assert_eq!(Vec::<u8>::from(&x25519_public_direct).len(), 32);
assert_eq!(Vec::<u8>::from(&x25519_public_via_private).len(), 32);
Ok(())
}
#[test]
fn test_x25519_diffie_hellman() -> Result<(), CryptoError> {
let alice_seed = b"alice_test_seed_for_diffie_hellman!";
let alice_ed25519 = Ed25519Derivation::derive_from_seed(alice_seed.into_secret())?;
let alice_x25519 = alice_ed25519.to_x25519()?;
let alice_public = alice_x25519.derive_public_key();
let bob_seed = b"bob_test_seed_for_diffie_hellman!!!";
let bob_ed25519 = Ed25519Derivation::derive_from_seed(bob_seed.into_secret())?;
let bob_x25519 = bob_ed25519.to_x25519()?;
let bob_public = bob_x25519.derive_public_key();
let alice_shared = alice_x25519.diffie_hellman(&bob_public);
let bob_shared = bob_x25519.diffie_hellman(&alice_public);
assert_eq!(alice_shared, bob_shared);
assert_ne!(alice_shared, [0u8; 32]);
let alice_shared2 = alice_x25519.diffie_hellman(&bob_public);
let bob_shared2 = bob_x25519.diffie_hellman(&alice_public);
assert_eq!(alice_shared, alice_shared2);
assert_eq!(bob_shared, bob_shared2);
let charlie_seed = b"charlie_test_seed_different_result!";
let charlie_ed25519 = Ed25519Derivation::derive_from_seed(charlie_seed.into_secret())?;
let charlie_x25519 = charlie_ed25519.to_x25519()?;
let charlie_public = charlie_x25519.derive_public_key();
let alice_charlie_shared = alice_x25519.diffie_hellman(&charlie_public);
assert_ne!(alice_shared, alice_charlie_shared);
Ok(())
}
#[test]
fn test_x25519_debug_formatting() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 debug format!!!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let x25519_key = ed25519_key.to_x25519()?;
let debug_string = format!("{x25519_key:?}");
assert!(debug_string.contains("X25519PrivateKey"));
assert!(debug_string.contains("[REDACTED]"));
Ok(())
}
#[test]
fn test_x25519_serialization_round_trips() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 serialization!!!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let x25519_private = ed25519_key.to_x25519()?;
let x25519_public = x25519_private.derive_public_key();
let x25519_bytes: SecretBox<Vec<u8>> = (&x25519_private).into();
let recovered_x25519_private = X25519PrivateKey::try_from(x25519_bytes.expose_secret().as_slice())?;
assert_eq!(
SecretBox::<Vec<u8>>::from(&x25519_private).expose_secret(),
SecretBox::<Vec<u8>>::from(&recovered_x25519_private).expose_secret()
);
let x25519_pub_bytes: Vec<u8> = (&x25519_public).into();
let recovered_x25519_public = X25519PublicKey::try_from(x25519_pub_bytes.as_slice())?;
assert_eq!(Vec::<u8>::from(&x25519_public), Vec::<u8>::from(&recovered_x25519_public));
let secret_box_ref: SecretBox<Vec<u8>> = (&x25519_private).into();
assert_eq!(secret_box_ref.expose_secret().len(), 32);
let public_vec_owned: Vec<u8> = x25519_public.into();
let public_vec_ref: Vec<u8> = (&x25519_public).into();
assert_eq!(public_vec_owned, public_vec_ref);
Ok(())
}
#[test]
fn test_ed25519_invalid_key_material() {
let invalid_private = [0x01; 16]; assert!(Ed25519PrivateKey::try_from(invalid_private.as_slice()).is_err());
let invalid_public = [0x01; 16]; assert!(Ed25519PublicKey::try_from(invalid_public.as_slice()).is_err());
let invalid_x25519_private = [0x01; 16]; assert!(X25519PrivateKey::try_from(invalid_x25519_private.as_slice()).is_err());
let invalid_x25519_public = [0x01; 16]; assert!(X25519PublicKey::try_from(invalid_x25519_public.as_slice()).is_err());
}
#[test]
fn test_direct_x25519_key_operations() -> Result<(), CryptoError> {
let alice_private_bytes = [0x77; 32];
let alice_private = X25519PrivateKey::try_from(alice_private_bytes.as_slice())?;
let alice_public = alice_private.derive_public_key();
let bob_private_bytes = [0x88; 32];
let bob_private = X25519PrivateKey::try_from(bob_private_bytes.as_slice())?;
let bob_public = bob_private.derive_public_key();
let alice_shared = alice_private.diffie_hellman(&bob_public);
let bob_shared = bob_private.diffie_hellman(&alice_public);
assert_eq!(alice_shared, bob_shared);
assert_eq!(alice_shared.len(), 32);
assert_eq!(Vec::<u8>::from(&alice_public).len(), 32);
assert_eq!(Vec::<u8>::from(&bob_public).len(), 32);
Ok(())
}
#[test]
fn test_x25519_owned_conversions() -> Result<(), CryptoError> {
let private_bytes = [0x42; 32];
let x25519_private = X25519PrivateKey::try_from(private_bytes.as_slice())?;
let secret_box_owned: SecretBox<Vec<u8>> = x25519_private.into();
assert_eq!(secret_box_owned.expose_secret().len(), 32);
assert_eq!(secret_box_owned.expose_secret(), &private_bytes.to_vec());
Ok(())
}
#[test]
fn test_ed25519_public_key_uncompressed_bytes() -> Result<(), CryptoError> {
let seed = b"test seed for ed25519 uncompressed bytes";
let private_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let public_key = private_key.as_public_key();
let uncompressed = public_key.to_uncompressed_bytes();
assert_eq!(uncompressed.len(), 32);
let regular_bytes: Vec<u8> = (&public_key).into();
assert_eq!(uncompressed, regular_bytes);
Ok(())
}
#[test]
fn test_ed25519_public_key_error_cases() {
let wrong_length_bytes = [0x01; 16]; let result = Ed25519PublicKey::try_from(wrong_length_bytes.as_slice());
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::InvalidKeySize)));
let empty_bytes = [];
let result = Ed25519PublicKey::try_from(empty_bytes.as_slice());
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::InvalidKeySize)));
let too_long_bytes = [0x01; 64]; let result = Ed25519PublicKey::try_from(too_long_bytes.as_slice());
assert!(result.is_err());
assert!(matches!(result, Err(CryptoError::InvalidKeySize)));
}
#[test]
fn test_ed25519_to_x25519_public_conversion_edge_cases() -> Result<(), CryptoError> {
let seed = b"test seed for ed25519 to x25519 public edge";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let ed25519_public = ed25519_key.as_public_key();
let x25519_public = ed25519_public.to_x25519()?;
let x25519_bytes: Vec<u8> = (&x25519_public).into();
assert_eq!(x25519_bytes.len(), 32);
let x25519_public2 = ed25519_public.to_x25519()?;
let x25519_bytes2: Vec<u8> = (&x25519_public2).into();
assert_eq!(x25519_bytes, x25519_bytes2);
let alice_seed = b"alice_seed_for_conversion_test!!!!!!";
let alice_ed25519 = Ed25519Derivation::derive_from_seed(alice_seed.into_secret())?;
let alice_x25519_from_ed25519 = alice_ed25519.to_x25519()?;
let alice_x25519_public = alice_x25519_from_ed25519.derive_public_key();
let bob_seed = b"bob_seed_for_conversion_test_here!!!";
let bob_ed25519 = Ed25519Derivation::derive_from_seed(bob_seed.into_secret())?;
let bob_x25519_from_ed25519 = bob_ed25519.to_x25519()?;
let bob_x25519_public = bob_x25519_from_ed25519.derive_public_key();
let alice_shared = alice_x25519_from_ed25519.diffie_hellman(&bob_x25519_public);
let bob_shared = bob_x25519_from_ed25519.diffie_hellman(&alice_x25519_public);
assert_eq!(alice_shared, bob_shared);
Ok(())
}
#[test]
fn test_x25519_public_key_equality_and_hashing() -> Result<(), CryptoError> {
let seed1 = b"test seed for x25519 equality test 1!";
let seed2 = b"test seed for x25519 equality test 2!";
let ed25519_key1 = Ed25519Derivation::derive_from_seed(seed1.into_secret())?;
let ed25519_key2 = Ed25519Derivation::derive_from_seed(seed2.into_secret())?;
let x25519_key1 = ed25519_key1.to_x25519()?;
let x25519_key2 = ed25519_key2.to_x25519()?;
let x25519_public1 = x25519_key1.derive_public_key();
let x25519_public2 = x25519_key2.derive_public_key();
let x25519_public1_copy = x25519_key1.derive_public_key();
assert_eq!(x25519_public1, x25519_public1_copy);
assert_ne!(x25519_public1, x25519_public2);
let mut map = HashMap::new();
map.insert(x25519_public1, "alice");
map.insert(x25519_public2, "bob");
assert_eq!(map.len(), 2);
assert_eq!(map.get(&x25519_public1_copy), Some(&"alice"));
Ok(())
}
#[test]
fn test_x25519_copy_and_clone_traits() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 copy clone traits!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let x25519_key = ed25519_key.to_x25519()?;
let x25519_public = x25519_key.derive_public_key();
let x25519_public_copy = x25519_public;
assert_eq!(x25519_public, x25519_public_copy);
let x25519_public_clone = x25519_public;
assert_eq!(x25519_public, x25519_public_clone);
let bytes_original: Vec<u8> = x25519_public.into();
let bytes_copy: Vec<u8> = x25519_public_copy.into();
let bytes_clone: Vec<u8> = x25519_public_clone.into();
assert_eq!(bytes_original, bytes_copy);
assert_eq!(bytes_original, bytes_clone);
Ok(())
}
#[test]
fn test_x25519_dalek_public_key_conversion() {
let raw_bytes = [0x42; 32];
let dalek_public = DalekX25519PublicKey::from(raw_bytes);
let our_public = X25519PublicKey::from(dalek_public);
let our_bytes: Vec<u8> = our_public.into();
assert_eq!(our_bytes, raw_bytes.to_vec());
}
#[test]
fn test_ed25519_key_derivation_error_handling() {
let short_seed = b"short";
let result_short = Ed25519Derivation::derive_from_seed(short_seed.into_secret());
assert!(result_short.is_ok());
let long_seed = b"this is a very long seed that should still work for key derivation without any issues";
let result_long = Ed25519Derivation::derive_from_seed(long_seed.into_secret());
assert!(result_long.is_ok());
let empty_seed = b"";
let result_empty = Ed25519Derivation::derive_from_seed(empty_seed.into_secret());
assert!(result_empty.is_ok());
}
#[test]
fn test_x25519_private_key_zeroize() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 zeroize test!!!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let mut x25519_key = ed25519_key.to_x25519()?;
let original_bytes = SecretBox::<Vec<u8>>::from(&x25519_key);
assert_ne!(original_bytes.expose_secret(), &vec![0u8; 32]);
x25519_key.zeroize();
let zeroed_bytes = SecretBox::<Vec<u8>>::from(&x25519_key);
assert_eq!(zeroed_bytes.expose_secret(), &vec![0u8; 32]);
Ok(())
}
#[cfg(feature = "encryption")]
#[test]
fn test_x25519_encrypt_decrypt() -> Result<(), CryptoError> {
let seed = b"test seed for x25519 encrypt decrypt!";
let ed25519_key = Ed25519Derivation::derive_from_seed(seed.into_secret())?;
let x25519_private = ed25519_key.to_x25519()?;
let x25519_public = x25519_private.derive_public_key();
let plaintext = b"X25519 ECIES encryption test message";
let ciphertext_from_private = x25519_private.encrypt(plaintext)?;
assert!(!ciphertext_from_private.is_empty());
assert_ne!(ciphertext_from_private.as_slice(), plaintext);
let ciphertext_from_public = x25519_public.encrypt(plaintext)?;
assert!(!ciphertext_from_public.is_empty());
assert_ne!(ciphertext_from_public.as_slice(), plaintext);
assert_ne!(ciphertext_from_private, ciphertext_from_public);
let decrypted_from_private = x25519_private.decrypt(&ciphertext_from_private)?;
assert_eq!(decrypted_from_private, plaintext);
let decrypted_from_public = x25519_private.decrypt(&ciphertext_from_public)?;
assert_eq!(decrypted_from_public, plaintext);
let decrypt_result1 = x25519_public.decrypt(&ciphertext_from_private);
assert!(decrypt_result1.is_err());
assert!(matches!(decrypt_result1, Err(CryptoError::InvalidOperation)));
let decrypt_result2 = x25519_public.decrypt(&ciphertext_from_public);
assert!(decrypt_result2.is_err());
assert!(matches!(decrypt_result2, Err(CryptoError::InvalidOperation)));
let bob_seed = b"bob_seed_for_x25519_encryption_test!";
let bob_ed25519 = Ed25519Derivation::derive_from_seed(bob_seed.into_secret())?;
let bob_x25519_private = bob_ed25519.to_x25519()?;
let bob_x25519_public = bob_x25519_private.derive_public_key();
let ciphertext_for_bob = bob_x25519_public.encrypt(plaintext)?;
let decrypted_by_bob = bob_x25519_private.decrypt(&ciphertext_for_bob)?;
assert_eq!(decrypted_by_bob, plaintext);
let cross_decrypt_result = x25519_private.decrypt(&ciphertext_for_bob);
assert!(cross_decrypt_result.is_err());
Ok(())
}
}