Skip to content
This repository was archived by the owner on Sep 10, 2024. It is now read-only.
2 changes: 1 addition & 1 deletion .github/workflows/node.js.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x, 14.x, 16.x, 18.x, latest]
node-version: [14.x, 16.x, 18.x, latest]
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
node_modules/
coverage/
coverage/

yarn.lock
22 changes: 11 additions & 11 deletions lib/hdkey.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ var Buffer = require('safe-buffer').Buffer
var crypto = require('crypto')
var bs58check = require('bs58check')
var RIPEMD160 = require('ripemd160')
var secp256k1 = require('@exodus/secp256k1')
var secp256k1 = require('@exodus/bitcoinerlab-secp256k1')

var MASTER_SECRET = Buffer.from('Bitcoin seed', 'utf8')
var HARDENED_OFFSET = 0x80000000
Expand Down Expand Up @@ -33,10 +33,10 @@ Object.defineProperty(HDKey.prototype, 'privateKey', {
},
set: function (value) {
assert.equal(value.length, 32, 'Private key must be 32 bytes.')
assert(secp256k1.privateKeyVerify(value) === true, 'Invalid private key')
assert(secp256k1.isPrivate(value) === true, 'Invalid private key')

this._privateKey = value
this._publicKey = Buffer.from(secp256k1.publicKeyCreate(value, true))
this._publicKey = Buffer.from(secp256k1.pointFromScalar(value, true))
this._identifier = hash160(this.publicKey)
this._fingerprint = this._identifier.slice(0, 4).readUInt32BE(0)
}
Expand All @@ -55,9 +55,9 @@ Object.defineProperty(HDKey.prototype, 'publicKey', {
},
set: function (value) {
assert(value.length === 33 || value.length === 65, 'Public key must be 33 or 65 bytes.')
assert(secp256k1.publicKeyVerify(value) === true, 'Invalid public key')
assert(secp256k1.isPoint(value) === true, 'Invalid public key')
// force compressed point (performs public key verification)
const publicKey = (value.length === 65) ? secp256k1.publicKeyConvert(value, true) : value
const publicKey = (value.length === 65) ? secp256k1.pointCompress(value, true) : value
setPublicKey(this, publicKey)
}
})
Expand Down Expand Up @@ -131,7 +131,7 @@ HDKey.prototype.deriveChild = function (index) {
if (this.privateKey) {
// ki = parse256(IL) + kpar (mod n)
try {
hd.privateKey = Buffer.from(secp256k1.privateKeyTweakAdd(Buffer.from(this.privateKey), IL))
hd.privateKey = Buffer.from(secp256k1.privateAdd(Buffer.from(this.privateKey), IL))
// throw if IL >= n || (privateKey + IL) === 0
} catch (err) {
// In case parse256(IL) >= n or ki == 0, one should proceed with the next value for i
Expand All @@ -142,7 +142,7 @@ HDKey.prototype.deriveChild = function (index) {
// Ki = point(parse256(IL)) + Kpar
// = G*IL + Kpar
try {
hd.publicKey = Buffer.from(secp256k1.publicKeyTweakAdd(Buffer.from(this.publicKey), IL, true))
hd.publicKey = Buffer.from(secp256k1.pointAddScalar(Buffer.from(this.publicKey), IL, true))
// throw if IL >= n || (g**IL + publicKey) is infinity
} catch (err) {
// In case parse256(IL) >= n or Ki is the point at infinity, one should proceed with the next value for i
Expand All @@ -159,14 +159,14 @@ HDKey.prototype.deriveChild = function (index) {
}

HDKey.prototype.sign = function (hash) {
return Buffer.from(secp256k1.ecdsaSign(Uint8Array.from(hash), Uint8Array.from(this.privateKey)).signature)
return Buffer.from(secp256k1.sign(Uint8Array.from(hash), Uint8Array.from(this.privateKey)))
}

HDKey.prototype.verify = function (hash, signature) {
return secp256k1.ecdsaVerify(
Uint8Array.from(signature),
return secp256k1.verify(
Uint8Array.from(hash),
Uint8Array.from(this.publicKey)
Uint8Array.from(this.publicKey),
Uint8Array.from(signature)
)
}

Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "lib/hdkey.js",
"repository": {
"type": "git",
"url": "git://github.com/cryptocoinjs/hdkey"
"url": "git://github.com/ExodusMovement/hdkey"
},
"license": "MIT",
"keywords": [
Expand All @@ -18,9 +18,9 @@
"crypto"
],
"bugs": {
"url": "https://github.com/cryptocoinjs/hdkey/issues"
"url": "https://github.com/ExodusMovement/hdkey/issues"
},
"homepage": "https://github.com/cryptocoinjs/hdkey",
"homepage": "https://github.com/ExodusMovement/hdkey",
"files": [],
"devDependencies": {
"bigi": "^1.1.0",
Expand All @@ -34,10 +34,10 @@
"standard": "^7.1.1"
},
"dependencies": {
"@exodus/bitcoinerlab-secp256k1": "^1.0.5-exodus.1",
"bs58check": "^2.1.2",
"ripemd160": "^2.0.2",
"safe-buffer": "^5.1.1",
"@exodus/secp256k1": "^4.0.2-exodus.0"
"safe-buffer": "^5.1.1"
},
"scripts": {
"lint": "standard",
Expand Down
98 changes: 94 additions & 4 deletions test/fixtures/hdkey.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,99 @@
"path": "m/0/2147483647'/1/2147483646'/2",
"public": "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt",
"private": "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alexandrius what did u use to generate these?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracted from:
src/_local_modules/keys/derive.js createKeyAccess

"path": "m/44'/0'/0'",
"public": "xpub6Bj78LtBYv9W6wjeub9Uvivo7dko9XYHXpgaDXgbFDY3dTSkn8HsZr1ps5HRgFixDuqrED1m7VWSoyipD3YMFHaFaFAmrqKG36uQTSZU9rg",
"private": "xprv9xjkiqMHiYbCtTfBoZcUZaz4ZbvJk4pSAbkyR9Gygt14kf7cEayd23hM1oLtRwL8Kdcffs9rnVX9qdMnWTtCCGMDsLY2xvmuNNCv9BbtqyN"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/283'/0'",
"public": "xpub6D5jSGbfwpcKdc9TSdP8EwbpReEFUiZRBoCEZqqR71q9WWZPLtNXz75BNxFa5NcWsPpSXGbZCU7q9v5GcW29MNAH2ghE9F7FHsXzCXXw8co",
"private": "xprv9z6P2m4n7T42R84zLbr7sof5scPm5FqZpaGdmTRoYgJAdiEEoM4HSJkhXhe6Awn4X8f8XXfLs6Wv2NTX7jvmoiiLAU2yHBVYBY3e1iRweYW"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/84'/0'/0'",
"public": "xpub6CxednjUJboDP6B7UfFogysznCuw14LWkcrijYGACCw1jbou4GpZyPGmNHCsCRS3Dp9Upvr1mMtFVmgbQDXkn9jWNGJaqXqdcLD1ZoDpT3R",
"private": "xprv9yyJEHCaUEEvAc6eNdioKqwGEB5SbbcfPPw7w9rYdsQ2roUkWjWKRaxHX1rEzQy4TaWzVDoKoWt4AmJQ9fHiwfZuKMVipGtVCwt644QvR2G"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/1815'/0'",
"public": "xpub6CxN8G7WoHM6rswed4DREuEydKybriCUwWwaQoUaf9LUQPG8FKKtj32TWVjQ7VL37kL6uKimbdf4Wn8z8PXHrupjZkQ8chSRHXDebEJtLR2",
"private": "xprv9yy1ikacxunoePsBX2gQsmJF5J97TFUdaJ1ycR4y6ooVXavyhn1eBEhyfEUpKENkNy4aWr6rEcMECHLRbLsCwZS95nccsaLxmxD2p23JWJt"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/118'/0'",
"public": "xpub6CHiu9KznSSh9uVwbmyMdZ5Z5TUurD9jdxppNu54fca5YufXXrsTGqJjp5UPsxSVyedWMBKAzRowJxxmYLnpyAD1AZD3MVzK2fdfmA1e2zv",
"private": "xprv9yJNVdo6x4tPwRRUVkSMGR8pXReRSkRtGjuDaWfT7H36g7LNzKZCj2zFxnejhdFqSt64V2aCHDhkEPJKsn7jDFXb8FGcypB3bttwoWJixEt"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/60'/0'",
"public": "xpub6Bw1W7bAwU2VzMqocoW1vr8RBFiYfYMaHhwp76mujJhJNdQEGckwzZv9D2PMBFytXwJy8DaGQjuneSifZU2PH9yyCXEf4PjRgSNf9viiGvr",
"private": "xprv9xwf6c4H76UCmsmLWmy1ZiBgdDt4G5divV2DJiNJAyAKVq55j5ShSmbfMj3WRcT3QWVJcdbDSKmHgVaAVFaxCvMrEBQTjWgNJXL1iqF4A89"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/144'/0'",
"public": "xpub6CxYodsM6fZZFbB2gFo2pJgo692oYdnppCfxgQGY1jGULSCc15uPzKsSkf1xqHXsaYFHk2W9oucvnfR58Kij89Tx2F2tgJ91fJqVZ46FEuh",
"private": "xprv9yyCQ8LTGJ1G376ZaEG2TAk4Y7CK9B4ySykMt1rvTPjVTdsTTYb9SXYxuP7J4Wo6tTo1ByUDwueQWxMDfBqHiWjweMmCLbgaAuSjiqJWXgL"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/501'/0'",
"public": "xpub6CAAppkfPWX3Zb27ptHSQ6tvgPRXJeHQCrKdgvPnGPBhctUUAhaFnJev9QJ2EE6qugzHuMFdjYTs4wdcUX7KCiiNZWSa4kNrcJ5tzWgBadr",
"private": "xprv9yApRKDmZ8xkM6weirkS2xxC8Mb2uBZYqdQ2tXzAi3eik69KdAG1EWLSJAkPRbenDcGTfMDUdNDwEtBP1T7W1Vh72KKjoKpadiBhBjW4VWe"
},
{
"seed": "69afbf0608755b3480ca7314c145695c64f973c988790eabb165d19809c7991acecfe4518b1456f274e171d496ddd044942278577b6efcdb69a6374d5341ea0a",
"path": "m/44'/1729'/0'",
"public": "xpub6DHkhd3Q3HCFUp5ZcrPprp76nCeZSvebWbro7SWYPFhnVrYXj555kE7tfkRgf8cgYyUDLvbyMHmrrnVjLrTH5P8vvCRJRjgGBnqpytBC4Gw",
"private": "xprv9zJQJ7WWCudxGL16WprpVgANEAp53Tvk9NwCK46vpvAod4DPBXkqCRoQpSLthvPpE5f1r2a3Tna9HRGcdJTgExtZtS52vdMRutCx5qDEfrS"
}
],
"rawHex": [
{
"private": "3e798fb45904e429cf0eba4868453b4103eeb681783f10d4a9380e33fed750d7",
"public": "02b64d1f42c9462d9063078de5e0bbea741af8999951809f5c7dab319fa78552d0"
},
{
"private": "bfe85cee8a0ad77d9debafe2180816d90606d4f577a0684c0546993e2f6a6112",
"public": "0288c3e9da9327cf50c7b4fb3c6372e71b70b06a68951aad7051990dce25d8ce3c"
},
{
"private": "71fc2b9bd6a02bd9b50f3e8ebbb29cc4953f9b589d3d97f93ca60020180aa534",
"public": "029ccdf213a7d41f1753fff3097db57df179f17c24f175737ac09c3708dd41b4bf"
},
{
"private": "dde956d3257a0043628b862c44348b5621be7f0d7ea7f5a0660070017b8836f4",
"public": "02fb034a5f00248ed1563b732fb2d172bd5d896e015d67762f8689a5d6c8521fcf"
},
{
"private": "df7627ee2889e5b16e0a879e6f4ee0d28d83c688bcc8ca7702443cc829659c19",
"public": "03cb5c6d70e0ba5e4ca4fb8fb05ad5dc3c207cacad347e932d6db7679642f1e2f6"
},
{
"private": "abbe14f4b21ddac490c35996d47a62df429f6e6609e2f3db3fd0c658d2dad179",
"public": "03dc2cb5d8f479f4ceebf0b46f96b2306a06b63f086f5bea95778a9b9d9ca964f2"
},
{
"private": "4cc8f8f92a26fc31312b056af3931326586251bd55f23868698d568eb6934c49",
"public": "02c05d64323cb88e9b93564a14218e294002de39f7b946763c556dba7b86ebfda7"
},
{
"private": "da5711e9c9cdac2f626115d1c53e2123cfc92a486f476212cfcccd01d3675744",
"public": "0216c47fc709286f054a420f1a087858d9b17cc769bdd5938b235f09b2670c2845"
},
{
"private": "5e09e65124c80d2f5cab61d120af5552454373789119e0030ed7c07665f2aff2",
"public": "03efff78835d6a81bbce6cce42b1bbe6b0bec429aa22500f7f649efa4eba984795"
}
],
"invalid": [

]
}
"invalid": []
}
28 changes: 26 additions & 2 deletions test/hdkey.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,13 +66,37 @@ describe('hdkey', function () {
hdkey.publicKey = pub
})

it('should not throw if key is 33 bytes (compressed)', function () {
var priv = Buffer.from(fixtures.rawHex[0].private, 'hex')
var pub = curve.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(true)
assert.equal(pub.length, 33)
var hdkey = new HDKey()
hdkey.publicKey = pub
})

it('should not throw if key is 65 bytes (not compressed)', function () {
var priv = secureRandom.randomBuffer(32)
var pub = curve.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(false)
assert.equal(pub.length, 65)
var hdkey = new HDKey()
hdkey.publicKey = pub
})

it('should not throw if key is 65 bytes (not compressed)', function () {
var priv = Buffer.from(fixtures.rawHex[1].private, 'hex')
var pub = curve.G.multiply(BigInteger.fromBuffer(priv)).getEncoded(false)
assert.equal(pub.length, 65)
var hdkey = new HDKey()
hdkey.publicKey = pub
})

fixtures.rawHex.forEach(function (f) {
it('should convert to correct public key', function () {
var hdkey = new HDKey()
hdkey.privateKey = Buffer.from(f.private, 'hex')
assert.equal(hdkey.publicKey.toString('hex'), f.public)
})
})
})

describe('+ fromExtendedKey()', function () {
Expand Down Expand Up @@ -145,10 +169,10 @@ describe('hdkey', function () {

assert.throws(function () {
hdkey.verify(Buffer.alloc(99), a)
}, /message.*length/)
}, /Expected Scalar/)
assert.throws(function () {
hdkey.verify(ma, Buffer.alloc(99))
}, /signature.*length/)
}, /Expected Signature/)
})
})

Expand Down