Skip to content

feat(stronghold): support secp256k1 curve #2724

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 3 commits into
base: v2
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
2 changes: 1 addition & 1 deletion plugins/stronghold/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@

## \[2.0.0-beta.8]

- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the _minimum_ `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.

## \[2.0.0-beta.7]
Expand Down
2 changes: 1 addition & 1 deletion plugins/stronghold/api-iife.js

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

70 changes: 70 additions & 0 deletions plugins/stronghold/guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,76 @@ 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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @since 2.1.0
* @since 2.4.0

*/
async getSecp256k1EcdsaPublicKey(
privateKeyLocation: Location
): Promise<Uint8Array> {
return await invoke<number[]>('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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @since 2.1.0
* @since 2.4.0

*/
async getSecp256k1EcdsaEvmAddress(
privateKeyLocation: Location
): Promise<Uint8Array> {
return await invoke<number[]>('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
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @since 2.1.0
* @since 2.4.0

*/
async signSecp256k1Ecdsa(
flavor: 'Keccak256' | 'Sha256',
privateKeyLocation: Location,
msg: string
): Promise<Uint8Array> {
return await invoke<number[]>('plugin:stronghold|execute_procedure', {
...this.procedureArgs,
procedure: {
type: 'Secp256k1EcdsaSign',
payload: {
flavor,
privateKey: privateKeyLocation,
msg
}
}
}).then((n) => Uint8Array.from(n))
}
}

export class Client {
Expand Down
3 changes: 0 additions & 3 deletions plugins/stronghold/permissions/autogenerated/reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ operations are available from the stronghold plugin.

All non-destructive operations are enabled by default.



#### This default permission set includes the following:

- `allow-create-client`
Expand All @@ -28,7 +26,6 @@ All non-destructive operations are enabled by default.
<th>Description</th>
</tr>


<tr>
<td>

Expand Down
71 changes: 16 additions & 55 deletions plugins/stronghold/permissions/schemas/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,17 @@
"DefaultPermission": {
"description": "The default permission set of the plugin.\n\nWorks similarly to a permission with the \"default\" identifier.",
"type": "object",
"required": [
"permissions"
],
"required": ["permissions"],
"properties": {
"version": {
"description": "The version of the permission.",
"type": [
"integer",
"null"
],
"type": ["integer", "null"],
"format": "uint64",
"minimum": 1.0
},
"description": {
"description": "Human-readable description of what the permission does. Tauri convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
]
"type": ["string", "null"]
},
"permissions": {
"description": "All permissions this set contains.",
Expand All @@ -67,11 +59,7 @@
"PermissionSet": {
"description": "A set of direct permissions grouped together under a new name.",
"type": "object",
"required": [
"description",
"identifier",
"permissions"
],
"required": ["description", "identifier", "permissions"],
"properties": {
"identifier": {
"description": "A unique identifier for the permission.",
Expand All @@ -93,16 +81,11 @@
"Permission": {
"description": "Descriptions of explicit privileges of commands.\n\nIt can enable commands to be accessible in the frontend of the application.\n\nIf the scope is defined it can be used to fine grain control the access of individual or multiple commands.",
"type": "object",
"required": [
"identifier"
],
"required": ["identifier"],
"properties": {
"version": {
"description": "The version of the permission.",
"type": [
"integer",
"null"
],
"type": ["integer", "null"],
"format": "uint64",
"minimum": 1.0
},
Expand All @@ -112,10 +95,7 @@
},
"description": {
"description": "Human-readable description of what the permission does. Tauri internal convention is to use `<h4>` headings in markdown content for Tauri documentation generation purposes.",
"type": [
"string",
"null"
]
"type": ["string", "null"]
},
"commands": {
"description": "Allowed or denied commands when using this permission.",
Expand All @@ -139,10 +119,7 @@
},
"platforms": {
"description": "Target platforms this permission applies. By default all platforms are affected by this permission.",
"type": [
"array",
"null"
],
"type": ["array", "null"],
"items": {
"$ref": "#/definitions/Target"
}
Expand Down Expand Up @@ -177,20 +154,14 @@
"properties": {
"allow": {
"description": "Data that defines what is allowed by the scope.",
"type": [
"array",
"null"
],
"type": ["array", "null"],
"items": {
"$ref": "#/definitions/Value"
}
},
"deny": {
"description": "Data that defines what is denied by the scope. This should be prioritized by validation logic.",
"type": [
"array",
"null"
],
"type": ["array", "null"],
"items": {
"$ref": "#/definitions/Value"
}
Expand Down Expand Up @@ -257,37 +228,27 @@
{
"description": "MacOS.",
"type": "string",
"enum": [
"macOS"
]
"enum": ["macOS"]
},
{
"description": "Windows.",
"type": "string",
"enum": [
"windows"
]
"enum": ["windows"]
},
{
"description": "Linux.",
"type": "string",
"enum": [
"linux"
]
"enum": ["linux"]
},
{
"description": "Android.",
"type": "string",
"enum": [
"android"
]
"enum": ["android"]
},
{
"description": "iOS.",
"type": "string",
"enum": [
"iOS"
]
"enum": ["iOS"]
}
]
},
Expand Down Expand Up @@ -435,4 +396,4 @@
]
}
}
}
}
35 changes: 31 additions & 4 deletions plugins/stronghold/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -107,13 +107,15 @@ impl From<Slip10DeriveInputDto> for Slip10DeriveInput {
pub enum KeyType {
Ed25519,
X25519,
Secp256k1Ecdsa,
}

impl From<KeyType> for StrongholdKeyType {
fn from(ty: KeyType) -> StrongholdKeyType {
match ty {
KeyType::Ed25519 => StrongholdKeyType::Ed25519,
KeyType::X25519 => StrongholdKeyType::X25519,
KeyType::Secp256k1Ecdsa => StrongholdKeyType::Secp256k1Ecdsa,
}
}
}
Expand All @@ -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<E>(self, value: &str) -> std::result::Result<Self::Value, E>
Expand All @@ -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")),
}
}
Expand Down Expand Up @@ -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,
},
Comment on lines +188 to +197
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i couldn't try the changes yet but is this enum not missing a Secp256k1Ecdsa variant?

}

impl From<ProcedureDto> for StrongholdProcedure {
Expand Down Expand Up @@ -231,6 +244,20 @@ impl From<ProcedureDto> 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(),
}),
}
}
}
Expand Down
Loading