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

Feature/ckb #18

Open
wants to merge 9 commits into
base: feature/tron2
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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"wallet/coin-ethereum",
"wallet/coin-eos",
"wallet/coin-cosmos",
"wallet/coin-ckb",
"wallet/coin-substrate",
"wallet/coin-tron",
]
1 change: 1 addition & 0 deletions api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ coin-cosmos = {path = "../wallet/coin-cosmos"}
coin-filecoin = {path = "../wallet/coin-filecoin"}
coin-substrate = {path = "../wallet/coin-substrate"}
coin-tron = {path = "../wallet/coin-tron"}
coin-ckb = {path = "../wallet/coin-ckb"}
common = {path = "../common"}
bitcoin = "0.25.0"
ethereum-types = "0.6.0"
Expand Down
7 changes: 7 additions & 0 deletions api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ pub mod ethereum_signer;
pub mod filecoin_address;
pub mod filecoin_signer;
pub mod message_handler;
pub mod nervos_address;
pub mod nervos_signer;
pub mod substrate_address;
pub mod substrate_signer;
pub mod tron_address;
Expand Down Expand Up @@ -126,6 +128,7 @@ pub unsafe extern "C" fn call_imkey_api(hex_str: *const c_char) -> *const c_char
"POLKADOT" => substrate_address::get_address(&param),
"KUSAMA" => substrate_address::get_address(&param),
"TRON" => tron_address::get_address(&param),
"NERVOS" => nervos_address::get_address(&param),
_ => Err(format_err!("get_address unsupported_chain")),
}
}),
Expand Down Expand Up @@ -159,6 +162,7 @@ pub unsafe extern "C" fn call_imkey_api(hex_str: *const c_char) -> *const c_char
"POLKADOT" => substrate_address::display_address(&param),
"KUSAMA" => substrate_address::display_address(&param),
"TRON" => tron_address::display_address(&param),
"NERVOS" => nervos_address::display_address(&param),
_ => Err(format_err!("register_address unsupported_chain")),
}
}),
Expand Down Expand Up @@ -194,6 +198,9 @@ pub unsafe extern "C" fn call_imkey_api(hex_str: *const c_char) -> *const c_char
"TRON" => {
tron_signer::sign_transaction(&param.clone().input.unwrap().value, &param)
}
"NERVOS" => {
nervos_signer::sign_transaction(&param.clone().input.unwrap().value, &param)
}
_ => Err(format_err!("sign_tx unsupported_chain")),
}
}),
Expand Down
27 changes: 27 additions & 0 deletions api/src/nervos_address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use crate::api::{AddressParam, AddressResult};
use crate::error_handling::Result;
use crate::message_handler::encode_message;
use coin_ckb::address::CkbAddress;
use prost::Message;

pub fn get_address(param: &AddressParam) -> Result<Vec<u8>> {
let address = CkbAddress::get_address(param.network.as_ref(), param.path.as_ref())?;

let address_message = AddressResult {
path: param.path.to_owned(),
chain_type: param.chain_type.to_string(),
address,
};
encode_message(address_message)
}

pub fn display_address(param: &AddressParam) -> Result<Vec<u8>> {
let address = CkbAddress::display_address(param.network.as_ref(), param.path.as_ref())?;

let address_message = AddressResult {
path: param.path.to_owned(),
chain_type: param.chain_type.to_string(),
address,
};
encode_message(address_message)
}
12 changes: 12 additions & 0 deletions api/src/nervos_signer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
use crate::error_handling::Result;
use crate::message_handler::encode_message;
use coin_ckb::signer::CkbSigner;
use coin_ckb::CkbTxInput;
use common::SignParam;
use prost::Message;

pub fn sign_transaction(data: &[u8], sign_param: &SignParam) -> Result<Vec<u8>> {
let input: CkbTxInput = CkbTxInput::decode(data).unwrap();
let signed = CkbSigner::sign_transaction(&input, sign_param)?;
encode_message(signed)
}
4 changes: 4 additions & 0 deletions common/src/applet.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::constants::NERVOS_AID;

