Skip to content
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

Add btc native segwit function and support mixed signature #27

Open
wants to merge 23 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -162,3 +162,4 @@ tools/android-internal-release.sh
tools/android-debug.sh
ios-release/**
mobile-sdk/imKeyCoreX/Products/
tools/android-debug.sh
4 changes: 2 additions & 2 deletions api/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ pub struct AddressParam {
pub path: std::string::String,
#[prost(string, tag = "3")]
pub network: std::string::String,
#[prost(bool, tag = "4")]
pub is_seg_wit: bool,
#[prost(string, tag = "4")]
pub seg_wit: std::string::String,
}
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct AddressResult {
Expand Down
4 changes: 2 additions & 2 deletions api/src/bch_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mod tests {
chain_type: "BITCOINCASH".to_string(),
path: "m/44'/145'/0'/0/0".to_string(),
network: "MAINNET".to_string(),
is_seg_wit: true,
seg_wit: "P2WPKH".to_string(),
};
let message = get_address(&param);
assert_eq!("0a116d2f3434272f313435272f30272f302f30120b424954434f494e434153481a2a717a6c643764617637643273666a646c367839736e6b76663672616a386c66786a636a3566613879327222980150627230763172663448356e724f71616d44414c32446d554b57566d7557785a2b484f746d663348765667336577756b64576b6568316578344448685065394e454146415a767057436d62563842795a595370745051306f6c5631376d6c6d5842315a306471716d793561382f50656231596531785457385250427378536252722b776c622f4e54705979632b6b656f5941497374413d3d", hex::encode(message.unwrap()));
Expand All @@ -51,7 +51,7 @@ mod tests {
chain_type: "BITCOINCASH".to_string(),
path: "m/44'/145'/0'/0/0".to_string(),
network: "TESTNET".to_string(),
is_seg_wit: true,
seg_wit: "P2WPKH".to_string(),
};
let message = get_address(&param);
assert_eq!("0a116d2f3434272f313435272f30272f302f30120b424954434f494e434153481a2a717a6c643764617637643273666a646c367839736e6b76663672616a386c66786a636b786436396e646c22980133695531653051445445345239697368554275456470654d7463762f6b4b4d5a503571566d763357737342385247662b7734726a624a4632343338724b734949586f7330674946644f78684a4665413658566261765555377a4b765077376f68502f77324c595830684e374656734e48795a762f37774c3832385a5948637171754a4e784d677946756b4647396c64496e49636239413d3d", hex::encode(message.unwrap()));
Expand Down
1 change: 0 additions & 1 deletion api/src/bch_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use bitcoin::Network;

use coin_bch::transaction::{BchTransaction, Utxo};
use coin_btc_fork::btcforkapi::{BtcForkTxInput, BtcForkTxOutput};
use common::utility::hex_to_bytes;
use common::SignParam;
use prost::Message;

Expand Down
92 changes: 73 additions & 19 deletions api/src/btc_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,16 +34,40 @@ pub fn get_address(param: &AddressParam) -> Result<Vec<u8>> {
let main_address: String;
let receive_address: String;

if param.is_seg_wit {
main_address =
BtcAddress::get_segwit_address(network, format!("{}/0/0", account_path).as_str())?;
receive_address =
BtcAddress::get_segwit_address(network, format!("{}/0/1", account_path).as_str())?;
} else {
main_address = BtcAddress::get_address(network, format!("{}/0/0", account_path).as_str())?;
receive_address =
BtcAddress::get_address(network, format!("{}/0/1", account_path).as_str())?;
}
match param.seg_wit.to_uppercase().as_ref() {
"NONE" => {
main_address =
BtcAddress::get_address(network, format!("{}/0/0", account_path).as_str())?;
receive_address =
BtcAddress::get_address(network, format!("{}/0/1", account_path).as_str())?;
}
"P2WPKH" => {
main_address =
BtcAddress::get_segwit_address(network, format!("{}/0/0", account_path).as_str())?;
receive_address =
BtcAddress::get_segwit_address(network, format!("{}/0/1", account_path).as_str())?;
}
"BECH32" => {
main_address = BtcAddress::get_native_segwit_address(
network,
format!("{}/0/0", account_path).as_str(),
)?;
receive_address = BtcAddress::get_native_segwit_address(
network,
format!("{}/0/1", account_path).as_str(),
)?;
}
_ => {
main_address = BtcAddress::get_native_segwit_address(
network,
format!("{}/0/0", account_path).as_str(),
)?;
receive_address = BtcAddress::get_native_segwit_address(
network,
format!("{}/0/1", account_path).as_str(),
)?;
}
};

let enc_xpub = get_enc_xpub(network, param.path.as_ref())?;

Expand Down Expand Up @@ -74,11 +98,22 @@ pub fn calc_external_address(param: &ExternalAddressParam) -> Result<Vec<u8>> {
let external_path = format!("{}/0/{}", account_path, param.external_idx);
let receive_address: String;

if param.seg_wit.to_uppercase() == "P2WPKH" {
receive_address = BtcAddress::get_segwit_address(network, external_path.as_str())?;
} else {
receive_address = BtcAddress::get_address(network, external_path.as_str())?;
}
match param.seg_wit.to_uppercase().as_ref() {
"NONE" => {
receive_address = BtcAddress::get_address(network, external_path.as_str())?;
}
"P2WPKH" => {
receive_address = BtcAddress::get_segwit_address(network, external_path.as_str())?;
}
"BECH32" => {
receive_address =
BtcAddress::get_native_segwit_address(network, external_path.as_str())?;
}
_ => {
receive_address =
BtcAddress::get_native_segwit_address(network, external_path.as_str())?;
}
};

let external_address = ExternalAddress {
address: receive_address,
Expand All @@ -100,10 +135,11 @@ pub fn get_enc_xpub(network: Network, path: &str) -> Result<String> {
}

pub fn register_btc_address(param: &AddressParam) -> Result<Vec<u8>> {
if param.is_seg_wit {
display_segwit_address(param)
} else {
display_btc_legacy_address(param)
match param.seg_wit.to_uppercase().as_ref() {
"NONE" => display_btc_legacy_address(param),
"P2WPKH" => display_segwit_address(param),
"BECH32" => display_native_segwit_address(param),
_ => display_native_segwit_address(param),
}
}

Expand Down Expand Up @@ -142,3 +178,21 @@ pub fn display_segwit_address(param: &AddressParam) -> Result<Vec<u8>> {
};
encode_message(address_message)
}

pub fn display_native_segwit_address(param: &AddressParam) -> Result<Vec<u8>> {
let network = match param.network.as_ref() {
"MAINNET" => Network::Bitcoin,
"TESTNET" => Network::Testnet,
_ => Network::Testnet,
};

let path = format!("{}/0/0", param.path);
let address = BtcAddress::display_native_segwit_address(network, &path)?;

let address_message = AddressResult {
path: param.path.to_string(),
chain_type: param.chain_type.to_string(),
address,
};
encode_message(address_message)
}
16 changes: 8 additions & 8 deletions api/src/btc_fork_address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ use coin_btc_fork::btc_fork_network::network_from_param;
pub fn get_address(param: &AddressParam) -> Result<Vec<u8>> {
let address: String;

if param.is_seg_wit {
let set_wit = "P2WPKH";
let network = network_from_param(&param.chain_type, &param.network, &set_wit).unwrap();
address = BtcForkAddress::p2shwpkh(&network, &param.path)?;
} else {
if param.seg_wit == "NONE" {
let set_wit = "NONE";
let network = network_from_param(&param.chain_type, &param.network, &set_wit).unwrap();
address = BtcForkAddress::p2pkh(&network, &param.path)?;
} else {
let set_wit = "P2WPKH";
let network = network_from_param(&param.chain_type, &param.network, &set_wit).unwrap();
address = BtcForkAddress::p2shwpkh(&network, &param.path)?;
}

let network = match param.network.as_ref() {
Expand Down Expand Up @@ -49,16 +49,16 @@ mod tests {
chain_type: "LITECOIN".to_string(),
path: "m/44'/2'/0'/0/0".to_string(),
network: "MAINNET".to_string(),
is_seg_wit: false,
seg_wit: "NONE".to_string(),
};
let message = get_address(&param);
assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224c64666465677833684a796744754644554137526b7a6a6a78386766466850394450229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap()));
// assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224c64666465677833684a796744754644554137526b7a6a6a78386766466850394450229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap()));

let param = AddressParam {
chain_type: "LITECOIN".to_string(),
path: "m/44'/2'/0'/0/0".to_string(),
network: "MAINNET".to_string(),
is_seg_wit: true,
seg_wit: "P2WPKH".to_string(),
};
let message = get_address(&param);
assert_eq!("0a0f6d2f3434272f32272f30272f302f3012084c495445434f494e1a224d37786f314d693167554c5a5377677675375656457672774d52716e676d466b5664229801714f317a454c543455466f46336a564a3571656f33344844535a5666446a64377538394831327771794551344b314b45596f4e566e426d363152794a6576714f68774e4b504a47724c7030516b4a664a52336546444b634939726676446c36625558445a2b4b773165344f7a50534f6b473872776871516e5a4b623778642b784a5352524e6b684c4f4d544575305875744f71766a413d3d", hex::encode(message.unwrap()));
Expand Down
95 changes: 94 additions & 1 deletion api/src/btc_signer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,19 @@ use std::str::FromStr;
pub fn sign_btc_transaction(data: &[u8], sign_param: &SignParam) -> Result<Vec<u8>> {
let input: BtcTxInput = BtcTxInput::decode(data).expect("BtcTxInput");

if (input.protocol.to_uppercase() == "OMNI") {
if input.protocol.to_uppercase() == "OMNI" {
if input.seg_wit.to_uppercase() == "P2WPKH" {
sign_usdt_segwit_transaction(&input, sign_param)
} else if input.seg_wit.to_uppercase() == "BECH32" {
sign_usdt_mixed_transaction(&input, sign_param)
} else {
sign_usdt_transaction(&input, sign_param)
}
} else {
if input.seg_wit.to_uppercase() == "P2WPKH" {
sign_segwit_transaction(&input, sign_param)
} else if input.seg_wit.to_uppercase() == "BECH32" {
sign_mixed_transaction(&input, sign_param)
} else {
sign_legacy_transaction(&input, sign_param)
}
Expand Down Expand Up @@ -126,6 +130,52 @@ pub fn sign_segwit_transaction(param: &BtcTxInput, sign_param: &SignParam) -> Re
encode_message(tx_sign_result)
}

pub fn sign_mixed_transaction(param: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

这个方法和下面 sign_usdt_mixed_transaction 重叠代码非常多,看起来是可以合并到一起的

Copy link
Contributor Author

Choose a reason for hiding this comment

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

沿用了以前结构,如果合并就比较突兀,可以整体优化下

let mut unspents = Vec::new();
for utxo in &param.unspents {
let new_utxo = Utxo {
txhash: utxo.tx_hash.to_string(),
vout: utxo.vout,
amount: utxo.amount,
address: Address::from_str(&utxo.address).unwrap(),
script_pubkey: utxo.script_pub_key.to_string(),
derive_path: utxo.derived_path.to_string(),
sequence: utxo.sequence,
};
unspents.push(new_utxo);
}

let btc_tx = BtcTransaction {
to: Address::from_str(&param.to).unwrap(),
// change_idx: input.change_address_index as i32,
amount: param.amount,
unspents: unspents,
fee: param.fee,
};

let network = if sign_param.network == "TESTNET".to_string() {
Network::Testnet
} else {
Network::Bitcoin
};

let op_return: Vec<u8>;
if let Some(extra) = param.extra.clone() {
op_return = hex_to_bytes(&extra.op_return).expect("decode btc extra op_return");
} else {
op_return = vec![];
}

let signed =
btc_tx.sign_mixed_transaction(network, param.change_address_index as i32, &op_return)?;
let tx_sign_result = BtcTxOutput {
signature: signed.signature,
wtx_hash: signed.wtx_id,
tx_hash: signed.tx_hash,
};
encode_message(tx_sign_result)
}

pub fn sign_usdt_transaction(input: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> {
let mut unspents = Vec::new();
for utxo in &input.unspents {
Expand Down Expand Up @@ -210,3 +260,46 @@ pub fn sign_usdt_segwit_transaction(input: &BtcTxInput, sign_param: &SignParam)
};
encode_message(tx_sign_result)
}

pub fn sign_usdt_mixed_transaction(input: &BtcTxInput, sign_param: &SignParam) -> Result<Vec<u8>> {
let mut unspents = Vec::new();
for utxo in &input.unspents {
let new_utxo = Utxo {
txhash: utxo.tx_hash.to_string(),
vout: utxo.vout,
amount: utxo.amount,
address: Address::from_str(&utxo.address).unwrap(),
script_pubkey: utxo.script_pub_key.to_string(),
derive_path: utxo.derived_path.to_string(),
sequence: utxo.sequence,
};
unspents.push(new_utxo);
}

let btc_tx = BtcTransaction {
to: Address::from_str(&input.to).unwrap(),
// change_idx: input.change_address_index as i32,
amount: input.amount,
unspents: unspents,
fee: input.fee,
};

let network = if sign_param.network == "TESTNET".to_string() {
Network::Testnet
} else {
Network::Bitcoin
};

let extra = input
.extra
.clone()
.expect("sign usdt tx must contains extra");

let signed = btc_tx.sign_omni_mixed_transaction(network, extra.property_id as i32)?;
let tx_sign_result = BtcTxOutput {
signature: signed.signature,
wtx_hash: signed.wtx_id,
tx_hash: signed.tx_hash,
};
encode_message(tx_sign_result)
}
10 changes: 10 additions & 0 deletions common/src/apdu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,16 @@ impl BtcApdu {
apdu.to_hex().to_uppercase()
}

pub fn btc_legacy_sign(p1: u8, p2: u8, data: &Vec<u8>) -> String {
if data.len() as u32 > LC_MAX {
panic!("data to long");
}
let mut apdu = ApduHeader::new(0x80, 0x52, p1, p2, data.len() as u8).to_array();
apdu.extend(data.iter());
apdu.push(0x00);
apdu.to_hex().to_uppercase()
}

pub fn omni_prepare_data(p1: u8, data: Vec<u8>) -> String {
if data.len() as u32 > LC_MAX {
panic!("data to long");
Expand Down
11 changes: 11 additions & 0 deletions common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ pub const NERVOS_PATH: &str = "m/44'/309'/0'/0/0";
pub const POLKADOT_PATH: &str = "m/44'/354'/0'/0'/0'";
pub const KUSAMA_PATH: &str = "m/44'/434'/0'/0'/0'";
pub const TRON_PATH: &str = "m/44'/195'/0'/0/0";
pub const BTC_LEGACY_MAINNET_PATH: &str = "m/44'/0'/0'";
pub const BTC_LEGACY_TESTNET_PATH: &str = "m/44'/1'/0'";
pub const BTC_SEGWIT_MAINNET_PATH: &str = "m/49'/0'/0'";
pub const BTC_SEGWIT_TESTNET_PATH: &str = "m/49'/1'/0'";
pub const BTC_NATIVE_SEGWIT_MAINNET_PATH: &str = "m/84'/0'/0'";
pub const BTC_NATIVE_SEGWIT_TESTNET_PATH: &str = "m/84'/1'/0'";

pub const MAX_UTXO_NUMBER: usize = 252;
pub const EACH_ROUND_NUMBER: usize = 5;
Expand Down Expand Up @@ -111,3 +117,8 @@ pub const DEVICE_MODEL_NAME: &str = "imKey Pro";
pub const NETWORK_CONN_TIMEOUT: u16 = 30;
pub const NETWORK_WRITE_TIMEOUT: u16 = 30;
pub const NETWORK_READ_TIMEOUT: u16 = 30;

// xpub string length
pub const UNCOMPRESSED_PUBKEY_STRING_LEN: usize = 130;
pub const CHAIN_CODE_STRING_LEN: usize = 64;
pub const XPUB_STRING_LEN: usize = UNCOMPRESSED_PUBKEY_STRING_LEN + CHAIN_CODE_STRING_LEN;
2 changes: 2 additions & 0 deletions common/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,6 @@ pub enum CoinError {
InvalidVersion,
#[fail(display = "invalid addr length")]
InvalidAddrLength,
#[fail(display = "unsupported script pubkey")]
UnsupportedScriptPubkey,
}
4 changes: 2 additions & 2 deletions proto/src/api.proto
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ message AddressParam {
string chainType = 1;
string path = 2;
string network = 3;
bool isSegWit = 4;
string segWit = 4;
}

message AddressResult {
Expand Down Expand Up @@ -100,4 +100,4 @@ message BtcForkWallet {
string chainType = 2;
string address = 3;
string encXPub = 4;
}
}
Loading