Skip to content

add commits #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
224 changes: 224 additions & 0 deletions src/ethereum.rs
Original file line number Diff line number Diff line change
@@ -1 +1,225 @@
// Coming soon :)
pub mod key_chain;

use crate::ring::digest;
use crate::{
chain_path::ChainPath,
ed25519_dalek::{PublicKey, SecretKey as Sk},
traits::{Deserialize, Serialize},
extended_key::{EthereumExPrivateKey, EthereumExPublicKey}
};
use key_chain::{Derivation, KeyChain};

use base58::{FromBase58, ToBase58};

use std::rc::Rc;

use crate::error::Error;

#[derive(Debug, PartialEq, Eq)]
pub struct PrivKey {
pub derivation: Derivation,
pub extended_key: EthereumExPrivateKey,
}

impl PrivKey {
pub fn from_master_key(extended_key: EthereumExPrivateKey) -> Self {
PrivKey {
extended_key,
derivation: Derivation::master(),
}
}
}

#[derive(Debug, PartialEq, Eq)]

pub struct PubKey {
pub derivation: Derivation,
pub extended_key: EthereumExPublicKey,
}

impl PubKey {
pub fn from_private_key(priv_key: &PrivKey) -> PubKey {
let pub_key = EthereumExPublicKey::from_private_key(&priv_key.extended_key);

PubKey {
derivation: priv_key.derivation.clone(),
extended_key: pub_key.unwrap(),
}
}
}

trait DerivationExt {
fn parent_fingerprint(&self) -> Vec<u8>;
}

impl DerivationExt for Derivation {
fn parent_fingerprint(&self) -> Vec<u8> {
match self.parent_key {
Some(ref key) => {
let pubkey = EthereumExPublicKey::from_private_key(key);
let buf = digest::digest(&digest::SHA256, &pubkey.unwrap().0.to_bytes());
buf.as_ref()[0..4].to_vec()
}
None => vec![0; 4],
}
}
}

fn encode_derivation(buf: &mut Vec<u8>, derivation: &Derivation) {
buf.extend_from_slice(&derivation.depth.to_be_bytes());
buf.extend_from_slice(&derivation.parent_fingerprint());

match derivation.key_index {
Some(key_index) => {
buf.extend_from_slice(&key_index.raw_index().to_be_bytes());
}
None => buf.extend_from_slice(&[0; 4]),
}
}

fn decode_derivation(data: (&dyn KeyChain, ChainPath)) -> Result<Derivation, Error> {
let slice: String = data.1.to_string();
let chain_path = &slice[..(slice.len())];
let (_extended_key, derivation) = data
.0
.derive_private_key(chain_path.into())
.expect("fetch key");

Ok(derivation)
}

fn encode_checksum(buf: &mut Vec<u8>) {
let check_sum = {
let buf = digest::digest(&digest::SHA256, buf);
digest::digest(&digest::SHA256, buf.as_ref())
};

buf.extend_from_slice(&check_sum.as_ref()[0..4]);
}

impl Serialize<Vec<u8>> for PrivKey {
fn serialize(&self) -> Vec<u8> {
let mut buf: Vec<u8> = [].to_vec();

encode_derivation(&mut buf, &self.derivation);

buf.extend_from_slice(&self.extended_key.chain_code);
buf.extend_from_slice(&[0]);
let private_key = Rc::try_unwrap(Rc::clone(&self.extended_key.private_key)).unwrap_err();
buf.extend_from_slice(&private_key.to_bytes());
assert_eq!(buf.len(), 74);
encode_checksum(&mut buf);

buf
}
}

impl Serialize<String> for PrivKey {
fn serialize(&self) -> String {
Serialize::<Vec<u8>>::serialize(self).to_base58()
}
}

impl Serialize<Vec<u8>> for PubKey {
fn serialize(&self) -> Vec<u8> {
let mut buf: Vec<u8> = [].to_vec();

encode_derivation(&mut buf, &self.derivation);

buf.extend_from_slice(&self.extended_key.0.to_bytes());
encode_checksum(&mut buf);

buf
}
}

