Skip to content

Commit

Permalink
feat: add bitcoin sign message api
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoguang1010 committed Aug 3, 2024
1 parent f233fa4 commit 125eb04
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 27 deletions.
2 changes: 2 additions & 0 deletions imkey-core/ikc-common/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ pub struct SignParam {
pub sender: ::prost::alloc::string::String,
#[prost(string, tag = "8")]
pub fee: ::prost::alloc::string::String,
#[prost(string, tag = "9")]
pub seg_wit: ::prost::alloc::string::String,
}
1 change: 1 addition & 0 deletions imkey-core/ikc-proto/src/common.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ message SignParam {
string receiver = 6;
string sender = 7;
string fee = 8;
string segWit = 9;
}
2 changes: 1 addition & 1 deletion imkey-core/ikc-wallet/coin-bitcoin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pub mod common;
pub mod psbt;
pub mod transaction;
pub mod usdt_transaction;
mod message;
pub mod message;

extern crate anyhow;
use core::result;
Expand Down
84 changes: 64 additions & 20 deletions imkey-core/ikc-wallet/coin-bitcoin/src/message.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,41 @@
use std::str::FromStr;
use bitcoin::{Address, Network, OutPoint, PackedLockTime, Script, Sequence, Transaction, Txid, TxIn, TxOut, Witness};
use bitcoin::consensus::serialize;
use bitcoin::{Address, OutPoint, PackedLockTime, Script, Sequence, Transaction, Txid, TxIn, TxOut, Witness};
use bitcoin::psbt::PartiallySignedTransaction;
use bitcoin_hashes::hex::ToHex;
use hex::FromHex;
use ikc_common::error::CoinError;
use crate::Result;
use ikc_common::utility::{sha256_hash, utf8_or_hex_to_bytes};
use ikc_common::utility::{network_convert, sha256_hash, utf8_or_hex_to_bytes};
use crate::address::BtcAddress;
use crate::btcapi::{BtcMessageInput, BtcMessageOutput};
use crate::common::select_btc_applet;
use crate::psbt::PsbtSigner;

