Skip to content
This repository was archived by the owner on Oct 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Features not supported:
- signing transactions
- managing storage (neither in node.js or the browser)

## API
## Wallet API

Constructors:

Expand Down Expand Up @@ -54,6 +54,27 @@ Instance methods:

All of the above instance methods return a Buffer or JSON. Use the `String` suffixed versions for a string output, such as `getPrivateKeyString()`.

## HD Wallet API

To use BIP32 HD wallets, first include the `hdkey` submodule:

`var hdkey = require('ethereumjs-wallet/hdkey')`

Constructors:

* `fromMasterSeed(seed)` - create an instance based on a seed
* `formExtendedKey(key)` - create an instance based on a BIP32 extended private or public key

For the seed we suggest to use [bip39](https://npmjs.org/packages/bip39) to create one from a BIP39 mnemonic.

Instance methods:

* `privateExtendedKey()` - return a BIP32 extended private key
* `publicExtendedKey()` - return a BIP32 extended private key
* `derivePath(path)` - derive a node based on a path (e.g. m/44'/0'/0/1)
* `deriveChild(index)` - derive a node based on a child index
* `getWallet()` - return a `Wallet` instance as seen above

### Remarks about `toV3`

The `options` is an optional object hash, where all the serialization parameters can be fine tuned:
Expand Down Expand Up @@ -82,3 +103,9 @@ The following settings are favoured by the Go Ethereum implementation and we def
- `r`: `8`
- `p`: `1`
- `cipher`: `aes-128-ctr`

## License

MIT License

Copyright (C) 2016 Alex Beregszaszi
48 changes: 48 additions & 0 deletions hdkey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const HDKey = require('hdkey')
const Wallet = require('./index.js')

function EthereumHDKey () {
}

/*
* Horrible wrapping.
*/
function fromHDKey (hdkey) {
var ret = new EthereumHDKey()
ret._hdkey = hdkey
return ret
}

EthereumHDKey.fromMasterSeed = function (seedBuffer) {
return fromHDKey(HDKey.fromMasterSeed(seedBuffer))
}

EthereumHDKey.fromExtendedKey = function (base58key) {
return fromHDKey(HDKey.fromExtendedKey(base58key))
}

EthereumHDKey.prototype.privateExtendedKey = function () {
return this._hdkey.privateExtendedKey
}

EthereumHDKey.prototype.publicExtendedKey = function () {
return this._hdkey.publicExtendedKey
}

EthereumHDKey.prototype.derivePath = function (path) {
return fromHDKey(this._hdkey.derive(path))
}

EthereumHDKey.prototype.deriveChild = function (index) {
return fromHDKey(this._hdkey.deriveChild(index))
}

EthereumHDKey.prototype.getWallet = function () {
if (this._hdkey._privateKey) {
return Wallet.fromPrivateKey(this._hdkey._privateKey)
} else {
return Wallet.fromPublicKey(this._hdkey._publicKey)
}
}

module.exports = EthereumHDKey
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"lint": "standard",
"prepublish": "npm run lint && npm run test",
"test": "mocha ./test/index.js"
"test": "mocha ./test/index.js && mocha ./test/hdkey.js"
},
"repository": {
"type": "git",
Expand All @@ -27,6 +27,7 @@
"aes-js": "^0.2.3",
"bs58check": "^1.0.8",
"ethereumjs-util": "^4.3.0",
"hdkey": "^0.7.0",
"scrypt.js": "^0.1.0",
"secp256k1": "^3.0.1",
"uuid": "^2.0.1",
Expand Down
74 changes: 74 additions & 0 deletions test/hdkey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
var assert = require('assert')
var HDKey = require('../hdkey.js')

// from BIP39 mnemonic: awake book subject inch gentle blur grant damage process float month clown
var fixtureseed = new Buffer('747f302d9c916698912d5f70be53a6cf53bc495803a5523d3a7c3afa2afba94ec3803f838b3e1929ab5481f9da35441372283690fdcf27372c38f40ba134fe03', 'hex')
var fixturehd = HDKey.fromMasterSeed(fixtureseed)

describe('.fromMasterSeed()', function () {
it('should work', function () {
assert.doesNotThrow(function () {
HDKey.fromMasterSeed(fixtureseed)
})
})
})

describe('.privateExtendedKey()', function () {
it('should work', function () {
assert.equal(fixturehd.privateExtendedKey(), 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY')
})
})

describe('.publicExtendedKey()', function () {
it('should work', function () {
assert.equal(fixturehd.publicExtendedKey(), 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ')
})
})

describe('.fromExtendedKey()', function () {
it('should work with public', function () {
var hdnode = HDKey.fromExtendedKey('xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ')
assert.equal(hdnode.publicExtendedKey(), 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ')
assert.throws(function () {
hdnode.privateExtendedKey()
})
})
it('should work with private', function () {
var hdnode = HDKey.fromExtendedKey('xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY')
assert.equal(hdnode.publicExtendedKey(), 'xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ')
assert.equal(hdnode.privateExtendedKey(), 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY')
})
})

describe('.deriveChild()', function () {
it('should work', function () {
var hdnode = fixturehd.deriveChild(1)
assert.equal(hdnode.privateExtendedKey(), 'xprv9vYSvrg3eR5FaKbQE4Ao2vHdyvfFL27aWMyH6X818mKWMsqqQZAN6HmRqYDGDPLArzaqbLExRsxFwtx2B2X2QKkC9uoKsiBNi22tLPKZHNS')
})
})

describe('.derivePath()', function () {
it('should work with m', function () {
var hdnode = fixturehd.derivePath('m')
assert.equal(hdnode.privateExtendedKey(), 'xprv9s21ZrQH143K4KqQx9Zrf1eN8EaPQVFxM2Ast8mdHn7GKiDWzNEyNdduJhWXToy8MpkGcKjxeFWd8oBSvsz4PCYamxR7TX49pSpp3bmHVAY')
})
it('should work with m/44\'/0\'/0/1', function () {
var hdnode = fixturehd.derivePath('m/44\'/0\'/0/1')
assert.equal(hdnode.privateExtendedKey(), 'xprvA1ErCzsuXhpB8iDTsbmgpkA2P8ggu97hMZbAXTZCdGYeaUrDhyR8fEw47BNEgLExsWCVzFYuGyeDZJLiFJ9kwBzGojQ6NB718tjVJrVBSrG')
})
})

describe('.getWallet()', function () {
it('should work', function () {
assert.equal(fixturehd.getWallet().getPrivateKeyString(), '0x26cc9417b89cd77c4acdbe2e3cd286070a015d8e380f9cd1244ae103b7d89d81')
assert.equal(fixturehd.getWallet().getPublicKeyString(),
'0x0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1')
})
it('should work with public nodes', function () {
var hdnode = HDKey.fromExtendedKey('xpub661MyMwAqRbcGout4B6s29b6gGQsowyoiF6UgXBEr7eFCWYfXuZDvRxP9zEh1Kwq3TLqDQMbkbaRpSnoC28oWvjLeshoQz1StZ9YHM1EpcJ')
assert.throws(function () {
hdnode.getWallet().getPrivateKeyString()
})
assert.equal(hdnode.getWallet().getPublicKeyString(), '0x030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d')
})
})
1 change: 0 additions & 1 deletion test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ describe('.fromExtendedPublicKey()', function () {
})
})


describe('.generate()', function () {
it('should generate an account', function () {
assert.equal(Wallet.generate().getPrivateKey().length, 32)
Expand Down