From 4b872279df41f12adb785231423f04814d17f5a9 Mon Sep 17 00:00:00 2001 From: cebgcontract <99630598+cebgcontract@users.noreply.github.com> Date: Sat, 22 Oct 2022 23:27:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=92=B1=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/test.rs | 64 +++++++++------ src/lib.rs | 143 ++++++++++++++------------------- src/wallet/wallet_impl.rs | 164 ++++++++++++++++++++++++++++++-------- 3 files changed, 232 insertions(+), 139 deletions(-) diff --git a/examples/test.rs b/examples/test.rs index f58b5ee..e67b32c 100644 --- a/examples/test.rs +++ b/examples/test.rs @@ -5,42 +5,60 @@ // use std::ffi::CStr; +use std::os::raw::c_char; //use rustylib::gen::{CWallet}; -use rustwallet::{fetch_cwallet, free_cwallet, sign, sss_sign, CWallet}; +use rustwallet::{new_wallet, get_address, free_cwallet, CWallet}; fn main() { unsafe { - // let wallet: CWallet = generate_cwallet(); - // println!("---- generated a wallet to be used on C-side ----"); - // print_wallet(&wallet); + let msg = "111"; + let cstr = std::ffi::CString::new(msg).unwrap(); + let wallet: CWallet = new_wallet(cstr.into_raw()); + println!("---- generated a wallet to be used on C-side ----"); + print_wallet(&wallet); + let address = get_address(wallet); + let address_str = cchar_str(address); + println!("address: {}", address_str); + let key0 = "b8256097c1ff2bdd483ffb53d35203a8a7ff19547d65d97f2810732a27e80c1f"; + let key1 = "8e25c8b2e2c8504ea3d6d37cc268facec17ae60667048cfeb7a0092cfda8323a"; + let key2 = "642630ce039174bfff6daba5b17ff1f4daf6b2b850a3407e472f9f2fd3685855"; // println!("---- saving the wallet to wallet.json ----"); // save_wallet(&wallet); // println!("---- saved! ----"); - println!("---- fetching the saved wallet to be exposed to C-side ----"); - let fetched = fetch_cwallet(); - print_wallet(&fetched); - sign(); - let sign_str = "111"; - let cstr = std::ffi::CString::new(sign_str).unwrap(); - sss_sign(cstr.into_raw()); + // println!("---- fetching the saved wallet to be exposed to C-side ----"); + // let fetched = fetch_cwallet(); + // print_wallet(&fetched); + // sign(); + // let sign_str = "111"; + // let cstr = std::ffi::CString::new(sign_str).unwrap(); + // sss_sign(cstr.into_raw()); - // free_cwallet(wallet); // 对应 generate_cwallet() - free_cwallet(fetched); // 对应 fetch_wallet() + // // free_cwallet(wallet); // 对应 generate_cwallet() + // free_cwallet(fetched); // 对应 fetch_wallet() } } -unsafe fn print_wallet(wallet: &CWallet) { - let a = CStr::from_ptr(wallet.public_addr); - let pa = a.to_str().unwrap(); - println!("public address=> {}", pa); +unsafe fn print_wallet(cwallet: &CWallet) { + let msg = CStr::from_ptr(cwallet.msg_key); + let pmsg = msg.to_str().unwrap(); + println!("msg=> {}", pmsg); - let pk = CStr::from_ptr(wallet.public_key); - let ppk = pk.to_str().unwrap(); - println!("public key=> {}", ppk); + let m = CStr::from_ptr(cwallet.master_key); + let pm = m.to_str().unwrap(); + println!("master key=> {}", pm); - let sk = CStr::from_ptr(wallet.private_key); - let psk = sk.to_str().unwrap(); - println!("private key=> {}", psk); + let s = CStr::from_ptr(cwallet.second_key); + let ps = s.to_str().unwrap(); + println!("second key=> {}", ps); + + let b = CStr::from_ptr(cwallet.backup_key); + let pb = b.to_str().unwrap(); + println!("backup key=> {}", pb); +} + +unsafe fn cchar_str(cstr: *mut c_char) -> &'static str { + let msg = CStr::from_ptr(cstr); + msg.to_str().unwrap() } diff --git a/src/lib.rs b/src/lib.rs index d6ecd46..d8bff02 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,100 +19,77 @@ use crate::wallet::*; #[repr(C)] pub struct CWallet { - pub public_key: *mut c_char, - pub private_key: *mut c_char, - pub public_addr: *mut c_char, + pub msg_key: *mut c_char, + pub master_key: *mut c_char, + pub second_key: *mut c_char, + pub backup_key: *mut c_char, } #[no_mangle] -pub unsafe extern "C" fn generate_cwallet() -> CWallet { +pub unsafe extern "C" fn new_wallet(msg: *const c_char) -> CWallet { println!("generating wallet"); - let (secret_key, pub_key) = wallet_impl::generate_keypair(); + let c_str = CStr::from_ptr(msg); + let str = c_str.to_str().unwrap(); + let rust_wallet = wallet_impl::Wallet::new(str); + println!("rust_wallet: {:?}", &rust_wallet); + convert_to_cwallet(rust_wallet) +} - // println!("secret key: {}", &secret_key.to_string()); - // println!("public key: {}", &pub_key.to_string()); - - //let pub_address = eth_wallet::public_key_address(&pub_key); - //println!("public address: {:?}", pub_address); - - let rust_wallet = wallet_impl::Wallet::new(&secret_key, &pub_key); +#[no_mangle] +pub unsafe extern "C" fn restore_cwallet(msg: *const c_char) -> CWallet { + println!("generating wallet"); + let c_str = CStr::from_ptr(msg); + let str = c_str.to_str().unwrap(); + let rust_wallet = wallet_impl::Wallet::new(str); println!("rust_wallet: {:?}", &rust_wallet); convert_to_cwallet(rust_wallet) } #[no_mangle] pub unsafe extern "C" fn free_cwallet(cw: CWallet) { - drop(CString::from_raw(cw.public_key)); - drop(CString::from_raw(cw.private_key)); - drop(CString::from_raw(cw.public_addr)); + drop(CString::from_raw(cw.msg_key)); + drop(CString::from_raw(cw.master_key)); + drop(CString::from_raw(cw.second_key)); + drop(CString::from_raw(cw.backup_key)); } #[no_mangle] -pub unsafe extern "C" fn save_wallet(cw: &CWallet) { - let rwallet = convert_to_rwallet(cw); - wallet_impl::Wallet::save_keys(&rwallet, "wallet.json").unwrap(); -} - -#[no_mangle] -pub unsafe extern "C" fn fetch_cwallet() -> CWallet { - match wallet_impl::Wallet::retrieve_keys("wallet.json") { - Err(_) => { - let wallet = wallet_impl::Wallet { - secret_key: "".to_string(), - public_key: "".to_string(), - public_address: "".to_string(), - }; - return convert_to_cwallet(wallet); - } - Ok(w) => return convert_to_cwallet(w), - }; -} -#[no_mangle] -pub unsafe extern "C" fn sign() { - match wallet_impl::Wallet::retrieve_keys("wallet.json") { - Err(_) => { - println!("error sign"); - } - Ok(w) => match w.sign("111") { - Err(err) => { - println!("error sign: {:?}", err); - } - Ok(sig) => { - println!("sig result: {:?}", sig); - } - }, - }; -} - -#[no_mangle] -pub unsafe extern "C" fn sss_sign(msg: *const std::os::raw::c_char) { - let c_str = CStr::from_ptr(msg); - let str = c_str.to_str().unwrap(); - match wallet_impl::Wallet::retrieve_keys("wallet.json") { - Err(_) => { - println!("error sign"); - } - Ok(w) => { - w.sss_sign(&str); - } - }; +pub unsafe extern "C" fn get_address(cw: CWallet) -> *mut c_char{ + let rwallet = convert_to_rwallet(&cw); + let address = rwallet.get_address(); + println!("raw address: {}", address.to_string()); + let c_address = CString::new(address.to_string()).unwrap(); + c_address.into_raw() } unsafe fn convert_to_cwallet(rwallet: Wallet) -> CWallet { // 转换Rust字符串数据为C的字符串并移交ownership - let pubkey = CString::new(rwallet.public_key).unwrap(); - let c_pubkey: *mut c_char = pubkey.into_raw(); - let seckey = CString::new(rwallet.secret_key).unwrap(); - let c_seckey: *mut c_char = seckey.into_raw(); - let pubaddr = CString::new(rwallet.public_address).unwrap(); - let c_pubaddr: *mut c_char = pubaddr.into_raw(); + let msgkey = CString::new(rwallet.msg_key).unwrap(); + let c_msgkey: *mut c_char = msgkey.into_raw(); + let masterkey = CString::new(rwallet.master_key).unwrap(); + let c_masterkey: *mut c_char = masterkey.into_raw(); + let secondkey = match rwallet.second_key { + Some(val) => { + CString::new(val).unwrap() + }, + None => CString::new("").unwrap() + }; + let c_secondkey: *mut c_char = secondkey.into_raw(); + let backupkey = match rwallet.backup_key { + Some(val) => { + CString::new(val).unwrap() + }, + None => CString::new("").unwrap() + }; + let c_backupkey: *mut c_char = backupkey.into_raw(); //println!("crypto wallet address: {}", CStr::from_ptr(c_pubaddr).to_str().unwrap()); let cw = CWallet { - public_key: c_pubkey, - private_key: c_seckey, - public_addr: c_pubaddr, + msg_key: c_msgkey, + master_key: c_masterkey, + second_key: c_secondkey, + backup_key: c_backupkey, }; //println!("crypto_wallet addr: {}", CStr::from_ptr(cw.public_addr).to_str().unwrap()); @@ -121,17 +98,21 @@ unsafe fn convert_to_cwallet(rwallet: Wallet) -> CWallet { } unsafe fn convert_to_rwallet(cwallet: &CWallet) -> Wallet { - let a = CStr::from_ptr(cwallet.public_addr); - let pa = a.to_str().unwrap(); + let msg = CStr::from_ptr(cwallet.msg_key); + let pmsg = msg.to_str().unwrap(); - let pk = CStr::from_ptr(cwallet.public_key); - let ppk = pk.to_str().unwrap(); + let m = CStr::from_ptr(cwallet.master_key); + let pm = m.to_str().unwrap(); - let sk = CStr::from_ptr(cwallet.private_key); - let psk = sk.to_str().unwrap(); + let s = CStr::from_ptr(cwallet.second_key); + let ps = s.to_str().unwrap(); + + let b = CStr::from_ptr(cwallet.backup_key); + let pb = b.to_str().unwrap(); Wallet { - secret_key: psk.to_string(), - public_key: ppk.to_string(), - public_address: pa.to_string(), + msg_key: pmsg.to_string(), + master_key: pm.to_string(), + second_key: Some(ps.to_string()), + backup_key: Some(pb.to_string()) } } diff --git a/src/wallet/wallet_impl.rs b/src/wallet/wallet_impl.rs index 2cc6a73..e852158 100644 --- a/src/wallet/wallet_impl.rs +++ b/src/wallet/wallet_impl.rs @@ -7,10 +7,8 @@ use secp256k1::{Message, PublicKey, Secp256k1, SecretKey}; use serde::{Deserialize, Serialize}; use shamir_secret_sharing::num_bigint::BigInt; use shamir_secret_sharing::ShamirSecretSharing as SSS; -use std::io::BufWriter; use std::str; use std::str::FromStr; -use std::{fs::OpenOptions, io::BufReader}; use tiny_keccak::keccak256; use web3::types::{Address, H256}; @@ -28,12 +26,38 @@ pub fn public_key_address(public_key: &PublicKey) -> Address { Address::from_slice(&hash[12..]) } -pub fn get_public_key(secret_key: &str) -> PublicKey { +pub fn get_public_key(secret_key: &SecretKey) -> PublicKey { let secp = Secp256k1::new(); - let secret = SecretKey::from_str(secret_key).unwrap(); - PublicKey::from_secret_key(&secp, &secret) + PublicKey::from_secret_key(&secp, secret_key) } +pub fn get_sss(msg: &str) -> SSS { + let k_hash = keccak256(msg.as_bytes()); + let s = hex::encode(&k_hash); + let pb = BigInt::parse_bytes(&s.as_bytes(), 16).unwrap(); + SSS { + threshold: 2, + share_amount: 3, + prime: pb, + } +} + +pub fn generate_sss_keypair(msg: &str, skey: &str) -> Vec { + let secret = BigInt::parse_bytes( + &skey.as_bytes(), + 16, + ) + .unwrap(); + let sss = get_sss(msg); + let shares = sss.split(secret.clone()); + let mut shares_str: Vec = Vec::new(); + for (_i, v) in &shares { + shares_str.push(v.to_str_radix(16)); + } + shares_str +} + + pub fn hash_message(message: S) -> H256 where S: AsRef<[u8]>, @@ -48,45 +72,116 @@ where #[derive(Serialize, Deserialize, Debug)] pub struct Wallet { - pub secret_key: String, - pub public_key: String, - pub public_address: String, + pub msg_key: String, + pub master_key: String, + pub second_key: Option, + pub backup_key: Option, } impl Wallet { - pub fn new(secret_key: &SecretKey, public_key: &PublicKey) -> Self { - let addr: Address = public_key_address(&public_key); - println!("secret key: {:?}", secret_key); + pub fn new(msg: &str) -> Self{ + let (secret_key, _pub_key) = generate_keypair(); let s = hex::encode(&secret_key.serialize_secret()); - println!("{:?}", s); + let sk2 = "b8256097c1ff2bdd483ffb53d35203a8a7ff19547d65d97f2810732a27e80c1f"; + let shares_str = generate_sss_keypair(msg, &sk2); + // let addr: Address = public_key_address(&pub_key); + println!("secret key: {:?}", secret_key); + println!("{:?}", s); + let second_key = shares_str.get(1).map(String::clone); + let backup_key = shares_str.get(2).map(String::clone); Wallet { - secret_key: s, - public_key: public_key.to_string(), - public_address: format!("{:?}", addr), + msg_key: msg.to_string(), + master_key: shares_str.get(0).unwrap().to_string(), + second_key: second_key, + backup_key: backup_key } } - pub fn save_keys(&self, file_path: &str) -> Result<()> { - let file = OpenOptions::new() - .write(true) - .create(true) - .open(file_path)?; - let buf_writer = BufWriter::new(file); - serde_json::to_writer_pretty(buf_writer, self)?; - - Ok(()) + pub fn restore_wallet(msg: &str, _key_master: &str, _key_second: Option<&str>, _key_backup: Option<&str>) -> Self { + let key_second: Option = match _key_second { + None => None, + Some(val) => Some(val.to_string()) + }; + let key_backup: Option = match _key_backup { + None => None, + Some(val) => Some(val.to_string()) + }; + Wallet { + msg_key: msg.to_string(), + master_key: _key_master.to_string(), + second_key: key_second, + backup_key: key_backup + } } - pub fn retrieve_keys(file_path: &str) -> Result { - let file = OpenOptions::new().read(true).open(file_path)?; - let buf_reader = BufReader::new(file); - let wallet: Wallet = serde_json::from_reader(buf_reader)?;; - let public_key = get_public_key(&wallet.secret_key); - println!("public key from secret: {:?}", public_key.to_string()); - Ok(wallet) + pub fn reset_eallet(msg: &str, _key_master: &str, _key_second: Option<&str>, _key_backup: Option<&str>) -> Self{ + let tmp_wallet = Wallet::restore_wallet(msg, _key_master, _key_second, _key_backup); + let secret_key = tmp_wallet.get_secret_key(); + let s = hex::encode(&secret_key.serialize_secret()); + let shares_str = generate_sss_keypair(msg, &s); + let second_key = shares_str.get(1).map(String::clone); + let backup_key = shares_str.get(2).map(String::clone); + Wallet { + msg_key: msg.to_string(), + master_key: shares_str.get(0).unwrap().to_string(), + second_key: second_key, + backup_key: backup_key + } } + fn get_secret_key(&self) -> SecretKey { + let key_str_0: &str = &self.master_key; + let key0 = BigInt::parse_bytes( + &key_str_0.as_bytes(), + 16, + ).unwrap(); + let kp0: (usize, BigInt) = (1, key0); + let i: usize; + let key_str_1: &str; + if let Some(val) = &self.second_key { + i = 2; + key_str_1 = val; + } else if let Some(val) = &self.backup_key { + i = 3; + key_str_1 = val; + } else { + println!("error"); + i = 2; + key_str_1 = ""; + } + let key1 = BigInt::parse_bytes( + &key_str_1.as_bytes(), + 16, + ) + .unwrap(); + let kp1 = (i, key1); + let _tmp = vec![kp0, kp1]; + let sss = get_sss(&self.msg_key); + let secret_b = sss.recover(&_tmp); + let s_key_str = secret_b.to_str_radix(16); + SecretKey::from_str(&s_key_str).expect("32 bytes, within curve order") + } + + pub fn get_public_key(&self) -> PublicKey { + let s_key = self.get_secret_key(); + get_public_key(&s_key) + } + + pub fn get_address(&self) -> Address { + let public_key = self.get_public_key(); + public_key_address(&public_key) + } + + // pub fn retrieve_keys(file_path: &str) -> Result { + // let file = OpenOptions::new().read(true).open(file_path)?; + // let buf_reader = BufReader::new(file); + // let wallet: Wallet = serde_json::from_reader(buf_reader)?;; + // let public_key = get_public_key(&wallet.secret_key); + // println!("public key from secret: {:?}", public_key.to_string()); + // Ok(wallet) + // } + pub fn sss_sign(&self, msg: &str) { let k_hash = keccak256(msg.as_bytes()); println!("k_hash: {:?}", &k_hash); @@ -138,15 +233,14 @@ impl Wallet { S: AsRef<[u8]>, { let secp = Secp256k1::new(); - println!("secret key str: {:?}", self.secret_key); + let secret_key = self.get_secret_key(); let message = msg.as_ref(); let message_hash = hash_message(message.as_ref()); - let pk = SecretKey::from_str(&self.secret_key).expect("32 bytes, within curve order"); - // println!("secret key: {:?}", pk); + println!("secret key: {:?}", &secret_key); let message_to_hash = Message::from_slice(message_hash.as_ref()).unwrap(); let (recovery_id, signature) = secp - .sign_ecdsa_recoverable(&message_to_hash, &pk) + .sign_ecdsa_recoverable(&message_to_hash, &secret_key) .serialize_compact(); let mut s = hex::encode(signature);