Assorted improvements for ethstore and ethkey (#6961)

* Testing many passwords for presale wallet.

* Add multiple threads.

* WiP: ethkey brain wallets recover.

* Refactor pre-sale-wallet cracking.

* Generate in multiple threads. Brain with prefix.

* Validate bain wallet phrase.

* Brain wallet recovery.

* Self-review fixes.

* Fix tests.

* More docs.

* Bump versions.

* Remove cmd_find from borked merge.

* Update wasm submodules.

* Use threadpool.
This commit is contained in:
Tomasz Drwięga 2017-12-01 09:40:07 +01:00 committed by Svyatoslav Nikolsky
parent d1bf0e0e62
commit 7663451116
16 changed files with 674 additions and 119 deletions

77
Cargo.lock generated
View File

@ -398,6 +398,11 @@ name = "dtoa"
version = "0.4.2" version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "edit-distance"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "either" name = "either"
version = "1.1.0" version = "1.1.0"
@ -488,8 +493,8 @@ dependencies = [
"ethcore-stratum 1.9.0", "ethcore-stratum 1.9.0",
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethjson 0.1.0", "ethjson 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"ethstore 0.1.0", "ethstore 0.2.0",
"evm 0.1.0", "evm 0.1.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"hardware-wallet 1.9.0", "hardware-wallet 1.9.0",
@ -512,7 +517,7 @@ dependencies = [
"migration 0.1.0", "migration 0.1.0",
"native-contracts 0.1.0", "native-contracts 0.1.0",
"num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-machine 0.1.0", "parity-machine 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"patricia-trie 0.1.0", "patricia-trie 0.1.0",
@ -645,7 +650,7 @@ dependencies = [
"ethcore-logger 1.9.0", "ethcore-logger 1.9.0",
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak-hash 0.1.0", "keccak-hash 0.1.0",
@ -677,7 +682,7 @@ dependencies = [
"ethcore-logger 1.9.0", "ethcore-logger 1.9.0",
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"futures-cpupool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.10.13 (registry+https://github.com/rust-lang/crates.io-index)",
@ -757,7 +762,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)",
"ethcore-bigint 0.2.1", "ethcore-bigint 0.2.1",
"ethkey 0.2.0", "ethkey 0.3.0",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -777,12 +782,15 @@ dependencies = [
[[package]] [[package]]
name = "ethkey" name = "ethkey"
version = "0.2.0" version = "0.3.0"
dependencies = [ dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)", "eth-secp256k1 0.5.7 (git+https://github.com/paritytech/rust-secp256k1)",
"ethcore-bigint 0.2.1", "ethcore-bigint 0.2.1",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -794,24 +802,27 @@ name = "ethkey-cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethkey 0.2.0", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ethkey 0.3.0",
"panic_hook 0.1.0", "panic_hook 0.1.0",
"parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
name = "ethstore" name = "ethstore"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"ethcore-bigint 0.2.1", "ethcore-bigint 0.2.1",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-wordlist 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
"rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)",
@ -830,8 +841,10 @@ name = "ethstore-cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ethstore 0.1.0", "ethstore 0.2.0",
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_hook 0.1.0", "panic_hook 0.1.0",
"parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
@ -850,7 +863,7 @@ dependencies = [
"ethcore-light 1.9.0", "ethcore-light 1.9.0",
"ethcore-network 1.9.0", "ethcore-network 1.9.0",
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "heapsize 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)", "ipnetwork 0.12.7 (registry+https://github.com/rust-lang/crates.io-index)",
"keccak-hash 0.1.0", "keccak-hash 0.1.0",
@ -970,7 +983,7 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1013,7 +1026,7 @@ name = "hardware-wallet"
version = "1.9.0" version = "1.9.0"
dependencies = [ dependencies = [
"ethcore-bigint 0.2.1", "ethcore-bigint 0.2.1",
"ethkey 0.2.0", "ethkey 0.3.0",
"hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)", "hidapi 0.3.1 (git+https://github.com/paritytech/hidapi-rs)",
"libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)", "libusb 0.3.0 (git+https://github.com/paritytech/libusb-rs)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1095,7 +1108,7 @@ dependencies = [
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)",
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1817,7 +1830,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "num_cpus" name = "num_cpus"
version = "1.6.2" version = "1.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1920,7 +1933,7 @@ dependencies = [
"ethcore-secretstore 1.0.0", "ethcore-secretstore 1.0.0",
"ethcore-stratum 1.9.0", "ethcore-stratum 1.9.0",
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"ethsync 1.9.0", "ethsync 1.9.0",
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1936,7 +1949,7 @@ dependencies = [
"migration 0.1.0", "migration 0.1.0",
"node-filter 1.9.0", "node-filter 1.9.0",
"node-health 0.1.0", "node-health 0.1.0",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"panic_hook 0.1.0", "panic_hook 0.1.0",
"parity-dapps 1.9.0", "parity-dapps 1.9.0",
@ -2074,7 +2087,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"ethcore 1.9.0", "ethcore 1.9.0",
"ethcore-io 1.9.0", "ethcore-io 1.9.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"kvdb 0.1.0", "kvdb 0.1.0",
"kvdb-memorydb 0.1.0", "kvdb-memorydb 0.1.0",
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2119,8 +2132,8 @@ dependencies = [
"ethcore-util 1.9.0", "ethcore-util 1.9.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethjson 0.1.0", "ethjson 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"ethstore 0.1.0", "ethstore 0.2.0",
"ethsync 1.9.0", "ethsync 1.9.0",
"fetch 0.1.0", "fetch 0.1.0",
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2274,7 +2287,7 @@ dependencies = [
"ethcore-bigint 0.2.1", "ethcore-bigint 0.2.1",
"ethcore-network 1.9.0", "ethcore-network 1.9.0",
"ethcrypto 0.1.0", "ethcrypto 0.1.0",
"ethkey 0.2.0", "ethkey 0.3.0",
"hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)", "jsonrpc-core 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)",
"jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)", "jsonrpc-macros 8.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.9)",
@ -2296,7 +2309,7 @@ dependencies = [
[[package]] [[package]]
name = "parity-wordlist" name = "parity-wordlist"
version = "1.1.0" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2570,7 +2583,7 @@ dependencies = [
"futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.31 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -3111,6 +3124,14 @@ dependencies = [
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "threadpool"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "time" name = "time"
version = "0.1.38" version = "0.1.38"
@ -3571,6 +3592,7 @@ dependencies = [
"checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8" "checksum difference 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3304d19798a8e067e48d8e69b2c37f0b5e9b4e462504ad9e27e9f3fce02bba8"
"checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a" "checksum docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3b5b93718f8b3e5544fcc914c43de828ca6c6ace23e0332c6080a2977b49787a"
"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab"
"checksum edit-distance 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a34f5204fbc13582de418611cf3a7dcdd07c6d312a5b631597ba72c06b9d9c9"
"checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a" "checksum either 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18785c1ba806c258137c937e44ada9ee7e69a37e3c72077542cd2f069d78562a"
"checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85" "checksum elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "258ff6a9a94f648d0379dbd79110e057edbb53eb85cc237e33eadf8e5a30df85"
"checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b"
@ -3656,7 +3678,7 @@ dependencies = [
"checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01" "checksum num-iter 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)" = "7485fcc84f85b4ecd0ea527b14189281cf27d60e583ae65ebc9c088b13dffe01"
"checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790" "checksum num-rational 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "288629c76fac4b33556f4b7ab57ba21ae202da65ba8b77466e6d598e31990790"
"checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0" "checksum num-traits 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "99843c856d68d8b4313b03a17e33c4bb42ae8f6610ea81b28abe076ac721b9b0"
"checksum num_cpus 1.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aec53c34f2d0247c5ca5d32cca1478762f301740468ee9ee6dcb7a0dd7a0c584" "checksum num_cpus 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "514f0d73e64be53ff320680ca671b64fe3fb91da01e1ae2ddc99eb51d453b20d"
"checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902" "checksum number_prefix 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "59a14be9c211cb9c602bad35ac99f41e9a84b44d71b8cbd3040e3bd02a214902"
"checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba" "checksum odds 0.2.25 (registry+https://github.com/rust-lang/crates.io-index)" = "c3df9b730298cea3a1c3faa90b7e2f9df3a9c400d0936d6015e6165734eefcba"
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c" "checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
@ -3670,7 +3692,7 @@ dependencies = [
"checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git)" = "<none>" "checksum parity-ui-old-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-v1.git)" = "<none>"
"checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git)" = "<none>" "checksum parity-ui-precompiled 1.9.0 (git+https://github.com/js-dist-paritytech/parity-master-1-9-shell.git)" = "<none>"
"checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d" "checksum parity-wasm 0.15.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8431a184ad88cfbcd71a792aaca319cc7203a94300c26b8dce2d0df0681ea87d"
"checksum parity-wordlist 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "81451bfab101d186f8fc4a0aa13cb5539b31b02c4ed96425a0842e2a413daba6" "checksum parity-wordlist 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d0dec124478845b142f68b446cbee953d14d4b41f1bc0425024417720dce693"
"checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e"
"checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595" "checksum parking_lot_core 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "4f610cb9664da38e417ea3225f23051f589851999535290e077939838ab7a595"
"checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356" "checksum percent-encoding 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "de154f638187706bde41d9b4738748933d64e6b37bdbffc0b47a97d16a6ae356"
@ -3758,6 +3780,7 @@ dependencies = [
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209" "checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd" "checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14"
"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
"checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520" "checksum time 0.1.38 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d788d3aa77bc0ef3e9621256885555368b47bd495c13dd2e7413c89f845520"
"checksum tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52d12ad79e4063e0cb0ca5efa202ed7244b6ce4d25f4d3abe410b2a66128292" "checksum tiny-keccak 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d52d12ad79e4063e0cb0ca5efa202ed7244b6ce4d25f4d3abe410b2a66128292"
"checksum tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e85d419699ec4b71bfe35bbc25bb8771e52eff0471a7f75c853ad06e200b4f86" "checksum tokio-core 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e85d419699ec4b71bfe35bbc25bb8771e52eff0471a7f75c853ad06e200b4f86"

View File

@ -1,14 +1,17 @@
[package] [package]
name = "ethkey" name = "ethkey"
version = "0.2.0" version = "0.3.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
rand = "0.3.14"
lazy_static = "0.2"
tiny-keccak = "1.3"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
rustc-hex = "1.0"
ethcore-bigint = { path = "../util/bigint" }
rust-crypto = "0.2"
byteorder = "1.0" byteorder = "1.0"
edit-distance = "2.0"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1" }
ethcore-bigint = { path = "../util/bigint" }
lazy_static = "0.2"
log = "0.3"
parity-wordlist = "1.2"
rand = "0.3.14"
rust-crypto = "0.2"
rustc-hex = "1.0"
tiny-keccak = "1.3"

View File

@ -16,13 +16,13 @@ Ethereum keys generator.
Copyright 2016, 2017 Parity Technologies (UK) Ltd Copyright 2016, 2017 Parity Technologies (UK) Ltd
Usage: Usage:
ethkey info <secret> [options] ethkey info <secret-or-phrase> [options]
ethkey generate random [options] ethkey generate random [options]
ethkey generate prefix <prefix> <iterations> [options] ethkey generate prefix <prefix> [options]
ethkey generate brain <seed> [options]
ethkey sign <secret> <message> ethkey sign <secret> <message>
ethkey verify public <public> <signature> <message> ethkey verify public <public> <signature> <message>
ethkey verify address <address> <signature> <message> ethkey verify address <address> <signature> <message>
ethkey recover <address> <known-phrase>
ethkey [-h | --help] ethkey [-h | --help]
Options: Options:
@ -30,15 +30,15 @@ Options:
-s, --secret Display only the secret. -s, --secret Display only the secret.
-p, --public Display only the public. -p, --public Display only the public.
-a, --address Display only the address. -a, --address Display only the address.
-b, --brain Use parity brain wallet algorithm.
Commands: Commands:
info Display public and address of the secret. info Display public and address of the secret.
generate Generates new ethereum key. generate random Generates new random ethereum key.
random Random generation. generate prefix Random generation, but address must start with a prefix.
prefix Random generation, but address must start with a prefix
brain Generate new key from string seed.
sign Sign message using secret. sign Sign message using secret.
verify Verify signer of the signature. verify Verify signer of the signature.
recover Try to find brain phrase matching given address from partial phrase.
``` ```
### Examples ### Examples
@ -60,20 +60,22 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5
-- --
#### `generate brain <seed>`
*Generate new brain-wallet keypair using 16384 iterations.*
- `<seed>` - brain-wallet seed, any string #### `info --brain <phrase>`
*Display info about private key generate from brain wallet recovery phrase.*
- `<phrase>` - Parity recovery phrase, 12 words
``` ```
ethkey generate brain "this is sparta" ethkey info --brain "this is sparta"
``` ```
``` ```
secret: 17d08f5fe8c77af811caa0c9a187e668ce3b74a99acc3f6d976f075fa8e0be55 The recover phrase was not generated by Parity: The word 'this' does not come from the dictionary.
public: 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6e09f3ff04ca2b2a5cd22f62941db103c0356df1a8ed20ce322cab2483db67685afd124
address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5 secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2
public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4
address: 006e27b6a72e1f34c626762f3c4761547aff1421
``` ```
-- --
@ -93,14 +95,30 @@ address: a8fa5dd30a87bb9e3288d604eb74949c515ab66e
-- --
#### `generate prefix <prefix> <iterations>` #### `generate random --brain`
*Generate new keypair with recovery phrase randomly.*
```
ethkey generate random --brain
```
```
recovery phrase: thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon
secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0
public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0
address: 00cf3711cbd3a1512570639280758118ba0b2bcb
```
--
#### `generate prefix <prefix>`
*Generate new keypair randomly with address starting with prefix.* *Generate new keypair randomly with address starting with prefix.*
- `<prefix>` - desired address prefix, 0 - 32 bytes long. - `<prefix>` - desired address prefix, 0 - 32 bytes long.
- `<iterations>` - maximum number of tries before generation is assumed to be a failure.
``` ```
ethkey generate prefix ff 1000 ethkey generate prefix ff
``` ```
``` ```
@ -111,6 +129,24 @@ address: fff7e25dff2aa60f61f9d98130c8646a01f31649
-- --
#### `generate prefix --brain <prefix>`
*Generate new keypair with recovery phrase randomly with address starting with prefix.*
- `<prefix>` - desired address prefix, 0 - 32 bytes long.
```
ethkey generate prefix --brain 00cf
```
```
recovery phrase: thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon
secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0
public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0
address: 00cf3711cbd3a1512570639280758118ba0b2bcb
```
--
#### `sign <secret> <message>` #### `sign <secret> <message>`
*Sign a message with a secret.* *Sign a message with a secret.*
@ -159,9 +195,32 @@ ethkey verify address 689268c0ff57a20cd299fa60d3fb374862aff565b20b5f1767906a99e6
true true
``` ```
--
# Ethcore toolchain #### `recover <address> <known-phrase>`
*this project is a part of the ethcore toolchain* *Try to recover an account given expected address and partial (too short or with invalid words) recovery phrase.*
- `<address>` - ethereum address, 20 bytes long
- `<known-phrase>` - known phrase, can be in a form of `thwarting * creamer`
```
RUST_LOG="info" ethkey recover "00cf3711cbd3a1512570639280758118ba0b2bcb" "thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octag"
```
```
INFO:ethkey::brain_recover: Invalid word 'octag', looking for potential substitutions.
INFO:ethkey::brain_recover: Closest words: ["ocean", "octagon", "octane", "outage", "tag", "acting", "acts", "aorta", "cage", "chug"]
INFO:ethkey::brain_recover: Starting to test 7776 possible combinations.
thwarting scandal creamer nuzzle asparagus blast crouch trusting anytime elixir frenzied octagon
secret: 001ce488d50d2f7579dc190c4655f32918d505cee3de63bddc7101bc91c0c2f0
public: 4e19a5fdae82596e1485c69b687c9cc52b5078e5b0668ef3ce8543cd90e712cb00df822489bc1f1dcb3623538a54476c7b3def44e1a51dc174e86448b63f42d0
address: 00cf3711cbd3a1512570639280758118ba0b2bcb
```
# Parity toolchain
*this project is a part of the parity toolchain*
- [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer. - [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer.
- [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management. - [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management.

View File

@ -4,12 +4,15 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
docopt = "0.8"
env_logger = "0.4"
ethkey = { path = "../" } ethkey = { path = "../" }
panic_hook = { path = "../../panic_hook" }
parity-wordlist="1.2"
rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
rustc-hex = "1.0" threadpool = "1.7"
docopt = "0.8"
panic_hook = { path = "../../panic_hook" }
[[bin]] [[bin]]
name = "ethkey" name = "ethkey"

View File

@ -15,32 +15,36 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate docopt; extern crate docopt;
extern crate rustc_hex; extern crate env_logger;
extern crate serde;
#[macro_use]
extern crate serde_derive;
extern crate ethkey; extern crate ethkey;
extern crate panic_hook; extern crate panic_hook;
extern crate parity_wordlist;
extern crate rustc_hex;
extern crate serde;
extern crate threadpool;
#[macro_use]
extern crate serde_derive;
use std::{env, fmt, process};
use std::num::ParseIntError; use std::num::ParseIntError;
use std::{env, fmt, process, io, sync};
use docopt::Docopt; use docopt::Docopt;
use ethkey::{KeyPair, Random, Brain, BrainPrefix, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address, brain_recover};
use rustc_hex::{ToHex, FromHex, FromHexError}; use rustc_hex::{ToHex, FromHex, FromHexError};
use ethkey::{KeyPair, Random, Brain, Prefix, Error as EthkeyError, Generator, sign, verify_public, verify_address};
use std::io;
pub const USAGE: &'static str = r#" pub const USAGE: &'static str = r#"
Ethereum keys generator. Ethereum keys generator.
Copyright 2016, 2017 Parity Technologies (UK) Ltd Copyright 2016, 2017 Parity Technologies (UK) Ltd
Usage: Usage:
ethkey info <secret> [options] ethkey info <secret-or-phrase> [options]
ethkey generate random [options] ethkey generate random [options]
ethkey generate prefix <prefix> <iterations> [options] ethkey generate prefix <prefix> [options]
ethkey generate brain <seed> [options]
ethkey sign <secret> <message> ethkey sign <secret> <message>
ethkey verify public <public> <signature> <message> ethkey verify public <public> <signature> <message>
ethkey verify address <address> <signature> <message> ethkey verify address <address> <signature> <message>
ethkey recover <address> <known-phrase>
ethkey [-h | --help] ethkey [-h | --help]
Options: Options:
@ -48,15 +52,15 @@ Options:
-s, --secret Display only the secret. -s, --secret Display only the secret.
-p, --public Display only the public. -p, --public Display only the public.
-a, --address Display only the address. -a, --address Display only the address.
-b, --brain Use parity brain wallet algorithm.
Commands: Commands:
info Display public and address of the secret. info Display public and address of the secret.
generate Generates new ethereum key. generate random Generates new random ethereum key.
random Random generation. generate prefix Random generation, but address must start with a prefix.
prefix Random generation, but address must start with a prefix
brain Generate new key from string seed.
sign Sign message using secret. sign Sign message using secret.
verify Verify signer of the signature. verify Verify signer of the signature.
recover Try to find brain phrase matching given address from partial phrase.
"#; "#;
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@ -65,15 +69,15 @@ struct Args {
cmd_generate: bool, cmd_generate: bool,
cmd_random: bool, cmd_random: bool,
cmd_prefix: bool, cmd_prefix: bool,
cmd_brain: bool,
cmd_sign: bool, cmd_sign: bool,
cmd_verify: bool, cmd_verify: bool,
cmd_public: bool, cmd_public: bool,
cmd_address: bool, cmd_address: bool,
cmd_recover: bool,
arg_prefix: String, arg_prefix: String,
arg_iterations: String,
arg_seed: String,
arg_secret: String, arg_secret: String,
arg_secret_or_phrase: String,
arg_known_phrase: String,
arg_message: String, arg_message: String,
arg_public: String, arg_public: String,
arg_address: String, arg_address: String,
@ -81,6 +85,7 @@ struct Args {
flag_secret: bool, flag_secret: bool,
flag_public: bool, flag_public: bool,
flag_address: bool, flag_address: bool,
flag_brain: bool,
} }
#[derive(Debug)] #[derive(Debug)]
@ -157,6 +162,7 @@ impl DisplayMode {
fn main() { fn main() {
panic_hook::set(); panic_hook::set();
env_logger::init().expect("Logger initialized only once.");
match execute(env::args()) { match execute(env::args()) {
Ok(ok) => println!("{}", ok), Ok(ok) => println!("{}", ok),
@ -167,9 +173,13 @@ fn main() {
} }
} }
fn display(keypair: KeyPair, mode: DisplayMode) -> String { fn display(result: (KeyPair, Option<String>), mode: DisplayMode) -> String {
let keypair = result.0;
match mode { match mode {
DisplayMode::KeyPair => format!("{}", keypair), DisplayMode::KeyPair => match result.1 {
Some(extra_data) => format!("{}\n{}", extra_data, keypair),
None => format!("{}", keypair)
},
DisplayMode::Secret => format!("{}", keypair.secret().to_hex()), DisplayMode::Secret => format!("{}", keypair.secret().to_hex()),
DisplayMode::Public => format!("{:?}", keypair.public()), DisplayMode::Public => format!("{:?}", keypair.public()),
DisplayMode::Address => format!("{:?}", keypair.address()), DisplayMode::Address => format!("{:?}", keypair.address()),
@ -182,23 +192,53 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
return if args.cmd_info { return if args.cmd_info {
let display_mode = DisplayMode::new(&args); let display_mode = DisplayMode::new(&args);
let secret = args.arg_secret.parse().map_err(|_| EthkeyError::InvalidSecret)?;
let keypair = KeyPair::from_secret(secret)?; let result = if args.flag_brain {
Ok(display(keypair, display_mode)) let phrase = args.arg_secret_or_phrase;
let phrase_info = validate_phrase(&phrase);
let keypair = Brain::new(phrase).generate().expect("Brain wallet generator is infallible; qed");
(keypair, Some(phrase_info))
} else {
let secret = args.arg_secret_or_phrase.parse().map_err(|_| EthkeyError::InvalidSecret)?;
(KeyPair::from_secret(secret)?, None)
};
Ok(display(result, display_mode))
} else if args.cmd_generate { } else if args.cmd_generate {
let display_mode = DisplayMode::new(&args); let display_mode = DisplayMode::new(&args);
let keypair = if args.cmd_random { let result = if args.cmd_random {
Random.generate()? if args.flag_brain {
let mut brain = BrainPrefix::new(vec![0], usize::max_value(), BRAIN_WORDS);
let keypair = brain.generate()?;
let phrase = format!("recovery phrase: {}", brain.phrase());
(keypair, Some(phrase))
} else {
(Random.generate()?, None)
}
} else if args.cmd_prefix { } else if args.cmd_prefix {
let prefix = args.arg_prefix.from_hex()?; let prefix = args.arg_prefix.from_hex()?;
let iterations = usize::from_str_radix(&args.arg_iterations, 10)?; let brain = args.flag_brain;
Prefix::new(prefix, iterations).generate()? in_threads(move || {
} else if args.cmd_brain { let iterations = 1024;
Brain::new(args.arg_seed).generate().expect("Brain wallet generator is infallible; qed") let prefix = prefix.clone();
move || {
let prefix = prefix.clone();
let res = if brain {
let mut brain = BrainPrefix::new(prefix, iterations, BRAIN_WORDS);
let result = brain.generate();
let phrase = format!("recovery phrase: {}", brain.phrase());
result.map(|keypair| (keypair, Some(phrase)))
} else { } else {
unreachable!(); let result = Prefix::new(prefix, iterations).generate();
result.map(|res| (res, None))
}; };
Ok(display(keypair, display_mode))
Ok(res.map(Some).unwrap_or(None))
}
})?
} else {
return Ok(format!("{}", USAGE))
};
Ok(display(result, display_mode))
} else if args.cmd_sign { } else if args.cmd_sign {
let secret = args.arg_secret.parse().map_err(|_| EthkeyError::InvalidSecret)?; let secret = args.arg_secret.parse().map_err(|_| EthkeyError::InvalidSecret)?;
let message = args.arg_message.parse().map_err(|_| EthkeyError::InvalidMessage)?; let message = args.arg_message.parse().map_err(|_| EthkeyError::InvalidMessage)?;
@ -214,12 +254,87 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
let address = args.arg_address.parse().map_err(|_| EthkeyError::InvalidAddress)?; let address = args.arg_address.parse().map_err(|_| EthkeyError::InvalidAddress)?;
verify_address(&address, &signature, &message)? verify_address(&address, &signature, &message)?
} else { } else {
unreachable!(); return Ok(format!("{}", USAGE))
}; };
Ok(format!("{}", ok)) Ok(format!("{}", ok))
} else { } else if args.cmd_recover {
unreachable!(); let display_mode = DisplayMode::new(&args);
let known_phrase = args.arg_known_phrase;
let address = args.arg_address.parse().map_err(|_| EthkeyError::InvalidAddress)?;
let (phrase, keypair) = in_threads(move || {
let mut it = brain_recover::PhrasesIterator::from_known_phrase(&known_phrase, BRAIN_WORDS);
move || {
let mut i = 0;
while let Some(phrase) = it.next() {
i += 1;
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address() == address {
return Ok(Some((phrase, keypair)))
} }
if i >= 1024 {
return Ok(None)
}
}
Err(EthkeyError::Custom("Couldn't find any results.".into()))
}
})?;
Ok(display((keypair, Some(phrase)), display_mode))
} else {
Ok(format!("{}", USAGE))
}
}
const BRAIN_WORDS: usize = 12;
fn validate_phrase(phrase: &str) -> String {
match Brain::validate_phrase(phrase, BRAIN_WORDS) {
Ok(()) => format!("The recovery phrase looks correct.\n"),
Err(err) => format!("The recover phrase was not generated by Parity: {}", err)
}
}
fn in_threads<F, X, O>(prepare: F) -> Result<O, EthkeyError> where
O: Send + 'static,
X: Send + 'static,
F: Fn() -> X,
X: FnMut() -> Result<Option<O>, EthkeyError>,
{
let pool = threadpool::Builder::new().build();
let (tx, rx) = sync::mpsc::sync_channel(1);
let is_done = sync::Arc::new(sync::atomic::AtomicBool::default());
for _ in 0..pool.max_count() {
let is_done = is_done.clone();
let tx = tx.clone();
let mut task = prepare();
pool.execute(move || {
loop {
if is_done.load(sync::atomic::Ordering::SeqCst) {
return;
}
let res = match task() {
Ok(None) => continue,
Ok(Some(v)) => Ok(v),
Err(err) => Err(err),
};
// We are interested only in the first response.
let _ = tx.send(res);
}
});
}
if let Ok(solution) = rx.recv() {
is_done.store(true, sync::atomic::Ordering::SeqCst);
return solution;
}
Err(EthkeyError::Custom("No results found.".into()))
} }
#[cfg(test)] #[cfg(test)]
@ -242,13 +357,15 @@ address: 26d1ec50b4e62c1d1a40d16e7cacc6a6580757d5".to_owned();
#[test] #[test]
fn brain() { fn brain() {
let command = vec!["ethkey", "generate", "brain", "this is sparta"] let command = vec!["ethkey", "info", "--brain", "this is sparta"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
let expected = let expected =
"secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2 "The recover phrase was not generated by Parity: The word 'this' does not come from the dictionary.
secret: aa22b54c0cb43ee30a014afe5ef3664b1cde299feabca46cd3167a85a57c39f2
public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4 public: c4c5398da6843632c123f543d714d2d2277716c11ff612b2a2f23c6bda4d6f0327c31cd58c55a9572c3cc141dade0c32747a13b7ef34c241b26c84adbb28fcf4
address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned(); address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
assert_eq!(execute(command).unwrap(), expected); assert_eq!(execute(command).unwrap(), expected);
@ -256,7 +373,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
#[test] #[test]
fn secret() { fn secret() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--secret"] let command = vec!["ethkey", "info", "--brain", "this is sparta", "--secret"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
@ -267,7 +384,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
#[test] #[test]
fn public() { fn public() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--public"] let command = vec!["ethkey", "info", "--brain", "this is sparta", "--public"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
@ -278,7 +395,7 @@ address: 006e27b6a72e1f34c626762f3c4761547aff1421".to_owned();
#[test] #[test]
fn address() { fn address() {
let command = vec!["ethkey", "generate", "brain", "this is sparta", "--address"] let command = vec!["ethkey", "info", "-b", "this is sparta", "--address"]
.into_iter() .into_iter()
.map(Into::into) .map(Into::into)
.collect::<Vec<String>>(); .collect::<Vec<String>>();

View File

@ -16,6 +16,7 @@
use keccak::Keccak256; use keccak::Keccak256;
use super::{KeyPair, Generator, Secret}; use super::{KeyPair, Generator, Secret};
use parity_wordlist;
/// Simple brainwallet. /// Simple brainwallet.
pub struct Brain(String); pub struct Brain(String);
@ -24,13 +25,17 @@ impl Brain {
pub fn new(s: String) -> Self { pub fn new(s: String) -> Self {
Brain(s) Brain(s)
} }
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
parity_wordlist::validate_phrase(phrase, expected_words)
}
} }
impl Generator for Brain { impl Generator for Brain {
type Error = ::Void; type Error = ::Void;
fn generate(self) -> Result<KeyPair, Self::Error> { fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let seed = self.0; let seed = self.0.clone();
let mut secret = seed.into_bytes().keccak256(); let mut secret = seed.into_bytes().keccak256();
let mut i = 0; let mut i = 0;
@ -43,7 +48,10 @@ impl Generator for Brain {
if let Ok(pair) = Secret::from_unsafe_slice(&secret) if let Ok(pair) = Secret::from_unsafe_slice(&secret)
.and_then(KeyPair::from_secret) .and_then(KeyPair::from_secret)
{ {
if pair.address()[0] == 0 { return Ok(pair) } if pair.address()[0] == 0 {
trace!("Testing: {}, got: {:?}", self.0, pair.address());
return Ok(pair)
}
} }
}, },
} }

View File

@ -0,0 +1,70 @@
// Copyright 2015-2017 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/>.
use super::{Generator, KeyPair, Error, Brain};
use parity_wordlist as wordlist;
/// Tries to find brain-seed keypair with address starting with given prefix.
pub struct BrainPrefix {
prefix: Vec<u8>,
iterations: usize,
no_of_words: usize,
last_phrase: String,
}
impl BrainPrefix {
pub fn new(prefix: Vec<u8>, iterations: usize, no_of_words: usize) -> Self {
BrainPrefix {
prefix,
iterations,
no_of_words,
last_phrase: String::new(),
}
}
pub fn phrase(&self) -> &str {
&self.last_phrase
}
}
impl Generator for BrainPrefix {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations {
let phrase = wordlist::random_phrase(self.no_of_words);
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address().starts_with(&self.prefix) {
self.last_phrase = phrase;
return Ok(keypair)
}
}
Err(Error::Custom("Could not find keypair".into()))
}
}
#[cfg(test)]
mod tests {
use {Generator, BrainPrefix};
#[test]
fn prefix_generator() {
let prefix = vec![0x00u8];
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12).generate().unwrap();
assert!(keypair.address().starts_with(&prefix));
}
}

175
ethkey/src/brain_recover.rs Normal file
View File

@ -0,0 +1,175 @@
// Copyright 2015-2017 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/>.
use std::collections::HashSet;
use edit_distance::edit_distance;
use parity_wordlist;
use super::{Address, Brain, Generator};
/// Tries to find a phrase for address, given the number
/// of expected words and a partial phrase.
///
/// Returns `None` if phrase couldn't be found.
pub fn brain_recover(
address: &Address,
known_phrase: &str,
expected_words: usize,
) -> Option<String> {
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
for phrase in it {
let keypair = Brain::new(phrase.clone()).generate().expect("Brain wallets are infallible; qed");
trace!("Testing: {}, got: {:?}", phrase, keypair.address());
if &keypair.address() == address {
return Some(phrase);
}
}
None
}
fn generate_substitutions(word: &str) -> Vec<&'static str> {
let mut words = parity_wordlist::WORDS.iter().cloned()
.map(|w| (edit_distance(w, word), w))
.collect::<Vec<_>>();
words.sort_by(|a, b| a.0.cmp(&b.0));
words.into_iter()
.map(|pair| pair.1)
.collect()
}
/// Iterator over possible
pub struct PhrasesIterator {
words: Vec<Vec<&'static str>>,
combinations: u64,
indexes: Vec<usize>,
has_next: bool,
}
impl PhrasesIterator {
pub fn from_known_phrase(known_phrase: &str, expected_words: usize) -> Self {
let known_words = parity_wordlist::WORDS.iter().cloned().collect::<HashSet<_>>();
let mut words = known_phrase.split(' ')
.map(|word| match known_words.get(word) {
None => {
info!("Invalid word '{}', looking for potential substitutions.", word);
let substitutions = generate_substitutions(word);
info!("Closest words: {:?}", &substitutions[..10]);
substitutions
},
Some(word) => vec![*word],
})
.collect::<Vec<_>>();
// add missing words
if words.len() < expected_words {
let to_add = expected_words - words.len();
info!("Number of words is insuficcient adding {} more.", to_add);
for _ in 0..to_add {
words.push(parity_wordlist::WORDS.iter().cloned().collect());
}
}
// start searching
PhrasesIterator::new(words)
}
pub fn new(words: Vec<Vec<&'static str>>) -> Self {
let combinations = words.iter().fold(1u64, |acc, x| acc * x.len() as u64);
let indexes = words.iter().map(|_| 0).collect();
info!("Starting to test {} possible combinations.", combinations);
PhrasesIterator {
words,
combinations,
indexes,
has_next: combinations > 0,
}
}
pub fn combinations(&self) -> u64 {
self.combinations
}
fn current(&self) -> String {
let mut s = self.words[0][self.indexes[0]].to_owned();
for i in 1..self.indexes.len() {
s.push(' ');
s.push_str(self.words[i][self.indexes[i]]);
}
s
}
fn next_index(&mut self) -> bool {
let mut pos = self.indexes.len();
while pos > 0 {
pos -= 1;
self.indexes[pos] += 1;
if self.indexes[pos] >= self.words[pos].len() {
self.indexes[pos] = 0;
} else {
return true;
}
}
false
}
}
impl Iterator for PhrasesIterator {
type Item = String;
fn next(&mut self) -> Option<String> {
if !self.has_next {
return None;
}
let phrase = self.current();
self.has_next = self.next_index();
Some(phrase)
}
}
#[cfg(test)]
mod tests {
use super::PhrasesIterator;
#[test]
fn should_generate_possible_combinations() {
let mut it = PhrasesIterator::new(vec![
vec!["1", "2", "3"],
vec!["test"],
vec!["a", "b", "c"],
]);
assert_eq!(it.combinations(), 9);
assert_eq!(it.next(), Some("1 test a".to_owned()));
assert_eq!(it.next(), Some("1 test b".to_owned()));
assert_eq!(it.next(), Some("1 test c".to_owned()));
assert_eq!(it.next(), Some("2 test a".to_owned()));
assert_eq!(it.next(), Some("2 test b".to_owned()));
assert_eq!(it.next(), Some("2 test c".to_owned()));
assert_eq!(it.next(), Some("3 test a".to_owned()));
assert_eq!(it.next(), Some("3 test b".to_owned()));
assert_eq!(it.next(), Some("3 test c".to_owned()));
assert_eq!(it.next(), None);
}
}

View File

@ -14,18 +14,25 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate rand; // #![warn(missing_docs)]
extern crate tiny_keccak;
extern crate secp256k1;
extern crate rustc_hex;
extern crate ethcore_bigint as bigint;
extern crate crypto as rcrypto;
extern crate byteorder; extern crate byteorder;
extern crate crypto as rcrypto;
extern crate edit_distance;
extern crate ethcore_bigint as bigint;
extern crate parity_wordlist;
extern crate rand;
extern crate rustc_hex;
extern crate secp256k1;
extern crate tiny_keccak;
#[macro_use] #[macro_use]
extern crate lazy_static; extern crate lazy_static;
#[macro_use]
extern crate log;
mod brain; mod brain;
mod brain_prefix;
mod error; mod error;
mod keypair; mod keypair;
mod keccak; mod keccak;
@ -35,9 +42,12 @@ mod signature;
mod secret; mod secret;
mod extended; mod extended;
pub mod brain_recover;
pub mod math; pub mod math;
pub use self::parity_wordlist::Error as WordlistError;
pub use self::brain::Brain; pub use self::brain::Brain;
pub use self::brain_prefix::BrainPrefix;
pub use self::error::Error; pub use self::error::Error;
pub use self::keypair::{KeyPair, public_to_address}; pub use self::keypair::{KeyPair, public_to_address};
pub use self::math::public_is_valid; pub use self::math::public_is_valid;
@ -62,7 +72,7 @@ pub trait Generator {
type Error; type Error;
/// Should be called to generate new keypair. /// Should be called to generate new keypair.
fn generate(self) -> Result<KeyPair, Self::Error>; fn generate(&mut self) -> Result<KeyPair, Self::Error>;
} }
pub type Address = H160; pub type Address = H160;

View File

@ -34,7 +34,7 @@ impl Prefix {
impl Generator for Prefix { impl Generator for Prefix {
type Error = Error; type Error = Error;
fn generate(self) -> Result<KeyPair, Error> { fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations { for _ in 0..self.iterations {
let keypair = Random.generate()?; let keypair = Random.generate()?;
if keypair.address().starts_with(&self.prefix) { if keypair.address().starts_with(&self.prefix) {

View File

@ -23,7 +23,7 @@ pub struct Random;
impl Generator for Random { impl Generator for Random {
type Error = ::std::io::Error; type Error = ::std::io::Error;
fn generate(self) -> Result<KeyPair, Self::Error> { fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let mut rng = OsRng::new()?; let mut rng = OsRng::new()?;
match rng.generate() { match rng.generate() {
Ok(pair) => Ok(pair), Ok(pair) => Ok(pair),
@ -32,10 +32,10 @@ impl Generator for Random {
} }
} }
impl<'a> Generator for &'a mut OsRng { impl Generator for OsRng {
type Error = ::Void; type Error = ::Void;
fn generate(self) -> Result<KeyPair, Self::Error> { fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let (sec, publ) = SECP256K1.generate_keypair(self) let (sec, publ) = SECP256K1.generate_keypair(self)
.expect("context always created with full capabilities; qed"); .expect("context always created with full capabilities; qed");

View File

@ -1,6 +1,6 @@
[package] [package]
name = "ethstore" name = "ethstore"
version = "0.1.0" version = "0.2.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]

View File

@ -21,6 +21,7 @@ Usage:
ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore import [--src DIR] [--dir DIR] ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore find-wallet-pass <path> <password>
ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
@ -50,6 +51,7 @@ Commands:
list List accounts. list List accounts.
import Import accounts from src. import Import accounts from src.
import-wallet Import presale wallet. import-wallet Import presale wallet.
find-wallet-pass Tries to open a wallet with list of passwords given.
remove Remove account. remove Remove account.
sign Sign message. sign Sign message.
public Displays public key for an address. public Displays public key for an address.
@ -164,6 +166,25 @@ ethstore import-wallet ethwallet.json password.txt
e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb e6a3d25a7cb7cd21cb720df5b5e8afd154af1bbb
``` ```
--
#### `find-wallet-pass <path> <password>`
Try to open presale wallet given a list of passwords from a file.
The list of passwords can be generated using e.g. [Phildo/brutedist](https://github.com/Phildo/brutedist).
- `<path>` - presale wallet path
- `<password>` - possible passwords, file path
```
ethstore find-wallet-pass ethwallet.json passwords.txt
```
```
Found password: test
```
-- --
#### `remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]` #### `remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]`
@ -318,8 +339,8 @@ OK
-- --
# Ethcore toolchain # Parity toolchain
*this project is a part of the ethcore toolchain* *this project is a part of the parity toolchain*
- [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer. - [**ethkey**](https://github.com/paritytech/ethkey) - Ethereum keys generator and signer.
- [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management. - [**ethstore**](https://github.com/paritytech/ethstore) - Ethereum key management.

View File

@ -4,10 +4,12 @@ version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"] authors = ["Parity Technologies <admin@parity.io>"]
[dependencies] [dependencies]
docopt = "0.8"
num_cpus = "1.6"
rustc-hex = "1.0" rustc-hex = "1.0"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
docopt = "0.8" parking_lot = "0.4"
ethstore = { path = "../" } ethstore = { path = "../" }
panic_hook = { path = "../../panic_hook" } panic_hook = { path = "../../panic_hook" }

50
ethstore/cli/src/crack.rs Normal file
View File

@ -0,0 +1,50 @@
use std::{cmp, thread};
use std::sync::Arc;
use std::collections::VecDeque;
use parking_lot::Mutex;
use ethstore::{PresaleWallet, Error};
use num_cpus;
pub fn run(passwords: VecDeque<String>, wallet_path: &str) -> Result<(), Error> {
let passwords = Arc::new(Mutex::new(passwords));
let mut handles = Vec::new();
for _ in 0..num_cpus::get() {
let passwords = passwords.clone();
let wallet = PresaleWallet::open(&wallet_path)?;
handles.push(thread::spawn(move || {
look_for_password(passwords, wallet);
}));
}
for handle in handles {
handle.join().map_err(|err| Error::Custom(format!("Error finishing thread: {:?}", err)))?;
}
Ok(())
}
fn look_for_password(passwords: Arc<Mutex<VecDeque<String>>>, wallet: PresaleWallet) {
let mut counter = 0;
while !passwords.lock().is_empty() {
let package = {
let mut passwords = passwords.lock();
let len = passwords.len();
passwords.split_off(cmp::min(len, 32))
};
for pass in package {
counter += 1;
match wallet.decrypt(&pass) {
Ok(_) => {
println!("Found password: {}", &pass);
passwords.lock().clear();
return;
},
_ if counter % 100 == 0 => print!("."),
_ => {},
}
}
}
}

View File

@ -14,21 +14,27 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
extern crate rustc_hex;
extern crate docopt; extern crate docopt;
extern crate ethstore;
extern crate num_cpus;
extern crate panic_hook;
extern crate parking_lot;
extern crate rustc_hex;
extern crate serde; extern crate serde;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate ethstore;
extern crate panic_hook;
use std::{env, process, fs, fmt}; use std::collections::VecDeque;
use std::io::Read; use std::io::Read;
use std::{env, process, fs, fmt};
use docopt::Docopt; use docopt::Docopt;
use ethstore::ethkey::Address;
use ethstore::dir::{paths, KeyDirectory, RootDiskDirectory}; use ethstore::dir::{paths, KeyDirectory, RootDiskDirectory};
use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, use ethstore::ethkey::Address;
SecretVaultRef, StoreAccountRef}; use ethstore::{EthStore, SimpleSecretStore, SecretStore, import_accounts, PresaleWallet, SecretVaultRef, StoreAccountRef};
mod crack;
pub const USAGE: &'static str = r#" pub const USAGE: &'static str = r#"
Ethereum key management. Ethereum key management.
@ -40,6 +46,7 @@ Usage:
ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore list [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore import [--src DIR] [--dir DIR] ethstore import [--src DIR] [--dir DIR]
ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore import-wallet <path> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore find-wallet-pass <path> <password>
ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore remove <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore sign <address> <password> <message> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD] ethstore public <address> <password> [--dir DIR] [--vault VAULT] [--vault-pwd VAULTPWD]
@ -69,6 +76,7 @@ Commands:
list List accounts. list List accounts.
import Import accounts from src. import Import accounts from src.
import-wallet Import presale wallet. import-wallet Import presale wallet.
find-wallet-pass Tries to open a wallet with list of passwords given.
remove Remove account. remove Remove account.
sign Sign message. sign Sign message.
public Displays public key for an address. public Displays public key for an address.
@ -86,6 +94,7 @@ struct Args {
cmd_list: bool, cmd_list: bool,
cmd_import: bool, cmd_import: bool,
cmd_import_wallet: bool, cmd_import_wallet: bool,
cmd_find_wallet_pass: bool,
cmd_remove: bool, cmd_remove: bool,
cmd_sign: bool, cmd_sign: bool,
cmd_public: bool, cmd_public: bool,
@ -239,6 +248,11 @@ fn execute<S, I>(command: I) -> Result<String, Error> where I: IntoIterator<Item
let vault_ref = open_args_vault(&store, &args)?; let vault_ref = open_args_vault(&store, &args)?;
let account_ref = store.insert_account(vault_ref, kp.secret().clone(), &password)?; let account_ref = store.insert_account(vault_ref, kp.secret().clone(), &password)?;
Ok(format!("0x{:?}", account_ref.address)) Ok(format!("0x{:?}", account_ref.address))
} else if args.cmd_find_wallet_pass {
let passwords = load_password(&args.arg_password)?;
let passwords = passwords.lines().map(str::to_owned).collect::<VecDeque<_>>();
crack::run(passwords, &args.arg_path)?;
Ok(format!("Password not found."))
} else if args.cmd_remove { } else if args.cmd_remove {
let address = args.arg_address.parse().map_err(|_| ethstore::Error::InvalidAccount)?; let address = args.arg_address.parse().map_err(|_| ethstore::Error::InvalidAccount)?;
let password = load_password(&args.arg_password)?; let password = load_password(&args.arg_password)?;