impl Serialize<String> for PubKey {
fn serialize(&self) -> String {
let serialized_key: Vec<u8> = self.serialize();
let public_address = Serialize::<Vec<u8>>::serialize(&self.extended_key).to_base58();

public_address + &serialized_key.to_base58()
}
}

impl Deserialize<(String, &dyn KeyChain, ChainPath<'_>), Error> for PrivKey {
fn deserialize(data: (String, &dyn KeyChain, ChainPath)) -> Result<PrivKey, Error> {
let buf = data.0.from_base58().map_err(|_| Error::InvalidBase58)?;

let derivation = decode_derivation((data.1, data.2))?;
let chain_code = buf[9..41].to_vec();
let private_key = Rc::new(Sk::from_bytes(&buf[42..74])?);

Ok(PrivKey {
derivation,
extended_key: EthereumExPrivateKey {
private_key,
chain_code,
},
})
}
}

impl Deserialize<(String, &dyn KeyChain, ChainPath<'_>), Error> for PubKey {
fn deserialize(data: (String, &dyn KeyChain, ChainPath)) -> Result<PubKey, Error> {
let buf = data.0[44..]
.from_base58()
.map_err(|_| Error::InvalidBase58)?;

let derivation = decode_derivation((data.1, data.2))?;

let public_key = PublicKey::from_bytes(&buf[9..41]).unwrap();

Ok(PubKey {
derivation,
extended_key: EthereumExPublicKey(public_key),
})
}
}
/*
#[cfg(test)]
mod tests {
use super::*;
use crate::mnemonic;
use crate::traits::Serialize;
use key_chain::{DefaultKeyChain, KeyChain};

#[test]
fn test_deserialize_priv_key() {
let new_mnemonic = mnemonic::new_mnemonic(24, "English");
let seed = mnemonic::new_seed(new_mnemonic.unwrap(), "".to_string());
let key_chain =
DefaultKeyChain::new(EthereumExPrivateKey::new_master_key(&seed).expect("master key"));
let (extended_key, derivation) =
key_chain.derive_private_key("m".into()).expect("fetch key");
let private_key = PrivKey {
derivation,
extended_key,
};
let serialized_key: String = private_key.serialize();
let deserialized_key =
PrivKey::deserialize((serialized_key, &key_chain, "m".into())).expect("deserialize");
assert_eq!(private_key, deserialized_key);
}

#[test]
fn test_deserialize_pub_key() {
let new_mnemonic = mnemonic::new_mnemonic(24, "English");
let seed = mnemonic::new_seed(new_mnemonic.unwrap(), "".to_string());
let key_chain =
DefaultKeyChain::new(EthereumExPrivateKey::new_master_key(&seed).expect("master key"));
let (extended_key, derivation) =
key_chain.derive_private_key("m".into()).expect("fetch key");
let private_key = PrivKey {
derivation,
extended_key,
};
let public_key = PubKey::from_private_key(&private_key);
let serialized_key: String = public_key.serialize();
let deserialized_key =
PubKey::deserialize((serialized_key, &key_chain, "m".into())).expect("deserialize");
assert_eq!(public_key, deserialized_key);
}
}
*/
164 changes: 164 additions & 0 deletions src/ethereum/key_chain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use crate::{error::Error, ChainPath, ChainPathError, KeyIndex, extended_key::EthereumExPrivateKey, SubPath};

/// KeyChain derivation info
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Derivation {
/// depth, 0 if it is master key
pub depth: u8,
/// parent key
pub parent_key: Option<EthereumExPrivateKey>,
/// key_index which used with parent key to derive this key
pub key_index: Option<KeyIndex>,
}

impl Derivation {
pub fn master() -> Self {
Derivation {
depth: 0,
parent_key: None,
key_index: None,
}
}
}

impl Default for Derivation {
fn default() -> Self {
Derivation::master()
}
}

pub trait KeyChain {
fn derive_private_key(
&self,
chain_path: ChainPath,
) -> Result<(EthereumExPrivateKey, Derivation), Error>;
}

pub struct DefaultKeyChain {
master_key: EthereumExPrivateKey,
}

