diff --git a/plugins/stronghold/guest-js/index.ts b/plugins/stronghold/guest-js/index.ts index c1945a21..09b1e758 100644 --- a/plugins/stronghold/guest-js/index.ts +++ b/plugins/stronghold/guest-js/index.ts @@ -256,6 +256,72 @@ class ProcedureExecutor { } }).then((n) => Uint8Array.from(n)) } + + /** + * Gets the Secp256k1Ecdsa public key of a SLIP10 private key. + * @param privateKeyLocation The location of the private key. Must be the `outputLocation` of a previous call to `deriveSLIP10`. + * @returns A promise resolving to the public key hex string. + * + * @since 2.1.0 + */ + async getSecp256k1EcdsaPublicKey(privateKeyLocation: Location): Promise { + return await invoke('plugin:stronghold|execute_procedure', { + ...this.procedureArgs, + procedure: { + type: 'PublicKey', + payload: { + type: 'Secp256k1Ecdsa', + privateKey: privateKeyLocation + } + } + }).then((n) => Uint8Array.from(n)) + } + + /** + * Gets the EVM address of a SLIP10 private key. + * @param privateKeyLocation The location of the private key. Must be the `outputLocation` of a previous call to `deriveSLIP10`. + * @returns A promise resolving to the EVM address + * + * @since 2.1.0 + */ + async getSecp256k1EcdsaEvmAddress(privateKeyLocation: Location): Promise { + return await invoke('plugin:stronghold|execute_procedure', { + ...this.procedureArgs, + procedure: { + type: 'GetEvmAddress', + payload: { + privateKey: privateKeyLocation + } + } + }).then((n) => Uint8Array.from(n)) + } + + /** + * Creates a Secp256k1Ecdsa signature from a private key. + * @param flavor The hash type + * @param privateKeyLocation The location of the record where the private key is stored. Must be the `outputLocation` of a previous call to `deriveSLIP10`. + * @param msg The message to sign. + * @returns A promise resolving to the signature hex string. + * + * @since 2.1.0 + */ + async signSecp256k1Ecdsa( + flavor: 'Keccak256' | 'Sha256', + privateKeyLocation: Location, + msg: string + ): Promise { + return await invoke('plugin:stronghold|execute_procedure', { + ...this.procedureArgs, + procedure: { + type: 'Secp256k1EcdsaSign', + payload: { + flavor, + privateKey: privateKeyLocation, + msg + } + } + }).then((n) => Uint8Array.from(n)) + } } export class Client { diff --git a/plugins/stronghold/src/lib.rs b/plugins/stronghold/src/lib.rs index 23acc3a2..4d02c4c8 100644 --- a/plugins/stronghold/src/lib.rs +++ b/plugins/stronghold/src/lib.rs @@ -20,9 +20,9 @@ use std::{ use crypto::keys::bip39; use iota_stronghold::{ procedures::{ - BIP39Generate, BIP39Recover, Curve, Ed25519Sign, KeyType as StrongholdKeyType, - MnemonicLanguage, PublicKey, Slip10Derive, Slip10DeriveInput, Slip10Generate, - StrongholdProcedure, + BIP39Generate, BIP39Recover, Curve, Ed25519Sign, GetEvmAddress, + KeyType as StrongholdKeyType, MnemonicLanguage, PublicKey, Secp256k1EcdsaFlavor, + Secp256k1EcdsaSign, Slip10Derive, Slip10DeriveInput, Slip10Generate, StrongholdProcedure, }, Client, Location, }; @@ -107,6 +107,7 @@ impl From for Slip10DeriveInput { pub enum KeyType { Ed25519, X25519, + Secp256k1Ecdsa, } impl From for StrongholdKeyType { @@ -114,6 +115,7 @@ impl From for StrongholdKeyType { match ty { KeyType::Ed25519 => StrongholdKeyType::Ed25519, KeyType::X25519 => StrongholdKeyType::X25519, + KeyType::Secp256k1Ecdsa => StrongholdKeyType::Secp256k1Ecdsa, } } } @@ -129,7 +131,7 @@ impl<'de> Deserialize<'de> for KeyType { type Value = KeyType; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("ed25519 or x25519") + formatter.write_str("ed25519, x25519, or secp256k1_ecdsa") } fn visit_str(self, value: &str) -> std::result::Result @@ -139,6 +141,7 @@ impl<'de> Deserialize<'de> for KeyType { match value.to_lowercase().as_str() { "ed25519" => Ok(KeyType::Ed25519), "x25519" => Ok(KeyType::X25519), + "secp256k1_ecdsa" => Ok(KeyType::Secp256k1Ecdsa), _ => Err(serde::de::Error::custom("unknown key type")), } } @@ -182,6 +185,16 @@ enum ProcedureDto { private_key: LocationDto, msg: String, }, + GetEvmAddress { + #[serde(rename = "privateKey")] + private_key: LocationDto, + }, + Secp256k1EcdsaSign { + flavor: Secp256k1EcdsaFlavor, + #[serde(rename = "privateKey")] + private_key: LocationDto, + msg: String, + }, } impl From for StrongholdProcedure { @@ -231,6 +244,20 @@ impl From for StrongholdProcedure { msg: msg.as_bytes().to_vec(), }) } + ProcedureDto::GetEvmAddress { private_key } => { + StrongholdProcedure::GetEvmAddress(GetEvmAddress { + private_key: private_key.into(), + }) + } + ProcedureDto::Secp256k1EcdsaSign { + flavor, + private_key, + msg, + } => StrongholdProcedure::Secp256k1EcdsaSign(Secp256k1EcdsaSign { + flavor, + private_key: private_key.into(), + msg: msg.as_bytes().to_vec(), + }), } } }