├── .eslintrc.js
├── .github
├── contributing.md
└── workflows
│ └── build.yml
├── .gitignore
├── .prettierignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── docs
├── README.md
├── classes
│ ├── ethereumhdkey.md
│ └── wallet.md
└── interfaces
│ ├── etherwalletoptions.md
│ └── evpkdfopts.md
├── karma.conf.js
├── package-lock.json
├── package.json
├── prettier.config.js
├── src
├── hdkey.ts
├── index.ts
└── thirdparty.ts
├── test
├── hdkey.spec.ts
└── index.spec.ts
├── tsconfig.json
└── tsconfig.prod.json
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | parser: '@typescript-eslint/parser',
3 | plugins: ['@typescript-eslint', 'implicit-dependencies', 'import', 'prettier'],
4 | env: {
5 | es2020: true,
6 | node: true,
7 | mocha: true
8 | },
9 | ignorePatterns: [
10 | 'node_modules/',
11 | 'dist/',
12 | 'coverage/',
13 | 'prettier.config.js',
14 | 'typedoc.js',
15 | 'karma.conf.js',
16 | ],
17 | extends: ['typestrict', 'eslint:recommended'],
18 | rules: {
19 | 'no-console': 'warn',
20 | 'no-debugger': 'error',
21 | 'prefer-const': 'error',
22 | 'no-var': 'error',
23 | 'no-constant-condition': 'warn',
24 | 'implicit-dependencies/no-implicit': ['error', { peer: true, dev: true, optional: true }],
25 | '@typescript-eslint/prefer-nullish-coalescing': 'error',
26 | '@typescript-eslint/no-use-before-define': 'warn',
27 | '@typescript-eslint/naming-convention': [
28 | 'error',
29 | {
30 | selector: 'interface',
31 | format: ['PascalCase', 'camelCase'],
32 | custom: {
33 | regex: '^I[A-Z]',
34 | match: false,
35 | },
36 | },
37 | ],
38 | 'no-unused-vars': 'off',
39 | '@typescript-eslint/no-unused-vars': [
40 | 'error',
41 | { argsIgnorePattern: '^_', varsIgnorePattern: '^_' },
42 | ],
43 | '@typescript-eslint/no-unnecessary-condition': 'off',
44 | 'no-dupe-class-members': 'off',
45 | 'no-extra-semi': 'off',
46 | 'prettier/prettier': 'error',
47 | 'no-redeclare': 'off',
48 | '@typescript-eslint/no-redeclare': ['error'],
49 | '@typescript-eslint/restrict-plus-operands': 'off',
50 | 'import/no-default-export' : 'off'
51 | },
52 | overrides: [
53 | {
54 | files: ['test/index.spec.ts'],
55 | rules: {
56 | 'no-invalid-this': 'off',
57 | 'no-prototype-builtins': 'off',
58 | '@typescript-eslint/no-floating-promises': 'off',
59 | },
60 | },
61 | ],
62 | parserOptions: {
63 | sourceType: 'module',
64 | project: './tsconfig.json',
65 | },
66 | }
67 |
68 |
--------------------------------------------------------------------------------
/.github/contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | Great that you want to contribute to the `EthereumJS` [ecosystem](https://ethereumjs.readthedocs.io/en/latest/introduction.html). `EthereumJS` is managed by the Ethereum Foundation and largely driven by the wider community. Everyone is welcome to join the effort and help to improve on the libraries (see our [Code of Conduct](https://ethereumjs.readthedocs.io/en/latest/code_of_conduct.html) 🌷).
4 |
5 | We have written up some [Contribution Guidelines](https://ethereumjs.readthedocs.io/en/latest/contributing.html#how-to-start) to help you getting started.
6 |
7 | These include information on how we work with **Git** and how our **general workflow** and **technical setup** looks like (stuff like language, tooling, code quality and style).
8 |
9 | Happy Coding! 👾 😀 💻
10 |
--------------------------------------------------------------------------------
/.github/workflows/build.yml:
--------------------------------------------------------------------------------
1 | name: Build
2 | on:
3 | push:
4 | branches:
5 | - master
6 | tags:
7 | - '*'
8 | pull_request:
9 | types: [opened, reopened, synchronize]
10 | jobs:
11 | test:
12 | runs-on: ubuntu-latest
13 | strategy:
14 | matrix:
15 | node-version: [14, 16, 18]
16 | steps:
17 | - uses: actions/checkout@v3
18 | - name: Use Node.js ${{ matrix.node-version }}
19 | uses: actions/setup-node@v2
20 | with:
21 | node-version: ${{ matrix.node-version }}
22 | cache: 'npm'
23 | - run: npm i
24 | - run: npm run lint
25 | - run: npm run coverage
26 | test-browser:
27 | runs-on: ubuntu-latest
28 | steps:
29 | - uses: actions/checkout@v3
30 | - name: Use Node.js 14
31 | uses: actions/setup-node@v2
32 | with:
33 | node-version: 14
34 | cache: 'npm'
35 | - run: npm i
36 | - run: npm run test:browser
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 | .nyc_output
17 |
18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
19 | .grunt
20 |
21 | # node-waf configuration
22 | .lock-wscript
23 |
24 | # Compiled binary addons (http://nodejs.org/api/addons.html)
25 | build/Release
26 |
27 | # Dependency directory
28 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git
29 | node_modules
30 |
31 | # Optional npm cache directory
32 | .npm
33 |
34 | # Optional REPL history
35 | .node_repl_history
36 |
37 |
38 | # IDE and text editor config files
39 | .idea
40 | .vscode
41 |
42 | # build output
43 | dist
44 | dist.browser
45 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .vscode
3 | package.json
4 | dist
5 | dist.browser
6 | .nyc_output
7 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file.
4 |
5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
6 | (modification: no type change headlines) and this project adheres to
7 | [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
8 |
9 | ## [1.0.2] - 2021-10-08
10 |
11 | - Updated dependencies to latest, added browser build, PR [#157](https://github.com/ethereumjs/ethereumjs-wallet/pull/157)
12 |
13 | #### Included Source Files
14 |
15 | Source files from the `src` folder are now included in the distribution build. This allows for a better debugging experience in debug tools like Chrome DevTools by having working source map references to the original sources available for inspection.
16 |
17 | [1.0.2]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v1.0.1...v1.0.2
18 |
19 | ## [1.0.1] - 2020-09-25
20 |
21 | - Fixed a browser issue in `Wallet.fromV3()` and `Wallet.toV3()` triggered when using web bundlers using Buffer v4 shim (Webpack 4),
22 | see PR [#135](https://github.com/ethereumjs/ethereumjs-wallet/pull/135)
23 |
24 | [1.0.1]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v1.0.0...v1.0.1
25 |
26 | ## [1.0.0] - 2020-06-23
27 |
28 | This is the first `TypeScript` release on the library (thanks @the-jackalope for the rewrite! ❤️), see PR [#93](https://github.com/ethereumjs/ethereumjs-wallet/pull/93) for the main PR here. The release comes with various breaking changes.
29 |
30 | ### Libray Import / API Documentation
31 |
32 | The way submodules are exposed has been changed along the `TypeScript` rewrite and you will likely have to update your imports. Here is an example for the `hdkey` submodule:
33 |
34 | Node.js / ES5:
35 |
36 | ```js
37 | const { hdkey } = require('ethereumjs-wallet')
38 | ```
39 |
40 | ESM / TypeScript:
41 |
42 | ```js
43 | import { hdkey } from 'ethereumjs-wallet'
44 | ```
45 |
46 | See [README](https://github.com/ethereumjs/ethereumjs-wallet#wallet-api) for examples on the other submodules.
47 |
48 | Together with the switch to `TypeScript` the previously static documentation has been automated to now being generated with `TypeDoc` to reflect all latest changes, see PR [#98](https://github.com/ethereumjs/ethereumjs-wallet/pull/98). See the new [docs](https://github.com/ethereumjs/ethereumjs-wallet/blob/master/docs/README.md) for an overview on the `TypeScript` based API.
49 |
50 | ### API Changes
51 |
52 | The API of the library hasn't been changed intentionally but has become more strict on type input by the explcit type definitions from the `TypeScript` code in function signatures together with the introduction of the `ethereumjs-util` [v7](https://github.com/ethereumjs/ethereumjs-util/releases) library within the `Wallet` library, which behaves more strict on type input on the various utility functions.
53 |
54 | This leads to cases where some input - while not having been the intended way to use the library - might have been worked before through implicit type conversion and is now not possible any more.
55 |
56 | One example for this is the `Wallet.fromPublicKey()` function, here is the old code of the function:
57 |
58 | ```js
59 | Wallet.fromPublicKey = function (pub, nonStrict) {
60 | if (nonStrict) {
61 | pub = ethUtil.importPublic(pub)
62 | }
63 | return new Wallet(null, pub)
64 | }
65 | ```
66 |
67 | and here the new `TypeScript` code:
68 |
69 | ```typescript
70 | public static fromPublicKey(publicKey: Buffer, nonStrict: boolean = false): Wallet {
71 | if (nonStrict) {
72 | publicKey = importPublic(publicKey)
73 | }
74 | return new Wallet(undefined, publicKey)
75 | }
76 | ```
77 |
78 | This function worked in the `v0.6.x` version also with passing in a string, since the `ethereumjs-util` `v6` `importPublic` method converted the input implicitly to a `Buffer`, the `v1.0.0` version now directly enforces the `fromPublicKey` input to be a `Buffer` first hand.
79 |
80 | There will likely be more cases like this in the code since the type input of the library hasn't been documented in the older version. So we recommend here to go through all your function signature usages and see if you uses the correct input types. While a bit annoying this is a one-time task you will never have to do again since you can now profit from the clear `TypeScript` input types being both documented and enforced by the `TypeScript` compiler.
81 |
82 | ### Pure JS Crypto Dependencies
83 |
84 | This library now uses pure JS crypto dependencies which doesn't bring in the need for native compilation on installation. For `scrypt` key derivation [scrypt-js](https://github.com/ricmoo/scrypt-js) from @ricmoo is used (see PR [#125](https://github.com/ethereumjs/ethereumjs-wallet/pull/125)).
85 |
86 | For BIP-32 key derivation the new [ethereum-cryptography](https://github.com/ethereum/js-ethereum-cryptography) library is used which is a new Ethereum Foundation backed and formally audited libray to provide pure JS cryptographic primitives within the Ethereum ecosystem (see PR [#128](https://github.com/ethereumjs/ethereumjs-wallet/pull/128)).
87 |
88 | ### Removed ProviderEngine
89 |
90 | Support for Provider Engine has been removed for security reasons, since the package is not very actively maintained and superseded by [`json-rpc-engine`](https://github.com/MetaMask/web3-provider-engine#web3-providerengine).
91 |
92 | If you need the removed functionality, it should be relatively easily possible to do this integration by adopting the code from [provider-engine.ts](https://github.com/ethereumjs/ethereumjs-wallet/blob/v0.6.x/src/provider-engine.js).
93 |
94 | See also: PR [#117](https://github.com/ethereumjs/ethereumjs-wallet/pull/117)
95 |
96 | ### Other Changes
97 |
98 | #### Bug Fixes
99 |
100 | - Fixes a bug where `salt`, `iv` and/or `uuid` options - being supplied as strings to `Wallet.toV3()` - could lead to errors during encryption and/or output that could not be decrypted,
101 | PR [#95](https://github.com/ethereumjs/ethereumjs-wallet/pull/95)
102 |
103 | #### Refactoring & Maintenance
104 |
105 | - `ES6` class rewrite,
106 | PR [#93](https://github.com/ethereumjs/ethereumjs-wallet/pull/93) (`TypeScript` PR)
107 | - Added support for Node 12, 13, and 14, upgraded CI provider to use GH Actions in place of Travis,
108 | PR [#120](https://github.com/ethereumjs/ethereumjs-wallet/pull/120)
109 | - Updated `ethereumjs-util` dependency from `v6` to
110 | [v7.0.2](https://github.com/ethereumjs/ethereumjs-util/releases/tag/v7.0.2 (stricter types),
111 | PR [#126](https://github.com/ethereumjs/ethereumjs-wallet/pull/126)
112 | - Refactored `Wallet.deciperBuffer()`,
113 | PR [#82](https://github.com/ethereumjs/ethereumjs-wallet/pull/82)
114 |
115 | #### Development & CI
116 |
117 | - Integrated the `ethereumjs-config` EthereumJS developer configuration standards,
118 | PR [#93](https://github.com/ethereumjs/ethereumjs-wallet/pull/93) (`TypeScript` PR)
119 | - Added org links and Git hooks,
120 | PR [#88](https://github.com/ethereumjs/ethereumjs-wallet/pull/88)
121 |
122 | [0.6.4]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.6.3...v1.0.0
123 |
124 | ## [0.6.4] - 2020-05-01
125 |
126 | This is the last release from the `v0.6.x` release series. It adds Node 12 compatibility while maintaining compatibility
127 | down to Node 6. To be able to do so the `scrypt.js` key derivation library is exchanged with `scryptsy`. While this solution is backwards-compatible the changed library only provides a pure JS implementation and no native bindings. If you need native performance pin your dependency to `v0.6.3` or update to the `v1.0.0` library version to be released shortly after this release.
128 |
129 | Change Summary:
130 |
131 | - v0.6.x back patch: added node v12 support, switched to `scryptsy` key derivation library (pure JS implementation),
132 | PR [#114](https://github.com/ethereumjs/ethereumjs-wallet/pull/114)
133 | - Updated `hdkey` to `v1.1.1`,
134 | PR [#87](https://github.com/ethereumjs/ethereumjs-wallet/pull/87)
135 | - Refactored `decipherBuffer()`,
136 | PR [#82](https://github.com/ethereumjs/ethereumjs-wallet/pull/82)
137 | - Added more tests for `Wallet.fromEthSale()`,
138 | PR [#80](https://github.com/ethereumjs/ethereumjs-wallet/pull/80)
139 |
140 | [0.6.4]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.6.3...v0.6.4
141 |
142 | ## [0.6.3] - 2018-12-19
143 |
144 | - Fixed installation errors for certain packaging tools, PR [#67](https://github.com/ethereumjs/ethereumjs-wallet/pull/67)
145 | - Remove dependency on `crypto.randomBytes` and use `randombytes` package instead, PR [#63](https://github.com/ethereumjs/ethereumjs-wallet/pull/63)
146 | - Add comprehensive test coverage for `fromV3`, PR [#62](https://github.com/ethereumjs/ethereumjs-wallet/pull/62)
147 | - Remove excess parameter from `decipherBuffer` usage, PR [#77](https://github.com/ethereumjs/ethereumjs-wallet/pull/77)
148 | - Update dependencies, including a fixed `scrypt.js`, which should resolve more installation issues, PR [#78](https://github.com/ethereumjs/ethereumjs-wallet/pull/78)
149 |
150 | [0.6.3]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.6.2...v0.6.3
151 |
152 | ## [0.6.2] - 2018-08-08
153 |
154 | - [PLEASE UPDATE!] Fixes a critical import bug introduced in `v0.6.1` accidentally
155 | changing the import path for the different submodules, see PR [#65](https://github.com/ethereumjs/ethereumjs-wallet/pull/65)
156 |
157 | [0.6.2]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.6.1...v0.6.2
158 |
159 | ## [0.6.1] - 2018-07-28 [DEPRECATED]
160 |
161 | - Added support for vanity address generation, PR [#5](https://github.com/ethereumjs/ethereumjs-wallet/pull/5)
162 | - Fixed typo in provider-engine, PR [#16](https://github.com/ethereumjs/ethereumjs-wallet/pull/16)
163 | - Accept the true range of addresses for ICAP direct, PR [#6](https://github.com/ethereumjs/ethereumjs-wallet/pull/6)
164 | - Switched to babel ES5 build, PR [#37](https://github.com/ethereumjs/ethereumjs-wallet/pull/37)
165 | - Improve test coverage (at 88% now), PR [#27](https://github.com/ethereumjs/ethereumjs-wallet/pull/27)
166 | - Various dependency updates, PR [#25](https://github.com/ethereumjs/ethereumjs-wallet/pull/25)
167 |
168 | [0.6.1]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.6.0...v0.6.1
169 |
170 | ## [0.6.0] - 2016-04-27
171 |
172 | - Added provider-engine integration, PR [#7](https://github.com/ethereumjs/ethereumjs-wallet/pull/7)
173 |
174 | [0.6.0]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.5.2...v0.6.0
175 |
176 | ## [0.5.2] - 2016-04-25
177 |
178 | - Dependency updates
179 |
180 | [0.5.2]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.5.1...v0.5.2
181 |
182 | ## [0.5.1] - 2016-03-26
183 |
184 | - Bugfix for `EthereumHDKey.privateExtendedKey()`
185 | - Added travis and coveralls support
186 | - Documentation and test improvements
187 |
188 | [0.5.1]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.5.0...v0.5.1
189 |
190 | ## [0.5.0] - 2016-03-23
191 |
192 | - Support HD keys using `cryptocoinjs/hdkey`
193 | - Ensure private keys are valid according to the curve
194 | - Support instantation with public keys
195 | - Support importing BIP32 xpub/xpriv
196 | - Only support Ethereum keys internally, non-strict mode for importing compressed ones
197 | - Thirdparty API doc improvements
198 |
199 | [0.5.0]: https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.4.0...v0.5.0
200 |
201 | ## Older releases:
202 |
203 | - [0.4.0](https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.3.0...v0.4.0) - 2016-03-16
204 | - [0.3.0](https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.2.1...v0.3.0) - 2016-03-09
205 | - [0.2.1](https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.2.0...v0.2.1) - 2016-03-07
206 | - [0.2.0](https://github.com/ethereumjs/ethereumjs-wallet/compare/v0.1.0...v0.2.0) - 2016-03-07
207 | - 0.1.0 - 2016-02-23
208 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Alex Beregszaszi
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ethereumjs-wallet
2 |
3 | > [!WARNING]
4 | > The repository has been merged into [ethereumjs-monorepo](https://github.com/ethereumjs/ethereumjs-monorepo). Please head to the new repo for updates.
5 |
6 | ---
7 |
8 |
9 | A lightweight wallet implementation. At the moment it supports key creation and conversion between various formats.
10 |
11 | It is complemented by the following packages:
12 |
13 | - [@ethereumjs/tx](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/tx) to sign transactions
14 | - [ethereumjs-icap](https://github.com/ethereumjs/ethereumjs-icap) to manipulate ICAP addresses
15 | - [store.js](https://github.com/marcuswestin/store.js) to use browser storage
16 |
17 | Motivations are:
18 |
19 | - be lightweight
20 | - work in a browser
21 | - use a single, maintained version of crypto library (and that should be in line with [`@ethereumjs/util`](https://github.com/ethereumjs/ethereumjs-monorepo/tree/master/packages/util) and `@ethereumjs/tx`)
22 | - support import/export between various wallet formats
23 | - support BIP32 HD keys
24 |
25 | Features not supported:
26 |
27 | - signing transactions
28 | - managing storage (neither in node.js or the browser)
29 |
30 | ## Wallet API
31 |
32 | For information about the Wallet's API, please go to [./docs/classes/wallet.md](./docs/classes/wallet.md).
33 |
34 | You can import the `Wallet` class like this
35 |
36 | Node.js / ES6:
37 |
38 | ```js
39 | const Wallet = require('ethereumjs-wallet').default
40 | ```
41 |
42 | ESM / TypeScript:
43 |
44 | ```js
45 | import Wallet from 'ethereumjs-wallet'
46 | ```
47 |
48 | ## Thirdparty API
49 |
50 | Importing various third party wallets is possible through the `thirdparty` submodule:
51 |
52 | Node.js / ES5:
53 |
54 | ```js
55 | const { thirdparty } = require('ethereumjs-wallet')
56 | ```
57 |
58 | ESM / TypeScript:
59 |
60 | ```js
61 | import { thirdparty } from 'ethereumjs-wallet'
62 | ```
63 |
64 | Please go to [./docs/README.md](./docs/README.md) for more info.
65 |
66 | ## HD Wallet API
67 |
68 | To use BIP32 HD wallets, first include the `hdkey` submodule:
69 |
70 | Node.js / ES5:
71 |
72 | ```js
73 | const { hdkey } = require('ethereumjs-wallet')
74 | ```
75 |
76 | ESM / TypeScript:
77 |
78 | ```js
79 | import { hdkey } from 'ethereumjs-wallet'
80 | ```
81 |
82 | Please go to [./docs/classes/ethereumhdkey.md](./docs/classes/ethereumhdkey.md) for more info.
83 |
84 | ## Provider Engine
85 |
86 | Provider Engine is
87 | [not very actively maintained](https://github.com/MetaMask/web3-provider-engine#web3-providerengine)
88 | and support has been removed along `v1.0.0` release, see
89 | issue [#115](https://github.com/ethereumjs/ethereumjs-wallet/issues/115) for context.
90 |
91 | You can use the the old `src/provider-engine.ts` code (see associated PR) as some boilerplate
92 | for your own integration if needed.
93 |
94 | ## Remarks about `toV3`
95 |
96 | The `options` is an optional object hash, where all the serialization parameters can be fine tuned:
97 |
98 | - uuid - UUID. One is randomly generated.
99 | - salt - Random salt for the `kdf`. Size must match the requirements of the KDF (key derivation function). Random number generated via `crypto.getRandomBytes` if nothing is supplied.
100 | - iv - Initialization vector for the `cipher`. Size must match the requirements of the cipher. Random number generated via `crypto.getRandomBytes` if nothing is supplied.
101 | - kdf - The key derivation function, see below.
102 | - dklen - Derived key length. For certain `cipher` settings, this must match the block sizes of those.
103 | - cipher - The cipher to use. Names must match those of supported by `OpenSSL`, e.g. `aes-128-ctr` or `aes-128-cbc`.
104 |
105 | Depending on the `kdf` selected, the following options are available too.
106 |
107 | For `pbkdf2`:
108 |
109 | - `c` - Number of iterations. Defaults to 262144.
110 | - `prf` - The only supported (and default) value is `hmac-sha256`. So no point changing it.
111 |
112 | For `scrypt`:
113 |
114 | - `n` - Iteration count. Defaults to 262144.
115 | - `r` - Block size for the underlying hash. Defaults to 8.
116 | - `p` - Parallelization factor. Defaults to 1.
117 |
118 | The following settings are favoured by the Go Ethereum implementation and we default to the same:
119 |
120 | - `kdf`: `scrypt`
121 | - `dklen`: `32`
122 | - `n`: `262144`
123 | - `r`: `8`
124 | - `p`: `1`
125 | - `cipher`: `aes-128-ctr`
126 |
127 | # EthereumJS
128 |
129 | See our organizational [documentation](https://ethereumjs.readthedocs.io) for an introduction to `EthereumJS` as well as information on current standards and best practices.
130 |
131 | If you want to join for work or do improvements on the libraries have a look at our [contribution guidelines](https://ethereumjs.readthedocs.io/en/latest/contributing.html).
132 |
133 | ## License
134 |
135 | MIT License
136 |
137 | Copyright (C) 2016 Alex Beregszaszi
138 |
139 | [actions-badge]: https://github.com/ethereumjs/ethereumjs-wallet/workflows/Build/badge.svg
140 | [actions-link]: https://github.com/ethereumjs/ethereumjs-wallet/actions
141 | [coverage-badge]: https://img.shields.io/coveralls/ethereumjs/ethereumjs-wallet.svg
142 | [coverage-link]: https://coveralls.io/r/ethereumjs/ethereumjs-wallet
143 | [discord-badge]: https://img.shields.io/static/v1?logo=discord&label=discord&message=Join&color=blue
144 | [discord-link]: https://discord.gg/TNwARpR
145 | [npm-badge]: https://img.shields.io/npm/v/ethereumjs-wallet.svg
146 | [npm-link]: https://www.npmjs.org/package/ethereumjs-wallet
147 |
--------------------------------------------------------------------------------
/docs/README.md:
--------------------------------------------------------------------------------
1 | # ethereumjs-wallet
2 |
3 | ## Index
4 |
5 | ### Classes
6 |
7 | - [EthereumHDKey](classes/ethereumhdkey.md)
8 | - [Wallet](classes/wallet.md)
9 |
10 | ### Interfaces
11 |
12 | - [EtherWalletOptions](interfaces/etherwalletoptions.md)
13 | - [EvpKdfOpts](interfaces/evpkdfopts.md)
14 |
15 | ### Functions
16 |
17 | - [fromEtherCamp](#fromethercamp)
18 | - [fromEtherWallet](#frometherwallet)
19 | - [fromQuorumWallet](#fromquorumwallet)
20 |
21 | ---
22 |
23 | ## Functions
24 |
25 |
26 |
27 | ### fromEtherCamp
28 |
29 | ▸ **fromEtherCamp**(passphrase: _`string`_): [Wallet](classes/wallet.md)
30 |
31 | _Defined in [thirdparty.ts:169](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L169)_
32 |
33 | **Parameters:**
34 |
35 | | Name | Type |
36 | | ---------- | -------- |
37 | | passphrase | `string` |
38 |
39 | **Returns:** [Wallet](classes/wallet.md)
40 |
41 | ---
42 |
43 |
44 |
45 | ### fromEtherWallet
46 |
47 | ▸ **fromEtherWallet**(input: _`string` \| [EtherWalletOptions](interfaces/etherwalletoptions.md)_, password: _`string`_): [Wallet](classes/wallet.md)
48 |
49 | _Defined in [thirdparty.ts:121](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L121)_
50 |
51 | **Parameters:**
52 |
53 | | Name | Type |
54 | | -------- | ------------------------------------------------------------------ |
55 | | input | `string` \| [EtherWalletOptions](interfaces/etherwalletoptions.md) |
56 | | password | `string` |
57 |
58 | **Returns:** [Wallet](classes/wallet.md)
59 |
60 | ---
61 |
62 |
63 |
64 | ### fromQuorumWallet
65 |
66 | ▸ **fromQuorumWallet**(passphrase: _`string`_, userid: _`string`_): [Wallet](classes/wallet.md)
67 |
68 | _Defined in [thirdparty.ts:265](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L265)_
69 |
70 | **Parameters:**
71 |
72 | | Name | Type |
73 | | ---------- | -------- |
74 | | passphrase | `string` |
75 | | userid | `string` |
76 |
77 | **Returns:** [Wallet](classes/wallet.md)
78 |
79 | ---
80 |
--------------------------------------------------------------------------------
/docs/classes/ethereumhdkey.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-wallet](../README.md) > [EthereumHDKey](../classes/ethereumhdkey.md)
2 |
3 | # Class: EthereumHDKey
4 |
5 | ## Hierarchy
6 |
7 | **EthereumHDKey**
8 |
9 | ## Index
10 |
11 | ### Constructors
12 |
13 | - [constructor](ethereumhdkey.md#constructor)
14 |
15 | ### Properties
16 |
17 | - [\_hdkey](ethereumhdkey.md#_hdkey)
18 |
19 | ### Methods
20 |
21 | - [deriveChild](ethereumhdkey.md#derivechild)
22 | - [derivePath](ethereumhdkey.md#derivepath)
23 | - [getWallet](ethereumhdkey.md#getwallet)
24 | - [privateExtendedKey](ethereumhdkey.md#privateextendedkey)
25 | - [publicExtendedKey](ethereumhdkey.md#publicextendedkey)
26 | - [fromExtendedKey](ethereumhdkey.md#fromextendedkey)
27 | - [fromMasterSeed](ethereumhdkey.md#frommasterseed)
28 |
29 | ---
30 |
31 | ## Constructors
32 |
33 |
34 |
35 | ### constructor
36 |
37 | ⊕ **new EthereumHDKey**(\_hdkey: _`any`_): [EthereumHDKey](ethereumhdkey.md)
38 |
39 | _Defined in [hdkey.ts:21](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L21)_
40 |
41 | **Parameters:**
42 |
43 | | Name | Type |
44 | | ------------------ | ----- |
45 | | `Optional` \_hdkey | `any` |
46 |
47 | **Returns:** [EthereumHDKey](ethereumhdkey.md)
48 |
49 | ---
50 |
51 | ## Properties
52 |
53 |
54 |
55 | ### ` `` ` \_hdkey
56 |
57 | **● \_hdkey**: _`any`_
58 |
59 | _Defined in [hdkey.ts:23](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L23)_
60 |
61 | ---
62 |
63 | ## Methods
64 |
65 |
66 |
67 | ### deriveChild
68 |
69 | ▸ **deriveChild**(index: _`number`_): [EthereumHDKey](ethereumhdkey.md)
70 |
71 | _Defined in [hdkey.ts:52](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L52)_
72 |
73 | **Parameters:**
74 |
75 | | Name | Type |
76 | | ----- | -------- |
77 | | index | `number` |
78 |
79 | **Returns:** [EthereumHDKey](ethereumhdkey.md)
80 |
81 | ---
82 |
83 |
84 |
85 | ### derivePath
86 |
87 | ▸ **derivePath**(path: _`string`_): [EthereumHDKey](ethereumhdkey.md)
88 |
89 | _Defined in [hdkey.ts:45](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L45)_
90 |
91 | **Parameters:**
92 |
93 | | Name | Type |
94 | | ---- | -------- |
95 | | path | `string` |
96 |
97 | **Returns:** [EthereumHDKey](ethereumhdkey.md)
98 |
99 | ---
100 |
101 |
102 |
103 | ### getWallet
104 |
105 | ▸ **getWallet**(): [Wallet](wallet.md)
106 |
107 | _Defined in [hdkey.ts:59](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L59)_
108 |
109 | **Returns:** [Wallet](wallet.md)
110 |
111 | ---
112 |
113 |
114 |
115 | ### privateExtendedKey
116 |
117 | ▸ **privateExtendedKey**(): `Buffer`
118 |
119 | _Defined in [hdkey.ts:28](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L28)_
120 |
121 | **Returns:** `Buffer`
122 |
123 | ---
124 |
125 |
126 |
127 | ### publicExtendedKey
128 |
129 | ▸ **publicExtendedKey**(): `Buffer`
130 |
131 | _Defined in [hdkey.ts:38](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L38)_
132 |
133 | **Returns:** `Buffer`
134 |
135 | ---
136 |
137 |
138 |
139 | ### `` fromExtendedKey
140 |
141 | ▸ **fromExtendedKey**(base58Key: _`string`_): [EthereumHDKey](ethereumhdkey.md)
142 |
143 | _Defined in [hdkey.ts:19](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L19)_
144 |
145 | **Parameters:**
146 |
147 | | Name | Type |
148 | | --------- | -------- |
149 | | base58Key | `string` |
150 |
151 | **Returns:** [EthereumHDKey](ethereumhdkey.md)
152 |
153 | ---
154 |
155 |
156 |
157 | ### `` fromMasterSeed
158 |
159 | ▸ **fromMasterSeed**(seedBuffer: _`Buffer`_): [EthereumHDKey](ethereumhdkey.md)
160 |
161 | _Defined in [hdkey.ts:12](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/hdkey.ts#L12)_
162 |
163 | **Parameters:**
164 |
165 | | Name | Type |
166 | | ---------- | -------- |
167 | | seedBuffer | `Buffer` |
168 |
169 | **Returns:** [EthereumHDKey](ethereumhdkey.md)
170 |
171 | ---
172 |
--------------------------------------------------------------------------------
/docs/classes/wallet.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-wallet](../README.md) > [Wallet](../classes/wallet.md)
2 |
3 | # Class: Wallet
4 |
5 | ## Hierarchy
6 |
7 | **Wallet**
8 |
9 | ## Index
10 |
11 | ### Constructors
12 |
13 | - [constructor](wallet.md#constructor)
14 |
15 | ### Properties
16 |
17 | - [privateKey](wallet.md#privatekey)
18 | - [publicKey](wallet.md#publickey)
19 |
20 | ### Accessors
21 |
22 | - [privKey](wallet.md#privkey)
23 | - [pubKey](wallet.md#pubkey)
24 |
25 | ### Methods
26 |
27 | - [getAddress](wallet.md#getaddress)
28 | - [getAddressString](wallet.md#getaddressstring)
29 | - [getChecksumAddressString](wallet.md#getchecksumaddressstring)
30 | - [getPrivateKey](wallet.md#getprivatekey)
31 | - [getPrivateKeyString](wallet.md#getprivatekeystring)
32 | - [getPublicKey](wallet.md#getpublickey)
33 | - [getPublicKeyString](wallet.md#getpublickeystring)
34 | - [getV3Filename](wallet.md#getv3filename)
35 | - [toV3](wallet.md#tov3)
36 | - [toV3String](wallet.md#tov3string)
37 | - [fromEthSale](wallet.md#fromethsale)
38 | - [fromExtendedPrivateKey](wallet.md#fromextendedprivatekey)
39 | - [fromExtendedPublicKey](wallet.md#fromextendedpublickey)
40 | - [fromPrivateKey](wallet.md#fromprivatekey)
41 | - [fromPublicKey](wallet.md#frompublickey)
42 | - [fromV1](wallet.md#fromv1)
43 | - [fromV3](wallet.md#fromv3)
44 | - [generate](wallet.md#generate)
45 | - [generateVanityAddress](wallet.md#generatevanityaddress)
46 |
47 | ---
48 |
49 | ## Constructors
50 |
51 |
52 |
53 | ### constructor
54 |
55 | ⊕ **new Wallet**(privateKey: _`Buffer` \| `undefined`_, publicKey?: _`Buffer` \| `undefined`_): [Wallet](wallet.md)
56 |
57 | _Defined in [index.ts:229](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L229)_
58 |
59 | **Parameters:**
60 |
61 | | Name | Type | Default value |
62 | | ------------------------- | ----------------------- | ------------- |
63 | | `Optional` privateKey | `Buffer` \| `undefined` | - |
64 | | `Default value` publicKey | `Buffer` \| `undefined` | undefined |
65 |
66 | **Returns:** [Wallet](wallet.md)
67 |
68 | ---
69 |
70 | ## Properties
71 |
72 |
73 |
74 | ### ` `` ` privateKey
75 |
76 | **● privateKey**: _`Buffer` \| `undefined`_
77 |
78 | _Defined in [index.ts:231](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L231)_
79 |
80 | ---
81 |
82 |
83 |
84 | ### `` publicKey
85 |
86 | **● publicKey**: _`Buffer` \| `undefined`_
87 |
88 | _Defined in [index.ts:232](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L232)_
89 |
90 | ---
91 |
92 | ## Accessors
93 |
94 |
95 |
96 | ### `` privKey
97 |
98 | **privKey**:
99 |
100 | _Defined in [index.ts:480](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L480)_
101 |
102 | ---
103 |
104 |
105 |
106 | ### `` pubKey
107 |
108 | **pubKey**:
109 |
110 | _Defined in [index.ts:470](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L470)_
111 |
112 | ---
113 |
114 | ## Methods
115 |
116 |
117 |
118 | ### getAddress
119 |
120 | ▸ **getAddress**(): `Buffer`
121 |
122 | _Defined in [index.ts:520](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L520)_
123 |
124 | **Returns:** `Buffer`
125 |
126 | ---
127 |
128 |
129 |
130 | ### getAddressString
131 |
132 | ▸ **getAddressString**(): `string`
133 |
134 | _Defined in [index.ts:527](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L527)_
135 |
136 | **Returns:** `string`
137 |
138 | ---
139 |
140 |
141 |
142 | ### getChecksumAddressString
143 |
144 | ▸ **getChecksumAddressString**(): `string`
145 |
146 | _Defined in [index.ts:535](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L535)_
147 |
148 | **Returns:** `string`
149 |
150 | ---
151 |
152 |
153 |
154 | ### getPrivateKey
155 |
156 | ▸ **getPrivateKey**(): `Buffer`
157 |
158 | _Defined in [index.ts:494](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L494)_
159 |
160 | **Returns:** `Buffer`
161 |
162 | ---
163 |
164 |
165 |
166 | ### getPrivateKeyString
167 |
168 | ▸ **getPrivateKeyString**(): `string`
169 |
170 | _Defined in [index.ts:498](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L498)_
171 |
172 | **Returns:** `string`
173 |
174 | ---
175 |
176 |
177 |
178 | ### getPublicKey
179 |
180 | ▸ **getPublicKey**(): `Buffer`
181 |
182 | _Defined in [index.ts:506](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L506)_
183 |
184 | **Returns:** `Buffer`
185 |
186 | ---
187 |
188 |
189 |
190 | ### getPublicKeyString
191 |
192 | ▸ **getPublicKeyString**(): `string`
193 |
194 | _Defined in [index.ts:513](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L513)_
195 |
196 | **Returns:** `string`
197 |
198 | ---
199 |
200 |
201 |
202 | ### getV3Filename
203 |
204 | ▸ **getV3Filename**(timestamp: _`undefined` \| `number`_): `string`
205 |
206 | _Defined in [index.ts:617](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L617)_
207 |
208 | **Parameters:**
209 |
210 | | Name | Type |
211 | | -------------------- | ----------------------- |
212 | | `Optional` timestamp | `undefined` \| `number` |
213 |
214 | **Returns:** `string`
215 |
216 | ---
217 |
218 |
219 |
220 | ### toV3
221 |
222 | ▸ **toV3**(password: _`string`_, opts: _`Partial`<`V3Params`>_): `V3Keystore`
223 |
224 | _Defined in [index.ts:545](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L545)_
225 |
226 | **Parameters:**
227 |
228 | | Name | Type | Description |
229 | | --------------- | --------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
230 | | password | `string` | The password used to encrypt the Keystore. |
231 | | `Optional` opts | `Partial`<`V3Params`> | The options for the keystore. See [its spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) for more info. |
232 |
233 | **Returns:** `V3Keystore`
234 |
235 | ---
236 |
237 |
238 |
239 | ### toV3String
240 |
241 | ▸ **toV3String**(password: _`string`_, opts: _`Partial`<`V3Params`>_): `string`
242 |
243 | _Defined in [index.ts:635](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L635)_
244 |
245 | **Parameters:**
246 |
247 | | Name | Type |
248 | | --------------- | --------------------- |
249 | | password | `string` |
250 | | `Optional` opts | `Partial`<`V3Params`> |
251 |
252 | **Returns:** `string`
253 |
254 | ---
255 |
256 |
257 |
258 | ### `` fromEthSale
259 |
260 | ▸ **fromEthSale**(input: _`string` \| `EthSaleKeystore`_, password: _`string`_): [Wallet](wallet.md)
261 |
262 | _Defined in [index.ts:444](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L444)_
263 |
264 | **Parameters:**
265 |
266 | | Name | Type |
267 | | -------- | ----------------------------- |
268 | | input | `string` \| `EthSaleKeystore` |
269 | | password | `string` |
270 |
271 | **Returns:** [Wallet](wallet.md)
272 |
273 | ---
274 |
275 |
276 |
277 | ### `` fromExtendedPrivateKey
278 |
279 | ▸ **fromExtendedPrivateKey**(extendedPrivateKey: _`string`_): [Wallet](wallet.md)
280 |
281 | _Defined in [index.ts:321](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L321)_
282 |
283 | **Parameters:**
284 |
285 | | Name | Type |
286 | | ------------------ | -------- |
287 | | extendedPrivateKey | `string` |
288 |
289 | **Returns:** [Wallet](wallet.md)
290 |
291 | ---
292 |
293 |
294 |
295 | ### `` fromExtendedPublicKey
296 |
297 | ▸ **fromExtendedPublicKey**(extendedPublicKey: _`string`_): [Wallet](wallet.md)
298 |
299 | _Defined in [index.ts:302](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L302)_
300 |
301 | **Parameters:**
302 |
303 | | Name | Type |
304 | | ----------------- | -------- |
305 | | extendedPublicKey | `string` |
306 |
307 | **Returns:** [Wallet](wallet.md)
308 |
309 | ---
310 |
311 |
312 |
313 | ### `` fromPrivateKey
314 |
315 | ▸ **fromPrivateKey**(privateKey: _`Buffer`_): [Wallet](wallet.md)
316 |
317 | _Defined in [index.ts:314](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L314)_
318 |
319 | **Parameters:**
320 |
321 | | Name | Type |
322 | | ---------- | -------- |
323 | | privateKey | `Buffer` |
324 |
325 | **Returns:** [Wallet](wallet.md)
326 |
327 | ---
328 |
329 |
330 |
331 | ### `` fromPublicKey
332 |
333 | ▸ **fromPublicKey**(publicKey: _`Buffer`_, nonStrict?: _`boolean`_): [Wallet](wallet.md)
334 |
335 | _Defined in [index.ts:292](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L292)_
336 |
337 | **Parameters:**
338 |
339 | | Name | Type | Default value |
340 | | ------------------------- | --------- | ------------- |
341 | | publicKey | `Buffer` | - |
342 | | `Default value` nonStrict | `boolean` | false |
343 |
344 | **Returns:** [Wallet](wallet.md)
345 |
346 | ---
347 |
348 |
349 |
350 | ### `` fromV1
351 |
352 | ▸ **fromV1**(input: _`string` \| `V1Keystore`_, password: _`string`_): [Wallet](wallet.md)
353 |
354 | _Defined in [index.ts:338](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L338)_
355 |
356 | **Parameters:**
357 |
358 | | Name | Type | Description |
359 | | -------- | ------------------------ | ---------------------------------------------------------------- |
360 | | input | `string` \| `V1Keystore` | A JSON serialized string, or an object representing V1 Keystore. |
361 | | password | `string` | The keystore password. |
362 |
363 | **Returns:** [Wallet](wallet.md)
364 |
365 | ---
366 |
367 |
368 |
369 | ### `` fromV3
370 |
371 | ▸ **fromV3**(input: _`string` \| `V3Keystore`_, password: _`string`_, nonStrict?: _`boolean`_): [Wallet](wallet.md)
372 |
373 | _Defined in [index.ts:378](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L378)_
374 |
375 | **Parameters:**
376 |
377 | | Name | Type | Default value | Description |
378 | | ------------------------- | ------------------------ | ------------- | ---------------------------------------------------------------- |
379 | | input | `string` \| `V3Keystore` | - | A JSON serialized string, or an object representing V3 Keystore. |
380 | | password | `string` | - | The keystore password. |
381 | | `Default value` nonStrict | `boolean` | false |
382 |
383 | **Returns:** [Wallet](wallet.md)
384 |
385 | ---
386 |
387 |
388 |
389 | ### `` generate
390 |
391 | ▸ **generate**(icapDirect?: _`boolean`_): [Wallet](wallet.md)
392 |
393 | _Defined in [index.ts:254](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L254)_
394 |
395 | **Parameters:**
396 |
397 | | Name | Type | Default value | Description |
398 | | -------------------------- | --------- | ------------- | --------------------------------------------------------------------------------------- |
399 | | `Default value` icapDirect | `boolean` | false | setting this to \`true\` will generate an address suitable for the \`ICAP Direct mode\` |
400 |
401 | **Returns:** [Wallet](wallet.md)
402 |
403 | ---
404 |
405 |
406 |
407 | ### `` generateVanityAddress
408 |
409 | ▸ **generateVanityAddress**(pattern: _`RegExp` \| `string`_): [Wallet](wallet.md)
410 |
411 | _Defined in [index.ts:271](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/index.ts#L271)_
412 |
413 | **Parameters:**
414 |
415 | | Name | Type |
416 | | ------- | -------------------- |
417 | | pattern | `RegExp` \| `string` |
418 |
419 | **Returns:** [Wallet](wallet.md)
420 |
421 | ---
422 |
--------------------------------------------------------------------------------
/docs/interfaces/etherwalletoptions.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-wallet](../README.md) > [EtherWalletOptions](../interfaces/etherwalletoptions.md)
2 |
3 | # Interface: EtherWalletOptions
4 |
5 | ## Hierarchy
6 |
7 | **EtherWalletOptions**
8 |
9 | ## Index
10 |
11 | ### Properties
12 |
13 | - [address](etherwalletoptions.md#address)
14 | - [encrypted](etherwalletoptions.md#encrypted)
15 | - [hash](etherwalletoptions.md#hash)
16 | - [locked](etherwalletoptions.md#locked)
17 | - [private](etherwalletoptions.md#private)
18 | - [public](etherwalletoptions.md#public)
19 |
20 | ---
21 |
22 | ## Properties
23 |
24 |
25 |
26 | ### address
27 |
28 | **● address**: _`string`_
29 |
30 | _Defined in [thirdparty.ts:108](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L108)_
31 |
32 | ---
33 |
34 |
35 |
36 | ### encrypted
37 |
38 | **● encrypted**: _`boolean`_
39 |
40 | _Defined in [thirdparty.ts:109](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L109)_
41 |
42 | ---
43 |
44 |
45 |
46 | ### hash
47 |
48 | **● hash**: _`string`_
49 |
50 | _Defined in [thirdparty.ts:111](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L111)_
51 |
52 | ---
53 |
54 |
55 |
56 | ### locked
57 |
58 | **● locked**: _`boolean`_
59 |
60 | _Defined in [thirdparty.ts:110](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L110)_
61 |
62 | ---
63 |
64 |
65 |
66 | ### private
67 |
68 | **● private**: _`string`_
69 |
70 | _Defined in [thirdparty.ts:112](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L112)_
71 |
72 | ---
73 |
74 |
75 |
76 | ### public
77 |
78 | **● public**: _`string`_
79 |
80 | _Defined in [thirdparty.ts:113](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L113)_
81 |
82 | ---
83 |
--------------------------------------------------------------------------------
/docs/interfaces/evpkdfopts.md:
--------------------------------------------------------------------------------
1 | [ethereumjs-wallet](../README.md) > [EvpKdfOpts](../interfaces/evpkdfopts.md)
2 |
3 | # Interface: EvpKdfOpts
4 |
5 | ## Hierarchy
6 |
7 | **EvpKdfOpts**
8 |
9 | ## Index
10 |
11 | ### Properties
12 |
13 | - [count](evpkdfopts.md#count)
14 | - [digest](evpkdfopts.md#digest)
15 | - [ivsize](evpkdfopts.md#ivsize)
16 | - [keysize](evpkdfopts.md#keysize)
17 |
18 | ---
19 |
20 | ## Properties
21 |
22 |
23 |
24 | ### count
25 |
26 | **● count**: _`number`_
27 |
28 | _Defined in [thirdparty.ts:17](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L17)_
29 |
30 | ---
31 |
32 |
33 |
34 | ### digest
35 |
36 | **● digest**: _`string`_
37 |
38 | _Defined in [thirdparty.ts:20](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L20)_
39 |
40 | ---
41 |
42 |
43 |
44 | ### ivsize
45 |
46 | **● ivsize**: _`number`_
47 |
48 | _Defined in [thirdparty.ts:19](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L19)_
49 |
50 | ---
51 |
52 |
53 |
54 | ### keysize
55 |
56 | **● keysize**: _`number`_
57 |
58 | _Defined in [thirdparty.ts:18](https://github.com/ethereumjs/ethereumjs-wallet/blob/13fb20d/src/thirdparty.ts#L18)_
59 |
60 | ---
61 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | module.exports = function(config) {
2 | config.set({
3 | frameworks: ['mocha', 'karma-typescript'],
4 | files: ['src/**/*.ts', 'test/**/*.spec.ts'],
5 | preprocessors: {
6 | '**/*.ts': ['karma-typescript'],
7 | },
8 | plugins: ['karma-mocha', 'karma-typescript', 'karma-chrome-launcher', 'karma-firefox-launcher'],
9 | karmaTypescriptConfig: {
10 | tsconfig: './tsconfig.json',
11 | bundlerOptions: {
12 | entrypoints: /\.spec\.ts$/,
13 | acornOptions: {
14 | ecmaVersion: 11
15 | }
16 | },
17 | },
18 | colors: true,
19 | reporters: ['progress', 'karma-typescript'],
20 | browsers: ['FirefoxHeadless', 'ChromeHeadless'],
21 | singleRun: true,
22 | concurrency: 1,
23 | // Extend timeouts for long tests
24 | browserDisconnectTimeout: 1000000,
25 | browserNoActivityTimeout: 1000000,
26 | })
27 | }
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ethereumjs-wallet",
3 | "version": "1.0.2",
4 | "description": "Utilities for handling Ethereum keys",
5 | "main": "dist/index.js",
6 | "types": "dist/index.d.ts",
7 | "browser": "dist.browser/index.js",
8 | "files": [
9 | "src",
10 | "dist",
11 | "dist.browser"
12 | ],
13 | "homepage": "https://github.com/ethereumjs/ethereumjs-wallet",
14 | "dependencies": {
15 | "@ethereumjs/util": "^8.0.0",
16 | "@scure/base": "1.1.1",
17 | "ethereum-cryptography": "1.2.0",
18 | "js-md5": "0.7.3",
19 | "uuid": "8.3.2"
20 | },
21 | "devDependencies": {
22 | "eslint": "6.8.0",
23 | "@typescript-eslint/eslint-plugin": "4.27.0",
24 | "@typescript-eslint/parser": "4.27.0",
25 | "eslint-config-prettier": "6.11.0",
26 | "eslint-config-typestrict": "1.0.3",
27 | "eslint-plugin-implicit-dependencies": "1.0.4",
28 | "eslint-plugin-import": "2.26.0",
29 | "eslint-plugin-prettier": "3.1.3",
30 | "eslint-plugin-sonarjs": "0.5.0",
31 | "@types/js-md5": "0.4.3",
32 | "@types/lodash.zip": "4.2.7",
33 | "@types/mocha": "9.1.1",
34 | "@types/node": "18.0.0",
35 | "ethers": "5.6.9",
36 | "husky": "4.2.5",
37 | "karma": "6.4.0",
38 | "karma-chrome-launcher": "3.1.1",
39 | "karma-firefox-launcher": "2.1.2",
40 | "karma-mocha": "2.0.1",
41 | "karma-typescript": "5.5.3",
42 | "lodash.zip": "4.2.0",
43 | "mocha": "10.0.0",
44 | "nyc": "15.1.0",
45 | "prettier": "2.6.2",
46 | "ts-node": "10.9.1",
47 | "typedoc": "0.23.9",
48 | "typedoc-plugin-markdown": "3.13.4",
49 | "typescript": "4.7.3"
50 | },
51 | "scripts": {
52 | "postinstall": "npm run build",
53 | "build": "tsc -p tsconfig.prod.json",
54 | "prepublishOnly": "npm run lint && npm run build && npm run test",
55 | "docs:build": "typedoc --out docs --mode file --readme none --theme markdown --mdEngine github --excludeNotExported src",
56 | "coverage": "npm run build && nyc --reporter=lcov npm run test:unit",
57 | "tsc": "tsc -p tsconfig.prod.json --noEmit",
58 | "lint": "eslint --format codeframe --config ./.eslintrc.js . --ext .js,.jsx,.ts,.tsx",
59 | "lint:fix": "eslint --fix --format codeframe --config ./.eslintrc.js . --ext .js,.jsx,.ts,.tsx",
60 | "test": "npm run test:unit && npm run test:browser",
61 | "test:unit": "mocha --require ts-node/register ./test/**/*.spec.ts",
62 | "test:browser": "karma start karma.conf.js"
63 | },
64 | "husky": {
65 | "hooks": {
66 | "pre-push": "npm run lint"
67 | }
68 | },
69 | "repository": {
70 | "type": "git",
71 | "url": "https://github.com/ethereumjs/ethereumjs-wallet.git"
72 | },
73 | "keywords": [
74 | "ethereum",
75 | "wallets",
76 | "keys"
77 | ],
78 | "author": "Alex Beregszaszi ",
79 | "license": "MIT",
80 | "bugs": {
81 | "url": "https://github.com/ethereumjs/ethereumjs-wallet/issues"
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | semi: false,
3 | singleQuote: true,
4 | printWidth: 100,
5 | }
6 |
--------------------------------------------------------------------------------
/src/hdkey.ts:
--------------------------------------------------------------------------------
1 | import { HDKey } from 'ethereum-cryptography/hdkey'
2 | import Wallet from './index'
3 |
4 | export default class EthereumHDKey {
5 | /**
6 | * Creates an instance based on a seed.
7 | *
8 | * For the seed we suggest to use [bip39](https://npmjs.org/package/bip39) to
9 | * create one from a BIP39 mnemonic.
10 | */
11 | public static fromMasterSeed(seedBuffer: Buffer): EthereumHDKey {
12 | return new EthereumHDKey(HDKey.fromMasterSeed(seedBuffer))
13 | }
14 |
15 | /**
16 | * Create an instance based on a BIP32 extended private or public key.
17 | */
18 | public static fromExtendedKey(base58Key: string): EthereumHDKey {
19 | return new EthereumHDKey(HDKey.fromExtendedKey(base58Key))
20 | }
21 |
22 | constructor(private readonly _hdkey: HDKey) {}
23 |
24 | /**
25 | * Returns a BIP32 extended private key (xprv)
26 | */
27 | public privateExtendedKey(): string {
28 | if (!this._hdkey.privateExtendedKey) {
29 | throw new Error('This is a public key only wallet')
30 | }
31 | return this._hdkey.privateExtendedKey
32 | }
33 |
34 | /**
35 | * Return a BIP32 extended public key (xpub)
36 | */
37 | public publicExtendedKey(): string {
38 | return this._hdkey.publicExtendedKey
39 | }
40 |
41 | /**
42 | * Derives a node based on a path (e.g. m/44'/0'/0/1)
43 | */
44 | public derivePath(path: string): EthereumHDKey {
45 | return new EthereumHDKey(this._hdkey.derive(path))
46 | }
47 |
48 | /**
49 | * Derive a node based on a child index
50 | */
51 | public deriveChild(index: number): EthereumHDKey {
52 | return new EthereumHDKey(this._hdkey.deriveChild(index))
53 | }
54 |
55 | /**
56 | * Return a `Wallet` instance as seen above
57 | */
58 | public getWallet(): Wallet {
59 | if (this._hdkey.privateKey) {
60 | return Wallet.fromPrivateKey(Buffer.from(this._hdkey.privateKey))
61 | }
62 | if (!this._hdkey.publicKey) throw new Error('No hdkey')
63 | return Wallet.fromPublicKey(Buffer.from(this._hdkey.publicKey), true)
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | bufferToHex,
3 | privateToAddress,
4 | publicToAddress,
5 | toChecksumAddress,
6 | privateToPublic,
7 | importPublic,
8 | isValidPrivate,
9 | isValidPublic,
10 | } from '@ethereumjs/util'
11 | import { base58check } from '@scure/base'
12 | import * as aes from 'ethereum-cryptography/aes'
13 | import { keccak256 } from 'ethereum-cryptography/keccak'
14 | import { getRandomBytesSync } from 'ethereum-cryptography/random'
15 | import { pbkdf2 } from 'ethereum-cryptography/pbkdf2'
16 | import { scrypt } from 'ethereum-cryptography/scrypt'
17 | import { sha256 } from 'ethereum-cryptography/sha256'
18 |
19 | export { default as hdkey } from './hdkey'
20 | export { default as thirdparty } from './thirdparty'
21 | const uuidv4 = require('uuid').v4
22 |
23 | const bs58check = base58check(sha256)
24 | function randomBytes(num: number) {
25 | return Buffer.from(getRandomBytesSync(num))
26 | }
27 | interface KDFParamsV1 {
28 | N: number
29 | P: number
30 | R: number
31 | DkLen: number
32 | }
33 | function scryptV1(password: Buffer, salt: Buffer, kdfparams: KDFParamsV1) {
34 | const { N, P, R, DkLen } = kdfparams
35 | return scrypt(password, salt, N, P, R, DkLen)
36 | }
37 | function scryptV3(password: string, kdfparams: ScryptKDFParams) {
38 | const { salt, n, p, r, dklen } = kdfparams
39 | return scrypt(Buffer.from(password), salt, n, p, r, dklen)
40 | }
41 | function scryptV3Out(password: string, kdfparams: ScryptKDFParamsOut) {
42 | const { salt, n, p, r, dklen } = kdfparams
43 | return scrypt(Buffer.from(password), Buffer.from(salt, 'hex'), n, p, r, dklen)
44 | }
45 |
46 | // parameters for the toV3() method
47 |
48 | interface V3Params {
49 | kdf: string
50 | cipher: string
51 | salt: string | Buffer
52 | iv: string | Buffer
53 | uuid: string | Buffer
54 | dklen: number
55 | c: number
56 | n: number
57 | r: number
58 | p: number
59 | }
60 |
61 | interface V3ParamsStrict {
62 | kdf: string
63 | cipher: string
64 | salt: Buffer
65 | iv: Buffer
66 | uuid: Buffer
67 | dklen: number
68 | c: number
69 | n: number
70 | r: number
71 | p: number
72 | }
73 |
74 | // helpers
75 | function keyExists(k: Buffer | undefined | null): k is Buffer {
76 | return k !== undefined && k !== null
77 | }
78 |
79 | function validateHexString(paramName: string, str: string, length?: number) {
80 | if (str.toLowerCase().startsWith('0x')) {
81 | str = str.slice(2)
82 | }
83 | if (!str && !length) {
84 | return str
85 | }
86 | if ((length as number) % 2) {
87 | throw new Error(`Invalid length argument, must be an even number`)
88 | }
89 | if (typeof length === 'number' && str.length !== length) {
90 | throw new Error(`Invalid ${paramName}, string must be ${length} hex characters`)
91 | }
92 | if (!/^([0-9a-f]{2})+$/i.test(str)) {
93 | const howMany = typeof length === 'number' ? length : 'empty or a non-zero even number of'
94 | throw new Error(`Invalid ${paramName}, string must be ${howMany} hex characters`)
95 | }
96 | return str
97 | }
98 |
99 | function validateBuffer(paramName: string, buff: Buffer, length?: number) {
100 | if (!Buffer.isBuffer(buff)) {
101 | const howManyHex =
102 | typeof length === 'number' ? `${length * 2}` : 'empty or a non-zero even number of'
103 | const howManyBytes = typeof length === 'number' ? ` (${length} bytes)` : ''
104 | throw new Error(
105 | `Invalid ${paramName}, must be a string (${howManyHex} hex characters) or buffer${howManyBytes}`
106 | )
107 | }
108 | if (typeof length === 'number' && buff.length !== length) {
109 | throw new Error(`Invalid ${paramName}, buffer must be ${length} bytes`)
110 | }
111 | return buff
112 | }
113 |
114 | function mergeToV3ParamsWithDefaults(params?: Partial): V3ParamsStrict {
115 | const v3Defaults: V3ParamsStrict = {
116 | cipher: 'aes-128-ctr',
117 | kdf: 'scrypt',
118 | salt: randomBytes(32),
119 | iv: randomBytes(16),
120 | uuid: randomBytes(16),
121 | dklen: 32,
122 | c: 262144,
123 | n: 262144,
124 | r: 8,
125 | p: 1,
126 | }
127 |
128 | if (!params) {
129 | return v3Defaults
130 | }
131 |
132 | if (typeof params.salt === 'string') {
133 | params.salt = Buffer.from(validateHexString('salt', params.salt), 'hex')
134 | }
135 | if (typeof params.iv === 'string') {
136 | params.iv = Buffer.from(validateHexString('iv', params.iv, 32), 'hex')
137 | }
138 | if (typeof params.uuid === 'string') {
139 | params.uuid = Buffer.from(validateHexString('uuid', params.uuid, 32), 'hex')
140 | }
141 |
142 | if (params.salt) {
143 | validateBuffer('salt', params.salt)
144 | }
145 | if (params.iv) {
146 | validateBuffer('iv', params.iv, 16)
147 | }
148 | if (params.uuid) {
149 | validateBuffer('uuid', params.uuid, 16)
150 | }
151 |
152 | return {
153 | ...v3Defaults,
154 | ...(params as V3ParamsStrict),
155 | }
156 | }
157 |
158 | // KDF
159 |
160 | const enum KDFFunctions {
161 | PBKDF = 'pbkdf2',
162 | Scrypt = 'scrypt',
163 | }
164 |
165 | interface ScryptKDFParams {
166 | dklen: number
167 | n: number
168 | p: number
169 | r: number
170 | salt: Buffer
171 | }
172 |
173 | interface ScryptKDFParamsOut {
174 | dklen: number
175 | n: number
176 | p: number
177 | r: number
178 | salt: string
179 | }
180 |
181 | interface PBKDFParams {
182 | c: number
183 | dklen: number
184 | prf: string
185 | salt: Buffer
186 | }
187 |
188 | interface PBKDFParamsOut {
189 | c: number
190 | dklen: number
191 | prf: string
192 | salt: string
193 | }
194 |
195 | type KDFParams = ScryptKDFParams | PBKDFParams
196 | type KDFParamsOut = ScryptKDFParamsOut | PBKDFParamsOut
197 |
198 | function kdfParamsForPBKDF(opts: V3ParamsStrict): PBKDFParams {
199 | return {
200 | dklen: opts.dklen,
201 | salt: opts.salt,
202 | c: opts.c,
203 | prf: 'hmac-sha256',
204 | }
205 | }
206 |
207 | function kdfParamsForScrypt(opts: V3ParamsStrict): ScryptKDFParams {
208 | return {
209 | dklen: opts.dklen,
210 | salt: opts.salt,
211 | n: opts.n,
212 | p: opts.p,
213 | r: opts.r,
214 | }
215 | }
216 |
217 | // JSON keystore types
218 |
219 | // https://github.com/ethereum/homestead-guide/blob/master/old-docs-for-reference/go-ethereum-wiki.rst/Passphrase-protected-key-store-spec.rst
220 | interface V1Keystore {
221 | Address: string
222 | Crypto: {
223 | CipherText: string
224 | IV: string
225 | KeyHeader: {
226 | Kdf: string
227 | KdfParams: {
228 | DkLen: number
229 | N: number
230 | P: number
231 | R: number
232 | SaltLen: number
233 | }
234 | Version: string
235 | }
236 | MAC: string
237 | Salt: string
238 | }
239 | Id: string
240 | Version: string
241 | }
242 |
243 | // https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition
244 | interface V3Keystore {
245 | crypto: {
246 | cipher: string
247 | cipherparams: {
248 | iv: string
249 | }
250 | ciphertext: string
251 | kdf: string
252 | kdfparams: KDFParamsOut
253 | mac: string
254 | }
255 | id: string
256 | version: number
257 | }
258 |
259 | interface EthSaleKeystore {
260 | encseed: string
261 | ethaddr: string
262 | btcaddr: string
263 | email: string
264 | }
265 |
266 | // wallet implementation
267 |
268 | export default class Wallet {
269 | constructor(
270 | private readonly privateKey?: Buffer | undefined,
271 | private publicKey: Buffer | undefined = undefined
272 | ) {
273 | if (privateKey && publicKey) {
274 | throw new Error('Cannot supply both a private and a public key to the constructor')
275 | }
276 |
277 | if (privateKey && !isValidPrivate(privateKey)) {
278 | throw new Error('Private key does not satisfy the curve requirements (ie. it is invalid)')
279 | }
280 |
281 | if (publicKey && !isValidPublic(publicKey)) {
282 | throw new Error('Invalid public key')
283 | }
284 | }
285 |
286 | // static methods
287 |
288 | /**
289 | * Create an instance based on a new random key.
290 | *
291 | * @param icapDirect setting this to `true` will generate an address suitable for the `ICAP Direct mode`
292 | */
293 | public static generate(icapDirect = false): Wallet {
294 | if (icapDirect) {
295 | const max = BigInt('0x088f924eeceeda7fe92e1f5b0fffffffffffffff')
296 | for (;;) {
297 | const privateKey = randomBytes(32) as Buffer
298 | const hex = privateToAddress(privateKey).toString('hex')
299 | if (BigInt('0x' + hex) <= max) {
300 | return new Wallet(privateKey)
301 | }
302 | }
303 | } else {
304 | return new Wallet(randomBytes(32))
305 | }
306 | }
307 |
308 | /**
309 | * Create an instance where the address is valid against the supplied pattern (**this will be very slow**)
310 | */
311 | public static generateVanityAddress(pattern: RegExp | string): Wallet {
312 | if (!(pattern instanceof RegExp)) {
313 | pattern = new RegExp(pattern)
314 | }
315 |
316 | for (;;) {
317 | const privateKey = randomBytes(32) as Buffer
318 | const address = privateToAddress(privateKey)
319 |
320 | if (pattern.test(address.toString('hex'))) {
321 | return new Wallet(privateKey)
322 | }
323 | }
324 | }
325 |
326 | /**
327 | * Create an instance based on a public key (certain methods will not be available)
328 | *
329 | * This method only accepts uncompressed Ethereum-style public keys, unless
330 | * the `nonStrict` flag is set to true.
331 | */
332 | public static fromPublicKey(publicKey: Buffer, nonStrict = false): Wallet {
333 | if (nonStrict) {
334 | publicKey = importPublic(publicKey)
335 | }
336 | return new Wallet(undefined, publicKey)
337 | }
338 |
339 | /**
340 | * Create an instance based on a BIP32 extended public key (xpub)
341 | */
342 | public static fromExtendedPublicKey(extendedPublicKey: string): Wallet {
343 | if (extendedPublicKey.slice(0, 4) !== 'xpub') {
344 | throw new Error('Not an extended public key')
345 | }
346 | const publicKey: Uint8Array = bs58check.decode(extendedPublicKey).slice(45)
347 | // Convert to an Ethereum public key
348 | return Wallet.fromPublicKey(Buffer.from(publicKey), true)
349 | }
350 |
351 | /**
352 | * Create an instance based on a raw private key
353 | */
354 | public static fromPrivateKey(privateKey: Buffer): Wallet {
355 | return new Wallet(privateKey)
356 | }
357 |
358 | /**
359 | * Create an instance based on a BIP32 extended private key (xprv)
360 | */
361 | public static fromExtendedPrivateKey(extendedPrivateKey: string): Wallet {
362 | if (extendedPrivateKey.slice(0, 4) !== 'xprv') {
363 | throw new Error('Not an extended private key')
364 | }
365 | const tmp: Uint8Array = bs58check.decode(extendedPrivateKey)
366 | if (tmp[45] !== 0) {
367 | throw new Error('Invalid extended private key')
368 | }
369 | return Wallet.fromPrivateKey(Buffer.from(tmp.slice(46)))
370 | }
371 |
372 | /**
373 | * Import a wallet (Version 1 of the Ethereum wallet format).
374 | *
375 | * @param input A JSON serialized string, or an object representing V1 Keystore.
376 | * @param password The keystore password.
377 | */
378 | public static async fromV1(input: string | V1Keystore, password: string): Promise {
379 | const json: V1Keystore = typeof input === 'object' ? input : JSON.parse(input)
380 | if (json.Version !== '1') {
381 | throw new Error('Not a V1 Wallet')
382 | }
383 | if (json.Crypto.KeyHeader.Kdf !== 'scrypt') {
384 | throw new Error('Unsupported key derivation scheme')
385 | }
386 |
387 | const kdfparams = json.Crypto.KeyHeader.KdfParams
388 | const salt = Buffer.from(json.Crypto.Salt, 'hex')
389 | const derivedKey = await scryptV1(Buffer.from(password), salt, kdfparams)
390 | const ciphertext = Buffer.from(json.Crypto.CipherText, 'hex')
391 | const mac = keccak256(Buffer.concat([derivedKey.slice(16, 32), ciphertext]))
392 | if (Buffer.from(mac).toString('hex') !== json.Crypto.MAC) {
393 | throw new Error('Key derivation failed - possibly wrong passphrase')
394 | }
395 |
396 | const seed = await aes.decrypt(
397 | ciphertext,
398 | keccak256(derivedKey.slice(0, 16) as Buffer).slice(0, 16),
399 | Buffer.from(json.Crypto.IV, 'hex'),
400 | 'aes-128-cbc'
401 | )
402 | return new Wallet(Buffer.from(seed))
403 | }
404 |
405 | /**
406 | * Import a wallet (Version 3 of the Ethereum wallet format). Set `nonStrict` true to accept files with mixed-caps.
407 | *
408 | * @param input A JSON serialized string, or an object representing V3 Keystore.
409 | * @param password The keystore password.
410 | */
411 | public static async fromV3(
412 | input: string | V3Keystore,
413 | password: string,
414 | nonStrict = false
415 | ): Promise {
416 | const json: V3Keystore =
417 | typeof input === 'object' ? input : JSON.parse(nonStrict ? input.toLowerCase() : input)
418 |
419 | if (json.version !== 3) {
420 | throw new Error('Not a V3 wallet')
421 | }
422 |
423 | let derivedKey: Uint8Array, kdfparams: any
424 | if (json.crypto.kdf === 'scrypt') {
425 | kdfparams = json.crypto.kdfparams
426 | // FIXME: support progress reporting callback
427 | derivedKey = await scryptV3Out(password, kdfparams)
428 | } else if (json.crypto.kdf === 'pbkdf2') {
429 | kdfparams = json.crypto.kdfparams
430 |
431 | if (kdfparams.prf !== 'hmac-sha256') {
432 | throw new Error('Unsupported parameters to PBKDF2')
433 | }
434 |
435 | derivedKey = await pbkdf2(
436 | Buffer.from(password),
437 | Buffer.from(kdfparams.salt, 'hex'),
438 | kdfparams.c,
439 | kdfparams.dklen,
440 | 'sha256'
441 | )
442 | } else {
443 | throw new Error('Unsupported key derivation scheme')
444 | }
445 |
446 | const ciphertext = Buffer.from(json.crypto.ciphertext, 'hex')
447 | const mac = keccak256(Buffer.concat([Buffer.from(derivedKey.slice(16, 32)), ciphertext]))
448 | if (Buffer.from(mac).toString('hex') !== json.crypto.mac) {
449 | throw new Error('Key derivation failed - possibly wrong passphrase')
450 | }
451 |
452 | const seed = await aes.decrypt(
453 | ciphertext,
454 | derivedKey.slice(0, 16),
455 | Buffer.from(json.crypto.cipherparams.iv, 'hex'),
456 | json.crypto.cipher
457 | )
458 | return new Wallet(Buffer.from(seed))
459 | }
460 |
461 | /*
462 | * Import an Ethereum Pre Sale wallet.
463 | * Based on https://github.com/ethereum/pyethsaletool/blob/master/pyethsaletool.py
464 | * JSON fields: encseed, ethaddr, btcaddr, email
465 | *
466 | * @param input A JSON serialized string, or an object representing EthSale Keystore.
467 | * @param password The keystore password.
468 | */
469 | public static async fromEthSale(
470 | input: string | EthSaleKeystore,
471 | password: string
472 | ): Promise {
473 | const json: EthSaleKeystore = typeof input === 'object' ? input : JSON.parse(input)
474 |
475 | const encseed = Uint8Array.from(Buffer.from(json.encseed, 'hex'))
476 |
477 | // key derivation
478 | const pass = Buffer.from(password, 'utf8')
479 | const derivedKey = (await pbkdf2(pass, pass, 2000, 32, 'sha256')).slice(0, 16)
480 |
481 | // seed decoding (IV is first 16 bytes)
482 | // NOTE: crypto (derived from openssl) when used with aes-*-cbc will handle PKCS#7 padding internally
483 | // see also http://stackoverflow.com/a/31614770/4964819
484 | const seed = await aes.decrypt(
485 | encseed.slice(16),
486 | derivedKey,
487 | encseed.slice(0, 16),
488 | 'aes-128-cbc',
489 | true
490 | )
491 |
492 | const wallet = new Wallet(Buffer.from(keccak256(seed)))
493 | if (wallet.getAddress().toString('hex') !== json.ethaddr) {
494 | throw new Error('Decoded key mismatch - possibly wrong passphrase')
495 | }
496 | return wallet
497 | }
498 |
499 | // private getters
500 |
501 | /**
502 | * Returns the wallet's public key.
503 | */
504 | private get pubKey(): Buffer {
505 | if (!keyExists(this.publicKey)) {
506 | this.publicKey = privateToPublic(this.privateKey as Buffer)
507 | }
508 | return this.publicKey
509 | }
510 |
511 | /**
512 | * Returns the wallet's private key.
513 | */
514 | private get privKey(): Buffer {
515 | if (!keyExists(this.privateKey)) {
516 | throw new Error('This is a public key only wallet')
517 | }
518 | return this.privateKey
519 | }
520 |
521 | // public instance methods
522 |
523 | /**
524 | * Returns the wallet's private key.
525 | *
526 | */
527 | // tslint:disable-next-line
528 | public getPrivateKey(): Buffer {
529 | return this.privKey
530 | }
531 |
532 | public getPrivateKeyString(): string {
533 | return bufferToHex(this.privKey)
534 | }
535 |
536 | /**
537 | * Returns the wallet's public key.
538 | */
539 | // tslint:disable-next-line
540 | public getPublicKey(): Buffer {
541 | return this.pubKey
542 | }
543 |
544 | /**
545 | * Returns the wallet's public key as a "0x" prefixed hex string
546 | */
547 | public getPublicKeyString(): string {
548 | return bufferToHex(this.getPublicKey())
549 | }
550 |
551 | /**
552 | * Returns the wallet's address.
553 | */
554 | public getAddress(): Buffer {
555 | return publicToAddress(this.pubKey)
556 | }
557 |
558 | /**
559 | * Returns the wallet's address as a "0x" prefixed hex string
560 | */
561 | public getAddressString(): string {
562 | return bufferToHex(this.getAddress())
563 | }
564 |
565 | /**
566 | * Returns the wallet's private key as a "0x" prefixed hex string checksummed
567 | * according to [EIP 55](https://github.com/ethereum/EIPs/issues/55).
568 | */
569 | public getChecksumAddressString(): string {
570 | return toChecksumAddress(this.getAddressString())
571 | }
572 |
573 | /**
574 | * Returns an Etherem Version 3 Keystore Format object representing the wallet
575 | *
576 | * @param password The password used to encrypt the Keystore.
577 | * @param opts The options for the keystore. See [its spec](https://github.com/ethereum/wiki/wiki/Web3-Secret-Storage-Definition) for more info.
578 | */
579 | public async toV3(password: string, opts?: Partial): Promise {
580 | if (!keyExists(this.privateKey)) {
581 | throw new Error('This is a public key only wallet')
582 | }
583 |
584 | const v3Params: V3ParamsStrict = mergeToV3ParamsWithDefaults(opts)
585 |
586 | let kdfParams: KDFParams
587 | let derivedKey: Uint8Array
588 | switch (v3Params.kdf) {
589 | case KDFFunctions.PBKDF:
590 | kdfParams = kdfParamsForPBKDF(v3Params)
591 | derivedKey = await pbkdf2(
592 | Buffer.from(password),
593 | kdfParams.salt,
594 | kdfParams.c,
595 | kdfParams.dklen,
596 | 'sha256'
597 | )
598 | break
599 | case KDFFunctions.Scrypt:
600 | kdfParams = kdfParamsForScrypt(v3Params)
601 | // FIXME: support progress reporting callback
602 | derivedKey = await scryptV3(password, kdfParams)
603 | break
604 | default:
605 | throw new Error('Unsupported kdf')
606 | }
607 |
608 | const ciphertext = await aes.encrypt(
609 | this.privKey,
610 | derivedKey.slice(0, 16),
611 | v3Params.iv,
612 | v3Params.cipher,
613 | false
614 | )
615 | const mac = keccak256(
616 | Buffer.concat([Buffer.from(derivedKey.slice(16, 32)), Buffer.from(ciphertext)])
617 | )
618 |
619 | return {
620 | version: 3,
621 | id: uuidv4({ random: v3Params.uuid }),
622 | // @ts-ignore - the official V3 keystore spec omits the address key
623 | address: this.getAddress().toString('hex'),
624 | crypto: {
625 | ciphertext: Buffer.from(ciphertext).toString('hex'),
626 | cipherparams: { iv: v3Params.iv.toString('hex') },
627 | cipher: v3Params.cipher,
628 | kdf: v3Params.kdf,
629 | kdfparams: {
630 | ...kdfParams,
631 | salt: kdfParams.salt.toString('hex'),
632 | },
633 | mac: Buffer.from(mac).toString('hex'),
634 | },
635 | }
636 | }
637 |
638 | /**
639 | * Return the suggested filename for V3 keystores.
640 | */
641 | public getV3Filename(timestamp?: number): string {
642 | /*
643 | * We want a timestamp like 2016-03-15T17-11-33.007598288Z. Date formatting
644 | * is a pain in Javascript, everbody knows that. We could use moment.js,
645 | * but decide to do it manually in order to save space.
646 | *
647 | * toJSON() returns a pretty close version, so let's use it. It is not UTC though,
648 | * but does it really matter?
649 | *
650 | * Alternative manual way with padding and Date fields: http://stackoverflow.com/a/7244288/4964819
651 | *
652 | */
653 | const ts = timestamp ? new Date(timestamp) : new Date()
654 | return ['UTC--', ts.toJSON().replace(/:/g, '-'), '--', this.getAddress().toString('hex')].join(
655 | ''
656 | )
657 | }
658 |
659 | public async toV3String(password: string, opts?: Partial): Promise {
660 | return JSON.stringify(await this.toV3(password, opts))
661 | }
662 |
663 | /**
664 | * Verify the publicKey, privateKey pair
665 | *
666 | * @param publicKey the public key to verify against the private key of the wallet
667 | */
668 | public verifyPublicKey(publicKey: Buffer): boolean {
669 | return privateToPublic(this.privateKey as Buffer).equals(publicKey)
670 | }
671 | }
672 |
--------------------------------------------------------------------------------
/src/thirdparty.ts:
--------------------------------------------------------------------------------
1 | import { decrypt } from 'ethereum-cryptography/aes'
2 | import { keccak256 } from 'ethereum-cryptography/keccak'
3 | import { pbkdf2Sync } from 'ethereum-cryptography/pbkdf2'
4 | import { bytesToUtf8, utf8ToBytes } from 'ethereum-cryptography/utils'
5 | import * as md5 from 'js-md5'
6 | import Wallet from './index'
7 |
8 | // evp_kdf
9 |
10 | export interface EvpKdfOpts {
11 | count: number
12 | keysize: number
13 | ivsize: number
14 | digest: string
15 | }
16 |
17 | const evpKdfDefaults: EvpKdfOpts = {
18 | count: 1,
19 | keysize: 16,
20 | ivsize: 16,
21 | digest: 'md5',
22 | }
23 |
24 | function mergeEvpKdfOptsWithDefaults(opts?: Partial): EvpKdfOpts {
25 | if (!opts) {
26 | return evpKdfDefaults
27 | }
28 | return {
29 | count: opts.count ?? evpKdfDefaults.count,
30 | keysize: opts.keysize ?? evpKdfDefaults.keysize,
31 | ivsize: opts.ivsize ?? evpKdfDefaults.ivsize,
32 | digest: opts.digest ?? evpKdfDefaults.digest,
33 | }
34 | }
35 |
36 | /*
37 | * opts:
38 | * - digest - digest algorithm, defaults to md5
39 | * - count - hash iterations
40 | * - keysize - desired key size
41 | * - ivsize - desired IV size
42 | *
43 | * Algorithm form https://www.openssl.org/docs/manmaster/crypto/EVP_BytesToKey.html
44 | *
45 | * FIXME: not optimised at all
46 | */
47 | function evp_kdf(data: Buffer, salt: Buffer, opts?: Partial) {
48 | const params = mergeEvpKdfOptsWithDefaults(opts)
49 |
50 | // A single EVP iteration, returns `D_i`, where block equlas to `D_(i-1)`
51 | function iter(block: Buffer) {
52 | if (params.digest !== 'md5') throw new Error('Only md5 is supported in evp_kdf')
53 | let hash = md5.create()
54 | hash.update(block)
55 | hash.update(data)
56 | hash.update(salt)
57 | block = Buffer.from(hash.arrayBuffer())
58 |
59 | for (let i = 1, len = params.count; i < len; i++) {
60 | hash = md5.create()
61 | hash.update(block)
62 | block = Buffer.from(hash.arrayBuffer())
63 | }
64 | return block
65 | }
66 |
67 | const ret: Buffer[] = []
68 | let i = 0
69 | while (Buffer.concat(ret).length < params.keysize + params.ivsize) {
70 | ret[i] = iter(i === 0 ? Buffer.alloc(0) : ret[i - 1])
71 | i++
72 | }
73 | const tmp = Buffer.concat(ret)
74 |
75 | return {
76 | key: tmp.subarray(0, params.keysize),
77 | iv: tmp.subarray(params.keysize, params.keysize + params.ivsize),
78 | }
79 | }
80 |
81 | // http://stackoverflow.com/questions/25288311/cryptojs-aes-pattern-always-ends-with
82 | function decodeCryptojsSalt(input: string): { ciphertext: Buffer; salt?: Buffer } {
83 | const ciphertext = Buffer.from(input, 'base64')
84 | if (ciphertext.subarray(0, 8).toString() === 'Salted__') {
85 | return {
86 | salt: ciphertext.subarray(8, 16),
87 | ciphertext: ciphertext.subarray(16),
88 | }
89 | }
90 | return { ciphertext }
91 | }
92 |
93 | // {
94 | // "address": "0x169aab499b549eac087035e640d3f7d882ef5e2d",
95 | // "encrypted": true,
96 | // "locked": true,
97 | // "hash": "342f636d174cc1caa49ce16e5b257877191b663e0af0271d2ea03ac7e139317d",
98 | // "private": "U2FsdGVkX19ZrornRBIfl1IDdcj6S9YywY8EgOeOtLj2DHybM/CHL4Jl0jcwjT+36kDnjj+qEfUBu6J1mGQF/fNcD/TsAUgGUTEUEOsP1CKDvNHfLmWLIfxqnYHhHsG5",
99 | // "public": "U2FsdGVkX19EaDNK52q7LEz3hL/VR3dYW5VcoP04tcVKNS0Q3JINpM4XzttRJCBtq4g22hNDrOR8RWyHuh3nPo0pRSe9r5AUfEiCLaMBAhI16kf2KqCA8ah4brkya9ZLECdIl0HDTMYfDASBnyNXd87qodt46U0vdRT3PppK+9hsyqP8yqm9kFcWqMHktqubBE937LIU0W22Rfw6cJRwIw=="
100 | // }
101 |
102 | export interface EtherWalletOptions {
103 | address: string
104 | encrypted: boolean
105 | locked: boolean
106 | hash: string
107 | private: string
108 | public: string
109 | }
110 |
111 | /*
112 | * Third Party API: Import a wallet generated by EtherWallet
113 | * This wallet format is created by https://github.com/SilentCicero/ethereumjs-accounts
114 | * and used on https://www.myetherwallet.com/
115 | */
116 | export async function fromEtherWallet(
117 | input: string | EtherWalletOptions,
118 | password: string
119 | ): Promise {
120 | const json: EtherWalletOptions = typeof input === 'object' ? input : JSON.parse(input)
121 |
122 | let privateKey: Buffer
123 | if (!json.locked) {
124 | if (json.private.length !== 64) {
125 | throw new Error('Invalid private key length')
126 | }
127 | privateKey = Buffer.from(json.private, 'hex')
128 | } else {
129 | if (typeof password !== 'string') {
130 | throw new Error('Password required')
131 | }
132 |
133 | if (password.length < 7) {
134 | throw new Error('Password must be at least 7 characters')
135 | }
136 |
137 | // the "encrypted" version has the low 4 bytes
138 | // of the hash of the address appended
139 | const hash = json.encrypted ? json.private.slice(0, 128) : json.private
140 |
141 | // decode openssl ciphertext + salt encoding
142 | const cipher = decodeCryptojsSalt(hash)
143 | if (!cipher.salt) {
144 | throw new Error('Unsupported EtherWallet key format')
145 | }
146 |
147 | // derive key/iv using OpenSSL EVP as implemented in CryptoJS
148 | const evp = evp_kdf(Buffer.from(password), cipher.salt, { keysize: 32, ivsize: 16 })
149 |
150 | const pr = await decrypt(cipher.ciphertext, evp.key, evp.iv, 'aes-256-cbc')
151 |
152 | // NOTE: yes, they've run it through UTF8
153 | privateKey = Buffer.from(bytesToUtf8(pr), 'hex')
154 | }
155 | const wallet = new Wallet(privateKey)
156 | if (wallet.getAddressString() !== json.address) {
157 | throw new Error('Invalid private key or address')
158 | }
159 | return wallet
160 | }
161 |
162 | /**
163 | * Third Party API: Import a brain wallet used by Ether.Camp
164 | */
165 | export function fromEtherCamp(passphrase: string): Wallet {
166 | return new Wallet(Buffer.from(keccak256(Buffer.from(passphrase))))
167 | }
168 |
169 | /**
170 | * Third Party API: Import a brain wallet used by Quorum Wallet
171 | */
172 | export function fromQuorumWallet(passphrase: string, userid: string): Wallet {
173 | if (passphrase.length < 10) {
174 | throw new Error('Passphrase must be at least 10 characters')
175 | }
176 | if (userid.length < 10) {
177 | throw new Error('User id must be at least 10 characters')
178 | }
179 |
180 | const merged = utf8ToBytes(passphrase + userid)
181 | const seed = pbkdf2Sync(merged, merged, 2000, 32, 'sha256')
182 | return new Wallet(Buffer.from(seed))
183 | }
184 |
185 | const Thirdparty = {
186 | fromEtherWallet,
187 | fromEtherCamp,
188 | fromQuorumWallet,
189 | }
190 |
191 | export default Thirdparty
192 |
--------------------------------------------------------------------------------
/test/hdkey.spec.ts:
--------------------------------------------------------------------------------
1 | import * as assert from 'assert'
2 | import EthereumHDKey from '../src/hdkey'
3 |
4 | // from BIP39 mnemonic: awake book subject inch gentle blur grant damage process float month clown
5 | const fixtureseed = Buffer.from(
6 | '747f302d9c916698912d5f70be53a6cf53bc495803a5523d3a7c3afa2afba94ec3803f838b3e1929ab5481f9da35441372283690fdcf27372c38f40ba134fe03',
7 | 'hex'
8 | )
9 | const fixturehd = EthereumHDKey.fromMasterSeed(fixtureseed)
10 |
11 | describe('.fromMasterSeed()', function () {
12 | it('should work', function () {
13 | assert.doesNotThrow(function () {
14 | EthereumHDKey.fromMasterSeed(fixtureseed)
15 | })
16 | })
17 | })
18 |
19 | describe('.privateExtendedKey()', function () {
20 | it('should work', function () {
21 | assert.strictEqual(
22 | fixturehd.privateExtendedKey(),
23 | 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY'
24 | )
25 | })
26 | })
27 |
28 | describe('.publicExtendedKey()', function () {
29 | it('should work', function () {
30 | assert.strictEqual(
31 | fixturehd.publicExtendedKey(),
32 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
33 | )
34 | })
35 | })
36 |
37 | describe('.fromExtendedKey()', function () {
38 | it('should work with public', function () {
39 | const hdnode = EthereumHDKey.fromExtendedKey(
40 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
41 | )
42 | assert.strictEqual(
43 | hdnode.publicExtendedKey(),
44 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
45 | )
46 | assert.throws(function () {
47 | hdnode.privateExtendedKey()
48 | }, /^Error: No private key$/)
49 | })
50 | it('should work with private', function () {
51 | const hdnode = EthereumHDKey.fromExtendedKey(
52 | 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY'
53 | )
54 | assert.strictEqual(
55 | hdnode.publicExtendedKey(),
56 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
57 | )
58 | assert.strictEqual(
59 | hdnode.privateExtendedKey(),
60 | 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY'
61 | )
62 | })
63 | })
64 |
65 | describe('.deriveChild()', function () {
66 | it('should work', function () {
67 | const hdnode = fixturehd.deriveChild(1)
68 | assert.strictEqual(
69 | hdnode.privateExtendedKey(),
70 | 'xprv9vYSvrg3eR5FaKbQE4Ao2vHdyvfFL27aWMyH6X818mKWMsqqQZAN6HmRqYDGDPLArzaqbLExRsxFwtx2B2X2QKkC9uoKsiBNi22tLPKZHNS'
71 | )
72 | })
73 | })
74 |
75 | describe('.derivePath()', function () {
76 | it('should work with m', function () {
77 | const hdnode = fixturehd.derivePath('m')
78 | assert.strictEqual(
79 | hdnode.privateExtendedKey(),
80 | 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY'
81 | )
82 | })
83 | it("should work with m/44'/0'/0/1", function () {
84 | const hdnode = fixturehd.derivePath("m/44'/0'/0/1")
85 | assert.strictEqual(
86 | hdnode.privateExtendedKey(),
87 | 'xprvA1ErCzsuXhpB8iDTsbmgpkA2P8ggu97hMZbAXTZCdGYeaUrDhyR8fEw47BNEgLExsWCVzFYuGyeDZJLiFJ9kwBzGojQ6NB718tjVJrVBSrG'
88 | )
89 | })
90 | })
91 |
92 | describe('.getWallet()', function () {
93 | it('should work', function () {
94 | assert.strictEqual(
95 | fixturehd.getWallet().getPrivateKeyString(),
96 | '0x26cc9417b89cd77c4acdbe2e3cd286070a015d8e380f9cd1244ae103b7d89d81'
97 | )
98 | assert.strictEqual(
99 | fixturehd.getWallet().getPublicKeyString(),
100 | '0x0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1'
101 | )
102 | })
103 | it('should work with public nodes', function () {
104 | const hdnode = EthereumHDKey.fromExtendedKey(
105 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
106 | )
107 | assert.throws(function () {
108 | hdnode.getWallet().getPrivateKeyString()
109 | }, /^Error: This is a public key only wallet$/)
110 | assert.strictEqual(
111 | hdnode.getWallet().getPublicKeyString(),
112 | '0x0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1'
113 | )
114 | })
115 | })
116 |
--------------------------------------------------------------------------------
/test/index.spec.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable no-invalid-this */
2 | import * as assert from 'assert'
3 | import { Wallet as ethersWallet } from 'ethers'
4 |
5 | const zip = require('lodash.zip')
6 |
7 | import Wallet from '../src'
8 | import Thirdparty from '../src/thirdparty'
9 |
10 | const n = 262144
11 | const r = 8
12 | const p = 1
13 |
14 | const fixturePrivateKey = 'efca4cdd31923b50f4214af5d2ae10e7ac45a5019e9431cc195482d707485378'
15 | const fixturePrivateKeyStr = '0x' + fixturePrivateKey
16 | const fixturePrivateKeyBuffer = Buffer.from(fixturePrivateKey, 'hex')
17 |
18 | const fixturePublicKey =
19 | '5d4392f450262b276652c1fc037606abac500f3160830ce9df53aa70d95ce7cfb8b06010b2f3691c78c65c21eb4cf3dfdbfc0745d89b664ee10435bb3a0f906c'
20 | const fixturePublicKeyStr = '0x' + fixturePublicKey
21 | const fixturePublicKeyBuffer = Buffer.from(fixturePublicKey, 'hex')
22 |
23 | const fixtureWallet = Wallet.fromPrivateKey(fixturePrivateKeyBuffer)
24 | const fixtureEthersWallet = new ethersWallet(fixtureWallet.getPrivateKeyString())
25 |
26 | const isRunningInKarma = () => {
27 | return typeof (global as any).window !== 'undefined' && (global as any).window.__karma__
28 | }
29 |
30 | describe('.getPrivateKey()', function () {
31 | it('should work', function () {
32 | assert.strictEqual(fixtureWallet.getPrivateKey().toString('hex'), fixturePrivateKey)
33 | })
34 | it('should fail', function () {
35 | assert.throws(function () {
36 | Wallet.fromPrivateKey(Buffer.from('001122', 'hex'))
37 | }, /^Error: Private key does not satisfy the curve requirements \(ie\. it is invalid\)$/)
38 | })
39 | })
40 |
41 | describe('.getPrivateKeyString()', function () {
42 | it('should work', function () {
43 | assert.strictEqual(fixtureWallet.getPrivateKeyString(), fixturePrivateKeyStr)
44 | })
45 | })
46 |
47 | describe('.getPublicKey()', function () {
48 | it('should work', function () {
49 | assert.strictEqual(fixtureWallet.getPublicKey().toString('hex'), fixturePublicKey)
50 | })
51 | })
52 |
53 | describe('.getPublicKeyString()', function () {
54 | it('should work', function () {
55 | assert.strictEqual(fixtureWallet.getPublicKeyString(), fixturePublicKeyStr)
56 | })
57 | })
58 |
59 | describe('.getAddress()', function () {
60 | it('should work', function () {
61 | assert.strictEqual(
62 | fixtureWallet.getAddress().toString('hex'),
63 | 'b14ab53e38da1c172f877dbc6d65e4a1b0474c3c'
64 | )
65 | })
66 | })
67 |
68 | describe('.getAddressString()', function () {
69 | it('should work', function () {
70 | assert.strictEqual(
71 | fixtureWallet.getAddressString(),
72 | '0xb14ab53e38da1c172f877dbc6d65e4a1b0474c3c'
73 | )
74 | })
75 | })
76 |
77 | describe('.getChecksumAddressString()', function () {
78 | it('should work', function () {
79 | assert.strictEqual(
80 | fixtureWallet.getChecksumAddressString(),
81 | '0xB14Ab53E38DA1C172f877DBC6d65e4a1B0474C3c'
82 | )
83 | })
84 | })
85 |
86 | describe('.verifyPublicKey()', function () {
87 | it('should return true if publicKey, privateKey pair is valid', function () {
88 | assert.strictEqual(fixtureWallet.verifyPublicKey(fixturePublicKeyBuffer), true)
89 | })
90 | it('should return false if publicKey, privateKey pair is invalid', function () {
91 | assert.strictEqual(fixtureWallet.verifyPublicKey(Buffer.alloc(64, 0)), false)
92 | })
93 | })
94 |
95 | describe('public key only wallet', function () {
96 | const pubKey = Buffer.from(fixturePublicKey, 'hex')
97 | it('.fromPublicKey() should work', function () {
98 | assert.strictEqual(
99 | Wallet.fromPublicKey(pubKey).getPublicKey().toString('hex'),
100 | fixturePublicKey
101 | )
102 | })
103 | it('.fromPublicKey() should not accept compressed keys in strict mode', function () {
104 | assert.throws(function () {
105 | Wallet.fromPublicKey(
106 | Buffer.from('030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d', 'hex')
107 | )
108 | }, /^Error: Invalid public key$/)
109 | })
110 | it('.fromPublicKey() should accept compressed keys in non-strict mode', function () {
111 | const tmp = Buffer.from(
112 | '030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d',
113 | 'hex'
114 | )
115 | assert.strictEqual(
116 | Wallet.fromPublicKey(tmp, true).getPublicKey().toString('hex'),
117 | '0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1'
118 | )
119 | })
120 | it('.getAddress() should work', function () {
121 | assert.strictEqual(
122 | Wallet.fromPublicKey(pubKey).getAddress().toString('hex'),
123 | 'b14ab53e38da1c172f877dbc6d65e4a1b0474c3c'
124 | )
125 | })
126 | it('.getPrivateKey() should fail', function () {
127 | assert.throws(function () {
128 | Wallet.fromPublicKey(pubKey).getPrivateKey()
129 | }, /^Error: This is a public key only wallet$/)
130 | })
131 | // it('.toV3() should fail', function () {
132 | // assert.throws(function () {
133 | // Wallet.fromPublicKey(pubKey).toV3()
134 | // }, /^Error: This is a public key only wallet$/)
135 | // })
136 | })
137 |
138 | describe('.fromExtendedPrivateKey()', function () {
139 | it('should work', function () {
140 | const xprv =
141 | 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY'
142 | assert.strictEqual(
143 | Wallet.fromExtendedPrivateKey(xprv).getAddressString(),
144 | '0xb800bf5435f67c7ee7d83c3a863269969a57c57c'
145 | )
146 | })
147 | })
148 |
149 | describe('.fromExtendedPublicKey()', function () {
150 | it('should work', function () {
151 | const xpub =
152 | 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ'
153 | assert.strictEqual(
154 | Wallet.fromExtendedPublicKey(xpub).getAddressString(),
155 | '0xb800bf5435f67c7ee7d83c3a863269969a57c57c'
156 | )
157 | })
158 | })
159 |
160 | describe('.generate()', function () {
161 | it('should generate an account', function () {
162 | assert.strictEqual(Wallet.generate().getPrivateKey().length, 32)
163 | })
164 | it('should generate an account compatible with ICAP Direct', function () {
165 | const max = BigInt('0x088f924eeceeda7fe92e1f5b0fffffffffffffff')
166 | const wallet = Wallet.generate(true)
167 | assert.strictEqual(wallet.getPrivateKey().length, 32)
168 | const addr = wallet.getAddress().toString('hex')
169 | assert.strictEqual(BigInt('0x' + addr) <= max, true)
170 | })
171 | })
172 |
173 | describe('.generateVanityAddress()', function () {
174 | it('should generate an account with 000 prefix (object)', function () {
175 | this.timeout(0) // never
176 | const wallet = Wallet.generateVanityAddress(/^000/)
177 | assert.strictEqual(wallet.getPrivateKey().length, 32)
178 | assert.strictEqual(wallet.getAddress()[0], 0)
179 | assert.strictEqual(wallet.getAddress()[1] >>> 4, 0)
180 | })
181 | it('should generate an account with 000 prefix (string)', function () {
182 | this.timeout(0) // never
183 | const wallet = Wallet.generateVanityAddress('^000')
184 | assert.strictEqual(wallet.getPrivateKey().length, 32)
185 | assert.strictEqual(wallet.getAddress()[0], 0)
186 | assert.strictEqual(wallet.getAddress()[1] >>> 4, 0)
187 | })
188 | })
189 |
190 | describe('.getV3Filename()', function () {
191 | it('should work', function () {
192 | assert.strictEqual(
193 | fixtureWallet.getV3Filename(1457917509265),
194 | 'UTC--2016-03-14T01-05-09.265Z--b14ab53e38da1c172f877dbc6d65e4a1b0474c3c'
195 | )
196 | })
197 | })
198 |
199 | describe('.toV3()', function () {
200 | const pw = 'testtest'
201 | const salt = 'dc9e4a98886738bd8aae134a1f89aaa5a502c3fbd10e336136d4d5fe47448ad6'
202 | const iv = 'cecacd85e9cb89788b5aab2f93361233'
203 | const uuid = '7e59dc028d42d09db29aa8a0f862cc81'
204 |
205 | const strKdfOptions = { iv, salt, uuid }
206 | const buffKdfOptions = {
207 | salt: Buffer.from(salt, 'hex'),
208 | iv: Buffer.from(iv, 'hex'),
209 | uuid: Buffer.from(uuid, 'hex'),
210 | }
211 |
212 | // generate all possible combinations of salt, iv, uuid properties, e.g.
213 | // {salt: [string], iv: [buffer], uuid: [string]}
214 | // the number of objects is naturally a radix for selecting one of the
215 | // input values for a given property; example, three objects and two keys:
216 | // [{a: 0, b: 0},
217 | // {a: 1, b: 1},
218 | // {a: 2, b: 2}]
219 | type Perm = Array<{
220 | salt: string | Buffer
221 | iv: string | Buffer
222 | uuid: string | Buffer
223 | }>
224 | const makePermutations = (...objs: Array