diff --git a/Cargo.lock b/Cargo.lock index 7b42c92..3fe685b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -67,6 +67,12 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + [[package]] name = "bitcoin_hashes" version = "0.11.0" @@ -397,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" dependencies = [ "arrayref", - "base64", + "base64 0.13.1", "digest 0.9.0", "hmac-drbg", "libsecp256k1-core", @@ -565,6 +571,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "qrcodegen" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142" + [[package]] name = "quote" version = "1.0.21" @@ -649,11 +661,13 @@ name = "rustwallet" version = "0.1.0" dependencies = [ "anyhow", + "base64 0.21.0", "bitcoin_hashes", "ecies", "getrandom", "hex", "primitive-types", + "qrcodegen", "secp256k1", "serde", "serde_json", diff --git a/Cargo.toml b/Cargo.toml index eddb66e..04346c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,4 +27,6 @@ getrandom = { version = "0.2.7", features = ["js"]} ecies = {version = "0.2", default-features = false, features = ["pure"]} #[target.'cfg(target_arch = "wasm32")'.dependencies] wasm-bindgen = "0.2.83" +qrcodegen = "1.8.0" +base64 = "0.21.0" diff --git a/examples/test.rs b/examples/test.rs index 1c7703f..cafaeb6 100644 --- a/examples/test.rs +++ b/examples/test.rs @@ -5,7 +5,7 @@ // use rustwallet::{ - decrypt, encrypt, generate_sec_key, get_address, new_wallet, sign, sign_for_tran, CWallet, + generate_sec_key, new_wallet, sign, sign_for_tran, wdecrypt, wencrypt, wget_address, }; use std::ffi::{CStr, CString}; use std::os::raw::c_char; @@ -33,8 +33,7 @@ macro_rules! cchar_to_str { macro_rules! str_to_cchar { ($p1:expr) => {{ - let msgkey = CString::new($p1).unwrap(); - let c_msgkey: *mut c_char = msgkey.into_raw(); + let c_msgkey = $p1.to_string(); c_msgkey }}; } @@ -58,40 +57,42 @@ fn main() { let key1 = ""; let key2 = "cd00eb0126aeed39762579ce94c90a04695ad17fbd5e79aa4e9fc4a34ba32a5"; let private_key = generate_sec_key( - str_to_cchar!(msg), - str_to_cchar!(key0), + msg.to_string(), + key0.to_string(), str_to_cchar!(key1), str_to_cchar!(key2), ); - print_cchar!(private_key); + println!("private_key=> {}", private_key); - let address2 = get_address( + let address2 = wget_address( str_to_cchar!(msg), str_to_cchar!(key0), - str_to_cchar!(key1), + Option(key1), str_to_cchar!(key2), ); - print_cchar!(address2); + + println!("address=> {}", address2); let message = "helloword"; - let msg_encrypt = encrypt( + let msg_encrypt = wencrypt( str_to_cchar!(msg), str_to_cchar!(key0), str_to_cchar!(key1), str_to_cchar!(key2), str_to_cchar!(message), ); - print_cchar!(msg_encrypt); - let msg_decrypt = decrypt( + println!("msg_encrypt=> {}", msg_encrypt); + + let msg_decrypt = wdecrypt( str_to_cchar!(msg), str_to_cchar!(key0), str_to_cchar!(key1), str_to_cchar!(key2), msg_encrypt, ); - print_cchar!(msg_decrypt); - let msg_decrypt = cchar_to_str!(msg_decrypt); - assert_eq!(message, msg_decrypt); + + println!("msg_decrypt=> {}", msg_decrypt); + // let tmp_cwallet2 = restore_wallet(&tmp_cwallet); // let address3 = get_address(&tmp_cwallet2); // print_cchar!(address3); @@ -120,10 +121,3 @@ fn main() { // free_cwallet(fetched); // 对应 fetch_wallet() } } - -unsafe fn print_wallet(cwallet: &CWallet) { - print_cchar!("msg=> ", cwallet.msg_key); - print_cchar!("master key=> ", cwallet.master_key); - print_cchar!("second key=> ", cwallet.second_key); - print_cchar!("backup key=> ", cwallet.backup_key); -} diff --git a/rustwallet.h b/rustwallet.h index dfd9460..b0787c9 100644 --- a/rustwallet.h +++ b/rustwallet.h @@ -46,3 +46,15 @@ char *sign_for_tran(const char *msg_key, const char *second_key, const char *backup_key, const char *msg); + +char *encrypt(const char *msg_key, + const char *master_key, + const char *second_key, + const char *backup_key, + const char *msg); + +char *decrypt(const char *msg_key, + const char *master_key, + const char *second_key, + const char *backup_key, + const char *msg); diff --git a/scripts/android_build.sh b/scripts/android_build.sh index ccbf774..9dac2be 100755 --- a/scripts/android_build.sh +++ b/scripts/android_build.sh @@ -10,17 +10,13 @@ libName=librustwallet.a rm -rf ${jniLibs} -mkdir ${jniLibs} -mkdir ${jniLibs}/arm64-v8a -mkdir ${jniLibs}/armeabi-v7a -mkdir ${jniLibs}/x86_64 -mkdir ${jniLibs}/x86 +# mkdir ${jniLibs} +# mkdir ${jniLibs}/arm64-v8a +# mkdir ${jniLibs}/armeabi-v7a +# mkdir ${jniLibs}/x86_64 +# mkdir ${jniLibs}/x86 -targetBase=~/Documents/workspace/cocos/cocos2d-x/external/android -cp target/aarch64-linux-android/release/${libName} ${jniLibs}/arm64-v8a/${libName} -cp target/armv7-linux-androideabi/release/${libName} ${jniLibs}/armeabi-v7a/${libName} -cp target/x86_64-linux-android/release/${libName} ${jniLibs}/x86_64/${libName} -cp target/i686-linux-android/release/${libName} ${jniLibs}/x86/${libName} +targetBase=~/Documents/workspace/crypto/cocos_js/external/android cp target/aarch64-linux-android/release/${libName} ${targetBase}/arm64-v8a/${libName} cp target/armv7-linux-androideabi/release/${libName} ${targetBase}/armeabi-v7a/${libName} diff --git a/src/lib.rs b/src/lib.rs index 24a1638..d4415b3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,73 +5,18 @@ // 否则导致内存泄漏 // -use std::ffi::{CStr, CString}; -use std::os::raw::c_char; +use qr::qr_code::QR; +use utils::str_utils::{base64_to_hex, hex_to_base64}; use wasm_bindgen::prelude::*; +mod qr; mod wallet; use wallet_impl::Wallet; +mod utils; + use crate::wallet::*; -// #[cfg(target_os = "android")] -// mod android; -macro_rules! cchar_to_str { - ($p1:expr) => {{ - let s = CStr::from_ptr($p1); - let ps = s.to_str().unwrap(); - ps - }}; -} - -macro_rules! cchar_to_string { - ($p1:expr) => {{ - let s = CStr::from_ptr($p1); - let ps = s.to_str().unwrap(); - ps.to_string() - }}; -} - -macro_rules! cchar_to_ostring { - ($p1:expr) => {{ - let s = CStr::from_ptr($p1); - let pb = s.to_str().unwrap(); - let result = if pb.is_empty() { - None - } else { - Some(pb.to_string()) - }; - result - }}; -} - -macro_rules! str_to_cchar { - ($p1:expr) => {{ - let msgkey = CString::new($p1).unwrap(); - let c_msgkey: *mut c_char = msgkey.into_raw(); - c_msgkey - }}; -} - -macro_rules! ostr_to_cchar { - ($p1:expr) => {{ - let key = match $p1 { - Some(val) => CString::new(val).unwrap(), - None => CString::new("").unwrap(), - }; - let c_key: *mut c_char = key.into_raw(); - c_key - }}; -} - -#[repr(C)] -pub struct CWallet { - pub msg_key: *mut c_char, - pub master_key: *mut c_char, - pub second_key: *mut c_char, - pub backup_key: *mut c_char, -} - #[wasm_bindgen] extern "C" { // Use `js_namespace` here to bind `console.log(..)` instead of just @@ -96,45 +41,88 @@ macro_rules! console_log { ($($t:tt)*) => (log(&format_args!($($t)*).to_string())) } -#[no_mangle] -pub unsafe extern "C" fn new_wallet(msg: *const c_char) -> CWallet { - let str = cchar_to_str!(msg); - let rust_wallet = wallet_impl::Wallet::new(str); - convert_to_cwallet(rust_wallet) +#[wasm_bindgen] +pub fn new_wallet(msg_key: String) -> String { + let rust_wallet = wallet_impl::Wallet::new(&msg_key); + rust_wallet.get_public_key().to_string() } -#[no_mangle] -pub unsafe extern "C" fn reset_wallet( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, -) -> CWallet { - let rust_wallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let rust_wallet2 = rust_wallet.reset_wallet(); - convert_to_cwallet(rust_wallet2) +#[wasm_bindgen] +pub fn get_public_key( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, + }; + rwallet.get_public_key().to_string() } -#[no_mangle] -pub unsafe extern "C" fn free_cwallet(cw: CWallet) { - 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)); +#[wasm_bindgen] +pub fn generate_sec_key( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, + }; + rwallet.generate_sec_key() } -#[no_mangle] -pub unsafe extern "C" fn get_address( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let address = rwallet.get_address(); - let address_str = format!("{:?}", address); - let c_address = CString::new(address_str).unwrap(); - c_address.into_raw() +#[wasm_bindgen] +pub fn sign( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, + msg: String, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, + }; + let signature = rwallet.sign(msg); + let r = match signature { + Ok(v) => v, + Err(err) => panic!("Problem sign: {:?}", err), + }; + r +} + +#[wasm_bindgen] +pub fn sign_for_tran( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, + msg: String, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, + }; + + let signature = rwallet.sign_for_tran(msg); + let (r, recid) = match signature { + Ok((v, _recid)) => (v, _recid), + Err(err) => panic!("Problem sign: {:?}", err), + }; + let result = format!("{}|{}", r, recid); + result } #[wasm_bindgen] @@ -157,133 +145,58 @@ pub fn wget_address( address_str } -#[no_mangle] -pub unsafe extern "C" fn generate_sec_key( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let s_key = rwallet.generate_sec_key(); - let cs_key = CString::new(s_key).unwrap(); - cs_key.into_raw() -} - -#[no_mangle] -pub unsafe extern "C" fn sign( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, - msg: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let msg_str = cchar_to_str!(msg); - let signature = rwallet.sign(msg_str); - let r = match signature { - Ok(v) => v, - Err(err) => panic!("Problem sign: {:?}", err), +#[wasm_bindgen] +pub fn wencrypt( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, + msg: String, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, }; - str_to_cchar!(r) -} - -#[no_mangle] -pub unsafe extern "C" fn sign_for_tran( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, - msg: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let msg_str = cchar_to_str!(msg); - let signature = rwallet.sign_for_tran(msg_str); - let (r, recid) = match signature { - Ok((v, _recid)) => (v, _recid), - Err(err) => panic!("Problem sign: {:?}", err), - }; - let result = format!("{}|{}", r, recid); - str_to_cchar!(result) -} - -#[no_mangle] -pub unsafe extern "C" fn encrypt( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, - msg: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let msg_str = cchar_to_str!(msg); - let r = match rwallet.zencrypt(msg_str) { + let r = match rwallet.zencrypt(&msg) { Ok(v) => v, Err(err) => panic!("Problem encrypt: {:?}", err), }; - str_to_cchar!(r) + r } - -#[no_mangle] -pub unsafe extern "C" fn decrypt( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, - msg: *const c_char, -) -> *mut c_char { - let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); - let msg_str = cchar_to_str!(msg); - println!("{}", msg_str); - let r = match rwallet.zdecrypt(msg_str) { +#[wasm_bindgen] +pub fn wdecrypt( + msg_key: String, + master_key: String, + second_key: Option, + backup_key: Option, + msg: String, +) -> String { + let rwallet = Wallet { + msg_key, + master_key, + second_key, + backup_key, + }; + let r = match rwallet.zdecrypt(&msg) { Ok(v) => v, Err(err) => panic!("Problem encrypt: {:?}", err), }; - str_to_cchar!(r) + r } -unsafe fn convert_to_cwallet(rwallet: Wallet) -> CWallet { - let c_msgkey: *mut c_char = str_to_cchar!(rwallet.msg_key); - let c_masterkey: *mut c_char = str_to_cchar!(rwallet.master_key); - let c_secondkey = ostr_to_cchar!(rwallet.second_key); - let c_backupkey = ostr_to_cchar!(rwallet.backup_key); - - let cw = CWallet { - msg_key: c_msgkey, - master_key: c_masterkey, - second_key: c_secondkey, - backup_key: c_backupkey, - }; - cw +#[wasm_bindgen] +pub fn generate_qr(content: String) -> String { + QR::parse(&content) } -// unsafe fn convert_to_rwallet(cwallet: &CWallet) -> Wallet { -// let pmsg = cchar_to_string!(cwallet.msg_key); -// let pm = cchar_to_string!(cwallet.master_key); -// let second_key = cchar_to_ostring!(cwallet.second_key); -// let backup_key = cchar_to_ostring!(cwallet.backup_key); -// Wallet { -// msg_key: pmsg, -// master_key: pm, -// second_key: second_key, -// backup_key: backup_key -// } -// } - -unsafe fn generate_rwallet( - msg_key: *const c_char, - master_key: *const c_char, - second_key: *const c_char, - backup_key: *const c_char, -) -> Wallet { - let pmsg = cchar_to_string!(msg_key); - let pm = cchar_to_string!(master_key); - let second_key = cchar_to_ostring!(second_key); - let backup_key = cchar_to_ostring!(backup_key); - Wallet { - msg_key: pmsg, - master_key: pm, - second_key: second_key, - backup_key: backup_key, - } +#[wasm_bindgen] +pub fn str_deflate(content: String) -> String { + hex_to_base64(&content) +} + +#[wasm_bindgen] +pub fn str_inflate(content: String) -> String { + base64_to_hex(&content) } diff --git a/src/qr/mod.rs b/src/qr/mod.rs new file mode 100644 index 0000000..fa2f2bd --- /dev/null +++ b/src/qr/mod.rs @@ -0,0 +1 @@ +pub mod qr_code; diff --git a/src/qr/qr_code.rs b/src/qr/qr_code.rs new file mode 100644 index 0000000..c5503e8 --- /dev/null +++ b/src/qr/qr_code.rs @@ -0,0 +1,76 @@ +use qrcodegen::QrCode; +use qrcodegen::QrCodeEcc; +use std::fs::File; + +use std::io::Write; +use std::path::PathBuf; + +#[derive(Debug, Clone)] +pub struct QR { + pub content: String, +} + +impl QR { + pub fn parse(content: &String) -> String { + let qr = QrCode::encode_text(content, QrCodeEcc::Low).unwrap(); + QR::to_svg_string(&qr, 4) + } + // Returns a string of SVG code for an image depicting + // the given QR Code, with the given number of border modules. + // The string always uses Unix newlines (\n), regardless of the platform. + pub fn to_svg_string(qr: &QrCode, border: i32) -> String { + assert!(border >= 0, "Border must be non-negative"); + let mut result = String::new(); + result += "\n"; + result += "\n"; + let dimension = qr + .size() + .checked_add(border.checked_mul(2).unwrap()) + .unwrap(); + result += &format!( + "\n", dimension); + result += "\t\n"; + result += "\t\n"; + result += "\n"; + result + } + + pub fn print_qr(qr: &QrCode) { + let border: i32 = 4; + for y in -border..qr.size() + border { + for x in -border..qr.size() + border { + // 🀰 █ + let c: char = if qr.get_module(x, y) { '█' } else { ' ' }; + print!("{0}{0}", c); + } + println!(); + } + println!(); + } + + pub fn write_image(data: &String, file_path: &PathBuf) { + let file_name = "qr.svg"; + let mut path = file_path.clone(); + path.push(file_name); + println!("{}", path.as_path().display()); + let mut file: File = match File::create(&path) { + Err(why) => panic!("cannot create {}", why), + Ok(f) => f, + }; + match file.write_all(data.as_bytes()) { + Ok(_) => println!("write success: {}", file_name), + Err(why) => panic!("error write file: {}", why), + } + } +} diff --git a/src/utils/mod.rs b/src/utils/mod.rs new file mode 100644 index 0000000..d949670 --- /dev/null +++ b/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod str_utils; diff --git a/src/utils/str_utils.rs b/src/utils/str_utils.rs new file mode 100644 index 0000000..c701ebb --- /dev/null +++ b/src/utils/str_utils.rs @@ -0,0 +1,17 @@ +use base64::{engine::general_purpose, Engine as _}; + +pub fn hex_to_base64(content: &str) -> String { + let str_tmp = match hex::decode(content) { + Ok(v) => v, + Err(e) => panic!("error decode hex str: {}", e), + }; + general_purpose::STANDARD_NO_PAD.encode(&str_tmp) +} + +pub fn base64_to_hex(content: &str) -> String { + let str_tmp = match general_purpose::STANDARD_NO_PAD.decode(content) { + Ok(v) => v, + Err(e) => panic!("error decode base64 str: {}", e), + }; + hex::encode(&str_tmp) +}