impl DefaultKeyChain {
#[allow(dead_code)]
pub fn new(master_key: EthereumExPrivateKey) -> Self {
DefaultKeyChain { master_key }
}
}

impl KeyChain for DefaultKeyChain {
fn derive_private_key(
&self,
chain_path: ChainPath,
) -> Result<(EthereumExPrivateKey, Derivation), Error> {
let mut iter = chain_path.iter();
// chain_path must start with root
if iter.next() != Some(Ok(SubPath::Root)) {
return Err(ChainPathError::Invalid.into());
}
let mut key = self.master_key.clone();
let mut depth = 0;
let mut parent_key = None;
let mut key_index = None;
for sub_path in iter {
match sub_path? {
SubPath::Child(child_key_index) => {
depth += 1;
key_index = Some(child_key_index);
let child_key = key.derive_private_key(child_key_index)?;
parent_key = Some(key);
key = child_key;
}
_ => return Err(ChainPathError::Invalid.into()),
}
}

Ok((
key,
Derivation {
depth,
parent_key,
key_index,
},
))
}
}
/*
#[cfg(test)]
mod tests {
use super::*;
use crate::{solana::PrivKey, solana::PubKey, traits::Serialize};
use base58::ToBase58;

fn from_hex(hex_string: &str) -> Vec<u8> {
let strip_prefix = hex_string.starts_with("0x");
if strip_prefix {
hex::decode(&hex_string[2..]).expect("decode")
} else {
hex::decode(hex_string).expect("decode")
}
}

fn to_hex(buf: Vec<u8>) -> String {
hex::encode(buf)
}

#[test]
fn test_bip32_vector_1() {
let seed = from_hex("000102030405060708090a0b0c0d0e0f");
let key_chain =
DefaultKeyChain::new(EthereumExPrivateKey::new_master_key(&seed).expect("master key"));
for (chain_path, hex_priv_key, hex_pub_key) in &[
(
"m",
"2b4be7f19ee27bbf30c667b642d5f4aa69fd169872f8fc3059c08ebae2eb19e7",
"C5ukMV73nk32h52MjxtnZXTrrr7rupD9CTDDRnYYDRYQ",
),
(
"m/0H",
"68e0fe46dfb67e368c75379acec591dad19df3cde26e63b93a8e704f1dade7a3",
"ATcCGRoY87cSJESCXbHXEX6CDWQxepAViUvVnNsELhRu",
),
(
"m/0H/1H",
"b1d0bad404bf35da785a64ca1ac54b2617211d2777696fbffaf208f746ae84f2",
"2hMz2f8WbLw5m2icKR2WVrcizvnguw8xaAnXjaeohuHQ",
),
(
"m/0H/1H/2H",
"92a5b23c0b8a99e37d07df3fb9966917f5d06e02ddbd909c7e184371463e9fc9",
"CkYmXLvWehLXBzUAJ3g3wsfc5QjoCtWtSydquF7HDxXS",
),
(
"m/0H/1H/2H/2H",
"30d1dc7e5fc04c31219ab25a27ae00b50f6fd66622f6e9c913253d6511d1e662",
"ALYYdMp2jVV4HGsZZPfLy1BQLMHL2CQG5XHpzr2XiHCw",
),
(
"m/0H/1H/2H/2H/1000000000H",
"8f94d394a8e8fd6b1bc2f3f49f5c47e385281d5c17e65324b0f62483e37e8793",
"53n47S4RT9ozx5KrpH6uYfdnAjrTBJri8qZJBvRfw1Bf",
),
] {
let (key, derivation) = key_chain
.derive_private_key(ChainPath::from(*chain_path))
.expect("fetch key");
let priv_key = PrivKey {
derivation,
extended_key: key,
};

let pub_key = PubKey::from_private_key(&priv_key);

assert_eq!(
to_hex(priv_key.extended_key.private_key.to_bytes().to_vec()),
*hex_priv_key
);

assert_eq!(
&Serialize::<Vec<u8>>::serialize(&pub_key.extended_key).to_base58(),
hex_pub_key
);
}
}
}
*/
Loading