pub struct MessageSinger {
pub message: String,
pub struct MessageSinger{
pub derivation_path: String,
pub chain_type: String,
pub network: String,
pub seg_wit: String,
}

impl MessageSinger {
pub fn sign_message(&self, derivation_path: &str, network: Network, seg_wit: &str) ->Result<BtcMessageOutput>{
let data = utf8_or_hex_to_bytes(&self.message)?;
let path = format!("{}/0/0", derivation_path);
pub fn sign_message(&self, input: BtcMessageInput) ->Result<BtcMessageOutput>{
let data = utf8_or_hex_to_bytes(&input.message)?;

let path = format!("{}/0/0", self.derivation_path);

let pub_key = BtcAddress::get_pub_key(&path)?;
let address = BtcAddress::from_public_key(&pub_key, network, seg_wit)?;

let network = network_convert(&self.network);
let address = BtcAddress::from_public_key(&pub_key, network, &self.seg_wit)?;
let script_pubkey = Address::from_str(&address)?.script_pubkey();
let tx_id = get_spend_tx_id(&data, script_pubkey.clone())?;

select_btc_applet()?;

let mut psbt = create_to_sign_empty(tx_id, script_pubkey)?;
let mut psbt_signer = PsbtSigner::new(
&mut psbt,
derivation_path,
&self.derivation_path,
true,
network,
true,
Expand Down Expand Up @@ -150,6 +157,7 @@ fn witness_to_vec(witness: Vec<Vec<u8>>) -> Vec<u8> {
mod tests {
use std::str::FromStr;
use bitcoin::{Address, Network};
use ikc_common::SignParam;
use ikc_device::device_binding::bind_test;
use crate::address::BtcAddress;
use crate::btcapi::BtcMessageInput;
Expand All @@ -165,7 +173,6 @@ mod tests {
let seg_wit = "VERSION_0";
let address = BtcAddress::from_public_key(&pub_key, Network::Testnet, seg_wit).unwrap();
let address = Address::from_str(&address).unwrap();

let message = "hello world";

assert_eq!(
Expand All @@ -179,34 +186,71 @@ mod tests {
#[test]
fn test_bip32_p2sh_p2wpkh() {
bind_test();
let message_singer = MessageSinger{ message:"hello world".to_string() };
let output = message_singer.sign_message("m/49'/0'/0'", Network::Bitcoin, "P2WPKH").unwrap();

let singer = MessageSinger{
derivation_path: "m/49'/0'/0'".to_string(),
chain_type: "BITCOIN".to_string(),
network: "MAINNET".to_string(),
seg_wit: "P2WPKH".to_string(),
};
let input = BtcMessageInput{
message: "hello world".to_string(),
};

let output = singer.sign_message(input).unwrap();
assert_eq!(output.signature, "02473044022000ae3c9439681a4ba05e74d0805210f71c31f92130bcec28934d29beaf5f4f890220327cbf8a189eee4cb35a2599f6fd97b0774bec2e4191d74b3460f746732f8a03012103036695c5f3de2e2792b170f59679d4db88a8516728012eaa42a22ce6f8bf593b");

}

#[test]
fn test_bip32_p2pkh() {
bind_test();
let message_singer = MessageSinger{ message:"hello world".to_string() };
let output = message_singer.sign_message("m/44'/0'/0'", Network::Bitcoin, "NONE").unwrap();

let singer = MessageSinger{
derivation_path: "m/44'/0'/0'".to_string(),
chain_type: "BITCOIN".to_string(),
network: "MAINNET".to_string(),
seg_wit: "NONE".to_string(),
};
let input = BtcMessageInput{
message: "hello world".to_string(),
};
let output = singer.sign_message(input).unwrap();
assert_eq!(output.signature, "02483045022100dbbdfedfb1902ca12c6cba14d4892a98f77c434daaa4f97fd35e618374c908f602206527ff2b1ce550c16c836c2ce3508bfae543fa6c11759d2f4966cc0d3552c4430121026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868");

}

#[test]
fn test_bip322_p2wpkh() {
bind_test();
let message_singer = MessageSinger{ message:"hello world".to_string() };
let output = message_singer.sign_message("m/44'/0'/0'", Network::Bitcoin, "VERSION_0").unwrap();

let singer = MessageSinger{
derivation_path: "m/44'/0'/0'".to_string(),
chain_type: "BITCOIN".to_string(),
network: "MAINNET".to_string(),
seg_wit: "VERSION_0".to_string(),
};
let input = BtcMessageInput{
message: "hello world".to_string(),
};
let output = singer.sign_message(input).unwrap();
assert_eq!(output.signature, "024830450221009f003820d1db93bf78be08dafdd05b7dde7c31a73c9be36b705a15329bd3d0e502203eb6f1a34466995e4b9c281bf4a093a1f55a21b2ef961438c9ae284efab27dda0121026b5b6a9d041bc5187e0b34f9e496436c7bff261c6c1b5f3c06b433c61394b868");
}

#[test]
fn test_bip322_p2tr() {
bind_test();
let message_singer = MessageSinger{ message:"Sign this message to log in to https://www.subber.xyz // 200323342".to_string() };
let output = message_singer.sign_message("m/86'/0'/0'", Network::Bitcoin, "VERSION_1").unwrap();

let singer = MessageSinger{
derivation_path: "m/86'/0'/0'".to_string(),
chain_type: "BITCOIN".to_string(),
network: "MAINNET".to_string(),
seg_wit: "VERSION_1".to_string(),
};
let input = BtcMessageInput{
message: "Sign this message to log in to https://www.subber.xyz // 200323342".to_string(),
};
let output = singer.sign_message(input).unwrap();
// assert_eq!(output.signature, "0140a868e67a50f6dff3e25f6b015f595d89de54e330a6e1dfb4925269577730803e10a43562b25979a704f1d6c856e623681f292ce0ddf2281f42c033db013b4326");
}

Expand Down
1 change: 1 addition & 0 deletions imkey-core/ikc/src/bch_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ mod tests {
receiver: "".to_string(),
sender: "".to_string(),
fee: "".to_string(),
seg_wit: "".to_string(),
};

let message = sign_bch_transaction(&tx_input, &sign_param);
Expand Down
2 changes: 2 additions & 0 deletions imkey-core/ikc/src/btc_fork_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ mod tests {
receiver: "".to_string(),
sender: "".to_string(),
fee: "".to_string(),
seg_wit: "".to_string(),
};

let message = sign_legacy_transaction(&tx_input, &sign_param);
Expand Down Expand Up @@ -147,6 +148,7 @@ mod tests {
receiver: "".to_string(),
sender: "".to_string(),
fee: "".to_string(),
seg_wit: "".to_string(),
};

let message = sign_segwit_transaction(&tx_input, &sign_param);
Expand Down
17 changes: 14 additions & 3 deletions imkey-core/ikc/src/btc_signer.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::error_handling::Result;
use crate::message_handler::encode_message;
use bitcoin::{Address, Network};

use coin_bitcoin::btcapi::{BtcTxInput, BtcTxOutput};
use coin_bitcoin::btcapi::{BtcMessageInput, BtcTxInput, BtcTxOutput};
use coin_bitcoin::transaction::{BtcTransaction, Utxo};
use ikc_common::utility::hex_to_bytes;
use ikc_common::SignParam;
use prost::Message;
use std::str::FromStr;
use coin_bitcoin::message::MessageSinger;

pub fn sign_btc_transaction(data: &[u8], sign_param: &SignParam) -> Result<Vec<u8>> {
let input: BtcTxInput = BtcTxInput::decode(data).expect("BtcTxInput");
Expand Down Expand Up @@ -162,3 +161,15 @@ pub fn sign_usdt_segwit_transaction(input: &BtcTxInput, sign_param: &SignParam)
};
encode_message(tx_sign_result)
}

pub fn btc_sign_message(data: &[u8], sign_param: &SignParam) -> Result<Vec<u8>> {
let input: BtcMessageInput = BtcMessageInput::decode(data).expect("imkey_illegal_param");
let singer = MessageSinger{
derivation_path: sign_param.path.clone(),
chain_type: sign_param.chain_type.clone(),
network: sign_param.network.clone(),
seg_wit: sign_param.seg_wit.clone(),
};
let signed = singer.sign_message(input)?;
encode_message(signed)
}
9 changes: 9 additions & 0 deletions imkey-core/ikc/src/ethereum_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ mod tests {
receiver: "0x9Ed0c5350Bc17FF45529722eb07580Ff564c3a78".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.001316 ETH".to_string(),
seg_wit: "".to_string(),
};
let _x = sign_eth_transaction(data.as_slice(), &sign_param).unwrap();
println!("sign");
Expand All @@ -172,6 +173,7 @@ mod tests {
receiver: "0x9Ed0c5350Bc17FF45529722eb07580Ff564c3a78".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.001316 ETH".to_string(),
seg_wit: "".to_string(),
};
let _x = sign_eth_transaction(data.as_slice(), &sign_param).unwrap();
println!("sign");
Expand All @@ -191,6 +193,7 @@ mod tests {
receiver: "0x9Ed0c5350Bc17FF45529722eb07580Ff564c3a78".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.001316 ETH".to_string(),
seg_wit: "".to_string(),
};
let _x = sign_eth_transaction(data.as_slice(), &sign_param).unwrap();
println!("sign");
Expand All @@ -210,6 +213,7 @@ mod tests {
receiver: "0x9Ed0c5350Bc17FF45529722eb07580Ff564c3a78".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.001316 ETH".to_string(),
seg_wit: "".to_string(),
};
let _x = sign_eth_transaction(data.as_slice(), &sign_param).unwrap();
println!("sign");
Expand Down Expand Up @@ -249,6 +253,7 @@ mod tests {
receiver: "0xE6F4142dfFA574D1d9f18770BF73814df07931F3".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.0032 ether".to_string(),
seg_wit: "".to_string(),
};

let data = encode_message(tx).unwrap();
Expand Down Expand Up @@ -292,6 +297,7 @@ mod tests {
receiver: "0xE6F4142dfFA574D1d9f18770BF73814df07931F3".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.0032 ether".to_string(),
seg_wit: "".to_string(),
};

let data = encode_message(tx).unwrap();
Expand Down Expand Up @@ -360,6 +366,7 @@ mod tests {
receiver: "0xE6F4142dfFA574D1d9f18770BF73814df07931F3".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.0032 ether".to_string(),
seg_wit: "".to_string(),
};

let data = encode_message(tx).unwrap();
Expand Down Expand Up @@ -428,6 +435,7 @@ mod tests {
receiver: "0xE6F4142dfFA574D1d9f18770BF73814df07931F3".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.0032 ether".to_string(),
seg_wit: "".to_string(),
};

let data = encode_message(tx).unwrap();
Expand Down Expand Up @@ -469,6 +477,7 @@ mod tests {
receiver: "0xE6F4142dfFA574D1d9f18770BF73814df07931F3".to_string(),
sender: "0x6031564e7b2F5cc33737807b2E58DaFF870B590b".to_string(),
fee: "0.0032 ether".to_string(),
seg_wit: "".to_string(),
};

let data = hex::decode("0a0138120b32303030303030303030381a063138393030302228333533353335333533353335333533353335333533353335333533353335333533353335333533352a033531323a023238").unwrap();
Expand Down
5 changes: 4 additions & 1 deletion imkey-core/ikc/src/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,10 @@ pub(crate) fn get_public_keys(data: &[u8]) -> Result<Vec<u8>> {
pub(crate) fn sign_psbt(data: &[u8]) -> Result<Vec<u8>> {
let param: SignParam = SignParam::decode(data).expect("sign_psbt param");

if !"BITCOIN".eq(&param.chain_type) {
return Err(anyhow!("unsupported_chain_type"))
}

let psbt_input = PsbtInput::decode(
param
.input
Expand All @@ -308,7 +312,6 @@ pub(crate) fn sign_psbt(data: &[u8]) -> Result<Vec<u8>> {
Network::Bitcoin
};
encode_message(coin_bitcoin::psbt::sign_psbt(
&param.chain_type,
&param.path,
psbt_input,
network,
Expand Down
Loading

0 comments on commit 125eb04

Please sign in to comment.