This repository has been archived by the owner on Mar 11, 2024. It is now read-only.
Add method to derive x25519 from an ed25519 private key #112
Merged
brentzundel
merged 4 commits into
hyperledger-archives:master
from
andrewwhitehead:feature/derive-x25519
Apr 30, 2020
+101
−1
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
09e9f46
add method to derive x25519 from a private key; add nacl-compatible k…
andrewwhitehead b04f69a
adjust variable usage for clarity; handle longer seed
andrewwhitehead 107d22d
rename keypair_from_secret to expand_keypair; fix warning
andrewwhitehead 6d8904f
add docstrings, restrict includes to x25519 features
andrewwhitehead File filter
Filter by extension
Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
pub const ALGORITHM_NAME: &str = "ED25519_SHA2_512"; | ||
|
||
use super::{KeyGenOption, SignatureScheme}; | ||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
use ed25519_dalek::SecretKey as SK; | ||
use ed25519_dalek::{Keypair, PublicKey as PK, Signature}; | ||
pub use ed25519_dalek::{ | ||
EXPANDED_SECRET_KEY_LENGTH as PRIVATE_KEY_SIZE, PUBLIC_KEY_LENGTH as PUBLIC_KEY_SIZE, | ||
|
@@ -19,6 +21,19 @@ pub struct Ed25519Sha512; | |
|
||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
impl Ed25519Sha512 { | ||
/// Creates a curve25519 key from an ed25519 public key. | ||
/// | ||
/// Used to derive the public key for DH key exchange. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// use ursa::signatures::ed25519::Ed25519Sha512; | ||
/// use ursa::signatures::SignatureScheme; | ||
/// | ||
/// let (pk, sk) = Ed25519Sha512::new().keypair(None).unwrap(); | ||
/// let curve_pk = Ed25519Sha512::ver_key_to_key_exchange(&pk).unwrap(); | ||
/// let curve_sk = Ed25519Sha512::sign_key_to_key_exchange(&sk).unwrap(); | ||
/// ``` | ||
pub fn ver_key_to_key_exchange(pk: &PublicKey) -> Result<PublicKey, CryptoError> { | ||
use curve25519_dalek::edwards::CompressedEdwardsY; | ||
|
||
|
@@ -34,6 +49,60 @@ impl Ed25519Sha512 { | |
))), | ||
} | ||
} | ||
|
||
/// Creates a curve25519 key from an ed25519 private key. | ||
/// | ||
/// Used to derive the private key for DH key exchange. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// use ursa::signatures::ed25519::Ed25519Sha512; | ||
/// use ursa::signatures::SignatureScheme; | ||
/// | ||
/// let (pk, sk) = Ed25519Sha512::new().keypair(None).unwrap(); | ||
/// let curve_pk = Ed25519Sha512::ver_key_to_key_exchange(&pk).unwrap(); | ||
/// let curve_sk = Ed25519Sha512::sign_key_to_key_exchange(&sk).unwrap(); | ||
/// ``` | ||
pub fn sign_key_to_key_exchange(sk: &PrivateKey) -> Result<PrivateKey, CryptoError> { | ||
// Length is normally 64 but we only need the secret from the first half | ||
if sk.len() < 32 { | ||
return Err(CryptoError::ParseError(format!( | ||
"Invalid private key provided" | ||
))); | ||
} | ||
// hash secret | ||
let hash = sha2::Sha512::digest(&sk[..32]); | ||
let mut output = [0u8; 32]; | ||
output.copy_from_slice(&hash[..32]); | ||
// clamp result | ||
let secret = x25519_dalek::StaticSecret::from(output); | ||
Ok(PrivateKey(secret.to_bytes().to_vec())) | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments here to document the purpose of the expand_keypair function and how to use it |
||
/// Expand an ed25519 keypair from the input key material. | ||
/// | ||
/// Used to derive a complete keypair from a predetermined secret. | ||
/// | ||
/// # Example | ||
/// ``` | ||
/// use ursa::signatures::ed25519::Ed25519Sha512; | ||
/// | ||
/// let ikm = b"000000000000000000000000000Test1"; | ||
/// let (pk, sk) = Ed25519Sha512::expand_keypair(ikm).unwrap(); | ||
/// ``` | ||
pub fn expand_keypair(ikm: &[u8]) -> Result<(PublicKey, PrivateKey), CryptoError> { | ||
if ikm.len() < 32 { | ||
return Err(CryptoError::ParseError(format!( | ||
"Invalid key material provided" | ||
))); | ||
} | ||
let mut private = vec![0u8; 64]; | ||
private[..32].copy_from_slice(&ikm[..32]); | ||
let sk = SK::from_bytes(&ikm[..32]).unwrap(); | ||
let pk = PK::from(&sk).to_bytes().to_vec(); | ||
private[32..].copy_from_slice(pk.as_ref()); | ||
Ok((PublicKey(pk), PrivateKey(private))) | ||
} | ||
} | ||
|
||
impl SignatureScheme for Ed25519Sha512 { | ||
|
@@ -107,6 +176,12 @@ mod test { | |
const SIGNATURE_1: &str = "451b5b8e8725321541954997781de51f4142e4a56bab68d24f6a6b92615de5eefb74134138315859a32c7cf5fe5a488bc545e2e08e5eedfd1fb10188d532d808"; | ||
const PRIVATE_KEY: &str = "1c1179a560d092b90458fe6ab8291215a427fcd6b3927cb240701778ef55201927c96646f2d4632d4fc241f84cbc427fbc3ecaa95becba55088d6c7b81fc5bbf"; | ||
const PUBLIC_KEY: &str = "27c96646f2d4632d4fc241f84cbc427fbc3ecaa95becba55088d6c7b81fc5bbf"; | ||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
const PRIVATE_KEY_X25519: &str = | ||
"08e7286c232ec71b37918533ea0229bf0c75d3db4731df1c5c03c45bc909475f"; | ||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
const PUBLIC_KEY_X25519: &str = | ||
"9b4260484c889158c128796103dc8d8b883977f2ef7efb0facb12b6ca9b2ae3d"; | ||
|
||
#[test] | ||
#[ignore] | ||
|
@@ -202,11 +277,36 @@ mod test { | |
|
||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
#[test] | ||
fn ed25519_to_x25519() { | ||
fn ed25519_to_x25519_default() { | ||
let scheme = Ed25519Sha512::new(); | ||
let (p, _) = scheme.keypair(None).unwrap(); | ||
|
||
let res = Ed25519Sha512::ver_key_to_key_exchange(&p); | ||
assert!(res.is_ok()); | ||
} | ||
|
||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
#[test] | ||
fn ed25519_to_x25519_verify() { | ||
let sk = PrivateKey(hex::decode(PRIVATE_KEY).unwrap()); | ||
let pk = PublicKey(hex::decode(PUBLIC_KEY).unwrap()); | ||
|
||
let x_pk = Ed25519Sha512::ver_key_to_key_exchange(&pk).unwrap(); | ||
assert_eq!(hex::encode(&x_pk), PUBLIC_KEY_X25519); | ||
|
||
let x_sk = Ed25519Sha512::sign_key_to_key_exchange(&sk).unwrap(); | ||
assert_eq!(hex::encode(&x_sk), PRIVATE_KEY_X25519); | ||
} | ||
|
||
#[cfg(any(feature = "x25519", feature = "x25519_asm"))] | ||
#[test] | ||
fn nacl_derive_from_seed() { | ||
let seed = b"000000000000000000000000Trustee1"; | ||
let test_sk = hex::decode("3030303030303030303030303030303030303030303030305472757374656531e33aaf381fffa6109ad591fdc38717945f8fabf7abf02086ae401c63e9913097").unwrap(); | ||
let test_pk = &test_sk[32..]; | ||
|
||
let (pk, sk) = Ed25519Sha512::expand_keypair(seed).unwrap(); | ||
assert_eq!(pk.0, test_pk); | ||
assert_eq!(sk.0, test_sk); | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add comments here to document the purpose of the sign_key_to_key_exchange function and how to use it.