Unverified Commit 90b6cdd4 authored by Maciej Hirsz's avatar Maciej Hirsz Committed by GitHub
Browse files

Fixed Rust dependencies + BIP39 support (#232)

* feat: Fixed Rust dependencies + BIP39 support

* feat: Reintroduce checking for extra whitespace

* fix: Update headers for iOS

* fix: Restore iOS simulator build pipeline (fixes #176)
parent 86c57c56
...@@ -40,14 +40,14 @@ Parity Signer was built to be used offline. The mobile device used to run the ap ...@@ -40,14 +40,14 @@ Parity Signer was built to be used offline. The mobile device used to run the ap
- `rustup` (tested on `rustup 1.16.0`) - `rustup` (tested on `rustup 1.16.0`)
- `rustc` (tested on `rustc 1.32.0 (9fda7c223 2019-01-16)`) - `rustc` (tested on `rustc 1.32.0 (9fda7c223 2019-01-16)`)
- `cargo` (tested on `cargo 1.32.0 (8610973aa 2019-01-02)`) - `cargo` (tested on `cargo 1.32.0 (8610973aa 2019-01-02)`)
- `android_ndk` (tested on `r13b`) - `android_ndk` (tested on `r19`)
- `Android Studio` (only for Android, tested on `Version 3.3`) - `Android Studio` (only for Android, tested on `Version 3.3`)
- `Xcode` (only for iOS, tested on `Version 9.4.1 (9F2000)`) - `Xcode` (only for iOS, tested on `Version 9.4.1 (9F2000)`)
- `$NDK_HOME` envarionment variable set to ndk home directory (eg. `/usr/local/opt/android-ndk`) - `$NDK_HOME` envarionment variable set to ndk home directory (eg. `/usr/local/opt/android-ndk`)
- `$JAVA_HOME` envarionment variable set to java home directory (eg. `/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home`) - `$JAVA_HOME` envarionment variable set to java home directory (eg. `/Library/Java/JavaVirtualMachines/jdk1.8.0_60.jdk/Contents/Home`)
- `$ANDROID_HOME` environment variable set to Android SDK directory (eg. `/home/your_username/Android/Sdk`)*. - `$ANDROID_HOME` environment variable set to Android SDK directory (eg. `/home/your_username/Android/Sdk`)*.
\* It's recommended to install **Android Studio** and use that to install the necessary build tools and SDKs for the Android version you want to test on. It's also the best way to test in the emulator. **DO NOT INSTALL NDK VIA ANDROID STUDIO** as that will install the latest version instead of `r13b`. \* It's recommended to install **Android Studio** and use that to install the necessary build tools and SDKs for the Android version you want to test on. It's also the best way to test in the emulator. **DO NOT INSTALL NDK VIA ANDROID STUDIO** as that will install the latest version. Make sure to get `r19` instead.
### Setup ### Setup
...@@ -124,3 +124,11 @@ adb shell input keyevent 82 ...@@ -124,3 +124,11 @@ adb shell input keyevent 82
(You can find `adb` binary in your local Android SDK folder under `platform-tools`, eg. `/home/your_username/Android/Sdk/platform-tools`) (You can find `adb` binary in your local Android SDK folder under `platform-tools`, eg. `/home/your_username/Android/Sdk/platform-tools`)
This should open a menu on the device. In that menu go to `Dev Settings` > `Debug server host & port for device`, and enter your local IP address with port 8081 (eg. `192.168.1.42:8081`). Restart the app, the error should disappear. This should open a menu on the device. In that menu go to `Dev Settings` > `Debug server host & port for device`, and enter your local IP address with port 8081 (eg. `192.168.1.42:8081`). Restart the app, the error should disappear.
#### Upgrading NDK from `r13b` to `r19`
1. [Download NDK `r19`](https://developer.android.com/ndk/downloads/), unpack it in a convenient location.
1. Update your `NDK_HOME` env variable to the absolute path of the NDK directory.
1. Edit `./android/local.properties` so that `ndk.dir` points to the absolute path to the NDK directory.
1. Remove old NDK build with `rm -rf ./NDK`.
1. Build the new NDK with `./create-ndk-standalone.sh`.
...@@ -44,11 +44,6 @@ public class EthkeyBridge extends ReactContextBaseJavaModule { ...@@ -44,11 +44,6 @@ public class EthkeyBridge extends ReactContextBaseJavaModule {
promise.resolve(ethkeyBrainwalletAddress(seed)); promise.resolve(ethkeyBrainwalletAddress(seed));
} }
@ReactMethod
public void brainWalletSecret(String seed, Promise promise) {
promise.resolve(ethkeyBrainwalletSecret(seed));
}
@ReactMethod @ReactMethod
public void brainWalletSign(String seed, String message, Promise promise) { public void brainWalletSign(String seed, String message, Promise promise) {
promise.resolve(ethkeyBrainwalletSign(seed, message)); promise.resolve(ethkeyBrainwalletSign(seed, message));
...@@ -80,8 +75,8 @@ public class EthkeyBridge extends ReactContextBaseJavaModule { ...@@ -80,8 +75,8 @@ public class EthkeyBridge extends ReactContextBaseJavaModule {
} }
@ReactMethod @ReactMethod
public void randomPhrase(int words, Promise promise) { public void randomPhrase(Promise promise) {
promise.resolve(ethkeyRandomPhrase(words)); promise.resolve(ethkeyRandomPhrase());
} }
@ReactMethod @ReactMethod
...@@ -99,13 +94,12 @@ public class EthkeyBridge extends ReactContextBaseJavaModule { ...@@ -99,13 +94,12 @@ public class EthkeyBridge extends ReactContextBaseJavaModule {
} }
private static native String ethkeyBrainwalletAddress(String seed); private static native String ethkeyBrainwalletAddress(String seed);
private static native String ethkeyBrainwalletSecret(String seed);
private static native String ethkeyBrainwalletSign(String seed, String message); private static native String ethkeyBrainwalletSign(String seed, String message);
private static native String ethkeyRlpItem(String data, int position); private static native String ethkeyRlpItem(String data, int position);
private static native String ethkeyKeccak(String data); private static native String ethkeyKeccak(String data);
private static native String ethkeyEthSign(String data); private static native String ethkeyEthSign(String data);
private static native String ethkeyBlockiesIcon(String seed); private static native String ethkeyBlockiesIcon(String seed);
private static native String ethkeyRandomPhrase(int words); private static native String ethkeyRandomPhrase();
private static native String ethkeyEncryptData(String data, String password); private static native String ethkeyEncryptData(String data, String password);
private static native String ethkeyDecryptData(String data, String password); private static native String ethkeyDecryptData(String data, String password);
} }
...@@ -21,7 +21,7 @@ class EthkeyBridge: NSObject { ...@@ -21,7 +21,7 @@ class EthkeyBridge: NSObject {
ethkey_keypair_destroy(keypair_ptr) ethkey_keypair_destroy(keypair_ptr)
resolve(address) resolve(address)
} }
@objc func brainWalletSecret(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func brainWalletSecret(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
let keypair_ptr = ethkey_keypair_brainwallet(&seed_ptr) let keypair_ptr = ethkey_keypair_brainwallet(&seed_ptr)
...@@ -33,7 +33,7 @@ class EthkeyBridge: NSObject { ...@@ -33,7 +33,7 @@ class EthkeyBridge: NSObject {
ethkey_keypair_destroy(keypair_ptr) ethkey_keypair_destroy(keypair_ptr)
resolve(secret) resolve(secret)
} }
@objc func brainWalletSign(_ seed: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func brainWalletSign(_ seed: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
print(seed, " + ", message) print(seed, " + ", message)
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
...@@ -47,7 +47,7 @@ class EthkeyBridge: NSObject { ...@@ -47,7 +47,7 @@ class EthkeyBridge: NSObject {
ethkey_keypair_destroy(keypair_ptr) ethkey_keypair_destroy(keypair_ptr)
resolve(signature) resolve(signature)
} }
@objc func rlpItem(_ rlp: String, position: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func rlpItem(_ rlp: String, position: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var rlp_ptr = rlp.asPtr() var rlp_ptr = rlp.asPtr()
var error: UInt32 = 0 var error: UInt32 = 0
...@@ -62,7 +62,7 @@ class EthkeyBridge: NSObject { ...@@ -62,7 +62,7 @@ class EthkeyBridge: NSObject {
reject("invalid rlp", nil, nil) reject("invalid rlp", nil, nil)
} }
} }
@objc func keccak(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func keccak(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
let hash_rust_str = keccak256(&data_ptr) let hash_rust_str = keccak256(&data_ptr)
...@@ -72,7 +72,7 @@ class EthkeyBridge: NSObject { ...@@ -72,7 +72,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(hash_rust_str) rust_string_destroy(hash_rust_str)
resolve(hash) resolve(hash)
} }
@objc func ethSign(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func ethSign(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
let hash_rust_str = eth_sign(&data_ptr) let hash_rust_str = eth_sign(&data_ptr)
...@@ -82,7 +82,7 @@ class EthkeyBridge: NSObject { ...@@ -82,7 +82,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(hash_rust_str) rust_string_destroy(hash_rust_str)
resolve(hash) resolve(hash)
} }
@objc func blockiesIcon(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func blockiesIcon(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
let icon_rust_str = blockies_icon(&seed_ptr) let icon_rust_str = blockies_icon(&seed_ptr)
...@@ -92,16 +92,16 @@ class EthkeyBridge: NSObject { ...@@ -92,16 +92,16 @@ class EthkeyBridge: NSObject {
rust_string_destroy(icon_rust_str) rust_string_destroy(icon_rust_str)
resolve(icon) resolve(icon)
} }
@objc func randomPhrase(_ words: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func randomPhrase(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
let words_rust_str = random_phrase(words) let words_rust_str = random_phrase()
let words_rust_str_ptr = rust_string_ptr(words_rust_str) let words_rust_str_ptr = rust_string_ptr(words_rust_str)
let words = String.fromStringPtr(ptr: words_rust_str_ptr!.pointee) let words = String.fromStringPtr(ptr: words_rust_str_ptr!.pointee)
rust_string_ptr_destroy(words_rust_str_ptr) rust_string_ptr_destroy(words_rust_str_ptr)
rust_string_destroy(words_rust_str) rust_string_destroy(words_rust_str)
resolve(words) resolve(words)
} }
@objc func encryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func encryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
var password_ptr = password.asPtr() var password_ptr = password.asPtr()
...@@ -112,7 +112,7 @@ class EthkeyBridge: NSObject { ...@@ -112,7 +112,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(encrypted_data_rust_str) rust_string_destroy(encrypted_data_rust_str)
resolve(encrypted_data) resolve(encrypted_data)
} }
@objc func decryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func decryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
var password_ptr = password.asPtr() var password_ptr = password.asPtr()
......
...@@ -10,11 +10,11 @@ import Foundation ...@@ -10,11 +10,11 @@ import Foundation
@objc(EthkeyBridge) @objc(EthkeyBridge)
class EthkeyBridge: NSObject { class EthkeyBridge: NSObject {
open static func requiresMainQueueSetup() -> Bool { open static func requiresMainQueueSetup() -> Bool {
return true; return true;
} }
@objc func brainWalletAddress(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func brainWalletAddress(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
let keypair_ptr = ethkey_keypair_brainwallet(&seed_ptr) let keypair_ptr = ethkey_keypair_brainwallet(&seed_ptr)
...@@ -26,19 +26,7 @@ class EthkeyBridge: NSObject { ...@@ -26,19 +26,7 @@ class EthkeyBridge: NSObject {
ethkey_keypair_destroy(keypair_ptr) ethkey_keypair_destroy(keypair_ptr)
resolve(address) resolve(address)
} }
@objc func brainWalletSecret(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var seed_ptr = seed.asPtr()
let keypair_ptr = ethkey_keypair_brainwallet(&seed_ptr)
let secret_rust_str = ethkey_keypair_secret(keypair_ptr)
let secret_rust_str_ptr = rust_string_ptr(secret_rust_str)
let secret = String.fromStringPtr(ptr: secret_rust_str_ptr!.pointee)
rust_string_ptr_destroy(secret_rust_str_ptr)
rust_string_destroy(secret_rust_str)
ethkey_keypair_destroy(keypair_ptr)
resolve(secret)
}
@objc func brainWalletSign(_ seed: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func brainWalletSign(_ seed: String, message: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
print(seed, " + ", message) print(seed, " + ", message)
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
...@@ -52,7 +40,7 @@ class EthkeyBridge: NSObject { ...@@ -52,7 +40,7 @@ class EthkeyBridge: NSObject {
ethkey_keypair_destroy(keypair_ptr) ethkey_keypair_destroy(keypair_ptr)
resolve(signature) resolve(signature)
} }
@objc func rlpItem(_ rlp: String, position: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func rlpItem(_ rlp: String, position: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var rlp_ptr = rlp.asPtr() var rlp_ptr = rlp.asPtr()
var error: UInt32 = 0 var error: UInt32 = 0
...@@ -67,7 +55,7 @@ class EthkeyBridge: NSObject { ...@@ -67,7 +55,7 @@ class EthkeyBridge: NSObject {
reject("invalid rlp", nil, nil) reject("invalid rlp", nil, nil)
} }
} }
@objc func keccak(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func keccak(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
let hash_rust_str = keccak256(&data_ptr) let hash_rust_str = keccak256(&data_ptr)
...@@ -77,7 +65,7 @@ class EthkeyBridge: NSObject { ...@@ -77,7 +65,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(hash_rust_str) rust_string_destroy(hash_rust_str)
resolve(hash) resolve(hash)
} }
@objc func ethSign(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func ethSign(_ data: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
let hash_rust_str = eth_sign(&data_ptr) let hash_rust_str = eth_sign(&data_ptr)
...@@ -87,7 +75,7 @@ class EthkeyBridge: NSObject { ...@@ -87,7 +75,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(hash_rust_str) rust_string_destroy(hash_rust_str)
resolve(hash) resolve(hash)
} }
@objc func blockiesIcon(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func blockiesIcon(_ seed: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var seed_ptr = seed.asPtr() var seed_ptr = seed.asPtr()
let icon_rust_str = blockies_icon(&seed_ptr) let icon_rust_str = blockies_icon(&seed_ptr)
...@@ -97,16 +85,16 @@ class EthkeyBridge: NSObject { ...@@ -97,16 +85,16 @@ class EthkeyBridge: NSObject {
rust_string_destroy(icon_rust_str) rust_string_destroy(icon_rust_str)
resolve(icon) resolve(icon)
} }
@objc func randomPhrase(_ words: UInt32, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func randomPhrase(resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
let words_rust_str = random_phrase(words) let words_rust_str = random_phrase()
let words_rust_str_ptr = rust_string_ptr(words_rust_str) let words_rust_str_ptr = rust_string_ptr(words_rust_str)
let words = String.fromStringPtr(ptr: words_rust_str_ptr!.pointee) let words = String.fromStringPtr(ptr: words_rust_str_ptr!.pointee)
rust_string_ptr_destroy(words_rust_str_ptr) rust_string_ptr_destroy(words_rust_str_ptr)
rust_string_destroy(words_rust_str) rust_string_destroy(words_rust_str)
resolve(words) resolve(words)
} }
@objc func encryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func encryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
var password_ptr = password.asPtr() var password_ptr = password.asPtr()
...@@ -117,7 +105,7 @@ class EthkeyBridge: NSObject { ...@@ -117,7 +105,7 @@ class EthkeyBridge: NSObject {
rust_string_destroy(encrypted_data_rust_str) rust_string_destroy(encrypted_data_rust_str)
resolve(encrypted_data) resolve(encrypted_data)
} }
@objc func decryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void { @objc func decryptData(_ data: String, password: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
var data_ptr = data.asPtr() var data_ptr = data.asPtr()
var password_ptr = password.asPtr() var password_ptr = password.asPtr()
......
This diff is collapsed.
...@@ -3,17 +3,23 @@ name = "signer" ...@@ -3,17 +3,23 @@ name = "signer"
version = "0.1.0" version = "0.1.0"
authors = ["debris <marek.kotewicz@gmail.com>"] authors = ["debris <marek.kotewicz@gmail.com>"]
build = "build.rs" build = "build.rs"
edition = "2018"
[dependencies] [dependencies]
base64 = "0.10.1"
blockies = "0.2"
ethsign = { version = "0.6.1", default-features = false, features = ["pure-rust"] }
jni = { version = "0.10.2", default-features = false, optional = true }
libc = "0.2" libc = "0.2"
rustc-serialize = "0.3"
ethkey = { git = "https://github.com/paritytech/parity-ethereum" }
ethstore = { git = "https://github.com/paritytech/parity-ethereum" }
rlp = { version = "0.3.0", features = ["ethereum"] } rlp = { version = "0.3.0", features = ["ethereum"] }
tiny-keccak = "1.1" rustc-hex = "2.0.1"
blockies = "0.2" schnorrkel = "0.0.0"
parity-wordlist = { git = "https://github.com/paritytech/wordlist" } serde = "1.0"
jni = { git = "https://github.com/prevoty/jni-rs", default-features = false, optional = true } serde_json = "1.0"
sha2 = "0.8"
tiny-bip39 = { version = "0.6.1", default-features = false }
tiny-hderive = "0.1"
tiny-keccak = "1.4"
[lib] [lib]
name = "signer" name = "signer"
...@@ -21,7 +27,3 @@ crate-type = ["staticlib", "cdylib"] ...@@ -21,7 +27,3 @@ crate-type = ["staticlib", "cdylib"]
[features] [features]
default = ["jni"] default = ["jni"]
# https://github.com/DaGenix/rust-crypto/issues/383
[replace]
"rust-crypto:0.2.36" = { git = "https://github.com/debris/rust-crypto" }
NDK_STANDALONE = $(shell pwd)/../../NDK NDK_STANDALONE = $(shell pwd)/../../NDK
ARCHS_IOS = armv7-apple-ios armv7s-apple-ios aarch64-apple-ios ARCHS_IOS = i386-apple-ios x86_64-apple-ios armv7-apple-ios armv7s-apple-ios aarch64-apple-ios
ARCHS_ANDROID = aarch64-linux-android armv7-linux-androideabi i686-linux-android ARCHS_ANDROID = aarch64-linux-android armv7-linux-androideabi i686-linux-android
LIB=libsigner.a LIB=libsigner.a
......
...@@ -49,9 +49,6 @@ void ethkey_keypair_destroy(struct keypair_ptr* keypair); ...@@ -49,9 +49,6 @@ void ethkey_keypair_destroy(struct keypair_ptr* keypair);
// creates new brainwallet keypair from seed // creates new brainwallet keypair from seed
struct keypair_ptr* ethkey_keypair_brainwallet(const struct rust_string_ptr* seed); struct keypair_ptr* ethkey_keypair_brainwallet(const struct rust_string_ptr* seed);
// returns keypair secret
struct rust_string* ethkey_keypair_secret(const struct keypair_ptr* keypair);
// return keypair address // return keypair address
struct rust_string* ethkey_keypair_address(const struct keypair_ptr* keypair); struct rust_string* ethkey_keypair_address(const struct keypair_ptr* keypair);
...@@ -75,7 +72,7 @@ struct rust_string* blockies_icon(const struct rust_string_ptr* blockies_seed); ...@@ -75,7 +72,7 @@ struct rust_string* blockies_icon(const struct rust_string_ptr* blockies_seed);
// random phrase ffi // random phrase ffi
struct rust_string* random_phrase(const uint32_t words); struct rust_string* random_phrase();
// data encryption ffi // data encryption ffi
......
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Ethereum key utils
use bip39::{Mnemonic, Seed, Language};
use ethsign::{SecretKey, PublicKey, Error};
use tiny_hderive::bip32::ExtendedPrivKey;
use tiny_keccak::keccak256;
pub struct KeyPair {
secret: SecretKey,
public: PublicKey,
}
impl KeyPair {
pub fn from_secret(secret: SecretKey) -> KeyPair {
let public = secret.public();
KeyPair {
secret,
public,
}
}
pub fn from_parity_phrase(phrase: &str) -> KeyPair {
let mut secret = keccak256(phrase.as_bytes());
let mut i = 0;
loop {
secret = keccak256(&secret);
match i > 16384 {
false => i += 1,
true => {
if let Ok(pair) = SecretKey::from_raw(&secret).map(KeyPair::from_secret) {
if pair.public().address()[0] == 0 {
return pair
}
}
},
}
}
}
pub fn from_bip39_phrase(phrase: &str) -> Option<KeyPair> {
let mnemonic = Mnemonic::from_phrase(phrase, Language::English).ok()?;
let seed = Seed::new(&mnemonic, "");
let epriv = ExtendedPrivKey::derive(seed.as_bytes(), "m/44'/60'/0'/0/0").ok()?;
SecretKey::from_raw(&epriv.secret()).map(KeyPair::from_secret).ok()
}
pub fn from_auto_phrase(phrase: &str) -> KeyPair {
Self::from_bip39_phrase(phrase)
.unwrap_or_else(|| Self::from_parity_phrase(phrase))
}
pub fn secret(&self) -> &SecretKey {
&self.secret
}
pub fn public(&self) -> &PublicKey {
&self.public
}
pub fn address(&self) -> &[u8; 20] {
self.public().address()
}
pub fn sign(&self, message: &[u8]) -> Result<[u8; 65], Error> {
let signature = self.secret().sign(message)?;
let mut data: [u8; 65] = [0; 65];
data[0..32].copy_from_slice(&signature.r);
data[32..64].copy_from_slice(&signature.s);
data[64] = signature.v;
Ok(data)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bip39_phrase() {
let phrase = "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside";
let expected_address = b"\x63\xF9\xA9\x2D\x8D\x61\xb4\x8a\x9f\xFF\x8d\x58\x08\x04\x25\xA3\x01\x2d\x05\xC8";
let keypair = KeyPair::from_bip39_phrase(phrase).unwrap();
assert_eq!(keypair.address(), expected_address);
}
#[test]
fn test_parity_phrase() {
let phrase = "this is sparta";
let expected_address = b"\x00\x6E\x27\xB6\xA7\x2E\x1f\x34\xC6\x26\x76\x2F\x3C\x47\x61\x54\x7A\xff\x14\x21";
let keypair = KeyPair::from_parity_phrase(phrase);
assert_eq!(keypair.address(), expected_address);
}
#[test]
fn test_parity_empty_phrase() {
let phrase = "";
let expected_address = b"\x00\xa3\x29\xc0\x64\x87\x69\xA7\x3a\xfA\xc7\xF9\x38\x1E\x08\xFB\x43\xdB\xEA\x72";
let keypair = KeyPair::from_parity_phrase(phrase);
assert_eq!(keypair.address(), expected_address);
}
#[test]
fn test_auto_bip39_phrase() {
let phrase = "panda eyebrow bullet gorilla call smoke muffin taste mesh discover soft ostrich alcohol speed nation flash devote level hobby quick inner drive ghost inside";
let expected_address = b"\x63\xF9\xA9\x2D\x8D\x61\xb4\x8a\x9f\xFF\x8d\x58\x08\x04\x25\xA3\x01\x2d\x05\xC8";
let keypair = KeyPair::from_auto_phrase(phrase);
assert_eq!(keypair.address(), expected_address);
}
#[test]
fn test_auto_parity_phrase() {
let phrase = "this is sparta";
let expected_address = b"\x00\x6E\x27\xB6\xA7\x2E\x1f\x34\xC6\x26\x76\x2F\x3C\x47\x61\x54\x7A\xff\x14\x21";
let keypair = KeyPair::from_auto_phrase(phrase);
assert_eq!(keypair