From ac1f52fa448c070a3dc8d6ced30f772e741f6a0c Mon Sep 17 00:00:00 2001 From: bochaco Date: Mon, 18 Dec 2023 18:28:28 -0300 Subject: [PATCH] feat: expose API for EIP2333 key derivation --- ledger_device_sdk/src/ecc.rs | 37 +++++++++++++++++++++++++++++++++++- ledger_device_sdk/src/io.rs | 2 +- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/ledger_device_sdk/src/ecc.rs b/ledger_device_sdk/src/ecc.rs index 8434abb4..8e3636e0 100644 --- a/ledger_device_sdk/src/ecc.rs +++ b/ledger_device_sdk/src/ecc.rs @@ -403,6 +403,19 @@ pub fn bip32_derive(curve: CurvesId, path: &[u32], key: &mut [u8]) -> Result<(), Ok(()) } +/// Wrapper for 'os_perso_derive_eip2333' +pub fn eip2333_derive(path: &[u32], key: &mut [u8]) -> Result<(), CxError> { + unsafe { + os_perso_derive_eip2333( + CurvesId::Bls12381G1 as u8, + path.as_ptr(), + path.len() as u32, + key.as_mut_ptr(), + ) + }; + Ok(()) +} + /// Helper buffer that stores secrets that need to be cleared after use pub struct Secret([u8; N]); @@ -474,7 +487,7 @@ impl SeedDerive for Secp256r1 { } impl SeedDerive for Ed25519 { - type Target = ECPrivateKey<32, 'E'>; + type Target = ECPrivateKey<32, 'E'>; // TODO: review curve type fn derive_from_path(path: &[u32]) -> Self::Target { let mut tmp = Secret::<96>::new(); // Ignoring 'Result' here because known to be valid @@ -495,6 +508,19 @@ impl SeedDerive for Stark256 { } } +impl SeedDerive for Bls12381G1 { + type Target = ECPrivateKey<32, 'E'>; + fn derive_from_path(path: &[u32]) -> Self::Target { + let mut tmp = Secret::<32>::new(); + // Ignoring 'Result' here because known to be valid + let _ = eip2333_derive(path, tmp.as_mut()); + let mut sk = Self::Target::new(CurvesId::Bls12381G1); + let keylen = sk.key.len(); + sk.key.copy_from_slice(&tmp.0[..keylen]); + sk + } +} + /// This macro is used to easily generate zero-sized structures named after a Curve. /// Each curve has a method `new()` that takes no arguments and returns the correctly /// const-typed `ECPrivateKey`. @@ -530,6 +556,7 @@ impl_curve!(BrainpoolP512R1, 64, 'W'); impl_curve!(BrainpoolP512T1, 64, 'W'); impl_curve!(Stark256, 32, 'W'); impl_curve!(Ed25519, 32, 'E'); +impl_curve!(Bls12381G1, 32, 'E'); // TODO: review type of curve (...and sigining impl) // impl_curve!( FRP256v1, 32, 'W' ); // impl_curve!( Ed448, 57, 'E' ); @@ -788,6 +815,14 @@ mod tests { assert_eq!(pk.verify((&s.0, s.1), TEST_HASH, CX_SHA512), true); } + #[test] + fn eddsa_bls12381g1() { + let sk = Bls12381G1::derive_from_path(&PATH0); + let s = sk.sign(TEST_HASH).map_err(display_error_code)?; + let pk = sk.public_key().map_err(display_error_code)?; + assert_eq!(pk.verify((&s.0, s.1), TEST_HASH, CX_SHA512), true); + } + #[test] fn test_make_bip32_path() { { diff --git a/ledger_device_sdk/src/io.rs b/ledger_device_sdk/src/io.rs index 5ef272f3..da3459b4 100644 --- a/ledger_device_sdk/src/io.rs +++ b/ledger_device_sdk/src/io.rs @@ -78,7 +78,7 @@ impl From for Reply { // `Error` as `Infallible`. Since we need to convert such error in a status word (`Reply`) we need // to implement this trait here. impl From for Reply { - fn from(value: Infallible) -> Self { + fn from(_value: Infallible) -> Self { Reply(0x9000) } }