Skip to content
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

feat(api): Implement Ed25519-BIP32 #127

Merged
merged 112 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
112 commits
Select commit Hold shift + click to select a range
2e31a4c
feat: add ed25519-bip32 crate
bkioshn Feb 15, 2024
79214ca
fix: change key type to bstr
bkioshn Feb 16, 2024
a6e0c06
feat: impl new for Ed25519Bip32
bkioshn Feb 16, 2024
20e54b6
feat: implement state and resource holder
bkioshn Feb 16, 2024
6435b6c
chore: calling crypto state
bkioshn Feb 19, 2024
6379462
feat: implement get pub key
bkioshn Feb 19, 2024
5ee46c9
fix: state
bkioshn Feb 19, 2024
7da3a34
feat: implement sign data
bkioshn Feb 19, 2024
6908510
feat: implement check signature
bkioshn Feb 19, 2024
12bcd03
feat: implement resource drop crypto
bkioshn Feb 19, 2024
206782c
feat: implement derive
bkioshn Feb 19, 2024
96c5e4f
Merge branch 'main' into feat/crypto-api
bkioshn Feb 19, 2024
011e97a
fix: remove unnecessary struct
bkioshn Feb 19, 2024
cfddf95
fix: syntax cleanup
bkioshn Feb 19, 2024
89c078a
fix: cspell
bkioshn Feb 19, 2024
f605f51
fix: format
bkioshn Feb 19, 2024
a853123
chore: add dashmap crate
bkioshn Feb 20, 2024
a6af5a1
fix: change to type with fix size
bkioshn Feb 21, 2024
ab15853
fix: change signature length to 512
bkioshn Feb 22, 2024
d4803d8
fix: restructure crypto resource and states
bkioshn Feb 22, 2024
0250783
fix: crypto api implementation
bkioshn Feb 22, 2024
903ca0b
feat: add once_cell crate
bkioshn Feb 23, 2024
927658e
fix: extract state to its own mod
bkioshn Feb 23, 2024
028a623
fix: remove generic from impl
bkioshn Feb 23, 2024
3279506
fix: crypto state implementation
bkioshn Feb 25, 2024
97d66d7
fix: crypto state
bkioshn Feb 26, 2024
ad1480c
fix: crypto state
bkioshn Feb 27, 2024
73b2b00
Merge branch 'main' into feat/crypto-api
bkioshn Feb 27, 2024
5358c61
fix: counter and map in crypto state
bkioshn Feb 27, 2024
c770fc6
fix: use XPrv from lib
bkioshn Feb 28, 2024
41b6256
fix: create wrap Xprv
bkioshn Feb 28, 2024
5941bf4
fix: crypto state
bkioshn Feb 28, 2024
b5a0d4d
fix: remove FIXME and fix From impl
bkioshn Feb 29, 2024
f3b096b
fix: add thread safe test and comments
bkioshn Mar 2, 2024
bcbd2d5
chore: add println for esier debug
bkioshn Mar 3, 2024
5a14be3
chore: comment out old functionality
bkioshn Mar 4, 2024
c5d9a50
fix: add resource and test
bkioshn Mar 4, 2024
749402e
feat: add bip39 lib
bkioshn Mar 4, 2024
bfea699
feat: add bip32-ed25519 implementation
bkioshn Mar 4, 2024
793a9a6
fix: constructor to accept bip39
bkioshn Mar 4, 2024
b00319a
fix: mnemonic to xprv
bkioshn Mar 6, 2024
bde543f
fix: change mnemonic and passphrase to list
bkioshn Mar 6, 2024
5641c89
feat: add rand and rand_core lib
bkioshn Mar 6, 2024
979245a
feat: start implement generating mnemonic
bkioshn Mar 6, 2024
5669806
feat: implement mnemonic generating with prefix
bkioshn Mar 8, 2024
78939df
chore: add bip39 support lang
bkioshn Mar 8, 2024
1f63919
feat: add crypto error
bkioshn Mar 8, 2024
2b7ef0a
fix: add mnemonic to priv test and refactor
bkioshn Mar 8, 2024
a424920
fix: move bip39 to its own module + write doc and comment
bkioshn Mar 8, 2024
f0269ba
chore: fix func name and add comment
bkioshn Mar 11, 2024
310522b
feat: add bip32-ed25519 implementation
bkioshn Mar 11, 2024
4224896
fix: bip32-ed25519 name + add path to derive
bkioshn Mar 11, 2024
a8408db
feat: add bip32 crate
bkioshn Mar 12, 2024
92abf8c
feat: implement test
bkioshn Mar 12, 2024
54b84ad
Merge branch 'main' into feat/crypto-api
bkioshn Mar 12, 2024
53eea86
Merge branch 'main' into feat/crypto-api
stevenj Mar 12, 2024
ac88ecc
fix: host crypto
bkioshn Mar 13, 2024
a7d6dd1
fix: test vector
bkioshn Mar 13, 2024
7cfccd3
fix: add doc
bkioshn Mar 13, 2024
dc851b8
feat: implement derive, sign data, check sig, and pubkey
bkioshn Mar 13, 2024
1dbffa3
fix: state type
bkioshn Mar 13, 2024
68fd6a6
fix: wit file function and add err
bkioshn Mar 13, 2024
56b3604
fix: bip39 type
bkioshn Mar 13, 2024
d064cb3
fix: bip32_ed25519 type
bkioshn Mar 13, 2024
f5fe684
fix: host implementation
bkioshn Mar 13, 2024
7c59e30
chore: fix type and comment
bkioshn Mar 13, 2024
5a5c436
feat: add delete resource
bkioshn Mar 13, 2024
19ad050
fix: error handling
bkioshn Mar 13, 2024
3e4bdac
fix: import
bkioshn Mar 13, 2024
9073420
feat: implement drop resource
bkioshn Mar 14, 2024
81a95bf
chore: cleanup bip32-ed25519
bkioshn Mar 14, 2024
1b58ee4
fix: remove unused crate
bkioshn Mar 14, 2024
7710b14
fix: bip39 doc
bkioshn Mar 14, 2024
3849261
fix: add error crypto wit file
bkioshn Mar 14, 2024
0382acf
fix: syntax in bip32-ed25519
bkioshn Mar 14, 2024
88b299e
fix: bip39 syntax
bkioshn Mar 14, 2024
3a69466
fix: state syntax
bkioshn Mar 14, 2024
15383d2
fix: host syntax
bkioshn Mar 14, 2024
006679a
fix: add error
bkioshn Mar 14, 2024
b4a89a0
feat: add set state
bkioshn Mar 14, 2024
ad69083
Merge branch 'main' into feat/crypto-api
bkioshn Mar 14, 2024
9ab0b2c
fix: spelling
bkioshn Mar 14, 2024
54ab633
fix: nightly format
bkioshn Mar 14, 2024
42384ab
fix: spelling
bkioshn Mar 14, 2024
f70396a
fix: try no cache
bkioshn Mar 14, 2024
b2ef866
fix: delete no cache
bkioshn Mar 14, 2024
2711b6e
fix: add CC0-1 license to deny toml
bkioshn Mar 15, 2024
b40e84d
fix: implement new state, app -> resource
bkioshn Mar 15, 2024
4a736b5
fix: bip39 gen mnemonic implementation
bkioshn Mar 15, 2024
f67f98f
fix: move gen mnemonic and fix constructor
bkioshn Mar 15, 2024
faf6236
fix: bip39 types
bkioshn Mar 15, 2024
9229f1d
fix: crypto host
bkioshn Mar 16, 2024
391a81f
fix: remove errno
bkioshn Mar 16, 2024
b53f45f
fix: add state check
bkioshn Mar 16, 2024
f8f37ee
fix: todo comment
bkioshn Mar 18, 2024
a75c55c
fix: add project dict
bkioshn Mar 18, 2024
93fef0c
fix: typo
bkioshn Mar 18, 2024
4103caa
fix: formatter
bkioshn Mar 18, 2024
b7b32ec
fix: update rust ci version
bkioshn Mar 18, 2024
aefe00c
fix: try without cache
bkioshn Mar 18, 2024
983c7c1
fix: syntax
bkioshn Mar 18, 2024
cf24f20
fix: remove no cache
bkioshn Mar 18, 2024
e6e69ac
Merge branch 'main' into feat/crypto-api
bkioshn Mar 18, 2024
2003abf
fix: rust ci
bkioshn Mar 18, 2024
6f4a694
fix: add license
bkioshn Mar 18, 2024
c9b221d
fix: bip39 jap test
bkioshn Mar 18, 2024
ab50b4f
fix: unicode not nfc problem
bkioshn Mar 18, 2024
5251989
fix: rust base version
bkioshn Mar 18, 2024
897872e
chore: cleanup
bkioshn Mar 18, 2024
cacce90
fix: pr comment
bkioshn Mar 19, 2024
2b35c44
fix: spelling
bkioshn Mar 19, 2024
c207ba2
Merge branch 'main' into feat/crypto-api
bkioshn Mar 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions .config/dictionaries/project.dic
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ asyncio
auditability
backpressure
bindgen
bkioshn
blockdiag
blockfetch
bmac
BROTLI
CHAINCODE
cardano
chaincode
cbor
CBOR
cbork
Expand All @@ -26,6 +29,7 @@ coti
crontabs
cryptoxide
Datelike
dashmap
dbsync
dcbor
delegators
Expand Down Expand Up @@ -109,6 +113,7 @@ preopens
preprod
psql
pubkey
pubk
pubspec
pwrite
rapidoc
Expand Down Expand Up @@ -158,4 +163,8 @@ wasmtime
webasm
webassembly
WORKDIR
XPRV
xprivate
xprv
xpub
yoroi
8 changes: 7 additions & 1 deletion hermes/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,11 @@ chrono = "0.4.34"
chrono-tz = "0.8.6"
libtest-mimic = "0.7.0"
crossbeam-queue = "0.3.11"
once_cell = "1.19.0"
bip39 = "2.0.0"
iana-time-zone = "0.1.60"
cryptoxide = "0.4.4"
rand = "0.8.5"
bip32 = "0.5.1"
ed25519-bip32 = "0.4.1"
dashmap = "5.5.3"
once_cell = "1.19.0"
3 changes: 1 addition & 2 deletions hermes/Earthfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ VERSION 0.7

