Skip to content

Commit

Permalink
wasm: sign wallet comm using correct signing key (#148)
Browse files Browse the repository at this point in the history
* wasm: sign wallet comm using correct signing key

* chore: version packages
  • Loading branch information
sehyunc authored Jan 4, 2025
1 parent 9331c6e commit dea5932
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 69 deletions.
6 changes: 6 additions & 0 deletions packages/core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# @renegade-fi/core

## 0.4.14

### Patch Changes

- wasm: sign wallet using correct signing key

## 0.4.13

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/core/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@renegade-fi/core",
"description": "VanillaJS library for Renegade",
"version": "0.4.13",
"version": "0.4.14",
"repository": {
"type": "git",
"url": "https://github.com/renegade-fi/typescript-sdk.git",
Expand Down
38 changes: 19 additions & 19 deletions packages/core/src/utils.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
*/
export function generate_wallet_secrets(sign_message: Function): Promise<any>;
/**
* @param {string} wallet_id
* @param {string} blinder_seed
* @param {string} share_seed
* @param {string} pk_root
* @param {string} sk_match
* @param {string} symmetric_key
* @returns {Promise<any>}
* @param {string} path
* @param {any} headers
* @param {string} body
* @param {string} key
* @returns {string}
*/
export function create_external_wallet(wallet_id: string, blinder_seed: string, share_seed: string, pk_root: string, sk_match: string, symmetric_key: string): Promise<any>;
export function create_request_signature(path: string, headers: any, body: string, key: string): string;
/**
* @param {string} b64_key
* @returns {string}
*/
export function b64_to_hex_hmac_key(b64_key: string): string;
/**
* @param {string} seed
* @returns {any}
Expand Down Expand Up @@ -145,18 +148,15 @@ export function new_external_quote_request(base_mint: string, quote_mint: string
*/
export function assemble_external_match(do_gas_estimation: boolean, updated_order: string, signed_quote: string): any;
/**
* @param {string} path
* @param {any} headers
* @param {string} body
* @param {string} key
* @returns {string}
*/
export function create_request_signature(path: string, headers: any, body: string, key: string): string;
/**
* @param {string} b64_key
* @returns {string}
* @param {string} wallet_id
* @param {string} blinder_seed
* @param {string} share_seed
* @param {string} pk_root
* @param {string} sk_match
* @param {string} symmetric_key
* @returns {Promise<any>}
*/
export function b64_to_hex_hmac_key(b64_key: string): string;
export function create_external_wallet(wallet_id: string, blinder_seed: string, share_seed: string, pk_root: string, sk_match: string, symmetric_key: string): Promise<any>;
/**
* @param {string} wallet_id
* @param {string} blinder_seed
Expand Down
7 changes: 7 additions & 0 deletions packages/node/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @renegade-fi/node

## 0.4.14

### Patch Changes

- Updated dependencies
- @renegade-fi/core@0.4.14

## 0.4.13

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/node/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@renegade-fi/node",
"description": "Node.js library for Renegade",
"version": "0.4.13",
"version": "0.4.14",
"repository": {
"type": "git",
"url": "https://github.com/renegade-fi/typescript-sdk.git",
Expand Down
7 changes: 7 additions & 0 deletions packages/react/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @renegade-fi/react

## 0.4.15

### Patch Changes

- Updated dependencies
- @renegade-fi/core@0.4.14

## 0.4.14

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/react/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@renegade-fi/react",
"description": "React library for Renegade",
"version": "0.4.14",
"version": "0.4.15",
"repository": {
"type": "git",
"url": "https://github.com/renegade-fi/typescript-sdk.git",
Expand Down
7 changes: 7 additions & 0 deletions packages/test/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# @renegade-fi/test

## 0.3.13

### Patch Changes

- Updated dependencies
- @renegade-fi/core@0.4.14

## 0.3.12

### Patch Changes
Expand Down
2 changes: 1 addition & 1 deletion packages/test/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@renegade-fi/test",
"version": "0.3.12",
"version": "0.3.13",
"description": "Testing helpers for Renegade",
"private": true,
"files": [
Expand Down
43 changes: 23 additions & 20 deletions wasm/src/external_api/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub async fn deposit(
) -> Result<JsValue, JsError> {
let mut new_wallet = deserialize_wallet(wallet_str);

let next_public_key = wrap_eyre!(handle_key_rotation(
let (next_public_key, signing_key) = wrap_eyre!(handle_key_rotation(
&mut new_wallet,
seed.as_deref(),
new_public_key
Expand All @@ -173,9 +173,10 @@ pub async fn deposit(
new_wallet.reblind_wallet();

// Sign a commitment to the new shares
let statement_sig = sign_wallet_commitment(&new_wallet, seed.as_deref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let statement_sig =
sign_wallet_commitment(&new_wallet, signing_key.as_ref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;

let update_auth = WalletUpdateAuthorization {
statement_sig,
Expand Down Expand Up @@ -228,7 +229,7 @@ pub async fn withdraw(
) -> Result<JsValue, JsError> {
let mut new_wallet = deserialize_wallet(wallet_str);

let next_public_key = wrap_eyre!(handle_key_rotation(
let (next_public_key, signing_key) = wrap_eyre!(handle_key_rotation(
&mut new_wallet,
seed.as_deref(),
new_public_key
Expand Down Expand Up @@ -262,19 +263,19 @@ pub async fn withdraw(
new_wallet.reblind_wallet();

// Sign a commitment to the new shares
let statement_sig = sign_wallet_commitment(&new_wallet, seed.as_deref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let statement_sig =
sign_wallet_commitment(&new_wallet, signing_key.as_ref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;

let update_auth = WalletUpdateAuthorization {
statement_sig,
new_root_key: next_public_key,
};

let withdrawal_sig = sign_withdrawal_authorization(
&new_wallet,
seed.as_deref(),
mint,
signing_key.as_ref(),
mint.clone(),
amount.to_u128().unwrap(),
destination_addr.clone(),
sign_message.as_ref(),
Expand All @@ -285,7 +286,7 @@ pub async fn withdraw(
let req = WithdrawBalanceRequest {
amount,
destination_addr,
external_transfer_sig: withdrawal_sig.to_vec(),
external_transfer_sig: withdrawal_sig,
update_auth,
};
Ok(JsValue::from_str(&serde_json::to_string(&req).unwrap()))
Expand Down Expand Up @@ -395,7 +396,7 @@ pub async fn create_order_request(
) -> Result<CreateOrderRequest, JsError> {
let mut new_wallet = deserialize_wallet(wallet_str);

let next_public_key = wrap_eyre!(handle_key_rotation(
let (next_public_key, signing_key) = wrap_eyre!(handle_key_rotation(
&mut new_wallet,
seed.as_deref(),
new_public_key
Expand All @@ -418,9 +419,10 @@ pub async fn create_order_request(
new_wallet.reblind_wallet();

// Sign a commitment to the new shares
let statement_sig = sign_wallet_commitment(&new_wallet, seed.as_deref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let statement_sig =
sign_wallet_commitment(&new_wallet, signing_key.as_ref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;

let update_auth = WalletUpdateAuthorization {
statement_sig,
Expand Down Expand Up @@ -520,7 +522,7 @@ pub async fn cancel_order(
) -> Result<JsValue, JsError> {
let mut new_wallet = deserialize_wallet(wallet_str);

let next_public_key = wrap_eyre!(handle_key_rotation(
let (next_public_key, signing_key) = wrap_eyre!(handle_key_rotation(
&mut new_wallet,
seed.as_deref(),
new_public_key
Expand All @@ -539,9 +541,10 @@ pub async fn cancel_order(
new_wallet.reblind_wallet();

// Sign a commitment to the new shares
let statement_sig = sign_wallet_commitment(&new_wallet, seed.as_deref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;
let statement_sig =
sign_wallet_commitment(&new_wallet, signing_key.as_ref(), sign_message.as_ref())
.await
.map_err(|e| JsError::new(&e.to_string()))?;

let update_auth = WalletUpdateAuthorization {
statement_sig,
Expand Down
32 changes: 25 additions & 7 deletions wasm/src/key_rotation.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,47 @@
use crate::{
circuit_types::keychain::PublicSigningKey,
common::types::Wallet,
common::{derivation::derive_sk_root_scalars, types::Wallet},
helpers::{bytes_from_hex_string, public_sign_key_to_hex_string},
};
use k256::ecdsa::SigningKey;

/// Handles wallet key rotation based on whether a new external key is provided.
///
/// If no new key is provided (new_public_key is None), rotates to the next derived key using seed.
/// If a new key is provided, rotates to that key.
/// For internal key rotation, uses the provided seed to derive the next key.
/// For external key rotation, uses the provided new_public_key.
///
/// # Returns
/// The rotated public key, if any
/// A tuple containing:
/// - The new public key as a hex string, if rotation occurred
/// - The previous signing key, if seed was provided
pub fn handle_key_rotation(
wallet: &mut Wallet,
seed: Option<&str>,
new_public_key: Option<String>,
) -> Result<Option<String>, String> {
) -> Result<(Option<String>, Option<SigningKey>), String> {
// Extract the current signing key if seed is provided
let old_signing_key = match seed {
Some(seed_str) => {
let sk_root_scalars =
derive_sk_root_scalars(seed_str, &wallet.key_chain.public_keys.nonce);

Some(
SigningKey::try_from(&sk_root_scalars)
.map_err(|_| String::from("Failed to create signing key"))?,
)
}
None => None,
};

// Use existing rotation logic
let next_public_key = determine_next_key(wallet, seed, new_public_key)?;

// If we have a new key, perform the rotation
if let Some(ref next_key) = next_public_key {
maybe_rotate_to_key(wallet, next_key)?;
}

Ok(next_public_key)
Ok((next_public_key, old_signing_key))
}

/// Gets the next public key based on whether a new external key is provided.
Expand Down
34 changes: 15 additions & 19 deletions wasm/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,24 @@ use crate::{
circuit_types::transfers::{
to_contract_external_transfer, ExternalTransfer, ExternalTransferDirection,
},
common::{derivation::derive_sk_root_scalars, types::Wallet},
common::types::Wallet,
helpers::{bytes_from_hex_string, bytes_to_hex_string},
};

/// Signs a wallet commitment.
pub async fn sign_wallet_commitment(
wallet: &Wallet,
seed: Option<&str>,
signing_key: Option<&SigningKey>,
external_signer: Option<&Function>,
) -> Result<Vec<u8>, String> {
let comm = wallet.get_wallet_share_commitment();
let comm_bytes = comm.inner().serialize_to_bytes();
sign_message(wallet, seed, &comm_bytes, external_signer).await
sign_message(signing_key, &comm_bytes, external_signer).await
}

/// Signs a withdrawal authorization.
pub async fn sign_withdrawal_authorization(
wallet: &Wallet,
seed: Option<&str>,
signing_key: Option<&SigningKey>,
mint: BigUint,
amount: u128,
account_addr: BigUint,
Expand All @@ -50,36 +49,33 @@ pub async fn sign_withdrawal_authorization(
let contract_transfer_bytes = postcard::to_allocvec(&contract_transfer)
.map_err(|e| format!("Failed to serialize transfer: {e}"))?;

sign_message(wallet, seed, &contract_transfer_bytes, external_signer).await
sign_message(signing_key, &contract_transfer_bytes, external_signer).await
}

/// Signs a message using either internal or external signing method.
///
/// For internal signing, uses the seed to derive a signing key.
/// For internal signing, uses the provided SigningKey.
/// For external signing, uses the provided external_signer function.
pub async fn sign_message(
wallet: &Wallet,
seed: Option<&str>,
signing_key: Option<&SigningKey>,
message: &[u8],
external_signer: Option<&Function>,
) -> Result<Vec<u8>, String> {
if let Some(signer) = external_signer {
sign_with_external_key(message, Some(signer)).await
} else if let Some(seed) = seed {
sign_with_internal_key(wallet, seed, message)
} else if let Some(key) = signing_key {
sign_with_internal_key(key, message)
} else {
Err(String::from("Either seed or external signer is required"))
Err(String::from(
"Either signing key or external signer is required",
))
}
}

/// Helper function to sign a message with a derived SigningKey and return an Ethers Signature
fn sign_with_internal_key(wallet: &Wallet, seed: &str, message: &[u8]) -> Result<Vec<u8>, String> {
let sk_root_scalars = derive_sk_root_scalars(seed, &wallet.key_chain.public_keys.nonce);
let sk_root: SigningKey = SigningKey::try_from(&sk_root_scalars)
.map_err(|_| String::from("Failed to create signing key"))?;

/// Helper function to sign a message with a SigningKey and return an Ethers Signature
fn sign_with_internal_key(signing_key: &SigningKey, message: &[u8]) -> Result<Vec<u8>, String> {
let digest = keccak256(message);
let (sig, recovery_id) = sk_root
let (sig, recovery_id) = signing_key
.sign_prehash_recoverable(&digest)
.map_err(|_| String::from("Failed to sign message"))?;

Expand Down

0 comments on commit dea5932

Please sign in to comment.