增加wasm生成svg二维码的方法, 增加hex转base64的方法

This commit is contained in:
zhl 2023-03-01 14:22:06 +08:00
parent 0c35f61d70
commit 6ec2c56005
10 changed files with 269 additions and 243 deletions

16
Cargo.lock generated
View File

@ -67,6 +67,12 @@ version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
[[package]] [[package]]
name = "bitcoin_hashes" name = "bitcoin_hashes"
version = "0.11.0" version = "0.11.0"
@ -397,7 +403,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1"
dependencies = [ dependencies = [
"arrayref", "arrayref",
"base64", "base64 0.13.1",
"digest 0.9.0", "digest 0.9.0",
"hmac-drbg", "hmac-drbg",
"libsecp256k1-core", "libsecp256k1-core",
@ -565,6 +571,12 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "qrcodegen"
version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4339fc7a1021c9c1621d87f5e3505f2805c8c105420ba2f2a4df86814590c142"
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.21" version = "1.0.21"
@ -649,11 +661,13 @@ name = "rustwallet"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"base64 0.21.0",
"bitcoin_hashes", "bitcoin_hashes",
"ecies", "ecies",
"getrandom", "getrandom",
"hex", "hex",
"primitive-types", "primitive-types",
"qrcodegen",
"secp256k1", "secp256k1",
"serde", "serde",
"serde_json", "serde_json",

View File

@ -27,4 +27,6 @@ getrandom = { version = "0.2.7", features = ["js"]}
ecies = {version = "0.2", default-features = false, features = ["pure"]} ecies = {version = "0.2", default-features = false, features = ["pure"]}
#[target.'cfg(target_arch = "wasm32")'.dependencies] #[target.'cfg(target_arch = "wasm32")'.dependencies]
wasm-bindgen = "0.2.83" wasm-bindgen = "0.2.83"
qrcodegen = "1.8.0"
base64 = "0.21.0"

View File

@ -5,7 +5,7 @@
// //
use rustwallet::{ 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::ffi::{CStr, CString};
use std::os::raw::c_char; use std::os::raw::c_char;
@ -33,8 +33,7 @@ macro_rules! cchar_to_str {
macro_rules! str_to_cchar { macro_rules! str_to_cchar {
($p1:expr) => {{ ($p1:expr) => {{
let msgkey = CString::new($p1).unwrap(); let c_msgkey = $p1.to_string();
let c_msgkey: *mut c_char = msgkey.into_raw();
c_msgkey c_msgkey
}}; }};
} }
@ -58,40 +57,42 @@ fn main() {
let key1 = ""; let key1 = "";
let key2 = "cd00eb0126aeed39762579ce94c90a04695ad17fbd5e79aa4e9fc4a34ba32a5"; let key2 = "cd00eb0126aeed39762579ce94c90a04695ad17fbd5e79aa4e9fc4a34ba32a5";
let private_key = generate_sec_key( let private_key = generate_sec_key(
str_to_cchar!(msg), msg.to_string(),
str_to_cchar!(key0), key0.to_string(),
str_to_cchar!(key1), str_to_cchar!(key1),
str_to_cchar!(key2), 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!(msg),
str_to_cchar!(key0), str_to_cchar!(key0),
str_to_cchar!(key1), Option(key1),
str_to_cchar!(key2), str_to_cchar!(key2),
); );
print_cchar!(address2);
println!("address=> {}", address2);
let message = "helloword"; let message = "helloword";
let msg_encrypt = encrypt( let msg_encrypt = wencrypt(
str_to_cchar!(msg), str_to_cchar!(msg),
str_to_cchar!(key0), str_to_cchar!(key0),
str_to_cchar!(key1), str_to_cchar!(key1),
str_to_cchar!(key2), str_to_cchar!(key2),
str_to_cchar!(message), 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!(msg),
str_to_cchar!(key0), str_to_cchar!(key0),
str_to_cchar!(key1), str_to_cchar!(key1),
str_to_cchar!(key2), str_to_cchar!(key2),
msg_encrypt, msg_encrypt,
); );
print_cchar!(msg_decrypt);
let msg_decrypt = cchar_to_str!(msg_decrypt); println!("msg_decrypt=> {}", msg_decrypt);
assert_eq!(message, msg_decrypt);
// let tmp_cwallet2 = restore_wallet(&tmp_cwallet); // let tmp_cwallet2 = restore_wallet(&tmp_cwallet);
// let address3 = get_address(&tmp_cwallet2); // let address3 = get_address(&tmp_cwallet2);
// print_cchar!(address3); // print_cchar!(address3);
@ -120,10 +121,3 @@ fn main() {
// free_cwallet(fetched); // 对应 fetch_wallet() // 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);
}

View File

@ -46,3 +46,15 @@ char *sign_for_tran(const char *msg_key,
const char *second_key, const char *second_key,
const char *backup_key, const char *backup_key,
const char *msg); 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);

View File

@ -10,17 +10,13 @@ libName=librustwallet.a
rm -rf ${jniLibs} rm -rf ${jniLibs}
mkdir ${jniLibs} # mkdir ${jniLibs}
mkdir ${jniLibs}/arm64-v8a # mkdir ${jniLibs}/arm64-v8a
mkdir ${jniLibs}/armeabi-v7a # mkdir ${jniLibs}/armeabi-v7a
mkdir ${jniLibs}/x86_64 # mkdir ${jniLibs}/x86_64
mkdir ${jniLibs}/x86 # mkdir ${jniLibs}/x86
targetBase=~/Documents/workspace/cocos/cocos2d-x/external/android targetBase=~/Documents/workspace/crypto/cocos_js/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}
cp target/aarch64-linux-android/release/${libName} ${targetBase}/arm64-v8a/${libName} cp target/aarch64-linux-android/release/${libName} ${targetBase}/arm64-v8a/${libName}
cp target/armv7-linux-androideabi/release/${libName} ${targetBase}/armeabi-v7a/${libName} cp target/armv7-linux-androideabi/release/${libName} ${targetBase}/armeabi-v7a/${libName}

View File

@ -5,73 +5,18 @@
// 否则导致内存泄漏 // 否则导致内存泄漏
// //
use std::ffi::{CStr, CString}; use qr::qr_code::QR;
use std::os::raw::c_char; use utils::str_utils::{base64_to_hex, hex_to_base64};
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
mod qr;
mod wallet; mod wallet;
use wallet_impl::Wallet; use wallet_impl::Wallet;
mod utils;
use crate::wallet::*; 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] #[wasm_bindgen]
extern "C" { extern "C" {
// Use `js_namespace` here to bind `console.log(..)` instead of just // 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())) ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
} }
#[no_mangle] #[wasm_bindgen]
pub unsafe extern "C" fn new_wallet(msg: *const c_char) -> CWallet { pub fn new_wallet(msg_key: String) -> String {
let str = cchar_to_str!(msg); let rust_wallet = wallet_impl::Wallet::new(&msg_key);
let rust_wallet = wallet_impl::Wallet::new(str); rust_wallet.get_public_key().to_string()
convert_to_cwallet(rust_wallet)
} }
#[no_mangle] #[wasm_bindgen]
pub unsafe extern "C" fn reset_wallet( pub fn get_public_key(
msg_key: *const c_char, msg_key: String,
master_key: *const c_char, master_key: String,
second_key: *const c_char, second_key: Option<String>,
backup_key: *const c_char, backup_key: Option<String>,
) -> CWallet { ) -> String {
let rust_wallet = generate_rwallet(msg_key, master_key, second_key, backup_key); let rwallet = Wallet {
let rust_wallet2 = rust_wallet.reset_wallet(); msg_key,
convert_to_cwallet(rust_wallet2) master_key,
second_key,
backup_key,
};
rwallet.get_public_key().to_string()
} }
#[no_mangle] #[wasm_bindgen]
pub unsafe extern "C" fn free_cwallet(cw: CWallet) { pub fn generate_sec_key(
drop(CString::from_raw(cw.msg_key)); msg_key: String,
drop(CString::from_raw(cw.master_key)); master_key: String,
drop(CString::from_raw(cw.second_key)); second_key: Option<String>,
drop(CString::from_raw(cw.backup_key)); backup_key: Option<String>,
) -> String {
let rwallet = Wallet {
msg_key,
master_key,
second_key,
backup_key,
};
rwallet.generate_sec_key()
} }
#[no_mangle] #[wasm_bindgen]
pub unsafe extern "C" fn get_address( pub fn sign(
msg_key: *const c_char, msg_key: String,
master_key: *const c_char, master_key: String,
second_key: *const c_char, second_key: Option<String>,
backup_key: *const c_char, backup_key: Option<String>,
) -> *mut c_char { msg: String,
let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); ) -> String {
let address = rwallet.get_address(); let rwallet = Wallet {
let address_str = format!("{:?}", address); msg_key,
let c_address = CString::new(address_str).unwrap(); master_key,
c_address.into_raw() 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<String>,
backup_key: Option<String>,
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] #[wasm_bindgen]
@ -157,133 +145,58 @@ pub fn wget_address(
address_str address_str
} }
#[no_mangle] #[wasm_bindgen]
pub unsafe extern "C" fn generate_sec_key( pub fn wencrypt(
msg_key: *const c_char, msg_key: String,
master_key: *const c_char, master_key: String,
second_key: *const c_char, second_key: Option<String>,
backup_key: *const c_char, backup_key: Option<String>,
) -> *mut c_char { msg: String,
let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); ) -> String {
let s_key = rwallet.generate_sec_key(); let rwallet = Wallet {
let cs_key = CString::new(s_key).unwrap(); msg_key,
cs_key.into_raw() master_key,
} second_key,
backup_key,
#[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),
}; };
str_to_cchar!(r) let r = match rwallet.zencrypt(&msg) {
}
#[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) {
Ok(v) => v, Ok(v) => v,
Err(err) => panic!("Problem encrypt: {:?}", err), Err(err) => panic!("Problem encrypt: {:?}", err),
}; };
str_to_cchar!(r) r
} }
#[wasm_bindgen]
#[no_mangle] pub fn wdecrypt(
pub unsafe extern "C" fn decrypt( msg_key: String,
msg_key: *const c_char, master_key: String,
master_key: *const c_char, second_key: Option<String>,
second_key: *const c_char, backup_key: Option<String>,
backup_key: *const c_char, msg: String,
msg: *const c_char, ) -> String {
) -> *mut c_char { let rwallet = Wallet {
let rwallet = generate_rwallet(msg_key, master_key, second_key, backup_key); msg_key,
let msg_str = cchar_to_str!(msg); master_key,
println!("{}", msg_str); second_key,
let r = match rwallet.zdecrypt(msg_str) { backup_key,
};
let r = match rwallet.zdecrypt(&msg) {
Ok(v) => v, Ok(v) => v,
Err(err) => panic!("Problem encrypt: {:?}", err), Err(err) => panic!("Problem encrypt: {:?}", err),
}; };
str_to_cchar!(r) r
} }
unsafe fn convert_to_cwallet(rwallet: Wallet) -> CWallet { #[wasm_bindgen]
let c_msgkey: *mut c_char = str_to_cchar!(rwallet.msg_key); pub fn generate_qr(content: String) -> String {
let c_masterkey: *mut c_char = str_to_cchar!(rwallet.master_key); QR::parse(&content)
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
} }
// unsafe fn convert_to_rwallet(cwallet: &CWallet) -> Wallet { #[wasm_bindgen]
// let pmsg = cchar_to_string!(cwallet.msg_key); pub fn str_deflate(content: String) -> String {
// let pm = cchar_to_string!(cwallet.master_key); hex_to_base64(&content)
// 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( #[wasm_bindgen]
msg_key: *const c_char, pub fn str_inflate(content: String) -> String {
master_key: *const c_char, base64_to_hex(&content)
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,
}
} }

1
src/qr/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod qr_code;

76
src/qr/qr_code.rs Normal file
View File

@ -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 += "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
result += "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n";
let dimension = qr
.size()
.checked_add(border.checked_mul(2).unwrap())
.unwrap();
result += &format!(
"<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {0} {0}\" stroke=\"none\">\n", dimension);
result += "\t<rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/>\n";
result += "\t<path d=\"";
for y in 0..qr.size() {
for x in 0..qr.size() {
if qr.get_module(x, y) {
if x != 0 || y != 0 {
result += " ";
}
result += &format!("M{},{}h1v1h-1z", x + border, y + border);
}
}
}
result += "\" fill=\"#000000\"/>\n";
result += "</svg>\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),
}
}
}

1
src/utils/mod.rs Normal file
View File

@ -0,0 +1 @@
pub mod str_utils;

17
src/utils/str_utils.rs Normal file
View File

@ -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)
}