Skip to content

Commit

Permalink
Merge pull request #302 from 0xcregis/301-ed25519-private-key-derivation
Browse files Browse the repository at this point in the history
feat: ed25519 private key derivation
  • Loading branch information
loki-cmu authored Dec 10, 2024
2 parents c5d0e38 + 85a69f7 commit 1a767e5
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 15 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion crates/anychain-kms/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "anychain-kms"
description = "A Rust library providing Key Management Schema for AnyChain. Handles general security and signature algorithms."
version = "0.1.13"
version = "0.1.14"
keywords = ["cryptography", "security", "signature", "algorithm"]
categories = ["cryptography::cryptocurrencies"]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use core::{
fmt::{self, Debug},
str::FromStr,
};
//use hmac::{Mac, NewMac};
use curve25519_dalek::scalar::Scalar;
use hmac::Mac;
use subtle::{Choice, ConstantTimeEq};
use zeroize::Zeroize;
Expand All @@ -24,9 +24,12 @@ const BIP39_DOMAIN_SEPARATOR: [u8; 12] = [
0x42, 0x69, 0x74, 0x63, 0x6f, 0x69, 0x6e, 0x20, 0x73, 0x65, 0x65, 0x64,
];

/// Extended private secp256k1 ECDSA signing key.
/// Extended private secp256k1 signing key.
pub type XprvSecp256k1 = ExtendedPrivateKey<libsecp256k1::SecretKey>;

/// Extended private ed25519 signing key.
pub type XprvEd25519 = ExtendedPrivateKey<Scalar>;

/// Extended private keys derived using BIP32.
///
/// Generic around a [`PrivateKey`] type. When the `secp256k1` feature of this
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ where
attrs: self.attrs.clone(),
key_bytes: {
let mut key_bytes = [0u8; KEY_SIZE + 1];
key_bytes.copy_from_slice(&self.to_bytes());
let bytes = self.to_bytes();
let bytes = match bytes.len() {
KEY_SIZE => [vec![0u8], bytes].concat(),
_ => bytes,
};
key_bytes.copy_from_slice(&bytes);
key_bytes
},
}
Expand Down
2 changes: 1 addition & 1 deletion crates/anychain-kms/src/bip32/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub use extended_key::{
extended_public_key::ExtendedPublicKey, ExtendedKey,
};
pub use extended_key::{
extended_private_key::XprvSecp256k1,
extended_private_key::{XprvEd25519, XprvSecp256k1},
extended_public_key::{XpubEd25519, XpubSecp256k1},
};
pub use prefix::Prefix;
Expand Down
68 changes: 59 additions & 9 deletions crates/anychain-kms/src/bip32/private_key.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
//! Trait for deriving child keys on a given type.
use crate::bip32::{PublicKey, Result};
use crate::bip32::{Error, PublicKey, Result, XprvEd25519, XprvSecp256k1};

use crate::bip32::{Error, XprvSecp256k1};

use libsecp256k1;
use curve25519_dalek::{constants::ED25519_BASEPOINT_TABLE as G, scalar::Scalar};
use group::GroupEncoding;

/// Trait for key types which can be derived using BIP32.
pub trait PrivateKey: Sized {
Expand Down Expand Up @@ -65,16 +64,51 @@ impl From<&XprvSecp256k1> for libsecp256k1::SecretKey {
}
}

impl PrivateKey for Scalar {
type PublicKey = ed25519_dalek::PublicKey;

fn from_bytes(bytes: Vec<u8>) -> Result<Self> {
let mut sk = [0u8; 32];
sk.copy_from_slice(&bytes);
Ok(Scalar::from_bytes_mod_order(sk))
}

fn to_bytes(&self) -> Vec<u8> {
self.to_bytes().to_vec()
}

fn derive_child(&self, tweak: Vec<u8>) -> Result<Self> {
let mut _tweak = [0u8; 32];
_tweak.copy_from_slice(&tweak);
let tweak = Scalar::from_bytes_mod_order(_tweak);
Ok(self + tweak)
}

fn public_key(&self) -> Self::PublicKey {
let pk = (G * self).to_bytes();
ed25519_dalek::PublicKey::from_bytes(&pk).unwrap()
}
}

impl From<XprvEd25519> for Scalar {
fn from(xprv: XprvEd25519) -> Scalar {
Scalar::from(&xprv)
}
}

impl From<&XprvEd25519> for Scalar {
fn from(xprv: &XprvEd25519) -> Scalar {
*xprv.private_key()
}
}

#[cfg(test)]
mod tests {
use super::{XprvEd25519, XprvSecp256k1};
use hex_literal::hex;

//type XprvSecp256k1 = crate::bip32::ExtendedPrivateKey<k256::ecdsa::SigningKey>;

type XprvSecp256k1 = crate::bip32::ExtendedPrivateKey<libsecp256k1::SecretKey>;

#[test]
fn secp256k1_derivation() {
fn test_secp256k1_derivation() {
let seed = hex!(
"fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a2
9f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"
Expand All @@ -88,4 +122,20 @@ mod tests {
"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j".parse().unwrap()
);
}

#[test]
fn test_ed25519_derivation() {
let seed = hex!(
"fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a2
9f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"
);

let path = "m/0/2147483647'/1/2147483646'/2";
let xprv = XprvEd25519::new_from_path(seed, &path.parse().unwrap()).unwrap();

assert_eq!(
xprv,
"xprvA3jRL3NoAajWVMc6JWKPgQrxx5Xt6VVpgj8y6FMcBbseE4DkZEP8cfVqJQtQvyCqZpb39KZE5r7UUGwunJg9m3wksLj5x94cJv4ahGMarGU".parse().unwrap()
);
}
}

0 comments on commit 1a767e5

Please sign in to comment.