From 1886441fd0424ca91f1e7c45a1c69d8df4e4aee7 Mon Sep 17 00:00:00 2001 From: nickwest Date: Thu, 14 Dec 2023 03:51:57 -0800 Subject: [PATCH] support starknet wallets for sdk --- bindings/wasm/src/json_rpc_signer.rs | 7 +- bindings/wasm/src/rpc_type_converter.rs | 4 +- interface/src/json_rpc_signer.rs | 14 +-- interface/src/sign_transfer.rs | 1 + interface/src/sign_withdraw.rs | 3 +- .../src/starknet_signer/ecdsa_signature.rs | 11 +- signers/src/starknet_signer/pk_signer.rs | 104 +++++++++++------- .../starknet_json_rpc_signer.rs | 21 +++- signers/src/starknet_signer/typed_data/mod.rs | 2 +- signers/src/zklink_signer/pk_signer.rs | 3 +- types/src/signatures.rs | 7 +- 11 files changed, 101 insertions(+), 76 deletions(-) diff --git a/bindings/wasm/src/json_rpc_signer.rs b/bindings/wasm/src/json_rpc_signer.rs index ed9eb7ea..ef191b3d 100755 --- a/bindings/wasm/src/json_rpc_signer.rs +++ b/bindings/wasm/src/json_rpc_signer.rs @@ -28,20 +28,19 @@ pub struct JsonRpcSigner { //#[wasm_bindgen(constructor)] #[wasm_bindgen(js_name=newRpcSignerWtihProvider)] pub fn new_with_provider(provider: Provider) -> Result { - let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Provider(provider))?; + let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Provider(provider),None)?; Ok(JsonRpcSigner { inner }) } //#[wasm_bindgen(constructor)] #[wasm_bindgen(js_name=newRpcSignerWithSigner)] -pub fn new_with_signer(signer: Signer) -> Result { - let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Signer(signer))?; +pub fn new_with_signer(signer: Signer, pub_key: String) -> Result { + let inner = InterfaceJsonRpcSigner::new(JsonRpcProvider::Signer(signer),Some(pub_key))?; Ok(JsonRpcSigner { inner }) } #[wasm_bindgen] impl JsonRpcSigner { - #[wasm_bindgen(js_name = initZklinkSigner)] pub async fn init_zklink_signer(&mut self, signature: Option) -> Result<(), JsValue> { Ok(self.inner.init_zklink_signer(signature).await?) diff --git a/bindings/wasm/src/rpc_type_converter.rs b/bindings/wasm/src/rpc_type_converter.rs index 04b1abbe..1cbc7bc0 100644 --- a/bindings/wasm/src/rpc_type_converter.rs +++ b/bindings/wasm/src/rpc_type_converter.rs @@ -3,7 +3,7 @@ use wasm_bindgen::prelude::wasm_bindgen; use wasm_bindgen::JsValue; use zklink_sdk_provider::response::AccountQuery as RpcAccountQuery; use zklink_sdk_signers::eth_signer::{EIP1271Signature, PackedEthSignature}; -use zklink_sdk_signers::starknet_signer::{StarkECDSASignature, StarkSignature}; +use zklink_sdk_signers::starknet_signer::StarkECDSASignature; use zklink_sdk_signers::zklink_signer::PackedSignature; use zklink_sdk_types::basic_types::AccountId; use zklink_sdk_types::prelude::ZkLinkSignature; @@ -125,7 +125,7 @@ impl TryFrom for TypesTxLayer1Signature { ))) } L1SignatureType::Stark => { - let signature = StarkSignature::from_hex(&signature.signature) + let signature = StarkECDSASignature::from_hex(&signature.signature) .map_err(|e| JsValue::from_str(&format!("error: {e}")))?; Ok(TypesTxLayer1Signature::StarkSignature(signature)) diff --git a/interface/src/json_rpc_signer.rs b/interface/src/json_rpc_signer.rs index e193fc89..8579b337 100755 --- a/interface/src/json_rpc_signer.rs +++ b/interface/src/json_rpc_signer.rs @@ -12,7 +12,7 @@ use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::{ StarknetJsonRpcSigner,Signer as StarknetAccountSigner }; -use zklink_sdk_signers::zklink_signer::{ZkLinkSignature, ZkLinkSigner, ZkSignerError}; +use zklink_sdk_signers::zklink_signer::{ZkLinkSignature, ZkLinkSigner}; use zklink_sdk_types::prelude::PackedEthSignature; use zklink_sdk_types::signatures::TxSignature; use zklink_sdk_types::tx_type::change_pubkey::{ChangePubKey, ChangePubKeyAuthData, Create2Data}; @@ -22,9 +22,7 @@ use zklink_sdk_types::tx_type::transfer::Transfer; use zklink_sdk_types::tx_type::withdraw::Withdraw; use zklink_sdk_types::tx_type::zklink_tx::ZkLinkTx; use zklink_sdk_types::tx_type::ZkSignatureTrait; -use zklink_sdk_signers::eth_signer::EthSignerError; -use zklink_sdk_signers::starknet_signer::StarkSignature; -use zklink_sdk_signers::starknet_signer::typed_data::message::{TypedDataMessage, Message}; +use zklink_sdk_signers::starknet_signer::StarkECDSASignature; use zklink_sdk_signers::starknet_signer::error::StarkSignerError; pub enum JsonRpcProvider { @@ -42,12 +40,12 @@ pub struct JsonRpcSigner { } impl JsonRpcSigner { - pub fn new(provider: JsonRpcProvider) -> Result { + pub fn new(provider: JsonRpcProvider,pub_key: Option) -> Result { let eth_json_rpc_signer = match provider { JsonRpcProvider::Provider(provider) => Layer1JsonRpcSigner::EthSigner(EthJsonRpcSigner::new(provider)), JsonRpcProvider::Signer(signer) => - Layer1JsonRpcSigner::StarknetSigner(StarknetJsonRpcSigner::new(signer)) + Layer1JsonRpcSigner::StarknetSigner(StarknetJsonRpcSigner::new(signer,pub_key.unwrap())) }; let default_zklink_signer = ZkLinkSigner::new()?; Ok(Self { @@ -65,8 +63,8 @@ impl JsonRpcSigner { ZkLinkSigner::new_from_seed(&seed)? }, Layer1JsonRpcSigner::StarknetSigner(_) => { - let signature = StarkSignature::from_hex(&s)?; - let seed = signature.to_bytes_be(); + let signature = StarkECDSASignature::from_hex(&s)?; + let seed = signature.signature.to_bytes_be(); ZkLinkSigner::new_from_seed(&seed)? } } diff --git a/interface/src/sign_transfer.rs b/interface/src/sign_transfer.rs index 64e87d11..ea4f91ff 100644 --- a/interface/src/sign_transfer.rs +++ b/interface/src/sign_transfer.rs @@ -11,6 +11,7 @@ use zklink_sdk_signers::zklink_signer::pk_signer::ZkLinkSigner; use zklink_sdk_types::basic_types::GetBytes; use zklink_sdk_types::prelude::TxSignature; use zklink_sdk_types::tx_type::transfer::Transfer; +#[cfg(feature = "web")] use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; #[cfg(not(feature = "web"))] diff --git a/interface/src/sign_withdraw.rs b/interface/src/sign_withdraw.rs index 32a4d1a1..2d454614 100644 --- a/interface/src/sign_withdraw.rs +++ b/interface/src/sign_withdraw.rs @@ -10,9 +10,8 @@ use zklink_sdk_types::prelude::TxSignature; use zklink_sdk_types::tx_type::withdraw::Withdraw; use zklink_sdk_types::tx_type::ZkSignatureTrait; #[cfg(feature = "web")] -use crate::json_rpc_signer::Layer1JsonRpcSigner; -#[cfg(feature = "web")] use zklink_sdk_signers::starknet_signer::starknet_json_rpc_signer::StarknetJsonRpcSigner; +#[cfg(feature = "web")] use zklink_sdk_signers::starknet_signer::typed_data::message::TypedDataMessage; #[cfg(not(feature = "web"))] diff --git a/signers/src/starknet_signer/ecdsa_signature.rs b/signers/src/starknet_signer/ecdsa_signature.rs index 1eaad852..a226a61d 100644 --- a/signers/src/starknet_signer/ecdsa_signature.rs +++ b/signers/src/starknet_signer/ecdsa_signature.rs @@ -8,7 +8,6 @@ use starknet_signers::VerifyingKey; use std::fmt; use std::fmt::Formatter; use zklink_sdk_utils::serde::ZeroPrefixHexSerde; -use num::BigUint; use std::str::FromStr; #[derive(Clone, PartialEq,Serialize, Deserialize,Eq,Debug)] @@ -40,17 +39,13 @@ impl StarkSignature { } pub fn from_str(r:&str,s: &str) -> Result { - let r = BigUint::from_str(r) + let r = FieldElement::from_str(r) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; - let s = BigUint::from_str(s) + let s = FieldElement::from_str(s) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; - let mut bytes = [0;64]; - bytes[0..32].clone_from_slice(&s.to_bytes_be()); - bytes[32..].clone_from_slice(&r.to_bytes_be()); - Self::from_bytes_be(&bytes) + Ok(Self { s,r }) } - pub fn from_bytes_be(bytes: &[u8]) -> Result { let mut s = [0_u8; 32]; let mut r = [0_u8; 32]; diff --git a/signers/src/starknet_signer/pk_signer.rs b/signers/src/starknet_signer/pk_signer.rs index 9f08dd0c..d238b160 100644 --- a/signers/src/starknet_signer/pk_signer.rs +++ b/signers/src/starknet_signer/pk_signer.rs @@ -5,7 +5,7 @@ use starknet::core::crypto::compute_hash_on_elements; use starknet::core::types::FieldElement; use starknet_signers::SigningKey; -pub struct StarkSigner(SigningKey); +pub struct StarkSigner(pub SigningKey); impl Default for StarkSigner { fn default() -> Self { @@ -32,23 +32,20 @@ impl StarkSigner { /// 1. get the hash of the message /// 2. sign hash - pub fn sign_message(&self, msg: &[u8]) -> Result { + pub fn sign_message(&self, msg: &[u8]) -> Result { let hash = Self::get_msg_hash(msg); let signature = self .0 .sign(&hash) .map_err(|e| Error::sign_error(e.to_string()))?; - // let s = StarkECDSASignature { - // pub_key: self.public_key(), - // signature: StarkSignature { - // s: signature.s, - // r: signature.r, - // }, - // }; - Ok(StarkSignature { - s: signature.s, - r: signature.r, - }) + let s = StarkECDSASignature { + pub_key: self.public_key(), + signature: StarkSignature { + s: signature.s, + r: signature.r, + }, + }; + Ok(s) } /// 1. change msg to FieldElement list @@ -68,6 +65,9 @@ mod tests { use serde::{Deserialize, Serialize}; use crate::starknet_signer::typed_data::TypedData; use crate::starknet_signer::typed_data::message::{TypedDataMessage, Message}; + use starknet_signers::VerifyingKey; + use num::BigUint; + use std::str::FromStr; #[derive(Serialize, Deserialize, Debug)] struct TestSignature { @@ -78,34 +78,56 @@ mod tests { fn test_starknet_sign() { let private_key = "0x02c5dbad71c92a45cc4b40573ae661f8147869a91d57b8d9b8f48c8af7f83159"; let stark_signer = StarkSigner::new_from_hex_str(private_key).unwrap(); - let msg = b"hello world"; - let signature = stark_signer.sign_message(msg).unwrap(); - let is_ok = signature.verify(msg).unwrap(); - assert!(is_ok); - let data = TestSignature { signature }; - let s = serde_json::to_string(&data).unwrap(); - println!("{s}"); - let data2: TestSignature = serde_json::from_str(&s).unwrap(); - println!("{data2:?}"); + let msg_hash = "0x51d5faacb1bdeb6293d52fd4be0a7c62417cb73962cdd6aff385b67239cf081"; + let signature = stark_signer.0.sign(&FieldElement::from_hex_be(msg_hash).unwrap()).unwrap(); + //let pub_key = stark_signer.public_key(); + let pub_key = "0x3b478eae5afdd35358abcc7955bba7acda3d16f4485b62f2497f78ed6bc7126"; + let verifying_key = VerifyingKey::from_scalar(FieldElement::from_hex_be(pub_key).unwrap()); + let is_ok = verifying_key + .verify( + &FieldElement::from_hex_be(msg_hash).unwrap(), + &signature + ) + .unwrap(); + println!("{:?}",is_ok); + } - // #[test] - // fn test_signature_verify() { - // let r = "1242659239673499744454485192657408749892787349417938392478090301874476933289"; - // let s = "3203688086163592132535350422117785905751559823323905824858605377390311728388"; - // let pubkey = "0x4893e2057aabcfc20bfa81a09efdcf39807698f9748123c51145fc81aeadab1"; - // let msg = TypedDataMessage::CreateL2Key(Message { - // data: "Create zkLink L2".to_string() - // }); - // let typed_data = TypedData::new(msg); - // - // let signature = StarkECDSASignature { - // pub_key: FieldElement::from_hex_be(&pubkey).unwrap(), - // signature: StarkSignature { - // s: FieldElement::from_hex_be(&s).unwrap(), - // r: FieldElement::from_hex_be(&r).unwrap() - // } }; - // let is_ok = signature.verify(msg).unwrap(); - // assert!(is_ok); - // } + #[test] + fn test_signature_verify() { + let r_str = "1242659239673499744454485192657408749892787349417938392478090301874476933289"; + let s_str = "3203688086163592132535350422117785905751559823323905824858605377390311728388"; + let pubkey = "1082125475812817975721104073212648033952831721853656627074253194227094744819"; + let msg_hash = "0x51d5faacb1bdeb6293d52fd4be0a7c62417cb73962cdd6aff385b67239cf081"; + // let msg = TypedDataMessage::CreateL2Key(Message { + // data: "Create zkLink L2".to_string() + // }); + // let typed_data = TypedData::new(msg); + // + let mut s = [0;32]; + let mut r = [0;32]; + let r_num = BigUint::from_str(r_str).unwrap(); + let s_num = BigUint::from_str(s_str).unwrap(); + s.clone_from_slice(&s_num.to_bytes_be()); + r.clone_from_slice(&r_num.to_bytes_be()); + let pub_key = FieldElement::from_str(&pubkey).unwrap(); + // let signature = StarkECDSASignature { + // pub_key: FieldElement::from_hex_be(&pubkey).unwrap(), + // signature: StarkSignature { + // s: FieldElement::from_bytes_be(BigUint::from_str(s).unwrap().to_bytes_be()).unwrap(), + // r: FieldElement::from_bytes_be(BigUint::from_str(r).unwrap().to_bytes_be()).unwrap() + // } }; + + let verifying_key = VerifyingKey::from_scalar(pub_key); + let is_ok = verifying_key + .verify( + &FieldElement::from_hex_be(msg_hash).unwrap(), + &Signature { + s: FieldElement::from_str(&s_str).unwrap(), + r: FieldElement::from_str(&r_str).unwrap() + }, + ) + .unwrap(); + assert!(is_ok); + } } diff --git a/signers/src/starknet_signer/starknet_json_rpc_signer.rs b/signers/src/starknet_signer/starknet_json_rpc_signer.rs index 62bb4f97..9dd9809c 100644 --- a/signers/src/starknet_signer/starknet_json_rpc_signer.rs +++ b/signers/src/starknet_signer/starknet_json_rpc_signer.rs @@ -1,7 +1,9 @@ use wasm_bindgen::prelude::*; -use crate::starknet_signer::StarkSignature; +use crate::starknet_signer::{StarkSignature, StarkECDSASignature}; use crate::starknet_signer::error::StarkSignerError; use crate::starknet_signer::typed_data::{message::TypedDataMessage, TypedData}; +use starknet::core::types::FieldElement; +use std::str::FromStr; #[wasm_bindgen] // Rustfmt removes the 'async' keyword from async functions in extern blocks. It's fixed @@ -17,17 +19,18 @@ extern "C" { pub struct StarknetJsonRpcSigner { signer: Signer, + pub_key: String, } impl StarknetJsonRpcSigner { - pub fn new(signer: Signer) -> StarknetJsonRpcSigner{ - StarknetJsonRpcSigner { signer } + pub fn new(signer: Signer,pub_key: String) -> StarknetJsonRpcSigner{ + StarknetJsonRpcSigner { signer,pub_key } } pub async fn sign_message( &self, message: TypedDataMessage, - ) -> Result { + ) -> Result { let typed_data = TypedData::new(message); let typed_data = serde_wasm_bindgen::to_value(&typed_data) .map_err(|e| StarkSignerError::SignError(e.to_string()))?; @@ -38,7 +41,15 @@ impl StarknetJsonRpcSigner { })?; let signature: Vec = serde_wasm_bindgen::from_value::>(signature) .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; - StarkSignature::from_str(&signature[0],&signature[1]) + + let signature = StarkSignature::from_str(&signature[0],&signature[1]) + .map_err(|e| StarkSignerError::InvalidSignature(e.to_string()))?; + let pub_key = FieldElement::from_str(&self.pub_key) + .map_err(|e| StarkSignerError::SignError(e.to_string()))?; + Ok(StarkECDSASignature { + pub_key, + signature, + }) } } diff --git a/signers/src/starknet_signer/typed_data/mod.rs b/signers/src/starknet_signer/typed_data/mod.rs index 3f4ffdbe..4543c13a 100644 --- a/signers/src/starknet_signer/typed_data/mod.rs +++ b/signers/src/starknet_signer/typed_data/mod.rs @@ -48,7 +48,7 @@ impl TypedData { let domain = StarknetDomain { name: "zklink".to_string(), version: "1".to_string(), - chain_id: "SN_MAIN".to_string() + chain_id: "SN_GOERLI".to_string() }; Self { types, diff --git a/signers/src/zklink_signer/pk_signer.rs b/signers/src/zklink_signer/pk_signer.rs index 81668143..68af5cc7 100755 --- a/signers/src/zklink_signer/pk_signer.rs +++ b/signers/src/zklink_signer/pk_signer.rs @@ -58,6 +58,7 @@ pub fn sha256_bytes(input: &[u8]) -> Vec { impl ZkLinkSigner { const SIGN_MESSAGE: &'static str = "Sign this message to create a key to interact with zkLink's layer2 services.\nNOTE: This application is powered by zkLink protocol.\n\nOnly sign this message for a trusted client!"; + #[cfg(feature = "web")] const STARKNET_SIGN_MESSAGE: &'static str = "Create zkLink's layer2 key.\n"; pub fn new() -> Result { @@ -134,7 +135,7 @@ impl ZkLinkSigner { let signature = starknet_signer .sign_message(message) .await?; - let seed = signature.to_bytes_be(); + let seed = signature.signature.to_bytes_be(); Self::new_from_seed(&seed) } diff --git a/types/src/signatures.rs b/types/src/signatures.rs index 02e12652..1c2f2c96 100644 --- a/types/src/signatures.rs +++ b/types/src/signatures.rs @@ -3,7 +3,6 @@ use serde::{Deserialize, Serialize}; use zklink_sdk_signers::eth_signer::eip1271_signature::EIP1271Signature; use zklink_sdk_signers::eth_signer::packed_eth_signature::PackedEthSignature; use zklink_sdk_signers::starknet_signer::ecdsa_signature::StarkECDSASignature; -use zklink_sdk_signers::starknet_signer::StarkSignature; /// Representation of the signature secured by L1. /// May be either a signature generated via Ethereum private key @@ -14,7 +13,7 @@ use zklink_sdk_signers::starknet_signer::StarkSignature; pub enum TxLayer1Signature { EthereumSignature(PackedEthSignature), EIP1271Signature(EIP1271Signature), - StarkSignature(StarkSignature), + StarkSignature(StarkECDSASignature), } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -35,8 +34,8 @@ impl From for TxLayer1Signature { } } -impl From for TxLayer1Signature { - fn from(value: StarkSignature) -> Self { +impl From for TxLayer1Signature { + fn from(value: StarkECDSASignature) -> Self { Self::StarkSignature(value) } }