# Set up our target toolchains, and copy our files.
builder:
DO github.com/input-output-hk/catalyst-ci/earthly/rust:v2.9.3+SETUP

DO github.com/input-output-hk/catalyst-ci/earthly/rust:v2.9.8+SETUP
COPY --dir .cargo .config crates bin .
COPY Cargo.toml .
COPY clippy.toml deny.toml rustfmt.toml .
Expand Down
6 changes: 6 additions & 0 deletions hermes/bin/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ chrono-tz = { workspace = true }
iana-time-zone = { workspace = true }
libtest-mimic = { workspace = true }
crossbeam-queue = { workspace = true }
bip39 = { workspace = true, features = ["chinese-simplified", "chinese-traditional", "czech", "french", "italian", "japanese", "korean", "spanish" ] }
cryptoxide = { workspace = true }
rand = { workspace = true }
bip32 = { workspace = true }
ed25519-bip32 = { workspace = true }
dashmap = { workspace = true }
once_cell = { workspace = true }

[[test]]
Expand Down
224 changes: 224 additions & 0 deletions hermes/bin/src/runtime_extensions/hermes/crypto/bip32_ed25519.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
//! Implementation of Bip32-Ed25519.

use bip32::DerivationPath;
use ed25519_bip32::{DerivationScheme, Signature, XPrv};

