Compare commits

..

35 Commits

Author SHA1 Message Date
draganrakita 71bc62609e cicd fix v2 2020-12-21 16:13:17 +01:00
draganrakita 7336511246 cicd fix 2020-12-21 12:28:58 +01:00
draganrakita eb9041691e Disable windows2019, remove tagged windows artifact 2020-12-21 10:49:00 +01:00
rakita 51d8ac4219
Revert "Fix CI problems (#127)" and Remove sscache (#181)
This reverts commit 12afb13e9b.
2020-12-18 09:28:05 +01:00
draganrakita 64eb48ef39 Bump to 3.1.1-rc.1 2020-12-15 17:22:03 +01:00
draganrakita 0138e5c71f Tweaks in informer log 2020-12-15 17:21:41 +01:00
adria0.eth cf76d41bf4 Update ISSUE_TEMPLATE.md (#124)
Tell users to ask questions in discord instead of opening an issue.
2020-12-15 11:43:22 +01:00
Giacomo 2161bff690 Add custom windows runner (#162) 2020-12-15 11:43:22 +01:00
rakita 07a7281e26 Ancient target set. InvalidStateRoot bug (#69) (#149) 2020-12-15 11:43:22 +01:00
rakita fb975731bb TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135) 2020-12-15 11:43:22 +01:00
rakita 1bce9fa76d Fix broken doc comments (#151) 2020-12-15 11:43:21 +01:00
rakita 8f794afdb5 Add ws-max-paxload (#155) 2020-12-15 11:43:21 +01:00
rakita f9f536cd08 Trace comment on new block inclusion (#100) 2020-12-15 11:43:21 +01:00
rakita bfb65140d2 Remove sscache (#138) 2020-12-15 11:43:21 +01:00
rakita 5e2cadd9c7 Add flag to disable storage output in openethereum-evm tool #97 (#115) 2020-12-15 11:43:21 +01:00
adria0.eth 12afb13e9b Fix CI problems (#127)
* Temporally Fix CI compilation
2020-12-15 11:43:21 +01:00
Adria Massanet 4435e6645c Update linked-hash-map to 0.5.3 2020-12-15 11:43:21 +01:00
Lachezar Lechev 90e5eeefb8 ethstore - remove unnecessary dir & tiny-keccak dependencies from the lib (#107)
* ethstore - remove unnecessary dir & tiny-keccak dependencies
2020-12-15 11:43:20 +01:00
Giacomo c33d7fbb45 Fix deprecated set-env declaration (#106)
* Fix deprecated set-env declaration

* Fix add-path and set-env in install-sscache.ps1
2020-12-15 11:43:20 +01:00
Giacomo 3bbb647e5f Feature/improve dockerhub deployment (#98)
* Add docker deployment for Github actions

* Add docker specs for the release of tagged and latest versions, also add specs for nightly builds

Co-authored-by: Denis Granha <denis@gnosis.pm>
2020-12-15 11:43:20 +01:00
adria0.eth 007207d8ca EIP2565 impl (#82)
EIP2565 implementation
2020-12-15 11:43:20 +01:00
adria0.eth c8aea223ec Downgrade sccache to 1.1.2 (#93) 2020-12-15 11:43:20 +01:00
adria0.eth d52272983a EIP2929 with journaling + Yolov3 (#79) 2020-12-15 11:43:20 +01:00
rakita 905d76b436 Sync block verification (#74)
* Synchronize block verification
* max_round_blocks_to_import set to 1
* Fixed test that rely on 12block batches

Co-authored-by: adria0.eth <5526331+adria0@users.noreply.github.com>
2020-12-15 11:43:19 +01:00
Adria Massanet e69d2009cf Update gitactions for dev branch, deprecate stable branch 2020-12-15 11:43:19 +01:00
varasev a95b2de645 Add `wasmDisableTransition` spec option (#60)
* Add wasmDisableTransition spec option
2020-12-15 11:43:19 +01:00
adria0.eth 6ecc6ddcdf Fix warnings (#64) 2020-12-15 11:43:19 +01:00
rakita 6ecb66eff9 Change wiki links (#68) 2020-12-15 11:43:19 +01:00
Denis Granha 94a784bfe9
Add docker deployment for Github actions 2020-11-06 12:02:27 +01:00
draganrakita 2072341eca Bump to 3.1.0 2020-11-02 13:28:44 +01:00
Denis Granha 36d250a420 revert actions/cache to version 1.1.2 (#80) 2020-11-02 13:20:20 +01:00
rakita 6f7548f596 Use ubuntu-16.04 for glibc compatibility (#11888) (#73) 2020-11-02 13:20:07 +01:00
adria0.eth 1ccbe5cfd4 Update gitactions master->main (#72) 2020-11-02 13:19:11 +01:00
Denis Granha a8242ffef9 fix CD env param 2020-11-02 13:18:50 +01:00
Giacomo fb071acb09 Set AWS_REGION as a global env variable (#67) 2020-11-02 13:18:42 +01:00
930 changed files with 48138 additions and 25916 deletions

View File

@ -1,3 +1,3 @@
[target.x86_64-pc-windows-msvc]
# Link the C runtime statically ; https://github.com/openethereum/parity-ethereum/issues/6643
# Link the C runtime statically ; https://github.com/openethereum/openethereum/issues/6643
rustflags = ["-Ctarget-feature=+crt-static"]

View File

@ -1,33 +0,0 @@
name: Build and Test Suite on Windows
on:
push:
branches:
- main
- dev
jobs:
build-tests:
name: Test and Build
strategy:
matrix:
platform:
- windows2019 # custom runner
toolchain:
- 1.52.1
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout sources
uses: actions/checkout@main
with:
submodules: true
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: ${{ matrix.toolchain }}
profile: minimal
override: true
- name: Build tests
uses: actions-rs/cargo@v1
with:
command: test
args: --locked --all --release --features "json-tests" --verbose --no-run

View File

@ -15,7 +15,7 @@ jobs:
- ubuntu-16.04
- macos-latest
toolchain:
- 1.52.1
- stable
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout sources
@ -33,8 +33,3 @@ jobs:
with:
command: test
args: --locked --all --release --features "json-tests" --verbose --no-run
- name: Run tests for ${{ matrix.platform }}
uses: actions-rs/cargo@v1
with:
command: test
args: --locked --all --release --features "json-tests" --verbose

View File

@ -20,7 +20,7 @@ jobs:
- ubuntu-16.04
- macos-latest
toolchain:
- 1.52.1
- stable
runs-on: ${{ matrix.platform }}
steps:
- name: Checkout sources

View File

@ -15,10 +15,10 @@ jobs:
uses: actions/checkout@main
with:
submodules: true
- name: Install 1.52.1 toolchain
- name: Install stable toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 1.52.1
toolchain: stable
profile: minimal
override: true
- name: Run cargo check 1/3
@ -30,12 +30,12 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --manifest-path crates/runtime/io/Cargo.toml --no-default-features --verbose
args: --locked --manifest-path util/io/Cargo.toml --no-default-features --verbose
- name: Run cargo check 3/3
uses: actions-rs/cargo@v1
with:
command: check
args: --locked --manifest-path crates/runtime/io/Cargo.toml --features "mio" --verbose
args: --locked --manifest-path util/io/Cargo.toml --features "mio" --verbose
- name: Run cargo check evmbin
uses: actions-rs/cargo@v1
with:

View File

@ -16,7 +16,7 @@ jobs:
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 1.52.1
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub

View File

@ -17,7 +17,7 @@ jobs:
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 1.52.1
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub

View File

@ -17,7 +17,7 @@ jobs:
- name: Install toolchain
uses: actions-rs/toolchain@v1
with:
toolchain: 1.52.1
toolchain: stable
profile: minimal
override: true
- name: Deploy to docker hub

View File

@ -11,7 +11,7 @@ jobs:
- uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: 1.52.1
toolchain: stable
override: true
- run: rustup component add rustfmt
- uses: actions-rs/cargo@v1

8
.gitmodules vendored
View File

@ -1,3 +1,7 @@
[submodule "crates/ethcore/res/json_tests"]
path = crates/ethcore/res/json_tests
[submodule "ethcore/res/ethereum/tests"]
path = ethcore/res/ethereum/tests
url = https://github.com/ethereum/tests.git
branch = develop
[submodule "ethcore/res/wasm-tests"]
path = ethcore/res/wasm-tests
url = https://github.com/paritytech/wasm-tests

View File

@ -1,208 +1,55 @@
## OpenEthereum v3.3.3
Enhancements:
* Implement eip-3607 (#593)
## OpenEthereum v3.1.1-rc.1
Bug fixes:
* Add type field for legacy transactions in RPC calls (#580)
* Makes eth_mining to return False if not is not allowed to seal (#581)
* Made nodes data concatenate as RLP sequences instead of bytes (#598)
## OpenEthereum v3.3.2
* Ancient target set. InvalidStateRoot bug (#69) (#149)
* Update linked-hash-map to 0.5.3
Enhancements:
* London hardfork block: Sokol (24114400)
* Add --ws-max-paxload (#155)
* Add flag to disable storage output in openethereum-evm tool #97 (#115)
* ethstore - remove unnecessary dir & tiny-keccak dependencies from the lib (#107)
* Sync block verification (#74)
* Add `wasmDisableTransition` spec option (#60)
* EIP2929 with journaling + Yolov3 (#79)
* EIP2565 impl (#82)
* TypedTransaction (EIP-2718) and Optional access list (EIP-2930) (#135)
Bug fixes:
* Fix for maxPriorityFeePerGas overflow
DevOps:
* Add custom windows runner (#162)
* Remove sscache (#138)
* Fix deprecated set-env declaration (#106)
## OpenEthereum v3.3.1
Enhancements:
* Add eth_maxPriorityFeePerGas implementation (#570)
* Add a bootnode for Kovan
## OpenEthereum v3.1.0
Bug fixes:
* Fix for modexp overflow in debug mode (#578)
OpenEthereum 3.1.0 is a release based on v2.5.13 which is the last stable version known of the client that does not include any of the issues introduced in v2.7. It removes non core features like Ethereum Classic, Private Transactions, Light Client, Updater, IPFS and Swarm support, currently deprecated flags such as expanse, kotti, mordor testnets.
## OpenEthereum v3.3.0
Database migration utility currently in beta: https://github.com/openethereum/3.1-db-upgrade-tool
Enhancements:
* Add `validateServiceTransactionsTransition` spec option to be able to enable additional checking of zero gas price transactions by block verifier
The full list of included changes from v2.5.13 to v3.1.0:
## OpenEthereum v3.3.0-rc.15
* Revert eip1559BaseFeeMinValue activation on xDai at London hardfork block
## OpenEthereum v3.3.0-rc.14
Enhancements:
* Add eip1559BaseFeeMinValue and eip1559BaseFeeMinValueTransition spec options
* Activate eip1559BaseFeeMinValue on xDai at London hardfork block (19040000), set it to 20 GWei
* Activate eip1559BaseFeeMinValue on POA Core at block 24199500 (November 8, 2021), set it to 10 GWei
* Delay difficulty bomb to June 2022 for Ethereum Mainnet (EIP-4345)
## OpenEthereum v3.3.0-rc.13
Enhancements:
* London hardfork block: POA Core (24090200)
## OpenEthereum v3.3.0-rc.12
Enhancements:
* London hardfork block: xDai (19040000)
## OpenEthereum v3.3.0-rc.11
Bug fixes:
* Ignore GetNodeData requests only for non-AuRa chains
## OpenEthereum v3.3.0-rc.10
Enhancements:
* Add eip1559FeeCollector and eip1559FeeCollectorTransition spec options
## OpenEthereum v3.3.0-rc.9
Bug fixes:
* Add service transactions support for EIP-1559
* Fix MinGasPrice config option for POSDAO and EIP-1559
Enhancements:
* min_gas_price becomes min_effective_priority_fee
* added version 4 for TxPermission contract
## OpenEthereum v3.3.0-rc.8
Bug fixes:
* Ignore GetNodeData requests (#519)
## OpenEthereum v3.3.0-rc.7
Bug fixes:
* GetPooledTransactions is sent in invalid form (wrong packet id)
## OpenEthereum v3.3.0-rc.6
Enhancements:
* London hardfork block: kovan (26741100) (#502)
## OpenEthereum v3.3.0-rc.4
Enhancements:
* London hardfork block: mainnet (12,965,000) (#475)
* Support for eth/66 protocol version (#465)
* Bump ethereum/tests to v9.0.3
* Add eth_feeHistory
Bug fixes:
* GetNodeData from eth63 is missing (#466)
* Effective gas price not omitting (#477)
* London support in openethereum-evm (#479)
* gasPrice is required field for Transaction object (#481)
## OpenEthereum v3.3.0-rc.3
Bug fixes:
* Add effective_gas_price to eth_getTransactionReceipt #445 (#450)
* Update eth_gasPrice to support EIP-1559 #449 (#458)
* eth_estimateGas returns "Requires higher than upper limit of X" after London Ropsten Hard Fork #459 (#460)
## OpenEthereum v3.3.0-rc.2
Enhancements:
* EIP-1559: Fee market change for ETH 1.0 chain
* EIP-3198: BASEFEE opcode
* EIP-3529: Reduction in gas refunds
* EIP-3541: Reject new contracts starting with the 0xEF byte
* Delay difficulty bomb to December 2021 (EIP-3554)
* London hardfork blocks: goerli (5,062,605), rinkeby (8,897,988), ropsten (10,499,401)
* Add chainspecs for aleut and baikal
* Bump ethereum/tests to v9.0.2
## OpenEthereum v3.2.6
Enhancement:
* Berlin hardfork blocks: poacore (21,364,900), poasokol (21,050,600)
## OpenEthereum v3.2.5
Bug fixes:
* Backport: Block sync stopped without any errors. #277 (#286)
* Strict memory order (#306)
Enhancements:
* Executable queue for ancient blocks inclusion (#208)
* Backport AuRa commits for xdai (#330)
* Add Nethermind to clients that accept service transactions (#324)
* Implement the filter argument in parity_pendingTransactions (#295)
* Ethereum-types and various libs upgraded (#315)
* [evmbin] Omit storage output, now for std-json (#311)
* Freeze pruning while creating snapshot (#205)
* AuRa multi block reward (#290)
* Improved metrics. DB read/write. prometheus prefix config (#240)
* Send RLPx auth in EIP-8 format (#287)
* rpc module reverted for RPC JSON api (#284)
* Revert "Remove eth/63 protocol version (#252)"
* Support for eth/65 protocol version (#366)
* Berlin hardfork blocks: kovan (24,770,900), xdai (16,101,500)
* Bump ethereum/tests to v8.0.3
devops:
* Upgrade docker alpine to `v1.13.2`. for rust `v1.47`.
* Send SIGTERM instead of SIGHUP to OE daemon (#317)
## OpenEthereum v3.2.4
* Fix for Typed transaction broadcast.
## OpenEthereum v3.2.3
* Hotfix for berlin consensus error.
## OpenEthereum v3.2.2-rc.1
Bug fixes:
* Backport: Block sync stopped without any errors. #277 (#286)
* Strict memory order (#306)
Enhancements:
* Executable queue for ancient blocks inclusion (#208)
* Backport AuRa commits for xdai (#330)
* Add Nethermind to clients that accept service transactions (#324)
* Implement the filter argument in parity_pendingTransactions (#295)
* Ethereum-types and various libs upgraded (#315)
* Bump ethereum/tests to v8.0.2
* [evmbin] Omit storage output, now for std-json (#311)
* Freeze pruning while creating snapshot (#205)
* AuRa multi block reward (#290)
* Improved metrics. DB read/write. prometheus prefix config (#240)
* Send RLPx auth in EIP-8 format (#287)
* rpc module reverted for RPC JSON api (#284)
* Revert "Remove eth/63 protocol version (#252)"
devops:
* Upgrade docker alpine to `v1.13.2`. for rust `v1.47`.
* Send SIGTERM instead of SIGHUP to OE daemon (#317)
## OpenEthereum v3.2.1
Hot fix issue, related to initial sync:
* Initial sync gets stuck. (#318)
## OpenEthereum v3.2.0
Bug fixes:
* Update EWF's chains with Istanbul transition block numbers (#11482) (#254)
* fix Supplied instant is later than self (#169)
* ethcore/snapshot: fix double-lock in Service::feed_chunk (#289)
Enhancements:
* Berlin hardfork blocks: mainnet (12,244,000), goerli (4,460,644), rinkeby (8,290,928) and ropsten (9,812,189)
* yolo3x spec (#241)
* EIP-2930 RPC support
* Remove eth/63 protocol version (#252)
* Snapshot manifest block added to prometheus (#232)
* EIP-1898: Allow default block parameter to be blockHash
* Change ProtocolId to U64
* Use ubuntu-16.04 for glibc compatibility (#11888) (#73)
* Remove classic, kotti, mordor, expanse (#52)
* Added bad block header hash for ropsten (#49)
* Remove accounts bloom (#33)
* Bump jsonrpc-- to v15
* Implement eth/64, remove eth/62 (#46)
* No snapshotting by default (#11814)
* Update Ellaism chainspec
* Prometheus, heavy memory calls removed (#27)
* Update ethereum/tests
* Implement JSON test suite (#11801)
* Fix issues during block sync (#11265)
* Fix race same block (#11400)
* EIP-2537: Precompile for BLS12-381 curve operations (#11707)
* Remove private transactions
* Remove GetNodeData
* Remove IPFS integration (#11532)
* Remove updater
* Remove light client
* Remove C and Java bindings (#11346)
* Remove whisper (#10855)
* EIP-2315: Simple Subroutines for the EVM (#11629)
* Remove deprecated flags (removal of --geth flag)
* Remove support for hardware wallets (#10678)
* Update bootnodes

1232
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
description = "OpenEthereum"
name = "openethereum"
# NOTE Make sure to update util/version/Cargo.toml as well
version = "3.3.3"
version = "3.1.1-rc.1"
license = "GPL-3.0"
authors = [
"OpenEthereum developers",
@ -10,7 +10,7 @@ authors = [
]
[dependencies]
blooms-db = { path = "crates/db/blooms-db" }
blooms-db = { path = "util/blooms-db" }
log = "0.4"
rustc-hex = "1.0"
docopt = "1.0"
@ -22,7 +22,7 @@ number_prefix = "0.2"
rpassword = "1.0"
semver = "0.9"
ansi_term = "0.10"
parking_lot = "0.11.1"
parking_lot = "0.7"
regex = "1.0"
atty = "0.2.8"
toml = "0.4"
@ -35,43 +35,44 @@ fdlimit = "0.1"
ctrlc = { git = "https://github.com/paritytech/rust-ctrlc.git" }
jsonrpc-core = "15.0.0"
parity-bytes = "0.1"
common-types = { path = "crates/ethcore/types" }
ethcore = { path = "crates/ethcore", features = ["parity"] }
ethcore-accounts = { path = "crates/accounts", optional = true }
ethcore-blockchain = { path = "crates/ethcore/blockchain" }
ethcore-call-contract = { path = "crates/vm/call-contract"}
ethcore-db = { path = "crates/db/db" }
ethcore-io = { path = "crates/runtime/io" }
ethcore-logger = { path = "bin/oe/logger" }
ethcore-miner = { path = "crates/concensus/miner" }
ethcore-network = { path = "crates/net/network" }
ethcore-service = { path = "crates/ethcore/service" }
ethcore-sync = { path = "crates/ethcore/sync" }
ethereum-types = "0.9.2"
ethkey = { path = "crates/accounts/ethkey" }
ethstore = { path = "crates/accounts/ethstore" }
fetch = { path = "crates/net/fetch" }
node-filter = { path = "crates/net/node-filter" }
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
rlp = { version = "0.4.6" }
cli-signer= { path = "crates/util/cli-signer" }
common-types = { path = "ethcore/types" }
ethcore = { path = "ethcore", features = ["parity"] }
ethcore-accounts = { path = "accounts", optional = true }
ethcore-blockchain = { path = "ethcore/blockchain" }
ethcore-call-contract = { path = "ethcore/call-contract"}
ethcore-db = { path = "ethcore/db" }
ethcore-io = { path = "util/io" }
ethcore-logger = { path = "parity/logger" }
ethcore-miner = { path = "miner" }
ethcore-network = { path = "util/network" }
ethcore-service = { path = "ethcore/service" }
ethcore-sync = { path = "ethcore/sync" }
ethereum-types = "0.4"
ethkey = { path = "accounts/ethkey" }
ethstore = { path = "accounts/ethstore" }
fetch = { path = "util/fetch" }
node-filter = { path = "ethcore/node-filter" }
rlp = { version = "0.3.0", features = ["ethereum"] }
cli-signer= { path = "cli-signer" }
parity-daemonize = "0.3"
parity-local-store = { path = "crates/concensus/miner/local-store" }
parity-runtime = { path = "crates/runtime/runtime" }
parity-rpc = { path = "crates/rpc" }
parity-version = { path = "crates/util/version" }
parity-local-store = { path = "miner/local-store" }
parity-runtime = { path = "util/runtime" }
parity-rpc = { path = "rpc" }
parity-version = { path = "util/version" }
parity-path = "0.1"
dir = { path = "crates/util/dir" }
panic_hook = { path = "crates/util/panic-hook" }
keccak-hash = "0.5.0"
migration-rocksdb = { path = "crates/db/migration-rocksdb" }
dir = { path = "util/dir" }
panic_hook = { path = "util/panic-hook" }
keccak-hash = "0.1"
migration-rocksdb = { path = "util/migration-rocksdb" }
kvdb = "0.1"
kvdb-rocksdb = "0.1.3"
journaldb = { path = "crates/db/journaldb" }
stats = { path = "crates/util/stats" }
journaldb = { path = "util/journaldb" }
stats = { path = "util/stats" }
prometheus = "0.9.0"
# ethcore-secretstore = { path = "crates/util/secret-store", optional = true }
ethcore-secretstore = { path = "secret-store", optional = true }
registrar = { path = "util/registrar" }
[build-dependencies]
rustc_version = "0.2"
@ -80,7 +81,7 @@ rustc_version = "0.2"
pretty_assertions = "0.1"
ipnetwork = "0.12.6"
tempdir = "0.3"
fake-fetch = { path = "crates/net/fake-fetch" }
fake-fetch = { path = "util/fake-fetch" }
lazy_static = "1.2.0"
[target.'cfg(windows)'.dependencies]
@ -96,6 +97,7 @@ test-heavy = ["ethcore/test-heavy"]
evm-debug = ["ethcore/evm-debug"]
evm-debug-tests = ["ethcore/evm-debug-tests"]
slow-blocks = ["ethcore/slow-blocks"]
secretstore = ["ethcore-secretstore", "ethcore-secretstore/accounts"]
final = ["parity-version/final"]
deadlock_detection = ["parking_lot/deadlock_detection"]
# to create a memory profile (requires nightly rust), use e.g.
@ -107,10 +109,10 @@ deadlock_detection = ["parking_lot/deadlock_detection"]
memory_profiling = []
[lib]
path = "bin/oe/lib.rs"
path = "parity/lib.rs"
[[bin]]
path = "bin/oe/main.rs"
path = "parity/main.rs"
name = "openethereum"
[profile.test]
@ -126,8 +128,17 @@ lto = true
# in the dependency tree in any other way
# (i.e. pretty much only standalone CLI tools)
members = [
"bin/ethkey",
"bin/ethstore",
"bin/evmbin",
"bin/chainspec"
"accounts/ethkey/cli",
"accounts/ethstore/cli",
"chainspec",
"ethcore/wasm/run",
"evmbin",
"util/triehash-ethereum",
"util/keccak-hasher",
"util/patricia-trie-ethereum",
"util/fastmap",
"util/time-utils"
]
[patch.crates-io]
heapsize = { git = "https://github.com/cheme/heapsize.git", branch = "ec-macfix" }

View File

@ -297,9 +297,9 @@ Caching, Importing Blocks, and Block Information
In addition to the OpenEthereum client, there are additional tools in this repository available:
- [evmbin](./bin/evmbin) - OpenEthereum EVM Implementation.
- [ethstore](./crates/accounts/ethstore) - OpenEthereum Key Management.
- [ethkey](./crates/accounts/ethkey) - OpenEthereum Keys Generator.
- [evmbin](./evmbin) - OpenEthereum EVM Implementation.
- [ethstore](./accounts/ethstore) - OpenEthereum Key Management.
- [ethkey](./accounts/ethkey) - OpenEthereum Keys Generator.
The following tools are available in a separate repository:
- [ethabi](https://github.com/openethereum/ethabi) - OpenEthereum Encoding of Function Calls. [Docs here](https://crates.io/crates/ethabi)

View File

@ -12,12 +12,11 @@ common-types = { path = "../ethcore/types" }
ethkey = { path = "ethkey" }
ethstore = { path = "ethstore" }
log = "0.4"
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
parking_lot = "0.11.1"
parking_lot = "0.7"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
[dev-dependencies]
ethereum-types = "0.9.2"
ethereum-types = "0.4"
tempdir = "0.3"

View File

@ -6,15 +6,15 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
edit-distance = "2.0"
parity-crypto = { version = "0.6.2", features = ["publickey"] }
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "9791e79f21a5309dcb6e0bd254b1ef88fca2f1f4" }
ethereum-types = "0.9.2"
parity-crypto = "0.3.0"
eth-secp256k1 = { git = "https://github.com/paritytech/rust-secp256k1", rev = "ccc06e7480148b723eb44ac56cf4d20eec380b6f" }
ethereum-types = "0.4"
lazy_static = "1.0"
log = "0.4"
memzero = { path = "../../../crates/util/memzero" }
memzero = { path = "../../util/memzero" }
parity-wordlist = "1.3"
quick-error = "1.2.2"
rand = "0.7.3"
rand = "0.4"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"

View File

@ -7,9 +7,8 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
docopt = "1.0"
env_logger = "0.5"
ethkey = { path = "../../crates/accounts/ethkey" }
panic_hook = { path = "../../crates/util/panic-hook" }
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
ethkey = { path = "../" }
panic_hook = { path = "../../../util/panic-hook" }
parity-wordlist="1.3"
rustc-hex = "1.0"
serde = "1.0"

View File

@ -18,7 +18,6 @@ extern crate docopt;
extern crate env_logger;
extern crate ethkey;
extern crate panic_hook;
extern crate parity_crypto as crypto;
extern crate parity_wordlist;
extern crate rustc_hex;
extern crate serde;
@ -29,11 +28,11 @@ extern crate serde_derive;
use std::{env, fmt, io, num::ParseIntError, process, sync};
use crypto::publickey::{
sign, verify_address, verify_public, Error as EthkeyError, Generator, KeyPair, Random,
};
use docopt::Docopt;
use ethkey::{brain_recover, Brain, BrainPrefix, Prefix};
use ethkey::{
brain_recover, sign, verify_address, verify_public, Brain, BrainPrefix, Error as EthkeyError,
Generator, KeyPair, Prefix, Random,
};
use rustc_hex::{FromHex, FromHexError};
const USAGE: &'static str = r#"
@ -203,13 +202,15 @@ where
let result = if args.flag_brain {
let phrase = args.arg_secret_or_phrase;
let phrase_info = validate_phrase(&phrase);
let keypair = Brain::new(phrase).generate();
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::InvalidSecretKey)?;
.map_err(|_| EthkeyError::InvalidSecret)?;
(KeyPair::from_secret(secret)?, None)
};
Ok(display(result, display_mode))
@ -222,7 +223,7 @@ where
let phrase = format!("recovery phrase: {}", brain.phrase());
(keypair, Some(phrase))
} else {
(Random.generate(), None)
(Random.generate()?, None)
}
} else if args.cmd_prefix {
let prefix = args.arg_prefix.from_hex()?;
@ -253,7 +254,7 @@ where
let secret = args
.arg_secret
.parse()
.map_err(|_| EthkeyError::InvalidSecretKey)?;
.map_err(|_| EthkeyError::InvalidSecret)?;
let message = args
.arg_message
.parse()
@ -273,7 +274,7 @@ where
let public = args
.arg_public
.parse()
.map_err(|_| EthkeyError::InvalidPublicKey)?;
.map_err(|_| EthkeyError::InvalidPublic)?;
verify_public(&public, &signature, &message)?
} else if args.cmd_address {
let address = args
@ -300,7 +301,7 @@ where
while let Some(phrase) = it.next() {
i += 1;
let keypair = Brain::new(phrase.clone()).generate();
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address() == address {
return Ok(Some((phrase, keypair)));
}

View File

@ -14,10 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use parity_crypto::{
publickey::{KeyPair, Secret},
Keccak256,
};
use super::{Generator, KeyPair, Secret};
use keccak::Keccak256;
use parity_wordlist;
/// Simple brainwallet.
@ -31,8 +29,12 @@ impl Brain {
pub fn validate_phrase(phrase: &str, expected_words: usize) -> Result<(), ::WordlistError> {
parity_wordlist::validate_phrase(phrase, expected_words)
}
}
pub fn generate(&mut self) -> KeyPair {
impl Generator for Brain {
type Error = ::Void;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let seed = self.0.clone();
let mut secret = seed.into_bytes().keccak256();
@ -43,10 +45,12 @@ impl Brain {
match i > 16384 {
false => i += 1,
true => {
if let Ok(pair) = Secret::import_key(&secret).and_then(KeyPair::from_secret) {
if let Ok(pair) =
Secret::from_unsafe_slice(&secret).and_then(KeyPair::from_secret)
{
if pair.address()[0] == 0 {
trace!("Testing: {}, got: {:?}", self.0, pair.address());
return pair;
return Ok(pair);
}
}
}
@ -58,12 +62,13 @@ impl Brain {
#[cfg(test)]
mod tests {
use Brain;
use Generator;
#[test]
fn test_brain() {
let words = "this is sparta!".to_owned();
let first_keypair = Brain::new(words.clone()).generate();
let second_keypair = Brain::new(words.clone()).generate();
let first_keypair = Brain::new(words.clone()).generate().unwrap();
let second_keypair = Brain::new(words.clone()).generate().unwrap();
assert_eq!(first_keypair.secret(), second_keypair.secret());
}
}

View File

@ -14,8 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::Brain;
use parity_crypto::publickey::{Error, KeyPair};
use super::{Brain, Error, Generator, KeyPair};
use parity_wordlist as wordlist;
/// Tries to find brain-seed keypair with address starting with given prefix.
@ -39,12 +38,16 @@ impl BrainPrefix {
pub fn phrase(&self) -> &str {
&self.last_phrase
}
}
pub fn generate(&mut self) -> Result<KeyPair, Error> {
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();
if keypair.address().as_ref().starts_with(&self.prefix) {
let keypair = Brain::new(phrase.clone()).generate().unwrap();
if keypair.address().starts_with(&self.prefix) {
self.last_phrase = phrase;
return Ok(keypair);
}
@ -57,6 +60,7 @@ impl BrainPrefix {
#[cfg(test)]
mod tests {
use BrainPrefix;
use Generator;
#[test]
fn prefix_generator() {
@ -64,6 +68,6 @@ mod tests {
let keypair = BrainPrefix::new(prefix.clone(), usize::max_value(), 12)
.generate()
.unwrap();
assert!(keypair.address().as_bytes().starts_with(&prefix));
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@ -17,10 +17,9 @@
use std::collections::HashSet;
use edit_distance::edit_distance;
use parity_crypto::publickey::Address;
use parity_wordlist;
use super::Brain;
use super::{Address, Brain, Generator};
/// Tries to find a phrase for address, given the number
/// of expected words and a partial phrase.
@ -33,7 +32,9 @@ pub fn brain_recover(
) -> Option<String> {
let it = PhrasesIterator::from_known_phrase(known_phrase, expected_words);
for phrase in it {
let keypair = Brain::new(phrase.clone()).generate();
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);

View File

@ -0,0 +1,202 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
#![allow(deprecated)]
use parity_crypto::error::SymmError;
use secp256k1;
use std::io;
quick_error! {
#[derive(Debug)]
pub enum Error {
Secp(e: secp256k1::Error) {
display("secp256k1 error: {}", e)
cause(e)
from()
}
Io(e: io::Error) {
display("i/o error: {}", e)
cause(e)
from()
}
InvalidMessage {
display("invalid message")
}
Symm(e: SymmError) {
cause(e)
from()
}
}
}
/// ECDH functions
pub mod ecdh {
use super::Error;
use secp256k1::{self, ecdh, key};
use Public;
use Secret;
use SECP256K1;
/// Agree on a shared secret
pub fn agree(secret: &Secret, public: &Public) -> Result<Secret, Error> {
let context = &SECP256K1;
let pdata = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
let publ = key::PublicKey::from_slice(context, &pdata)?;
let sec = key::SecretKey::from_slice(context, &secret)?;
let shared = ecdh::SharedSecret::new_raw(context, &publ, &sec);
Secret::from_unsafe_slice(&shared[0..32])
.map_err(|_| Error::Secp(secp256k1::Error::InvalidSecretKey))
}
}
/// ECIES function
pub mod ecies {
use super::{ecdh, Error};
use ethereum_types::H128;
use parity_crypto::{aes, digest, hmac, is_equal};
use Generator;
use Public;
use Random;
use Secret;
/// Encrypt a message with a public key, writing an HMAC covering both
/// the plaintext and authenticated data.
///
/// Authenticated data may be empty.
pub fn encrypt(public: &Public, auth_data: &[u8], plain: &[u8]) -> Result<Vec<u8>, Error> {
let r = Random.generate()?;
let z = ecdh::agree(r.secret(), public)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let mut msg = vec![0u8; 1 + 64 + 16 + plain.len() + 32];
msg[0] = 0x04u8;
{
let msgd = &mut msg[1..];
msgd[0..64].copy_from_slice(r.public());
let iv = H128::random();
msgd[64..80].copy_from_slice(&iv);
{
let cipher = &mut msgd[(64 + 16)..(64 + 16 + plain.len())];
aes::encrypt_128_ctr(ekey, &iv, plain, cipher)?;
}
let mut hmac = hmac::Signer::with(&mkey);
{
let cipher_iv = &msgd[64..(64 + 16 + plain.len())];
hmac.update(cipher_iv);
}
hmac.update(auth_data);
let sig = hmac.sign();
msgd[(64 + 16 + plain.len())..].copy_from_slice(&sig);
}
Ok(msg)
}
/// Decrypt a message with a secret key, checking HMAC for ciphertext
/// and authenticated data validity.
pub fn decrypt(secret: &Secret, auth_data: &[u8], encrypted: &[u8]) -> Result<Vec<u8>, Error> {
let meta_len = 1 + 64 + 16 + 32;
if encrypted.len() < meta_len || encrypted[0] < 2 || encrypted[0] > 4 {
return Err(Error::InvalidMessage); //invalid message: publickey
}
let e = &encrypted[1..];
let p = Public::from_slice(&e[0..64]);
let z = ecdh::agree(secret, &p)?;
let mut key = [0u8; 32];
kdf(&z, &[0u8; 0], &mut key);
let ekey = &key[0..16];
let mkey = hmac::SigKey::sha256(&digest::sha256(&key[16..32]));
let clen = encrypted.len() - meta_len;
let cipher_with_iv = &e[64..(64 + 16 + clen)];
let cipher_iv = &cipher_with_iv[0..16];
let cipher_no_iv = &cipher_with_iv[16..];
let msg_mac = &e[(64 + 16 + clen)..];
// Verify tag
let mut hmac = hmac::Signer::with(&mkey);
hmac.update(cipher_with_iv);
hmac.update(auth_data);
let mac = hmac.sign();
if !is_equal(&mac.as_ref()[..], msg_mac) {
return Err(Error::InvalidMessage);
}
let mut msg = vec![0u8; clen];
aes::decrypt_128_ctr(ekey, cipher_iv, cipher_no_iv, &mut msg[..])?;
Ok(msg)
}
fn kdf(secret: &Secret, s1: &[u8], dest: &mut [u8]) {
// SEC/ISO/Shoup specify counter size SHOULD be equivalent
// to size of hash output, however, it also notes that
// the 4 bytes is okay. NIST specifies 4 bytes.
let mut ctr = 1u32;
let mut written = 0usize;
while written < dest.len() {
let mut hasher = digest::Hasher::sha256();
let ctrs = [
(ctr >> 24) as u8,
(ctr >> 16) as u8,
(ctr >> 8) as u8,
ctr as u8,
];
hasher.update(&ctrs);
hasher.update(secret);
hasher.update(s1);
let d = hasher.finish();
&mut dest[written..(written + 32)].copy_from_slice(&d);
written += 32;
ctr += 1;
}
}
}
#[cfg(test)]
mod tests {
use super::ecies;
use Generator;
use Random;
#[test]
fn ecies_shared() {
let kp = Random.generate().unwrap();
let message = b"So many books, so little time";
let shared = b"shared";
let wrong_shared = b"incorrect";
let encrypted = ecies::encrypt(kp.public(), shared, message).unwrap();
assert!(encrypted[..] != message[..]);
assert_eq!(encrypted[0], 0x04);
assert!(ecies::decrypt(kp.secret(), wrong_shared, &encrypted).is_err());
let decrypted = ecies::decrypt(kp.secret(), shared, &encrypted).unwrap();
assert_eq!(decrypted[..message.len()], message[..]);
}
}

View File

@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::Error as CryptoError;
use std::{error, fmt};
#[derive(Debug)]
@ -54,7 +53,7 @@ impl fmt::Display for Error {
impl error::Error for Error {
fn description(&self) -> &str {
format!("{:?}", &self)
"Crypto error"
}
}
@ -64,12 +63,6 @@ impl Into<String> for Error {
}
}
impl From<CryptoError> for Error {
fn from(e: CryptoError) -> Error {
Error::Custom(e.to_string())
}
}
impl From<::secp256k1::Error> for Error {
fn from(e: ::secp256k1::Error) -> Error {
match e {

View File

@ -0,0 +1,589 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Extended keys
pub use self::derivation::Error as DerivationError;
use ethereum_types::H256;
use secret::Secret;
use Public;
/// Represents label that can be stored as a part of key derivation
pub trait Label {
/// Length of the data that label occupies
fn len() -> usize;
/// Store label data to the key derivation sequence
/// Must not use more than `len()` bytes from slice
fn store(&self, target: &mut [u8]);
}
impl Label for u32 {
fn len() -> usize {
4
}
fn store(&self, target: &mut [u8]) {
let bytes = self.to_be_bytes();
target[0..4].copy_from_slice(&bytes);
}
}
/// Key derivation over generic label `T`
pub enum Derivation<T: Label> {
/// Soft key derivation (allow proof of parent)
Soft(T),
/// Hard key derivation (does not allow proof of parent)
Hard(T),
}
impl From<u32> for Derivation<u32> {
fn from(index: u32) -> Self {
if index < (2 << 30) {
Derivation::Soft(index)
} else {
Derivation::Hard(index)
}
}
}
impl Label for H256 {
fn len() -> usize {
32
}
fn store(&self, target: &mut [u8]) {
self.copy_to(&mut target[0..32]);
}
}
/// Extended secret key, allows deterministic derivation of subsequent keys.
pub struct ExtendedSecret {
secret: Secret,
chain_code: H256,
}
impl ExtendedSecret {
/// New extended key from given secret and chain code.
pub fn with_code(secret: Secret, chain_code: H256) -> ExtendedSecret {
ExtendedSecret {
secret: secret,
chain_code: chain_code,
}
}
/// New extended key from given secret with the random chain code.
pub fn new_random(secret: Secret) -> ExtendedSecret {
ExtendedSecret::with_code(secret, H256::random())
}
/// New extended key from given secret.
/// Chain code will be derived from the secret itself (in a deterministic way).
pub fn new(secret: Secret) -> ExtendedSecret {
let chain_code = derivation::chain_code(*secret);
ExtendedSecret::with_code(secret, chain_code)
}
/// Derive new private key
pub fn derive<T>(&self, index: Derivation<T>) -> ExtendedSecret
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::private(*self.secret, self.chain_code, index);
let derived_secret = Secret::from(derived_key.0);
ExtendedSecret::with_code(derived_secret, next_chain_code)
}
/// Private key component of the extended key.
pub fn as_raw(&self) -> &Secret {
&self.secret
}
}
/// Extended public key, allows deterministic derivation of subsequent keys.
pub struct ExtendedPublic {
public: Public,
chain_code: H256,
}
impl ExtendedPublic {
/// New extended public key from known parent and chain code
pub fn new(public: Public, chain_code: H256) -> Self {
ExtendedPublic {
public: public,
chain_code: chain_code,
}
}
/// Create new extended public key from known secret
pub fn from_secret(secret: &ExtendedSecret) -> Result<Self, DerivationError> {
Ok(ExtendedPublic::new(
derivation::point(**secret.as_raw())?,
secret.chain_code.clone(),
))
}
/// Derive new public key
/// Operation is defined only for index belongs [0..2^31)
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let (derived_key, next_chain_code) =
derivation::public(self.public, self.chain_code, index)?;
Ok(ExtendedPublic::new(derived_key, next_chain_code))
}
pub fn public(&self) -> &Public {
&self.public
}
}
pub struct ExtendedKeyPair {
secret: ExtendedSecret,
public: ExtendedPublic,
}
impl ExtendedKeyPair {
pub fn new(secret: Secret) -> Self {
let extended_secret = ExtendedSecret::new(secret);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
pub fn with_code(secret: Secret, public: Public, chain_code: H256) -> Self {
ExtendedKeyPair {
secret: ExtendedSecret::with_code(secret, chain_code.clone()),
public: ExtendedPublic::new(public, chain_code),
}
}
pub fn with_secret(secret: Secret, chain_code: H256) -> Self {
let extended_secret = ExtendedSecret::with_code(secret, chain_code);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Valid `Secret` always produces valid public; qed");
ExtendedKeyPair {
secret: extended_secret,
public: extended_public,
}
}
pub fn with_seed(seed: &[u8]) -> Result<ExtendedKeyPair, DerivationError> {
let (master_key, chain_code) = derivation::seed_pair(seed);
Ok(ExtendedKeyPair::with_secret(
Secret::from_unsafe_slice(&*master_key).map_err(|_| DerivationError::InvalidSeed)?,
chain_code,
))
}
pub fn secret(&self) -> &ExtendedSecret {
&self.secret
}
pub fn public(&self) -> &ExtendedPublic {
&self.public
}
pub fn derive<T>(&self, index: Derivation<T>) -> Result<Self, DerivationError>
where
T: Label,
{
let derived = self.secret.derive(index);
Ok(ExtendedKeyPair {
public: ExtendedPublic::from_secret(&derived)?,
secret: derived,
})
}
}
// Derivation functions for private and public keys
// Work is based on BIP0032
// https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki
mod derivation {
use super::{Derivation, Label};
use ethereum_types::{H256, H512, U256, U512};
use keccak;
use math::curve_order;
use parity_crypto::hmac;
use secp256k1::key::{PublicKey, SecretKey};
use SECP256K1;
#[derive(Debug)]
pub enum Error {
InvalidHardenedUse,
InvalidPoint,
MissingIndex,
InvalidSeed,
}
// Deterministic derivation of the key using secp256k1 elliptic curve.
// Derivation can be either hardened or not.
// For hardened derivation, pass u32 index at least 2^31 or custom Derivation::Hard(T) enum
//
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
pub fn private<T>(private_key: H256, chain_code: H256, index: Derivation<T>) -> (H256, H256)
where
T: Label,
{
match index {
Derivation::Soft(index) => private_soft(private_key, chain_code, index),
Derivation::Hard(index) => private_hard(private_key, chain_code, index),
}
}
fn hmac_pair(data: &[u8], private_key: H256, chain_code: H256) -> (H256, H256) {
let private: U256 = private_key.into();
// produces 512-bit derived hmac (I)
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
// left most 256 bits are later added to original private key
let hmac_key: U256 = H256::from_slice(&i_512[0..32]).into();
// right most 256 bits are new chain code for later derivations
let next_chain_code = H256::from(&i_512[32..64]);
let child_key = private_add(hmac_key, private).into();
(child_key, next_chain_code)
}
// Can panic if passed `private_key` is not a valid secp256k1 private key
// (outside of (0..curve_order()]) field
fn private_soft<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
where
T: Label,
{
let mut data = vec![0u8; 33 + T::len()];
let sec_private = SecretKey::from_slice(&SECP256K1, &*private_key)
.expect("Caller should provide valid private key");
let sec_public = PublicKey::from_secret_key(&SECP256K1, &sec_private)
.expect("Caller should provide valid private key");
let public_serialized = sec_public.serialize_vec(&SECP256K1, true);
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..]);
hmac_pair(&data, private_key, chain_code)
}
// Deterministic derivation of the key using secp256k1 elliptic curve
// This is hardened derivation and does not allow to associate
// corresponding public keys of the original and derived private keys
fn private_hard<T>(private_key: H256, chain_code: H256, index: T) -> (H256, H256)
where
T: Label,
{
let mut data: Vec<u8> = vec![0u8; 33 + T::len()];
let private: U256 = private_key.into();
// 0x00 (padding) -- private_key -- index
// 0 -- 1..33 -- 33..end
private.to_big_endian(&mut data[1..33]);
index.store(&mut data[33..(33 + T::len())]);
hmac_pair(&data, private_key, chain_code)
}
fn private_add(k1: U256, k2: U256) -> U256 {
let sum = U512::from(k1) + U512::from(k2);
modulo(sum, curve_order())
}
// todo: surely can be optimized
fn modulo(u1: U512, u2: U256) -> U256 {
let dv = u1 / U512::from(u2);
let md = u1 - (dv * U512::from(u2));
md.into()
}
pub fn public<T>(
public_key: H512,
chain_code: H256,
derivation: Derivation<T>,
) -> Result<(H512, H256), Error>
where
T: Label,
{
let index = match derivation {
Derivation::Soft(index) => index,
Derivation::Hard(_) => {
return Err(Error::InvalidHardenedUse);
}
};
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..65].copy_from_slice(&*public_key);
let public_sec =
PublicKey::from_slice(&SECP256K1, &public_sec_raw).map_err(|_| Error::InvalidPoint)?;
let public_serialized = public_sec.serialize_vec(&SECP256K1, true);
let mut data = vec![0u8; 33 + T::len()];
// curve point (compressed public key) -- index
// 0.33 -- 33..end
data[0..33].copy_from_slice(&public_serialized);
index.store(&mut data[33..(33 + T::len())]);
// HMAC512SHA produces [derived private(256); new chain code(256)]
let skey = hmac::SigKey::sha512(&*chain_code);
let i_512 = hmac::sign(&skey, &data[..]);
let new_private = H256::from(&i_512[0..32]);
let new_chain_code = H256::from(&i_512[32..64]);
// Generated private key can (extremely rarely) be out of secp256k1 key field
if curve_order() <= new_private.clone().into() {
return Err(Error::MissingIndex);
}
let new_private_sec = SecretKey::from_slice(&SECP256K1, &*new_private)
.expect("Private key belongs to the field [0..CURVE_ORDER) (checked above); So initializing can never fail; qed");
let mut new_public = PublicKey::from_secret_key(&SECP256K1, &new_private_sec)
.expect("Valid private key produces valid public key");
// Adding two points on the elliptic curves (combining two public keys)
new_public
.add_assign(&SECP256K1, &public_sec)
.expect("Addition of two valid points produce valid point");
let serialized = new_public.serialize_vec(&SECP256K1, false);
Ok((H512::from(&serialized[1..65]), new_chain_code))
}
fn sha3(slc: &[u8]) -> H256 {
keccak::Keccak256::keccak256(slc).into()
}
pub fn chain_code(secret: H256) -> H256 {
// 10,000 rounds of sha3
let mut running_sha3 = sha3(&*secret);
for _ in 0..99999 {
running_sha3 = sha3(&*running_sha3);
}
running_sha3
}
pub fn point(secret: H256) -> Result<H512, Error> {
let sec = SecretKey::from_slice(&SECP256K1, &*secret).map_err(|_| Error::InvalidPoint)?;
let public_sec =
PublicKey::from_secret_key(&SECP256K1, &sec).map_err(|_| Error::InvalidPoint)?;
let serialized = public_sec.serialize_vec(&SECP256K1, false);
Ok(H512::from(&serialized[1..65]))
}
pub fn seed_pair(seed: &[u8]) -> (H256, H256) {
let skey = hmac::SigKey::sha512(b"Bitcoin seed");
let i_512 = hmac::sign(&skey, seed);
let master_key = H256::from_slice(&i_512[0..32]);
let chain_code = H256::from_slice(&i_512[32..64]);
(master_key, chain_code)
}
}
#[cfg(test)]
mod tests {
use super::{derivation, Derivation, ExtendedKeyPair, ExtendedPublic, ExtendedSecret};
use ethereum_types::{H128, H256};
use secret::Secret;
use std::str::FromStr;
fn master_chain_basic() -> (H256, H256) {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
derivation::seed_pair(&*seed)
}
fn test_extended<F>(f: F, test_private: H256)
where
F: Fn(ExtendedSecret) -> ExtendedSecret,
{
let (private_seed, chain_code) = master_chain_basic();
let extended_secret = ExtendedSecret::with_code(Secret::from(private_seed.0), chain_code);
let derived = f(extended_secret);
assert_eq!(**derived.as_raw(), test_private);
}
#[test]
fn smoky() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
// hardened
assert_eq!(&**extended_secret.as_raw(), &*secret);
assert_eq!(
&**extended_secret.derive(2147483648.into()).as_raw(),
&"0927453daed47839608e414a3738dfad10aed17c459bbd9ab53f89b026c834b6".into()
);
assert_eq!(
&**extended_secret.derive(2147483649.into()).as_raw(),
&"44238b6a29c6dcbe9b401364141ba11e2198c289a5fed243a1c11af35c19dc0f".into()
);
// normal
assert_eq!(
&**extended_secret.derive(0.into()).as_raw(),
&"bf6a74e3f7b36fc4c96a1e12f31abc817f9f5904f5a8fc27713163d1f0b713f6".into()
);
assert_eq!(
&**extended_secret.derive(1.into()).as_raw(),
&"bd4fca9eb1f9c201e9448c1eecd66e302d68d4d313ce895b8c134f512205c1bc".into()
);
assert_eq!(
&**extended_secret.derive(2.into()).as_raw(),
&"86932b542d6cab4d9c65490c7ef502d89ecc0e2a5f4852157649e3251e2a3268".into()
);
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_public = extended_public
.derive(0.into())
.expect("First derivation of public should succeed");
assert_eq!(&*derived_public.public(), &"f7b3244c96688f92372bfd4def26dc4151529747bab9f188a4ad34e141d47bd66522ff048bc6f19a0a4429b04318b1a8796c000265b4fa200dae5f6dda92dd94".into());
let keypair = ExtendedKeyPair::with_secret(
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap(),
064.into(),
);
assert_eq!(
&**keypair
.derive(2147483648u32.into())
.expect("Derivation of keypair should succeed")
.secret()
.as_raw(),
&"edef54414c03196557cf73774bc97a645c9a1df2164ed34f0c2a78d1375a930c".into()
);
}
#[test]
fn h256_soft_match() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let derivation_secret =
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 0u64.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(Derivation::Soft(derivation_secret));
let derived_public0 = extended_public
.derive(Derivation::Soft(derivation_secret))
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
fn h256_hard() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let derivation_secret =
H256::from_str("51eaf04f9dbbc1417dc97e789edd0c37ecda88bac490434e367ea81b71b7b015")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1u64.into());
assert_eq!(
&**extended_secret
.derive(Derivation::Hard(derivation_secret))
.as_raw(),
&"2bc2d696fb744d77ff813b4a1ef0ad64e1e5188b622c54ba917acc5ebc7c5486".into()
);
}
#[test]
fn match_() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let extended_secret = ExtendedSecret::with_code(secret.clone(), 1.into());
let extended_public = ExtendedPublic::from_secret(&extended_secret)
.expect("Extended public should be created");
let derived_secret0 = extended_secret.derive(0.into());
let derived_public0 = extended_public
.derive(0.into())
.expect("First derivation of public should succeed");
let public_from_secret0 = ExtendedPublic::from_secret(&derived_secret0)
.expect("Extended public should be created");
assert_eq!(public_from_secret0.public(), derived_public0.public());
}
#[test]
fn test_seeds() {
let seed = H128::from_str("000102030405060708090a0b0c0d0e0f")
.expect("Seed should be valid H128")
.to_vec();
// private key from bitcoin test vector
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
let test_private =
H256::from_str("e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35")
.expect("Private should be decoded ok");
let (private_seed, _) = derivation::seed_pair(&*seed);
assert_eq!(private_seed, test_private);
}
#[test]
fn test_vector_1() {
// xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7
// H(0)
test_extended(
|secret| secret.derive(2147483648.into()),
H256::from_str("edb2e14f9ee77d26dd93b4ecede8d16ed408ce149b6cd80b0715a2d911a0afea")
.expect("Private should be decoded ok"),
);
}
#[test]
fn test_vector_2() {
// xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs
// H(0)/1
test_extended(
|secret| secret.derive(2147483648.into()).derive(1.into()),
H256::from_str("3c6cb8d0f6a264c91ea8b5030fadaa8e538b020f0a387421a12de9319dc93368")
.expect("Private should be decoded ok"),
);
}
}

View File

@ -0,0 +1,33 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use tiny_keccak::Keccak;
pub trait Keccak256<T> {
fn keccak256(&self) -> T
where
T: Sized;
}
impl Keccak256<[u8; 32]> for [u8] {
fn keccak256(&self) -> [u8; 32] {
let mut keccak = Keccak::new_keccak256();
let mut result = [0u8; 32];
keccak.update(self);
keccak.finalize(&mut result);
result
}
}

View File

@ -0,0 +1,120 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Address, Error, Public, Secret, SECP256K1};
use keccak::Keccak256;
use rustc_hex::ToHex;
use secp256k1::key;
use std::fmt;
pub fn public_to_address(public: &Public) -> Address {
let hash = public.keccak256();
let mut result = Address::default();
result.copy_from_slice(&hash[12..]);
result
}
#[derive(Debug, Clone, PartialEq)]
/// secp256k1 key pair
pub struct KeyPair {
secret: Secret,
public: Public,
}
impl fmt::Display for KeyPair {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "secret: {}", self.secret.to_hex())?;
writeln!(f, "public: {}", self.public.to_hex())?;
write!(f, "address: {}", self.address().to_hex())
}
}
impl KeyPair {
/// Create a pair from secret key
pub fn from_secret(secret: Secret) -> Result<KeyPair, Error> {
let context = &SECP256K1;
let s: key::SecretKey = key::SecretKey::from_slice(context, &secret[..])?;
let pub_key = key::PublicKey::from_secret_key(context, &s)?;
let serialized = pub_key.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
let keypair = KeyPair {
secret: secret,
public: public,
};
Ok(keypair)
}
pub fn from_secret_slice(slice: &[u8]) -> Result<KeyPair, Error> {
Self::from_secret(Secret::from_unsafe_slice(slice)?)
}
pub fn from_keypair(sec: key::SecretKey, publ: key::PublicKey) -> Self {
let context = &SECP256K1;
let serialized = publ.serialize_vec(context, false);
let secret = Secret::from(sec);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
KeyPair {
secret: secret,
public: public,
}
}
pub fn secret(&self) -> &Secret {
&self.secret
}
pub fn public(&self) -> &Public {
&self.public
}
pub fn address(&self) -> Address {
public_to_address(&self.public)
}
}
#[cfg(test)]
mod tests {
use std::str::FromStr;
use KeyPair;
use Secret;
#[test]
fn from_secret() {
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let _ = KeyPair::from_secret(secret).unwrap();
}
#[test]
fn keypair_display() {
let expected =
"secret: a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65
public: 8ce0db0b0359ffc5866ba61903cc2518c3675ef2cf380a7e54bde7ea20e6fa1ab45b7617346cd11b7610001ee6ae5b0155c41cad9527cbcdff44ec67848943a4
address: 5b073e9233944b5e729e46d618f0d8edf3d9c34a".to_owned();
let secret =
Secret::from_str("a100df7a048e50ed308ea696dc600215098141cb391e9527329df289f9383f65")
.unwrap();
let kp = KeyPair::from_secret(secret).unwrap();
assert_eq!(format!("{}", kp), expected);
}
}

View File

@ -0,0 +1,89 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
// #![warn(missing_docs)]
extern crate edit_distance;
extern crate ethereum_types;
extern crate memzero;
extern crate parity_crypto;
extern crate parity_wordlist;
#[macro_use]
extern crate quick_error;
extern crate rand;
extern crate rustc_hex;
extern crate secp256k1;
extern crate serde;
extern crate tiny_keccak;
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
mod brain;
mod brain_prefix;
mod error;
mod extended;
mod keccak;
mod keypair;
mod password;
mod prefix;
mod random;
mod secret;
mod signature;
pub mod brain_recover;
pub mod crypto;
pub mod math;
pub use self::{
brain::Brain,
brain_prefix::BrainPrefix,
error::Error,
extended::{Derivation, DerivationError, ExtendedKeyPair, ExtendedPublic, ExtendedSecret},
keypair::{public_to_address, KeyPair},
math::public_is_valid,
parity_wordlist::Error as WordlistError,
password::Password,
prefix::Prefix,
random::Random,
secret::Secret,
signature::{recover, sign, verify_address, verify_public, Signature},
};
use ethereum_types::H256;
pub use ethereum_types::{Address, Public};
pub type Message = H256;
lazy_static! {
pub static ref SECP256K1: secp256k1::Secp256k1 = secp256k1::Secp256k1::new();
}
/// Uninstantiatable error type for infallible generators.
#[derive(Debug)]
pub enum Void {}
/// Generates new keypair.
pub trait Generator {
type Error;
/// Should be called to generate new keypair.
fn generate(&mut self) -> Result<KeyPair, Self::Error>;
}

134
accounts/ethkey/src/math.rs Normal file
View File

@ -0,0 +1,134 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Error, Public, Secret, SECP256K1};
use ethereum_types::{H256, U256};
use secp256k1::{
constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
key,
};
/// Whether the public key is valid.
pub fn public_is_valid(public: &Public) -> bool {
to_secp256k1_public(public)
.ok()
.map_or(false, |p| p.is_valid())
}
/// Inplace multiply public key by secret key (EC point * scalar)
pub fn public_mul_secret(public: &mut Public, secret: &Secret) -> Result<(), Error> {
let key_secret = secret.to_secp256k1_secret()?;
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key_secret)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace add one public key to another (EC point + EC point)
pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
let other_public = to_secp256k1_public(other)?;
key_public.add_assign(&SECP256K1, &other_public)?;
set_public(public, &key_public);
Ok(())
}
/// Inplace sub one public key from another (EC point - EC point)
pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
let mut key_neg_other = to_secp256k1_public(other)?;
key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
let mut key_public = to_secp256k1_public(public)?;
key_public.add_assign(&SECP256K1, &key_neg_other)?;
set_public(public, &key_public);
Ok(())
}
/// Replace public key with its negation (EC point = - EC point)
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
let mut key_public = to_secp256k1_public(public)?;
key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
set_public(public, &key_public);
Ok(())
}
/// Return base point of secp256k1
pub fn generation_point() -> Public {
let mut public_sec_raw = [0u8; 65];
public_sec_raw[0] = 4;
public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
.expect("constructing using predefined constants; qed");
let mut public = Public::default();
set_public(&mut public, &public_key);
public
}
/// Return secp256k1 elliptic curve order
pub fn curve_order() -> U256 {
H256::from_slice(&CURVE_ORDER).into()
}
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
let public_data = {
let mut temp = [4u8; 65];
(&mut temp[1..65]).copy_from_slice(&public[0..64]);
temp
};
Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
}
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
public.copy_from_slice(&key_public_serialized[1..65]);
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
public_add, public_sub,
};
#[test]
fn public_addition_is_commutative() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut left = public1.clone();
public_add(&mut left, &public2).unwrap();
let mut right = public2.clone();
public_add(&mut right, &public1).unwrap();
assert_eq!(left, right);
}
#[test]
fn public_addition_is_reversible_with_subtraction() {
let public1 = Random.generate().unwrap().public().clone();
let public2 = Random.generate().unwrap().public().clone();
let mut sum = public1.clone();
public_add(&mut sum, &public2).unwrap();
public_sub(&mut sum, &public2).unwrap();
assert_eq!(sum, public1);
}
}

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use parity_crypto::publickey::{Error, Generator, KeyPair, Random};
use super::{Error, Generator, KeyPair, Random};
/// Tries to find keypair with address starting with given prefix.
pub struct Prefix {
@ -24,13 +24,20 @@ pub struct Prefix {
impl Prefix {
pub fn new(prefix: Vec<u8>, iterations: usize) -> Self {
Prefix { prefix, iterations }
Prefix {
prefix: prefix,
iterations: iterations,
}
}
}
pub fn generate(&mut self) -> Result<KeyPair, Error> {
impl Generator for Prefix {
type Error = Error;
fn generate(&mut self) -> Result<KeyPair, Error> {
for _ in 0..self.iterations {
let keypair = Random.generate();
if keypair.address().as_ref().starts_with(&self.prefix) {
let keypair = Random.generate()?;
if keypair.address().starts_with(&self.prefix) {
return Ok(keypair);
}
}
@ -41,6 +48,7 @@ impl Prefix {
#[cfg(test)]
mod tests {
use Generator;
use Prefix;
#[test]
@ -49,6 +57,6 @@ mod tests {
let keypair = Prefix::new(prefix.clone(), usize::max_value())
.generate()
.unwrap();
assert!(keypair.address().as_bytes().starts_with(&prefix));
assert!(keypair.address().starts_with(&prefix));
}
}

View File

@ -0,0 +1,45 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use super::{Generator, KeyPair, SECP256K1};
use rand::os::OsRng;
/// Randomly generates new keypair, instantiating the RNG each time.
pub struct Random;
impl Generator for Random {
type Error = ::std::io::Error;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let mut rng = OsRng::new()?;
match rng.generate() {
Ok(pair) => Ok(pair),
Err(void) => match void {}, // LLVM unreachable
}
}
}
impl Generator for OsRng {
type Error = ::Void;
fn generate(&mut self) -> Result<KeyPair, Self::Error> {
let (sec, publ) = SECP256K1
.generate_keypair(self)
.expect("context always created with full capabilities; qed");
Ok(KeyPair::from_keypair(sec, publ))
}
}

View File

@ -0,0 +1,322 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::H256;
use memzero::Memzero;
use rustc_hex::ToHex;
use secp256k1::{constants::SECRET_KEY_SIZE as SECP256K1_SECRET_KEY_SIZE, key};
use std::{fmt, ops::Deref, str::FromStr};
use Error;
use SECP256K1;
#[derive(Clone, PartialEq, Eq)]
pub struct Secret {
inner: Memzero<H256>,
}
impl ToHex for Secret {
fn to_hex(&self) -> String {
format!("{:x}", *self.inner)
}
}
impl fmt::LowerHex for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Debug for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
self.inner.fmt(fmt)
}
}
impl fmt::Display for Secret {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(
fmt,
"Secret: 0x{:x}{:x}..{:x}{:x}",
self.inner[0], self.inner[1], self.inner[30], self.inner[31]
)
}
}
impl Secret {
/// Creates a `Secret` from the given slice, returning `None` if the slice length != 32.
pub fn from_slice(key: &[u8]) -> Option<Self> {
if key.len() != 32 {
return None;
}
let mut h = H256::default();
h.copy_from_slice(&key[0..32]);
Some(Secret {
inner: Memzero::from(h),
})
}
/// Creates zero key, which is invalid for crypto operations, but valid for math operation.
pub fn zero() -> Self {
Secret {
inner: Memzero::from(H256::default()),
}
}
/// Imports and validates the key.
pub fn from_unsafe_slice(key: &[u8]) -> Result<Self, Error> {
let secret = key::SecretKey::from_slice(&super::SECP256K1, key)?;
Ok(secret.into())
}
/// Checks validity of this key.
pub fn check_validity(&self) -> Result<(), Error> {
self.to_secp256k1_secret().map(|_| ())
}
/// Inplace add one secret key to another (scalar + scalar)
pub fn add(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace subtract one secret key from another (scalar - scalar)
pub fn sub(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (false, true) => Ok(()),
(true, false) => {
*self = other.clone();
self.neg()
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let mut other_secret = other.to_secp256k1_secret()?;
other_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
key_secret.add_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace decrease secret key (scalar - 1)
pub fn dec(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => {
*self = key::MINUS_ONE_KEY.into();
Ok(())
}
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.add_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace multiply one secret key to another (scalar * scalar)
pub fn mul(&mut self, other: &Secret) -> Result<(), Error> {
match (self.is_zero(), other.is_zero()) {
(true, true) | (true, false) => Ok(()),
(false, true) => {
*self = Self::zero();
Ok(())
}
(false, false) => {
let mut key_secret = self.to_secp256k1_secret()?;
let other_secret = other.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &other_secret)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace negate secret key (-scalar)
pub fn neg(&mut self) -> Result<(), Error> {
match self.is_zero() {
true => Ok(()),
false => {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
*self = key_secret.into();
Ok(())
}
}
}
/// Inplace inverse secret key (1 / scalar)
pub fn inv(&mut self) -> Result<(), Error> {
let mut key_secret = self.to_secp256k1_secret()?;
key_secret.inv_assign(&SECP256K1)?;
*self = key_secret.into();
Ok(())
}
/// Compute power of secret key inplace (secret ^ pow).
/// This function is not intended to be used with large powers.
pub fn pow(&mut self, pow: usize) -> Result<(), Error> {
if self.is_zero() {
return Ok(());
}
match pow {
0 => *self = key::ONE_KEY.into(),
1 => (),
_ => {
let c = self.clone();
for _ in 1..pow {
self.mul(&c)?;
}
}
}
Ok(())
}
/// Create `secp256k1::key::SecretKey` based on this secret
pub fn to_secp256k1_secret(&self) -> Result<key::SecretKey, Error> {
Ok(key::SecretKey::from_slice(&SECP256K1, &self[..])?)
}
}
impl FromStr for Secret {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(H256::from_str(s)
.map_err(|e| Error::Custom(format!("{:?}", e)))?
.into())
}
}
impl From<[u8; 32]> for Secret {
fn from(k: [u8; 32]) -> Self {
Secret {
inner: Memzero::from(H256(k)),
}
}
}
impl From<H256> for Secret {
fn from(s: H256) -> Self {
s.0.into()
}
}
impl From<&'static str> for Secret {
fn from(s: &'static str) -> Self {
s.parse().expect(&format!(
"invalid string literal for {}: '{}'",
stringify!(Self),
s
))
}
}
impl From<key::SecretKey> for Secret {
fn from(key: key::SecretKey) -> Self {
let mut a = [0; SECP256K1_SECRET_KEY_SIZE];
a.copy_from_slice(&key[0..SECP256K1_SECRET_KEY_SIZE]);
a.into()
}
}
impl Deref for Secret {
type Target = H256;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
#[cfg(test)]
mod tests {
use super::{
super::{Generator, Random},
Secret,
};
use std::str::FromStr;
#[test]
fn multiplicating_secret_inversion_with_secret_gives_one() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.mul(&secret).unwrap();
assert_eq!(
inversion,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
}
#[test]
fn secret_inversion_is_reversible_with_inversion() {
let secret = Random.generate().unwrap().secret().clone();
let mut inversion = secret.clone();
inversion.inv().unwrap();
inversion.inv().unwrap();
assert_eq!(inversion, secret);
}
#[test]
fn secret_pow() {
let secret = Random.generate().unwrap().secret().clone();
let mut pow0 = secret.clone();
pow0.pow(0).unwrap();
assert_eq!(
pow0,
Secret::from_str("0000000000000000000000000000000000000000000000000000000000000001")
.unwrap()
);
let mut pow1 = secret.clone();
pow1.pow(1).unwrap();
assert_eq!(pow1, secret);
let mut pow2 = secret.clone();
pow2.pow(2).unwrap();
let mut pow2_expected = secret.clone();
pow2_expected.mul(&secret).unwrap();
assert_eq!(pow2, pow2_expected);
let mut pow3 = secret.clone();
pow3.pow(3).unwrap();
let mut pow3_expected = secret.clone();
pow3_expected.mul(&secret).unwrap();
pow3_expected.mul(&secret).unwrap();
assert_eq!(pow3, pow3_expected);
}
}

View File

@ -0,0 +1,325 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use ethereum_types::{H256, H520};
use public_to_address;
use rustc_hex::{FromHex, ToHex};
use secp256k1::{
key::{PublicKey, SecretKey},
Error as SecpError, Message as SecpMessage, RecoverableSignature, RecoveryId,
};
use std::{
cmp::PartialEq,
fmt,
hash::{Hash, Hasher},
ops::{Deref, DerefMut},
str::FromStr,
};
use Address;
use Error;
use Message;
use Public;
use Secret;
use SECP256K1;
/// Signature encoded as RSV components
#[repr(C)]
pub struct Signature([u8; 65]);
impl Signature {
/// Get a slice into the 'r' portion of the data.
pub fn r(&self) -> &[u8] {
&self.0[0..32]
}
/// Get a slice into the 's' portion of the data.
pub fn s(&self) -> &[u8] {
&self.0[32..64]
}
/// Get the recovery byte.
pub fn v(&self) -> u8 {
self.0[64]
}
/// Encode the signature into RSV array (V altered to be in "Electrum" notation).
pub fn into_electrum(mut self) -> [u8; 65] {
self.0[64] += 27;
self.0
}
/// Parse bytes as a signature encoded as RSV (V in "Electrum" notation).
/// May return empty (invalid) signature if given data has invalid length.
pub fn from_electrum(data: &[u8]) -> Self {
if data.len() != 65 || data[64] < 27 {
// fallback to empty (invalid) signature
return Signature::default();
}
let mut sig = [0u8; 65];
sig.copy_from_slice(data);
sig[64] -= 27;
Signature(sig)
}
/// Create a signature object from the sig.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Self {
let mut sig = [0u8; 65];
sig[0..32].copy_from_slice(&r);
sig[32..64].copy_from_slice(&s);
sig[64] = v;
Signature(sig)
}
/// Check if this is a "low" signature.
pub fn is_low_s(&self) -> bool {
H256::from_slice(self.s())
<= "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0".into()
}
/// Check if each component of the signature is in range.
pub fn is_valid(&self) -> bool {
self.v() <= 1
&& H256::from_slice(self.r())
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
&& H256::from_slice(self.r()) >= 1.into()
&& H256::from_slice(self.s())
< "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141".into()
&& H256::from_slice(self.s()) >= 1.into()
}
}
// manual implementation large arrays don't have trait impls by default.
// remove when integer generics exist
impl PartialEq for Signature {
fn eq(&self, other: &Self) -> bool {
&self.0[..] == &other.0[..]
}
}
// manual implementation required in Rust 1.13+, see `std::cmp::AssertParamIsEq`.
impl Eq for Signature {}
// also manual for the same reason, but the pretty printing might be useful.
impl fmt::Debug for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("Signature")
.field("r", &self.0[0..32].to_hex())
.field("s", &self.0[32..64].to_hex())
.field("v", &self.0[64..65].to_hex())
.finish()
}
}
impl fmt::Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{}", self.to_hex())
}
}
impl FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.from_hex() {
Ok(ref hex) if hex.len() == 65 => {
let mut data = [0; 65];
data.copy_from_slice(&hex[0..65]);
Ok(Signature(data))
}
_ => Err(Error::InvalidSignature),
}
}
}
impl Default for Signature {
fn default() -> Self {
Signature([0; 65])
}
}
impl Hash for Signature {
fn hash<H: Hasher>(&self, state: &mut H) {
H520::from(self.0).hash(state);
}
}
impl Clone for Signature {
fn clone(&self) -> Self {
Signature(self.0)
}
}
impl From<[u8; 65]> for Signature {
fn from(s: [u8; 65]) -> Self {
Signature(s)
}
}
impl Into<[u8; 65]> for Signature {
fn into(self) -> [u8; 65] {
self.0
}
}
impl From<Signature> for H520 {
fn from(s: Signature) -> Self {
H520::from(s.0)
}
}
impl From<H520> for Signature {
fn from(bytes: H520) -> Self {
Signature(bytes.into())
}
}
impl Deref for Signature {
type Target = [u8; 65];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for Signature {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub fn sign(secret: &Secret, message: &Message) -> Result<Signature, Error> {
let context = &SECP256K1;
let sec = SecretKey::from_slice(context, &secret)?;
let s = context.sign_recoverable(&SecpMessage::from_slice(&message[..])?, &sec)?;
let (rec_id, data) = s.serialize_compact(context);
let mut data_arr = [0; 65];
// no need to check if s is low, it always is
data_arr[0..64].copy_from_slice(&data[0..64]);
data_arr[64] = rec_id.to_i32() as u8;
Ok(Signature(data_arr))
}
pub fn verify_public(
public: &Public,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let sig = rsig.to_standard(context);
let pdata: [u8; 65] = {
let mut temp = [4u8; 65];
temp[1..65].copy_from_slice(&**public);
temp
};
let publ = PublicKey::from_slice(context, &pdata)?;
match context.verify(&SecpMessage::from_slice(&message[..])?, &sig, &publ) {
Ok(_) => Ok(true),
Err(SecpError::IncorrectSignature) => Ok(false),
Err(x) => Err(Error::from(x)),
}
}
pub fn verify_address(
address: &Address,
signature: &Signature,
message: &Message,
) -> Result<bool, Error> {
let public = recover(signature, message)?;
let recovered_address = public_to_address(&public);
Ok(address == &recovered_address)
}
pub fn recover(signature: &Signature, message: &Message) -> Result<Public, Error> {
let context = &SECP256K1;
let rsig = RecoverableSignature::from_compact(
context,
&signature[0..64],
RecoveryId::from_i32(signature[64] as i32)?,
)?;
let pubkey = context.recover(&SecpMessage::from_slice(&message[..])?, &rsig)?;
let serialized = pubkey.serialize_vec(context, false);
let mut public = Public::default();
public.copy_from_slice(&serialized[1..65]);
Ok(public)
}
#[cfg(test)]
mod tests {
use super::{recover, sign, verify_address, verify_public, Signature};
use std::str::FromStr;
use Generator;
use Message;
use Random;
#[test]
fn vrs_conversion() {
// given
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
// when
let vrs = signature.clone().into_electrum();
let from_vrs = Signature::from_electrum(&vrs);
// then
assert_eq!(signature, from_vrs);
}
#[test]
fn signature_to_and_from_str() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
let string = format!("{}", signature);
let deserialized = Signature::from_str(&string).unwrap();
assert_eq!(signature, deserialized);
}
#[test]
fn sign_and_recover_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert_eq!(keypair.public(), &recover(&signature, &message).unwrap());
}
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_public(keypair.public(), &signature, &message).unwrap());
}
#[test]
fn sign_and_verify_address() {
let keypair = Random.generate().unwrap();
let message = Message::default();
let signature = sign(keypair.secret(), &message).unwrap();
assert!(verify_address(&keypair.address(), &signature, &message).unwrap());
}
}

View File

@ -7,7 +7,7 @@ authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
log = "0.4"
libc = "0.2"
rand = "0.7.3"
rand = "0.4"
ethkey = { path = "../ethkey" }
serde = "1.0"
serde_json = "1.0"
@ -15,9 +15,9 @@ serde_derive = "1.0"
rustc-hex = "1.0"
time = "0.1.34"
itertools = "0.5"
parking_lot = "0.11.1"
parity-crypto = { version = "0.6.2", features = [ "publickey"] }
ethereum-types = "0.9.2"
parking_lot = "0.7"
parity-crypto = "0.3.0"
ethereum-types = "0.4"
smallvec = "0.6"
parity-wordlist = "1.3"
tempdir = "0.3"

View File

@ -11,10 +11,10 @@ num_cpus = "1.6"
rustc-hex = "1.0"
serde = "1.0"
serde_derive = "1.0"
parking_lot = "0.11.1"
ethstore = { path = "../../crates/accounts/ethstore" }
dir = { path = '../../crates/util/dir' }
panic_hook = { path = "../../crates/util/panic-hook" }
parking_lot = "0.7"
ethstore = { path = "../" }
dir = { path = '../../../util/dir' }
panic_hook = { path = "../../../util/panic-hook" }
[[bin]]
name = "ethstore"

View File

@ -15,8 +15,8 @@
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use account::{Aes128Ctr, Cipher, Kdf, Pbkdf2, Prf};
use crypto::{self, publickey::Secret, Keccak256};
use ethkey::Password;
use crypto::{self, Keccak256};
use ethkey::{Password, Secret};
use json;
use random::Random;
use smallvec::SmallVec;
@ -79,7 +79,7 @@ impl Crypto {
password: &Password,
iterations: NonZeroU32,
) -> Result<Self, crypto::Error> {
Crypto::with_plain(secret.as_bytes(), password, iterations)
Crypto::with_plain(&*secret, password, iterations)
}
/// Encrypt custom plain data
@ -94,7 +94,7 @@ impl Crypto {
// two parts of derived key
// DK = [ DK[0..15] DK[16..31] ] = [derived_left_bits, derived_right_bits]
let (derived_left_bits, derived_right_bits) =
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations.get());
crypto::derive_key_iterations(password.as_bytes(), &salt, iterations);
// preallocated (on-stack in case of `Secret`) buffer to hold cipher
// length = length(plain) as we are using CTR-approach
@ -127,7 +127,7 @@ impl Crypto {
}
let secret = self.do_decrypt(password, 32)?;
Ok(Secret::import_key(&secret)?)
Ok(Secret::from_unsafe_slice(&secret)?)
}
/// Try to decrypt and return result as is
@ -139,7 +139,7 @@ impl Crypto {
fn do_decrypt(&self, password: &Password, expected_len: usize) -> Result<Vec<u8>, Error> {
let (derived_left_bits, derived_right_bits) = match self.kdf {
Kdf::Pbkdf2(ref params) => {
crypto::derive_key_iterations(password.as_bytes(), &params.salt, params.c.get())
crypto::derive_key_iterations(password.as_bytes(), &params.salt, params.c)
}
Kdf::Scrypt(ref params) => crypto::scrypt::derive_key(
password.as_bytes(),
@ -179,7 +179,7 @@ impl Crypto {
#[cfg(test)]
mod tests {
use super::{Crypto, Error, NonZeroU32};
use crypto::publickey::{Generator, Random};
use ethkey::{Generator, Random};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
@ -187,7 +187,7 @@ mod tests {
#[test]
fn crypto_with_secret_create() {
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let passwd = "this is sparta".into();
let crypto = Crypto::with_secret(keypair.secret(), &passwd, *ITERATIONS).unwrap();
let secret = crypto.secret(&passwd).unwrap();
@ -196,7 +196,7 @@ mod tests {
#[test]
fn crypto_with_secret_invalid_password() {
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let crypto =
Crypto::with_secret(keypair.secret(), &"this is sparta".into(), *ITERATIONS).unwrap();
assert_matches!(

View File

@ -16,11 +16,10 @@
use super::crypto::Crypto;
use account::Version;
use crypto::{
self,
publickey::{ecdh::agree, sign, Address, KeyPair, Message, Public, Secret, Signature},
use crypto;
use ethkey::{
self, crypto::ecdh::agree, sign, Address, KeyPair, Message, Password, Public, Secret, Signature,
};
use ethkey::Password;
use json;
use std::num::NonZeroU32;
use Error;
@ -194,7 +193,7 @@ impl SafeAccount {
message: &[u8],
) -> Result<Vec<u8>, Error> {
let secret = self.crypto.secret(password)?;
crypto::publickey::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
ethkey::crypto::ecies::decrypt(&secret, shared_mac, message).map_err(From::from)
}
/// Agree on shared key.
@ -238,7 +237,7 @@ impl SafeAccount {
#[cfg(test)]
mod tests {
use super::{NonZeroU32, SafeAccount};
use crypto::publickey::{verify_public, Generator, Random};
use ethkey::{verify_public, Generator, Message, Random};
lazy_static! {
static ref ITERATIONS: NonZeroU32 = NonZeroU32::new(10240).expect("10240 > 0; qed");
@ -246,9 +245,9 @@ mod tests {
#[test]
fn sign_and_verify_public() {
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let message = [1u8; 32].into();
let message = Message::default();
let account = SafeAccount::create(
&keypair,
[0u8; 16],
@ -263,10 +262,10 @@ mod tests {
#[test]
fn change_password() {
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let first_password = "hello world".into();
let sec_password = "this is sparta".into();
let message = [1u8; 32].into();
let message = Message::default();
let account = SafeAccount::create(
&keypair,
[0u8; 16],

View File

@ -420,7 +420,7 @@ mod test {
use self::tempdir::TempDir;
use super::{KeyDirectory, RootDiskDirectory, VaultKey};
use account::SafeAccount;
use crypto::publickey::{Generator, Random};
use ethkey::{Generator, Random};
use std::{env, fs, num::NonZeroU32};
lazy_static! {
@ -432,7 +432,7 @@ mod test {
// given
let mut dir = env::temp_dir();
dir.push("ethstore_should_create_new_account");
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
@ -463,7 +463,7 @@ mod test {
// given
let mut dir = env::temp_dir();
dir.push("ethstore_should_handle_duplicate_filenames");
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let password = "hello world".into();
let directory = RootDiskDirectory::create(dir.clone()).unwrap();
@ -582,7 +582,7 @@ mod test {
.expect("Files hash should be calculated ok");
assert_eq!(hash, 15130871412783076140);
let keypair = Random.generate();
let keypair = Random.generate().unwrap();
let password = "test pass".into();
let account = SafeAccount::create(
&keypair,

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::publickey::Address;
use ethkey::Address;
use itertools;
use parking_lot::RwLock;
use std::collections::HashMap;
@ -70,7 +70,7 @@ impl KeyDirectory for MemoryDirectory {
let mut val = 0u64;
let accounts = self.accounts.read();
for acc in accounts.keys() {
val = val ^ acc.to_low_u64_be()
val = val ^ acc.low_u64()
}
Ok(val)
}

View File

@ -14,7 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::publickey::DerivationError;
use crypto::{self, Error as EthCryptoError};
use ethkey::{self, DerivationError, Error as EthKeyError};
use std::{fmt, io::Error as IoError};
/// Account-related errors.
@ -44,10 +45,12 @@ pub enum Error {
VaultNotFound,
/// Account creation failed.
CreationFailed,
/// `crypto::publickey::Error`
EthCrypto(crypto::Error),
/// `EthKey` error
EthKey(EthKeyError),
/// `ethkey::crypto::Error`
EthKeyCrypto(ethkey::crypto::Error),
/// `EthCrypto` error
EthCryptoPublicKey(crypto::publickey::Error),
EthCrypto(EthCryptoError),
/// Derivation error
Derivation(DerivationError),
/// Custom error
@ -69,8 +72,9 @@ impl fmt::Display for Error {
Error::InvalidVaultName => "Invalid vault name".into(),
Error::VaultNotFound => "Vault not found".into(),
Error::CreationFailed => "Account creation failed".into(),
Error::EthKey(ref err) => err.to_string(),
Error::EthKeyCrypto(ref err) => err.to_string(),
Error::EthCrypto(ref err) => err.to_string(),
Error::EthCryptoPublicKey(ref err) => err.to_string(),
Error::Derivation(ref err) => format!("Derivation error: {:?}", err),
Error::Custom(ref s) => s.clone(),
};
@ -85,14 +89,20 @@ impl From<IoError> for Error {
}
}
impl From<crypto::publickey::Error> for Error {
fn from(err: crypto::publickey::Error) -> Self {
Error::EthCryptoPublicKey(err)
impl From<EthKeyError> for Error {
fn from(err: EthKeyError) -> Self {
Error::EthKey(err)
}
}
impl From<crypto::Error> for Error {
fn from(err: crypto::Error) -> Self {
impl From<ethkey::crypto::Error> for Error {
fn from(err: ethkey::crypto::Error) -> Self {
Error::EthKeyCrypto(err)
}
}
impl From<EthCryptoError> for Error {
fn from(err: EthCryptoError) -> Self {
Error::EthCrypto(err)
}
}

View File

@ -16,7 +16,6 @@
//! ethkey reexport to make documentation look pretty.
pub use _ethkey::*;
pub use crypto::publickey::Address;
use json;
impl Into<json::H160> for Address {

View File

@ -24,10 +24,9 @@ use std::{
use account::SafeAccount;
use accounts_dir::{KeyDirectory, SetKeyError, VaultKey, VaultKeyDirectory};
use crypto::publickey::{
self, Address, ExtendedKeyPair, KeyPair, Message, Public, Secret, Signature,
use ethkey::{
self, Address, ExtendedKeyPair, KeyPair, Message, Password, Public, Secret, Signature,
};
use ethkey::Password;
use json::{self, OpaqueKeyFile, Uuid};
use presale::PresaleWallet;
use random::Random;
@ -555,17 +554,17 @@ impl EthMultiStore {
Derivation::Hierarchical(path) => {
for path_item in path {
extended = extended.derive(if path_item.soft {
publickey::Derivation::Soft(path_item.index)
ethkey::Derivation::Soft(path_item.index)
} else {
publickey::Derivation::Hard(path_item.index)
ethkey::Derivation::Hard(path_item.index)
})?;
}
}
Derivation::SoftHash(h256) => {
extended = extended.derive(publickey::Derivation::Soft(h256))?;
extended = extended.derive(ethkey::Derivation::Soft(h256))?;
}
Derivation::HardHash(h256) => {
extended = extended.derive(publickey::Derivation::Hard(h256))?;
extended = extended.derive(ethkey::Derivation::Hard(h256))?;
}
}
Ok(extended)
@ -616,7 +615,7 @@ impl SimpleSecretStore for EthMultiStore {
let accounts = self.get_matching(&account_ref, password)?;
for account in accounts {
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
return Ok(publickey::public_to_address(extended.public().public()));
return Ok(ethkey::public_to_address(extended.public().public()));
}
Err(Error::InvalidPassword)
}
@ -632,7 +631,7 @@ impl SimpleSecretStore for EthMultiStore {
for account in accounts {
let extended = self.generate(account.crypto.secret(password)?, derivation)?;
let secret = extended.secret().as_raw();
return Ok(publickey::sign(&secret, message)?);
return Ok(ethkey::sign(&secret, message)?);
}
Err(Error::InvalidPassword)
}
@ -899,14 +898,14 @@ mod tests {
use self::tempdir::TempDir;
use super::{EthMultiStore, EthStore};
use accounts_dir::{KeyDirectory, MemoryDirectory, RootDiskDirectory};
use crypto::publickey::{Generator, KeyPair, Random};
use ethereum_types::H256;
use ethkey::{Generator, KeyPair, Random};
use secret_store::{
Derivation, SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
};
fn keypair() -> KeyPair {
Random.generate()
Random.generate().unwrap()
}
fn store() -> EthStore {
@ -1052,7 +1051,6 @@ mod tests {
let passwd2 = "xzy".into();
let multi_store = multi_store();
let keypair = keypair();
let message = [1u8; 32].into();
let address = store
.insert_account(SecretVaultRef::Root, keypair.secret().clone(), &passwd1)
.unwrap();
@ -1075,7 +1073,9 @@ mod tests {
"First password should work for store."
);
assert!(
multi_store.sign(&address, &passwd2, &message).is_ok(),
multi_store
.sign(&address, &passwd2, &Default::default())
.is_ok(),
"Second password should work for second store."
);
assert_eq!(multi_store.accounts().unwrap().len(), 1);
@ -1462,7 +1462,7 @@ mod tests {
SecretVaultRef::Root,
&address,
&"test".into(),
Derivation::HardHash(H256::zero()),
Derivation::HardHash(H256::from(0)),
)
.unwrap();
@ -1470,10 +1470,11 @@ mod tests {
let accounts = store.accounts().unwrap();
assert_eq!(accounts.len(), 2);
let message = [1u8; 32].into();
// and we can sign with the derived contract
assert!(
store.sign(&derived, &"test".into(), &message).is_ok(),
store
.sign(&derived, &"test".into(), &Default::default())
.is_ok(),
"Second password should work for second store."
);
}

View File

@ -17,7 +17,7 @@
use std::{collections::HashSet, fs, path::Path};
use accounts_dir::{DiskKeyFileManager, KeyDirectory, KeyFileManager};
use crypto::publickey::Address;
use ethkey::Address;
use Error;
/// Import an account from a file.

View File

@ -159,7 +159,10 @@ impl<'a> Visitor<'a> for CryptoVisitor {
(Some(_), None) => return Err(V::Error::missing_field("cipherparams")),
};
let ciphertext = ciphertext.ok_or_else(|| V::Error::missing_field("ciphertext"))?;
let ciphertext = match ciphertext {
Some(ciphertext) => ciphertext,
None => return Err(V::Error::missing_field("ciphertext")),
};
let kdf = match (kdf, kdfparams) {
(Some(KdfSer::Pbkdf2), Some(KdfSerParams::Pbkdf2(params))) => Kdf::Pbkdf2(params),
@ -169,7 +172,10 @@ impl<'a> Visitor<'a> for CryptoVisitor {
(Some(_), None) => return Err(V::Error::missing_field("kdfparams")),
};
let mac = mac.ok_or_else(|| V::Error::missing_field("mac"))?;
let mac = match mac {
Some(mac) => mac,
None => return Err(V::Error::missing_field("mac")),
};
let result = Crypto {
cipher: cipher,

View File

@ -169,11 +169,20 @@ impl<'a> Visitor<'a> for KeyFileVisitor {
}
}
let id = id.ok_or_else(|| V::Error::missing_field("id"))?;
let id = match id {
Some(id) => id,
None => return Err(V::Error::missing_field("id")),
};
let version = version.ok_or_else(|| V::Error::missing_field("version"))?;
let version = match version {
Some(version) => version,
None => return Err(V::Error::missing_field("version")),
};
let crypto = crypto.ok_or_else(|| V::Error::missing_field("crypto"))?;
let crypto = match crypto {
Some(crypto) => crypto,
None => return Err(V::Error::missing_field("crypto")),
};
let result = KeyFile {
id: id,

View File

@ -74,4 +74,4 @@ pub use self::{
};
/// An opaque wrapper for secret.
pub struct OpaqueSecret(crypto::publickey::Secret);
pub struct OpaqueSecret(::ethkey::Secret);

View File

@ -14,12 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::{
self, pbkdf2,
publickey::{Address, KeyPair, Secret},
Keccak256,
};
use ethkey::Password;
use crypto::{self, pbkdf2, Keccak256};
use ethkey::{Address, KeyPair, Password, Secret};
use json;
use std::{fs, num::NonZeroU32, path::Path};
use Error;
@ -65,7 +61,7 @@ impl PresaleWallet {
let salt = pbkdf2::Salt(password.as_bytes());
let sec = pbkdf2::Secret(password.as_bytes());
let iter = NonZeroU32::new(2000).expect("2000 > 0; qed");
pbkdf2::sha256(iter.get(), salt, sec, &mut derived_key);
pbkdf2::sha256(iter, salt, sec, &mut derived_key);
let mut key = vec![0; self.ciphertext.len()];
let len =
@ -73,7 +69,7 @@ impl PresaleWallet {
.map_err(|_| Error::InvalidPassword)?;
let unpadded = &key[..len];
let secret = Secret::import_key(&unpadded.keccak256())?;
let secret = Secret::from_unsafe_slice(&unpadded.keccak256())?;
if let Ok(kp) = KeyPair::from_secret(secret) {
if kp.address() == self.address {
return Ok(kp);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng, RngCore};
use rand::{OsRng, Rng};
pub trait Random {
fn random() -> Self
@ -25,7 +25,7 @@ pub trait Random {
impl Random for [u8; 16] {
fn random() -> Self {
let mut result = [0u8; 16];
let mut rng = OsRng;
let mut rng = OsRng::new().unwrap();
rng.fill_bytes(&mut result);
result
}
@ -34,7 +34,7 @@ impl Random for [u8; 16] {
impl Random for [u8; 32] {
fn random() -> Self {
let mut result = [0u8; 32];
let mut rng = OsRng;
let mut rng = OsRng::new().unwrap();
rng.fill_bytes(&mut result);
result
}
@ -42,6 +42,6 @@ impl Random for [u8; 32] {
/// Generate a random string of given length.
pub fn random_string(length: usize) -> String {
let rng = OsRng;
rng.sample_iter(&Alphanumeric).take(length).collect()
let mut rng = OsRng::new().expect("Not able to operate without random source.");
rng.gen_ascii_chars().take(length).collect()
}

View File

@ -14,9 +14,8 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
use crypto::publickey::{Address, Message, Public, Secret, Signature};
use ethereum_types::H256;
use ethkey::Password;
use ethkey::{Address, Message, Password, Public, Secret, Signature};
use json::{OpaqueKeyFile, Uuid};
use std::{
cmp::Ordering,
@ -175,7 +174,7 @@ pub trait SecretStore: SimpleSecretStore {
secret: &OpaqueSecret,
message: &Message,
) -> Result<Signature, Error> {
Ok(crypto::publickey::sign(&secret.0, message)?)
Ok(::ethkey::sign(&secret.0, message)?)
}
/// Imports presale wallet

View File

@ -14,19 +14,15 @@
// You should have received a copy of the GNU General Public License
// along with OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate ethereum_types;
extern crate ethstore;
extern crate parity_crypto as crypto;
extern crate rand;
mod util;
use std::str::FromStr;
use crypto::publickey::{verify_address, Generator, KeyPair, Random, Secret};
use ethereum_types::H160;
use ethstore::{
accounts_dir::RootDiskDirectory, EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
accounts_dir::RootDiskDirectory,
ethkey::{verify_address, Generator, KeyPair, Random, Secret},
EthStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
};
use util::TransientDir;
@ -44,7 +40,7 @@ fn secret_store_open_not_existing() {
}
fn random_secret() -> Secret {
Random.generate().secret().clone()
Random.generate().unwrap().secret().clone()
}
#[test]
@ -70,10 +66,13 @@ fn secret_store_sign() {
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
let accounts = store.accounts().unwrap();
let message = [1u8; 32].into();
assert_eq!(accounts.len(), 1);
assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
assert!(store.sign(&accounts[0], &"1".into(), &message).is_err());
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_ok());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_err());
}
#[test]
@ -84,14 +83,19 @@ fn secret_store_change_password() {
.insert_account(SecretVaultRef::Root, random_secret(), &"".into())
.is_ok());
let accounts = store.accounts().unwrap();
let message = [1u8; 32].into();
assert_eq!(accounts.len(), 1);
assert!(store.sign(&accounts[0], &"".into(), &message).is_ok());
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_ok());
assert!(store
.change_password(&accounts[0], &"".into(), &"1".into())
.is_ok());
assert!(store.sign(&accounts[0], &"".into(), &message).is_err());
assert!(store.sign(&accounts[0], &"1".into(), &message).is_ok());
assert!(store
.sign(&accounts[0], &"".into(), &Default::default())
.is_err());
assert!(store
.sign(&accounts[0], &"1".into(), &Default::default())
.is_ok());
}
#[test]
@ -136,15 +140,9 @@ fn secret_store_laod_geth_files() {
assert_eq!(
store.accounts().unwrap(),
vec![
StoreAccountRef::root(
H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
),
StoreAccountRef::root(
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
),
StoreAccountRef::root(
H160::from_str("63121b431a52f8043c16fcf0d1df9cb7b5f66649").unwrap()
),
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
StoreAccountRef::root("63121b431a52f8043c16fcf0d1df9cb7b5f66649".into()),
]
);
}
@ -156,12 +154,8 @@ fn secret_store_load_pat_files() {
assert_eq!(
store.accounts().unwrap(),
vec![
StoreAccountRef::root(
H160::from_str("3f49624084b67849c7b4e805c5988c21a430f9d9").unwrap()
),
StoreAccountRef::root(
H160::from_str("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf").unwrap()
),
StoreAccountRef::root("3f49624084b67849c7b4e805c5988c21a430f9d9".into()),
StoreAccountRef::root("5ba4dcf897e97c2bdf8315b9ef26c13c085988cf".into()),
]
);
}
@ -188,16 +182,12 @@ fn test_decrypting_files_with_short_ciphertext() {
assert_eq!(
accounts,
vec![
StoreAccountRef::root(
H160::from_str("31e9d1e6d844bd3a536800ef8d8be6a9975db509").unwrap()
),
StoreAccountRef::root(
H160::from_str("d1e64e5480bfaf733ba7d48712decb8227797a4e").unwrap()
),
StoreAccountRef::root("31e9d1e6d844bd3a536800ef8d8be6a9975db509".into()),
StoreAccountRef::root("d1e64e5480bfaf733ba7d48712decb8227797a4e".into()),
]
);
let message = [1u8; 32].into();
let message = Default::default();
let s1 = store.sign(&accounts[0], &"foo".into(), &message).unwrap();
let s2 = store.sign(&accounts[1], &"foo".into(), &message).unwrap();

View File

@ -18,11 +18,11 @@ use ethstore::{
accounts_dir::{KeyDirectory, RootDiskDirectory},
Error, SafeAccount,
};
use rand::{rngs::OsRng, RngCore};
use rand::{OsRng, Rng};
use std::{env, fs, path::PathBuf};
pub fn random_dir() -> PathBuf {
let mut rng = OsRng;
let mut rng = OsRng::new().unwrap();
let mut dir = env::temp_dir();
dir.push(format!("{:x}-{:x}", rng.next_u64(), rng.next_u64()));
dir

View File

@ -18,8 +18,7 @@
use std::{collections::HashMap, time::Instant};
use crypto::publickey::Address;
use ethkey::Password;
use ethkey::{Address, Password};
use serde_derive::{Deserialize, Serialize};
use serde_json;

View File

@ -18,8 +18,6 @@
//! Account management.
extern crate parity_crypto as crypto;
mod account_data;
mod error;
mod stores;
@ -34,8 +32,7 @@ use std::{
time::{Duration, Instant},
};
use crypto::publickey::{Address, Generator, Message, Public, Random, Secret};
use ethkey::Password;
use ethkey::{Address, Generator, Message, Password, Public, Random, Secret};
use ethstore::{
accounts_dir::MemoryDirectory, random_string, EthMultiStore, EthStore, OpaqueSecret,
SecretStore, SecretVaultRef, SimpleSecretStore, StoreAccountRef,
@ -43,7 +40,7 @@ use ethstore::{
use log::*;
use parking_lot::RwLock;
pub use crypto::publickey::Signature;
pub use ethkey::Signature;
pub use ethstore::{Derivation, Error, IndexDerivation, KeyFile};
pub use self::{account_data::AccountMeta, error::SignError};
@ -137,7 +134,9 @@ impl AccountProvider {
/// Creates new random account and returns address and public key
pub fn new_account_and_public(&self, password: &Password) -> Result<(Address, Public), Error> {
let acc = Random.generate();
let acc = Random
.generate()
.expect("secp context has generation capabilities; qed");
let public = acc.public().clone();
let secret = acc.secret().clone();
let account = self
@ -356,8 +355,7 @@ impl AccountProvider {
} else {
// verify password by signing dump message
// result may be discarded
let dummy_msg = [1u8; 32].into();
let _ = self.sstore.sign(&account, &password, &dummy_msg)?;
let _ = self.sstore.sign(&account, &password, &Default::default())?;
}
let data = AccountData {
@ -634,16 +632,15 @@ impl AccountProvider {
#[cfg(test)]
mod tests {
use super::{AccountProvider, Unlock};
use crypto::publickey::{Address, Generator, Random};
use ethereum_types::H256;
use ethkey::{Address, Generator, Random};
use ethstore::{Derivation, StoreAccountRef};
use std::time::{Duration, Instant};
#[test]
fn unlock_account_temp() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
@ -653,13 +650,13 @@ mod tests {
assert!(ap
.unlock_account_temporarily(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
}
#[test]
fn derived_account_nosave() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
@ -672,7 +669,7 @@ mod tests {
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(999)),
Derivation::SoftHash(H256::from(999)),
false,
)
.expect("Derivation should not fail");
@ -686,7 +683,7 @@ mod tests {
#[test]
fn derived_account_save() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
@ -699,7 +696,7 @@ mod tests {
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(999)),
Derivation::SoftHash(H256::from(999)),
true,
)
.expect("Derivation should not fail");
@ -719,7 +716,7 @@ mod tests {
#[test]
fn derived_account_sign() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
assert!(ap
.insert_account(kp.secret().clone(), &"base".into())
@ -732,14 +729,14 @@ mod tests {
.derive_account(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(1999)),
Derivation::SoftHash(H256::from(1999)),
true,
)
.expect("Derivation should not fail");
ap.unlock_account_permanently(derived_addr, "base".into())
.expect("Should be ok because account is saved and password is valid");
let msg = [2u8; 32].into();
let msg = Default::default();
let signed_msg1 = ap
.sign(derived_addr, None, msg)
.expect("Signing with existing unlocked account should not fail");
@ -747,7 +744,7 @@ mod tests {
.sign_derived(
&kp.address(),
None,
Derivation::SoftHash(H256::from_low_u64_be(1999)),
Derivation::SoftHash(H256::from(1999)),
msg,
)
.expect("Derived signing with existing unlocked account should not fail");
@ -757,9 +754,8 @@ mod tests {
#[test]
fn unlock_account_perm() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
@ -769,20 +765,19 @@ mod tests {
assert!(ap
.unlock_account_permanently(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap
.unlock_account_temporarily(kp.address(), "test".into())
.is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
}
#[test]
fn unlock_account_timer() {
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
@ -792,35 +787,35 @@ mod tests {
assert!(ap
.unlock_account_timed(kp.address(), "test".into(), Duration::from_secs(60))
.is_ok());
assert!(ap.sign(kp.address(), None, dummy_msg).is_ok());
assert!(ap.sign(kp.address(), None, Default::default()).is_ok());
ap.unlocked
.write()
.get_mut(&StoreAccountRef::root(kp.address()))
.unwrap()
.unlock = Unlock::Timed(Instant::now());
assert!(ap.sign(kp.address(), None, dummy_msg).is_err());
assert!(ap.sign(kp.address(), None, Default::default()).is_err());
}
#[test]
fn should_sign_and_return_token() {
// given
let kp = Random.generate();
let kp = Random.generate().unwrap();
let ap = AccountProvider::transient_provider();
let dummy_msg = [1u8; 32].into();
assert!(ap
.insert_account(kp.secret().clone(), &"test".into())
.is_ok());
// when
let (_signature, token) = ap
.sign_with_token(kp.address(), "test".into(), dummy_msg)
.sign_with_token(kp.address(), "test".into(), Default::default())
.unwrap();
// then
ap.sign_with_token(kp.address(), token.clone(), dummy_msg)
ap.sign_with_token(kp.address(), token.clone(), Default::default())
.expect("First usage of token should be correct.");
assert!(
ap.sign_with_token(kp.address(), token, dummy_msg).is_err(),
ap.sign_with_token(kp.address(), token, Default::default())
.is_err(),
"Second usage of the same token should fail."
);
}

View File

@ -22,7 +22,7 @@ use std::{
path::{Path, PathBuf},
};
use crypto::publickey::Address;
use ethkey::Address;
use log::{trace, warn};
use crate::AccountMeta;
@ -172,7 +172,6 @@ impl<K: hash::Hash + Eq, V> DiskMap<K, V> {
mod tests {
use super::AddressBook;
use crate::account_data::AccountMeta;
use ethereum_types::H160;
use std::collections::HashMap;
use tempdir::TempDir;
@ -180,8 +179,8 @@ mod tests {
fn should_save_and_reload_address_book() {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
b.set_name(H160::from_low_u64_be(1), "One".to_owned());
b.set_meta(H160::from_low_u64_be(1), "{1:1}".to_owned());
b.set_name(1.into(), "One".to_owned());
b.set_meta(1.into(), "{1:1}".to_owned());
let b = AddressBook::new(tempdir.path());
assert_eq!(
b.get(),
@ -194,7 +193,7 @@ mod tests {
}
)]
.into_iter()
.map(|(a, b)| (H160::from_low_u64_be(a), b))
.map(|(a, b)| (a.into(), b))
.collect::<HashMap<_, _>>()
);
}
@ -204,10 +203,10 @@ mod tests {
let tempdir = TempDir::new("").unwrap();
let mut b = AddressBook::new(tempdir.path());
b.set_name(H160::from_low_u64_be(1), "One".to_owned());
b.set_name(H160::from_low_u64_be(2), "Two".to_owned());
b.set_name(H160::from_low_u64_be(3), "Three".to_owned());
b.remove(H160::from_low_u64_be(2));
b.set_name(1.into(), "One".to_owned());
b.set_name(2.into(), "Two".to_owned());
b.set_name(3.into(), "Three".to_owned());
b.remove(2.into());
let b = AddressBook::new(tempdir.path());
assert_eq!(
@ -231,7 +230,7 @@ mod tests {
),
]
.into_iter()
.map(|(a, b)| (H160::from_low_u64_be(a), b))
.map(|(a, b)| (a.into(), b))
.collect::<HashMap<_, _>>()
);
}

View File

@ -5,5 +5,5 @@ version = "0.1.0"
authors = ["Marek Kotewicz <marek@parity.io>"]
[dependencies]
ethjson = { path = "../../crates/ethjson" }
ethjson = { path = "../json" }
serde_json = "1.0"

View File

@ -7,8 +7,8 @@ version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.9.2"
ethereum-types = "0.4"
futures = "0.1"
rpassword = "1.0"
parity-rpc = { path = "../../rpc" }
parity-rpc = { path = "../rpc" }
parity-rpc-client = { path = "rpc-client" }

View File

@ -7,7 +7,7 @@ version = "1.4.0"
authors = ["Parity <admin@parity.io>"]
[dependencies]
ethereum-types = "0.9.2"
ethereum-types = "0.4"
futures = "0.1"
log = "0.4"
serde = "1.0"
@ -17,5 +17,5 @@ matches = "0.1"
parking_lot = "0.9"
jsonrpc-core = "15.0.0"
jsonrpc-ws-server = "15.0.0"
parity-rpc = { path = "../../../rpc" }
keccak-hash = "0.5.0"
parity-rpc = { path = "../../rpc" }
keccak-hash = "0.1"

View File

@ -259,7 +259,7 @@ impl Rpc {
{
let (c, p) = oneshot::<Result<JsonValue, RpcError>>();
let id = self.counter.fetch_add(1, Ordering::SeqCst);
let id = self.counter.fetch_add(1, Ordering::Relaxed);
self.pending.insert(id, c);
let request = MethodCall {

View File

@ -1,35 +0,0 @@
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
extern crate keccak_hash as hash;
pub type H256 = [u8; 32];
pub mod keccak_512 {
use super::hash;
pub use self::hash::{
keccak512 as inplace, keccak512_range as inplace_range, keccak_512 as write,
};
}
pub mod keccak_256 {
use super::hash;
pub use self::hash::{
keccak256 as inplace, keccak256_range as inplace_range, keccak_256 as write,
};
}

View File

@ -1,47 +0,0 @@
[package]
description = "OpenEthereum Miner Interface."
name = "ethcore-miner"
homepage = "https://github.com/openethereum/openethereum"
license = "GPL-3.0"
version = "1.12.0"
authors = ["Parity Technologies <admin@parity.io>"]
[dependencies]
# Only work_notify, consider a separate crate
ethash = { path = "../../concensus/ethash", optional = true }
fetch = { path = "../../net/fetch", optional = true }
hyper = { version = "0.12", optional = true }
url = { version = "2", optional = true }
# Miner
ansi_term = "0.10"
common-types = { path = "../../ethcore/types" }
error-chain = "0.12"
ethabi = "12.0.0"
ethabi-derive = "12.0.0"
ethabi-contract = "11.0.0"
ethcore-call-contract = { path = "../../vm/call-contract" }
ethereum-types = "0.9.2"
futures = "0.1"
keccak-hash = "0.5.0"
linked-hash-map = "0.5"
log = "0.4"
parity-crypto = { version = "0.6.2", features = [ "publickey" ] }
parity-runtime = { path = "../../runtime/runtime" }
parity-util-mem = "0.7"
parking_lot = "0.11.1"
price-info = { path = "./price-info", optional = true }
rlp = { version = "0.4.6" }
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
serde_json = "1.0"
trace-time = "0.1"
txpool = { path = "../../transaction-pool" }
[dev-dependencies]
env_logger = "0.5"
ethkey = { path = "../../accounts/ethkey" }
rustc-hex = "1.0"
[features]
work-notify = ["ethash", "fetch", "hyper", "url"]

View File

@ -1,129 +0,0 @@
// Copyright 2015-2021 Parity Technologies (UK) Ltd.
// This file is part of OpenEthereum.
// OpenEthereum 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.
// OpenEthereum 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 OpenEthereum. If not, see <http://www.gnu.org/licenses/>.
//! Filter options available in the parity_pendingTransaction endpoint of the JSONRPC API.
#![allow(missing_docs)]
use ethereum_types::{Address, U256};
use pool::VerifiedTransaction;
use types::transaction::Action;
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum SenderArgument {
eq(Address),
None,
}
impl Default for SenderArgument {
fn default() -> Self {
Self::None
}
}
impl SenderArgument {
fn matches(&self, value: &Address) -> bool {
match self {
Self::eq(expected) => value == expected,
Self::None => true,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum ActionArgument {
eq(Address),
action(String),
None,
}
impl Default for ActionArgument {
fn default() -> Self {
Self::None
}
}
impl ActionArgument {
fn matches(&self, value: &Action) -> bool {
match self {
Self::eq(expected) => *value == Action::Call(*expected),
Self::action(name) => *value == Action::Create && name == "contract_creation",
Self::None => true,
}
}
}
#[allow(non_camel_case_types)]
#[derive(Debug, Deserialize, Serialize)]
#[serde()]
pub enum ValueFilterArgument {
eq(U256),
lt(U256),
gt(U256),
None,
}
impl Default for ValueFilterArgument {
fn default() -> Self {
Self::None
}
}
impl ValueFilterArgument {
fn matches(&self, value: &U256) -> bool {
match self {
ValueFilterArgument::eq(expected) => value == expected,
ValueFilterArgument::lt(threshold) => value < threshold,
ValueFilterArgument::gt(threshold) => value > threshold,
ValueFilterArgument::None => true,
}
}
}
#[derive(Debug, Default, Deserialize, Serialize)]
#[serde(default, rename_all = "camelCase")]
pub struct TransactionFilter {
from: SenderArgument,
to: ActionArgument,
gas: ValueFilterArgument,
gas_price: ValueFilterArgument,
value: ValueFilterArgument,
nonce: ValueFilterArgument,
}
impl TransactionFilter {
pub fn matches(&self, transaction: &VerifiedTransaction) -> bool {
let tx = transaction.signed().tx();
self.from.matches(&transaction.sender)
&& self.to.matches(&tx.action)
&& self.gas.matches(&tx.gas)
&& self.gas_price.matches(&tx.gas_price)
&& self.nonce.matches(&tx.nonce)
&& self.value.matches(&tx.value)
}
}
pub fn match_filter(filter: &Option<TransactionFilter>, transaction: &VerifiedTransaction) -> bool {
match filter {
Some(f) => f.matches(transaction),
None => true,
}
}

Some files were not shown because too many files have changed in this diff Show More