Skip to content

Commit

Permalink
Implement from_seed_unchecked for Ed25519KeyPair (#663)
Browse files Browse the repository at this point in the history
* Implement `from_seed_unchecked` for `Ed25519KeyPair`

* Minor doc/test changes

---------

Co-authored-by: Justin Smith <justsmth@amazon.com>
  • Loading branch information
paolobarbolini and justsmth authored Jan 21, 2025
1 parent 9124243 commit 44fa00d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 3 deletions.
23 changes: 20 additions & 3 deletions aws-lc-rs/src/ed25519.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,26 @@ impl Ed25519KeyPair {
/// # Errors
/// `error::KeyRejected` if parse error, or if key is otherwise unacceptable.
pub fn from_seed_and_public_key(seed: &[u8], public_key: &[u8]) -> Result<Self, KeyRejected> {
let this = Self::from_seed_unchecked(seed)?;

constant_time::verify_slices_are_equal(public_key, &this.public_key.public_key_bytes)
.map_err(|_| KeyRejected::inconsistent_components())?;
Ok(this)
}

/// Constructs an Ed25519 key pair from the private key seed `seed`.
///
/// It is recommended to use `Ed25519KeyPair::from_pkcs8()` instead. If the public key is
/// available, prefer to use `Ed25519KeyPair::from_seed_and_public_key()` as it will verify
/// the validity of the key pair.
///
/// CAUTION: Both an Ed25519 seed and its public key are 32-bytes. If the bytes of a public key
/// are provided this function will create an (effectively) invalid `Ed25519KeyPair`. This
/// problem is undetectable by the API.
///
/// # Errors
/// `error::KeyRejected` if parse error, or if key is otherwise unacceptable.
pub fn from_seed_unchecked(seed: &[u8]) -> Result<Self, KeyRejected> {
if seed.len() < ED25519_SEED_LEN {
return Err(KeyRejected::inconsistent_components());
}
Expand All @@ -372,9 +392,6 @@ impl Ed25519KeyPair {
}
debug_assert_eq!(derived_public_key.len(), out_len);

constant_time::verify_slices_are_equal(public_key, &derived_public_key)
.map_err(|_| KeyRejected::inconsistent_components())?;

Ok(Self {
public_key: PublicKey {
public_key_bytes: derived_public_key,
Expand Down
15 changes: 15 additions & 0 deletions aws-lc-rs/tests/ed25519_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ fn test_signature_ed25519() {

let expected_sig = test_case.consume_bytes("SIG");

let key_pair = Ed25519KeyPair::from_seed_unchecked(&seed).unwrap();
let actual_sig = key_pair.sign(&msg);
assert_eq!(&expected_sig[..], actual_sig.as_ref());

let key_pair = Ed25519KeyPair::from_seed_and_public_key(&seed, &public_key).unwrap();
let actual_sig = key_pair.sign(&msg);
assert_eq!(&expected_sig[..], actual_sig.as_ref());
Expand Down Expand Up @@ -99,6 +103,12 @@ fn test_ed25519_from_seed_and_public_key_misuse() {

// Swapped public and private key.
assert!(Ed25519KeyPair::from_seed_and_public_key(PUBLIC_KEY, PRIVATE_KEY).is_err());

// From a private seed
assert!(Ed25519KeyPair::from_seed_unchecked(PRIVATE_KEY).is_ok());

// From a truncated private seed
assert!(Ed25519KeyPair::from_seed_unchecked(PRIVATE_KEY).is_ok());
}

#[test]
Expand Down Expand Up @@ -232,4 +242,9 @@ fn test_seed() {
let key_pair_copy_doc = key_pair_copy.to_pkcs8().unwrap();

assert_eq!(key_pair_doc.as_ref(), key_pair_copy_doc.as_ref());

let key_pair_seed_copy = Ed25519KeyPair::from_seed_unchecked(seed_buffer.as_ref()).unwrap();
let key_pair_seed_copy_doc = key_pair_seed_copy.to_pkcs8().unwrap();

assert_eq!(key_pair_doc.as_ref(), key_pair_seed_copy_doc.as_ref());
}

0 comments on commit 44fa00d

Please sign in to comment.