use crate::runtime_extensions::bindings::hermes::{
binary::api::Bstr,
crypto::api::{Bip32Ed25519PublicKey, Bip32Ed25519Signature, Errno},
};

/// Get public key from the given extended private key.
///
/// # Arguments
///
/// - `xprivate_key`: An extended private key of type `XPrv`.
///
/// # Returns
///
/// Returns a tuple of u64 values with length 4 representing the public key.
pub(crate) fn get_public_key(xprivate_key: &XPrv) -> Bip32Ed25519PublicKey {
let xpub = xprivate_key.public().public_key();
array_u8_32_to_tuple(&xpub)
}

/// Sign data with the given extended private key.
///
/// # Arguments
///
/// - `xprivate_key`: An extended private key of type `XPrv`.
/// - `data`: The data to sign.
///
/// # Returns
/// Returns a tuple of u64 values with length 8 representing the signature.
pub(crate) fn sign_data(xprivate_key: &XPrv, data: &Bstr) -> Bip32Ed25519Signature {
let sig: Signature<Bstr> = xprivate_key.sign(data);
let sig_bytes = sig.to_bytes();
array_u8_64_to_tuple(sig_bytes)
}

/// Check the signature on the given data.
///
/// # Arguments
///
/// - `xprivate_key`: An extended private key of type `XPrv`.
/// - `data`: The data to sign.
/// - `signature`: The signature to check.
///
/// # Returns
/// Returns a boolean value indicating if the signature match the sign data
/// from `xprivate_key` and data.
/// True if the signature is valid and match the sign data, false otherwise.
pub(crate) fn check_signature(
xprivate_key: &XPrv, data: &Bstr, signature: Bip32Ed25519Signature,
) -> bool {
let sig_array = b512_u64_tuple_to_u8_array(&signature);
// Verify the signature.
let signature: Signature<Bstr> = match Signature::from_slice(&sig_array) {
Ok(sig) => sig,
// Invalid signature
Err(_) => return false,
};
xprivate_key.verify(data, &signature)
}

