add wallet code

This commit is contained in:
cebgcontract 2022-09-23 14:32:35 +08:00
parent 0381fd1d76
commit 8c78a366cc
8 changed files with 2182 additions and 0 deletions

1954
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -4,5 +4,22 @@ version = "0.1.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "rustywallet"
# this is needed to build for iOS and Android.
crate-type = ["staticlib", "dylib"]
# this dependency is only needed for Android.
[target.'cfg(target_os = "android")'.dependencies]
jni = { version = "0.19.0", default-features = false }
[dependencies] [dependencies]
anyhow = "1.0.65"
openssl = { version = "0.10.41", features = ["vendored"] }
secp256k1 = { version = "0.24.0", features = ["rand"] }
serde = { version = "1.0.145", features = ["derive"]}
serde_json = "1.0.85"
shamir_secret_sharing = "0.1.1"
tiny-keccak = "1.5"
web3 = "0.18.0"

20
scripts/android_build.sh Executable file
View File

@ -0,0 +1,20 @@
#!/usr/bin/env bash
# set the version to use the library
min_ver=22
# verify before executing this that you have the proper targets installed
cargo ndk -t armeabi-v7a -t arm64-v8a -t x86_64 -p ${min_ver} build --release
# moving libraries to the android project
jniLibs=./android/rusty-android-lib/src/main/jniLibs
libName=librustywallet.so
rm -rf ${jniLibs}
mkdir ${jniLibs}
mkdir ${jniLibs}/arm64-v8a
mkdir ${jniLibs}/armeabi-v7a
mkdir ${jniLibs}/x86_64
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}

7
scripts/install_targets.sh Executable file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
# Android targets
rustup target add aarch64-linux-android armv7-linux-androideabi i686-linux-android x86_64-linux-android
# iOS targets
rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios

17
scripts/ios_build.sh Executable file
View File

@ -0,0 +1,17 @@
#!/usr/bin/env bash
# building
cbindgen src/lib.rs -l c > rustywallet.h
cargo lipo --release
# moving files to the ios project
proj=ios
inc=../${proj}/include
libs=../${proj}/libs
rm -rf ${inc} ${libs}
mkdir ${inc}
mkdir ${libs}
cp rustywallet.h ${inc}
cp target/universal/release/librustywallet.a ${libs}

107
src/lib.rs Normal file
View File

@ -0,0 +1,107 @@
// lib.rs
//
// 此部分代码主要负责Rust-C两侧的数据内存结构转换提供了C侧的函数接口。注意命名规范
// 在C侧使用时凡是函数名带有 '_cwallet'的,调用过之后都必须用'free_cwallet'释放内存,
// 否则导致内存泄漏
//
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
mod wallet;
use wallet_impl::Wallet;
use crate::wallet::*;
// #[cfg(target_os = "android")]
// mod android;
#[repr(C)]
pub struct CWallet {
pub public_key: *mut c_char,
pub private_key: *mut c_char,
pub public_addr: *mut c_char,
}
#[no_mangle]
pub unsafe extern "C" fn generate_cwallet() -> CWallet {
println!("generating wallet");
let (secret_key, pub_key) = wallet_impl::generate_keypair();
// 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);
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));
}
#[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),
};
}
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();
//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,
};
//println!("crypto_wallet addr: {}", CStr::from_ptr(cw.public_addr).to_str().unwrap());
cw
}
unsafe fn convert_to_rwallet(cwallet: &CWallet) -> Wallet {
let a = CStr::from_ptr(cwallet.public_addr);
let pa = a.to_str().unwrap();
let pk = CStr::from_ptr(cwallet.public_key);
let ppk = pk.to_str().unwrap();
let sk = CStr::from_ptr(cwallet.private_key);
let psk = sk.to_str().unwrap();
Wallet {
secret_key: psk.to_string(),
public_key: ppk.to_string(),
public_address: pa.to_string(),
}
}

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

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

59
src/wallet/wallet_impl.rs Normal file
View File

@ -0,0 +1,59 @@
use anyhow::Result;
use secp256k1::rand::rngs::OsRng;
use secp256k1::{PublicKey, SecretKey};
use serde::{Deserialize, Serialize};
use std::io::BufWriter;
use std::{fs::OpenOptions, io::BufReader};
use tiny_keccak::keccak256;
use web3::types::Address;
pub fn generate_keypair() -> (SecretKey, PublicKey) {
let secp = secp256k1::Secp256k1::new();
secp.generate_keypair(&mut OsRng)
}
pub fn public_key_address(public_key: &PublicKey) -> Address {
let public_key = public_key.serialize_uncompressed();
debug_assert_eq!(public_key[0], 0x04);
let hash = keccak256(&public_key[1..]);
Address::from_slice(&hash[12..])
}
#[derive(Serialize, Deserialize, Debug)]
pub struct Wallet {
pub secret_key: String,
pub public_key: String,
pub public_address: String,
}
impl Wallet {
pub fn new(secret_key: &SecretKey, public_key: &PublicKey) -> Self {
let addr: Address = public_key_address(&public_key);
Wallet {
secret_key: format!("{:?}", secret_key),
public_key: public_key.to_string(),
public_address: format!("{:?}", addr),
}
}
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 retrieve_keys(file_path: &str) -> Result<Wallet> {
let file = OpenOptions::new().read(true).open(file_path)?;
let buf_reader = BufReader::new(file);
let wallet: Wallet = serde_json::from_reader(buf_reader)?;
Ok(wallet)
}
}