add wallet code
This commit is contained in:
parent
0381fd1d76
commit
8c78a366cc
1954
Cargo.lock
generated
Normal file
1954
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
17
Cargo.toml
17
Cargo.toml
@ -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
20
scripts/android_build.sh
Executable 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
7
scripts/install_targets.sh
Executable 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
17
scripts/ios_build.sh
Executable 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
107
src/lib.rs
Normal 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
1
src/wallet/mod.rs
Normal file
@ -0,0 +1 @@
|
|||||||
|
pub mod wallet_impl;
|
59
src/wallet/wallet_impl.rs
Normal file
59
src/wallet/wallet_impl.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user