/// Derive a new extended private key from the given extended private key.
/// - V2 derivation scheme is used as it is mention in
/// [SLIP-0023](https://github.com/satoshilabs/slips/blob/master/slip-0023.md).
/// - More information about child key derivation can be found in
/// [BIP32-Ed25519](https://input-output-hk.github.io/adrestia/static/Ed25519_BIP.pdf).
///
/// # Arguments
///
/// - `xprivate_key`: An extended private key of type `XPrv`.
/// - `path`: Derivation path. eg. m/0/2'/3 where ' represents hardened derivation.
///
/// # Returns
///
/// Returns the `XPrv` extended private key as a `Result`.
/// If the derivation path is successful, it returns `Ok` with the extended private key
/// (`XPrv`).
///
/// # Errors
///
/// Returns an `InvalidDerivationalPath` if the derivation path is invalid.
pub(crate) fn derive_new_private_key(xprivate_key: XPrv, path: &str) -> Result<XPrv, Errno> {
let Ok(derivation_path) = path.parse::<DerivationPath>() else {
return Err(Errno::InvalidDerivationalPath);
};
let key = derivation_path
.iter()
.fold(xprivate_key, |xprv, child_num| {
if child_num.is_hardened() {
xprv.derive(DerivationScheme::V2, child_num.index() | 0x80_00_00_00)
} else {
xprv.derive(DerivationScheme::V2, child_num.index())
}
});
Ok(key)
}

/// Convert a 32 bytes array to a tuple of u64 values.
fn array_u8_32_to_tuple(array: &[u8; 32]) -> (u64, u64, u64, u64) {
let mut tuple = (0u64, 0u64, 0u64, 0u64);
let mut arr = [0u8; 8];
let slice1 = &array[0..8];
arr.copy_from_slice(slice1);
tuple.0 = u64::from_be_bytes(arr);

let slice2 = &array[8..16];
arr.copy_from_slice(slice2);
tuple.1 = u64::from_be_bytes(arr);

let slice3 = &array[16..24];
arr.copy_from_slice(slice3);
tuple.2 = u64::from_be_bytes(arr);

let slice4 = &array[24..32];
arr.copy_from_slice(slice4);
tuple.3 = u64::from_be_bytes(arr);

tuple
}

/// Convert a 64 bytes array to a tuple of u64 values.
fn array_u8_64_to_tuple(array: &[u8; 64]) -> (u64, u64, u64, u64, u64, u64, u64, u64) {
let mut tuple = (0u64, 0u64, 0u64, 0u64, 0u64, 0u64, 0u64, 0u64);
let mut arr = [0u8; 8];
let slice1 = &array[0..8];
arr.copy_from_slice(slice1);
tuple.0 = u64::from_be_bytes(arr);

let slice2 = &array[8..16];
arr.copy_from_slice(slice2);
tuple.1 = u64::from_be_bytes(arr);

let slice3 = &array[16..24];
arr.copy_from_slice(slice3);
tuple.2 = u64::from_be_bytes(arr);

let slice4 = &array[24..32];
arr.copy_from_slice(slice4);
tuple.3 = u64::from_be_bytes(arr);

let slice5 = &array[32..40];
arr.copy_from_slice(slice5);
tuple.4 = u64::from_be_bytes(arr);

let slice6 = &array[40..48];
arr.copy_from_slice(slice6);
tuple.5 = u64::from_be_bytes(arr);

let slice7 = &array[48..56];
arr.copy_from_slice(slice7);
tuple.6 = u64::from_be_bytes(arr);

let slice8 = &array[56..64];
arr.copy_from_slice(slice8);
tuple.7 = u64::from_be_bytes(arr);

tuple
}