pub fn get_appname_by_instid(instid: &str) -> Option<&str> {
match instid {
"695F627463" => Some("BTC"),
Expand All @@ -8,6 +10,7 @@ pub fn get_appname_by_instid(instid: &str) -> Option<&str> {
"695F656473725F6B736D" => Some("KSM"),
"695F656473725F646F74" => Some("DOT"),
"695F696D6B" => Some("IMK"),
NERVOS_AID => Some("Nervos"),
_ => None,
}
}
Expand All @@ -21,6 +24,7 @@ pub fn get_instid_by_appname(appname: &str) -> Option<&str> {
"KSM" => Some("695F656473725F6B736D"),
"DOT" => Some("695F656473725F646F74"),
"IMK" => Some("695F696D6B"),
"Nervos" => Some(NERVOS_AID),
_ => None,
}
}
Expand Down
2 changes: 2 additions & 0 deletions common/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ pub const BTC_AID: &str = "695F627463";
pub const COSMOS_AID: &str = "695F636F736D6F73";
pub const FILECOIN_AID: &str = "695F6B315F66696C";
pub const IMK_AID: &str = "695F696D6B";
pub const NERVOS_AID: &str = "695F6B315F636B62";
pub const POLKADOT_AID: &str = "695F656473725F646F74";
pub const KUSAMA_AID: &str = "695F656473725F6B736D";
pub const TRON_AID: &str = "695F6B315F74726F6E";
Expand All @@ -32,6 +33,7 @@ pub const COSMOS_PATH: &str = "m/44'/118'/0'/0/0";
pub const EOS_PATH: &str = "m/44'/194'/0'/0/0";
pub const ETH_PATH: &str = "m/44'/60'/0'/0/0";
pub const FILECOIN_PATH: &str = "m/44'/461'/0/0/0";
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";
Expand Down
2 changes: 1 addition & 1 deletion device/src/app_update.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ mod test {
assert!(hid_connect("imKey Pro").is_ok());
let seid = get_se_id().unwrap();
let device_cert = get_cert().unwrap();
let instance_aid = "695F627463".to_string();
let instance_aid = "695F6B315F636B62".to_string();
let exe_result =
AppUpdateRequest::build_request_data(seid, instance_aid, device_cert, None)
.send_message();
Expand Down
3 changes: 3 additions & 0 deletions proto/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ fn main() {
env::set_var("OUT_DIR", "../wallet/coin-filecoin/src");
prost_build::compile_protos(&["src/filecoin.proto"], &["src/"]).unwrap();

// ckb
env::set_var("OUT_DIR", "../wallet/coin-ckb/src");
prost_build::compile_protos(&["src/ckb.proto"], &["src/"]).unwrap();
// subtrate
env::set_var("OUT_DIR", "../wallet/coin-substrate/src");
prost_build::compile_protos(&["src/substrate.proto"], &["src/"]).unwrap();
Expand Down
46 changes: 46 additions & 0 deletions proto/src/ckb.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
syntax = "proto3";
package transaction;

message OutPoint {
string txHash = 1;
int32 index = 2;
}

message Witness {
string lock = 1;
string inputType = 2;
string outputType = 3;
}

message Script {
string args = 1;
string codeHash = 2;
string hashType = 3;
}

message CellInput {
OutPoint previousOutput = 1;
string since = 2;
}

message CachedCell {
int64 capacity = 1;
Script lock = 2;
OutPoint outPoint = 3;
string derivedPath = 4;
}

message CkbTxInput {
repeated CellInput inputs = 1;
repeated Witness witnesses = 2;

repeated CachedCell cachedCells = 3;

string txHash = 4;
}

message CkbTxOutput {
string txHash = 1;
repeated string witnesses = 2;
}

20 changes: 20 additions & 0 deletions wallet/coin-ckb/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
[package]
name = "coin-ckb"
version = "0.1.0"
authors = ["xiemener <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
common = {path = "../../common"}
device = {path = "../../device"}
transport = {path = "../../transport"}
blake2b-rs = "0.1.5"
failure = "0.1.6"
bech32 = "0.7.1"
hex = "0.4.0"
byteorder = "1.3.2"
prost = "0.6.1"
lazy_static = "1.4.0"
secp256k1 = {version ="0.19.0", features = ["rand", "recovery"] }
145 changes: 145 additions & 0 deletions wallet/coin-ckb/src/address.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use crate::hash::blake2b_160;
use crate::Result;
use bech32::ToBase32;
use common::apdu::{Apdu, ApduCheck, Secp256k1Apdu};
use common::constants;
use common::constants::NERVOS_AID;
use common::error::CoinError;
use common::path::check_path_validity;
use common::utility::{secp256k1_sign, secp256k1_sign_verify, uncompress_pubkey_2_compress};
use device::device_binding::KEY_MANAGER;
use transport::message::send_apdu;

pub struct CkbAddress {}

impl CkbAddress {
pub fn from_public_key(network: &str, pubkey: &[u8]) -> Result<String> {
let prefix = match network {
"TESTNET" => "ckt",
_ => "ckb",
};

let pub_key_hash = blake2b_160(pubkey);

let mut buf = vec![];
buf.extend(vec![0x1, 0x00]); // append short version for locks with popular codehash and default code hash index
buf.extend(pub_key_hash);

Ok(bech32::encode(prefix, buf.to_base32())?)
}

pub fn get_public_key(path: &str) -> Result<String> {
check_path_validity(path).expect("check path error");

let select_apdu = Apdu::select_applet(NERVOS_AID);
let select_response = send_apdu(select_apdu)?;
ApduCheck::check_response(&select_response)?;

let key_manager_obj = KEY_MANAGER.lock().unwrap();
let bind_signature = secp256k1_sign(&key_manager_obj.pri_key, path.as_bytes())?;

let mut apdu_pack: Vec<u8> = vec![];
apdu_pack.push(0x00);
apdu_pack.push(bind_signature.len() as u8);
apdu_pack.extend(bind_signature.as_slice());
apdu_pack.push(0x01);
apdu_pack.push(path.as_bytes().len() as u8);
apdu_pack.extend(path.as_bytes());

//get public
let msg_pubkey = Secp256k1Apdu::get_xpub(&apdu_pack);
let res_msg_pubkey = send_apdu(msg_pubkey)?;
ApduCheck::check_response(&res_msg_pubkey)?;

let sign_source_val = &res_msg_pubkey[..194];
let sign_result = &res_msg_pubkey[194..res_msg_pubkey.len() - 4];

//verify
let sign_verify_result = secp256k1_sign_verify(
&key_manager_obj.se_pub_key,
hex::decode(sign_result).unwrap().as_slice(),
hex::decode(sign_source_val).unwrap().as_slice(),
)?;
if !sign_verify_result {
return Err(CoinError::ImkeySignatureVerifyFail.into());
}

let pub_key = &res_msg_pubkey[0..130];
Ok(pub_key.to_string())
}

pub fn get_address(network: &str, path: &str) -> Result<String> {
let pub_key = CkbAddress::get_public_key(path)?;
let comprs_pubkey = uncompress_pubkey_2_compress(&pub_key);
let comprs_pubkey_bytes = hex::decode(&comprs_pubkey).expect("decode ckb pubkey error");
let address = CkbAddress::from_public_key(network, &comprs_pubkey_bytes)?;
Ok(address)
}

pub fn display_address(network: &str, path: &str) -> Result<String> {
let address = CkbAddress::get_address(network, path)?;
let menu_name = "CKB".as_bytes();
let reg_apdu = Secp256k1Apdu::register_address(menu_name, address.as_bytes());
let res_reg = send_apdu(reg_apdu)?;
ApduCheck::check_response(&res_reg)?;
Ok(address)
}
}

#[cfg(test)]
mod tests {
use crate::address::CkbAddress;
use common::constants;
use device::device_binding::bind_test;

#[test]
fn test_from_public_key() {
let bytes =
hex::decode("024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01")
.expect("hex decode error");
let network = "TESTNET";
assert_eq!(
CkbAddress::from_public_key(network, &bytes).expect("invalid public key"),
"ckt1qyqrdsefa43s6m882pcj53m4gdnj4k440axqswmu83"
);

let bytes =
hex::decode("024a501efd328e062c8675f2365970728c859c592beeefd6be8ead3d901330bc01")
.expect("hex decode error");
let network = "MAINNET";
assert_eq!(
CkbAddress::from_public_key(network, &bytes).expect("invalid public key"),
"ckb1qyqrdsefa43s6m882pcj53m4gdnj4k440axqdt9rtd"
);
}

#[test]
fn test_get_public_key() {
bind_test();

let network = "TESTNET";
let pk = CkbAddress::get_public_key(constants::NERVOS_PATH).expect("get pubkey fail");
assert_eq!(&pk, "04554851980004FF256888612BF0D64D9B1002BF82331450FD5A7405D1B23CC5BD2F4DDA9D71F6502CD761AFB29B1A89AECEBC832851CD361D3351216F08635BBF");
}

#[test]
fn test_get_address() {
bind_test();

let network = "TESTNET";
let address =
CkbAddress::get_address(network, constants::NERVOS_PATH).expect("get address fail");
assert_eq!(&address, "ckt1qyqtr684u76tu7r8efkd24hw8922xfvhnazskzdzy6");
}

#[test]
fn test_display_address() {
bind_test();

let network = "TESTNET";
let address =
CkbAddress::display_address(network, constants::NERVOS_PATH).expect("get address fail");
println!("address:{}", &address);
assert_eq!(&address, "ckt1qyqtr684u76tu7r8efkd24hw8922xfvhnazskzdzy6");
}
}
Loading