/// Convert a tuple of u64 values to a 64 bytes array.
fn b512_u64_tuple_to_u8_array(tuple: &(u64, u64, u64, u64, u64, u64, u64, u64)) -> [u8; 64] {
let mut bytes = [0u8; 64];
let (t1, t2, t3, t4, t5, t6, t7, t8) = tuple;
bytes[0..8].copy_from_slice(&t1.to_be_bytes());
bytes[8..16].copy_from_slice(&t2.to_be_bytes());
bytes[16..24].copy_from_slice(&t3.to_be_bytes());
bytes[24..32].copy_from_slice(&t4.to_be_bytes());
bytes[32..40].copy_from_slice(&t5.to_be_bytes());
bytes[40..48].copy_from_slice(&t6.to_be_bytes());
bytes[48..56].copy_from_slice(&t7.to_be_bytes());
bytes[56..64].copy_from_slice(&t8.to_be_bytes());
bytes
}

#[cfg(test)]
mod tests_bip32_ed25519 {
use super::*;

// Test vectors are converted from CIP-0011
// https://cips.cardano.org/cip/CIP-0011
const XPRV1: [u8; 64] = [
200, 191, 149, 165, 98, 208, 246, 104, 52, 11, 13, 195, 131, 134, 5, 150, 34, 84, 34, 234,
246, 156, 89, 44, 102, 183, 12, 25, 181, 229, 151, 68, 216, 238, 211, 173, 41, 106, 14, 51,
53, 217, 219, 231, 210, 32, 13, 82, 86, 83, 210, 195, 255, 75, 225, 13, 74, 150, 225, 78,
177, 165, 3, 214,
];

const CHAINCODE1: [u8; 32] = [
98, 56, 179, 184, 207, 42, 180, 226, 223, 22, 246, 228, 154, 15, 134, 223, 246, 201, 237,
64, 158, 145, 73, 32, 113, 98, 71, 129, 188, 170, 18, 213,
];
const PUBKEY1: &str = "3753d92d88778c4087c3fa59eb748a276eb654164ef23403aeae200ddd554d3e";
const DATA: &[u8; 4] = b"test";

#[test]
fn test_get_public_key() {
let xprv = XPrv::from_extended_and_chaincode(&XPRV1, &CHAINCODE1);
let pubk_tuple = get_public_key(&xprv);
let pubk_hex = format!(
"{:x}{:x}{:x}{:x}",
pubk_tuple.0, pubk_tuple.1, pubk_tuple.2, pubk_tuple.3
);
assert_eq!(pubk_hex, PUBKEY1);
}

#[test]
fn test_sign_data_and_check_signature() {
let xprv = XPrv::from_extended_and_chaincode(&XPRV1, &CHAINCODE1);
let sign_data = sign_data(&xprv, &DATA.to_vec());
let check_signature = check_signature(&xprv, &DATA.to_vec(), sign_data);
assert!(check_signature);
}

#[test]
fn test_derive_new_private_key() {
let xprv = XPrv::from_extended_and_chaincode(&XPRV1, &CHAINCODE1);
let derived_xprv =
derive_new_private_key(xprv, "m/1852'/1815'/0'/2/0").expect("Derivation failed");
assert_eq!(derived_xprv.to_string(), "b8ab42f1aacbcdb3ae858e3a3df88142b3ed27a2d3f432024e0d943fc1e597442d57545d84c8db2820b11509d944093bc605350e60c533b8886a405bd59eed6dcf356648fe9e9219d83e989c8ff5b5b337e2897b6554c1ab4e636de791fe5427");
}
}