From 41a67bacd2481a424a0638ceec8d78dcaafc24a9 Mon Sep 17 00:00:00 2001 From: azuchi Date: Mon, 12 Jan 2026 15:36:46 +0900 Subject: [PATCH] Update tiny-secp256k1 to remove elliptic dependency --- package-lock.json | 191 +++++++++++++------------- package.json | 4 +- src/ecpair.js | 12 +- src/index.js | 6 +- src/psbt.js | 32 +++-- test/ecpair.spec.ts | 2 +- test/integration/bip32.spec.ts | 5 +- test/integration/transactions.spec.ts | 16 +-- test/psbt.spec.ts | 32 ++--- ts_src/ecpair.ts | 11 +- ts_src/index.ts | 7 +- ts_src/psbt.ts | 50 +++++-- types/index.d.ts | 6 +- types/psbt.d.ts | 8 +- 14 files changed, 212 insertions(+), 170 deletions(-) diff --git a/package-lock.json b/package-lock.json index a2b5b620a..9ff1eb56b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "bech32": "^1.1.4", "bip174": "^2.1.0", - "bip32": "^2.0.6", + "bip32": "^5.0.0", "bip66": "^1.1.0", "bs58check": "^2.0.0", "create-hash": "^1.1.0", @@ -20,7 +20,7 @@ "pushdata-bitcoin": "^1.0.1", "randombytes": "^2.0.1", "tapyrus-ops": "^0.1.0", - "tiny-secp256k1": "^1.1.6", + "tiny-secp256k1": "^2.2.4", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" @@ -483,7 +483,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "dev": true, "engines": { "node": ">= 16" }, @@ -491,6 +490,15 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", @@ -700,14 +708,6 @@ "node": ">=8" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dependencies": { - "file-uri-to-path": "1.0.0" - } - }, "node_modules/bip174": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz", @@ -717,26 +717,54 @@ } }, "node_modules/bip32": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz", - "integrity": "sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-5.0.0.tgz", + "integrity": "sha512-h043yQ9n3iU4WZ8KLRpEECMl3j1yx2DQ1kcPlzWg8VZC0PtukbDiyLDKbe6Jm79mL6Tfg+WFuZMYxnzVyr/Hyw==", + "license": "MIT", "dependencies": { - "@types/node": "10.12.18", - "bs58check": "^2.1.1", - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "tiny-secp256k1": "^1.1.3", - "typeforce": "^1.11.5", - "wif": "^2.0.6" + "@noble/hashes": "^1.2.0", + "@scure/base": "^1.1.1", + "uint8array-tools": "^0.0.8", + "valibot": "^0.37.0", + "wif": "^5.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=18.0.0" + } + }, + "node_modules/bip32/node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/bip32/node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" } }, - "node_modules/bip32/node_modules/@types/node": { - "version": "10.12.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", - "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" + "node_modules/bip32/node_modules/bs58check": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-4.0.0.tgz", + "integrity": "sha512-FsGDOnFg9aVI9erdriULkd/JjEWONV/lQE5aYziB5PoBsXRind56lh8doIZIc9X4HoxT5x4bLjMWN1/NB8Zp5g==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^6.0.0" + } + }, + "node_modules/bip32/node_modules/wif": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/wif/-/wif-5.0.0.tgz", + "integrity": "sha512-iFzrC/9ne740qFbNjTZ2FciSRJlHIXoxqk/Y5EnE08QOXu1WjJyCCswwDTYbohAOEnlCtLaAAQBhyaLRFh2hMA==", + "license": "MIT", + "dependencies": { + "bs58check": "^4.0.0" + } }, "node_modules/bip39": { "version": "3.1.0", @@ -781,7 +809,8 @@ "node_modules/bn.js": { "version": "4.12.0", "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", - "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true }, "node_modules/brace-expansion": { "version": "2.0.2", @@ -804,11 +833,6 @@ "node": ">=8" } }, - "node_modules/brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" - }, "node_modules/browser-stdout": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", @@ -1232,20 +1256,6 @@ "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", "dev": true }, - "node_modules/elliptic": { - "version": "6.6.1", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", - "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", - "dependencies": { - "bn.js": "^4.11.9", - "brorand": "^1.1.0", - "hash.js": "^1.0.0", - "hmac-drbg": "^1.0.1", - "inherits": "^2.0.4", - "minimalistic-assert": "^1.0.1", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", @@ -1319,11 +1329,6 @@ "node": ">=4" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" - }, "node_modules/fill-keys": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz", @@ -1669,15 +1674,6 @@ "node": ">=4" } }, - "node_modules/hash.js": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", - "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", - "dependencies": { - "inherits": "^2.0.3", - "minimalistic-assert": "^1.0.1" - } - }, "node_modules/hasha": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/hasha/-/hasha-5.2.2.tgz", @@ -1714,16 +1710,6 @@ "he": "bin/he" } }, - "node_modules/hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", - "dependencies": { - "hash.js": "^1.0.3", - "minimalistic-assert": "^1.0.0", - "minimalistic-crypto-utils": "^1.0.1" - } - }, "node_modules/hoodwink": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hoodwink/-/hoodwink-2.0.0.tgz", @@ -2242,16 +2228,6 @@ "pushdata-bitcoin": "^1.0.1" } }, - "node_modules/minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" - }, - "node_modules/minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" - }, "node_modules/minimatch": { "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", @@ -2352,11 +2328,6 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==" - }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -3202,19 +3173,24 @@ } }, "node_modules/tiny-secp256k1": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.7.tgz", - "integrity": "sha512-eb+F6NabSnjbLwNoC+2o5ItbmP1kg7HliWue71JgLegQt6A5mTN8YbvTLCazdlg6e5SV6A+r8OGvZYskdlmhqQ==", - "hasInstallScript": true, + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-2.2.4.tgz", + "integrity": "sha512-FoDTcToPqZE454Q04hH9o2EhxWsm7pOSpicyHkgTwKhdKWdsTUuqfP5MLq3g+VjAtl2vSx6JpXGdwA2qpYkI0Q==", + "license": "MIT", "dependencies": { - "bindings": "^1.3.0", - "bn.js": "^4.11.8", - "create-hmac": "^1.1.7", - "elliptic": "^6.4.0", - "nan": "^2.13.2" + "uint8array-tools": "0.0.7" }, "engines": { - "node": ">=6.0.0" + "node": ">=14.0.0" + } + }, + "node_modules/tiny-secp256k1/node_modules/uint8array-tools": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.7.tgz", + "integrity": "sha512-vrrNZJiusLWoFWBqz5Y5KMCgP9W9hnjZHzZiZRT8oNAkq3d5Z5Oe76jAvVVSRh4U8GGR90N2X1dWtrhvx6L8UQ==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, "node_modules/to-buffer": { @@ -3515,7 +3491,7 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "dev": true, + "devOptional": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3524,6 +3500,15 @@ "node": ">=14.17" } }, + "node_modules/uint8array-tools": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/uint8array-tools/-/uint8array-tools-0.0.8.tgz", + "integrity": "sha512-xS6+s8e0Xbx++5/0L+yyexukU7pz//Yg6IHg3BKhXotg1JcYtgxVcUctQ0HxLByiJzpAkNFawz1Nz5Xadzo82g==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", @@ -3580,6 +3565,20 @@ "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true }, + "node_modules/valibot": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.37.0.tgz", + "integrity": "sha512-FQz52I8RXgFgOHym3XHYSREbNtkgSjF9prvMFH1nBsRyfL6SfCzoT1GuSDTlbsuPubM7/6Kbw0ZMQb8A+V+VsQ==", + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, "node_modules/varuint-bitcoin": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", diff --git a/package.json b/package.json index 018e5ec28..e3f13768c 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "dependencies": { "bech32": "^1.1.4", "bip174": "^2.1.0", - "bip32": "^2.0.6", + "bip32": "^5.0.0", "bip66": "^1.1.0", "bs58check": "^2.0.0", "create-hash": "^1.1.0", @@ -59,7 +59,7 @@ "pushdata-bitcoin": "^1.0.1", "randombytes": "^2.0.1", "tapyrus-ops": "^0.1.0", - "tiny-secp256k1": "^1.1.6", + "tiny-secp256k1": "^2.2.4", "typeforce": "^1.11.3", "varuint-bitcoin": "^1.1.2", "wif": "^2.0.1" diff --git a/src/ecpair.js b/src/ecpair.js index c2ed1f0b3..0dce51c87 100644 --- a/src/ecpair.js +++ b/src/ecpair.js @@ -25,13 +25,15 @@ class ECPair { this.compressed = options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.prod; - if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); + if (__Q !== undefined) + this.__Q = Buffer.from(ecc.pointCompress(__Q, this.compressed)); } get privateKey() { return this.__D; } get publicKey() { - if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed); + if (!this.__Q) + this.__Q = Buffer.from(ecc.pointFromScalar(this.__D, this.compressed)); return this.__Q; } toWIF() { @@ -42,7 +44,7 @@ class ECPair { if (!this.__D) throw new Error('Missing private key'); if (lowR === undefined) lowR = this.lowR; if (lowR === false) { - return ecc.sign(hash, this.__D); + return Buffer.from(ecc.sign(hash, this.__D)); } else { let sig = ecc.sign(hash, this.__D); const extraData = Buffer.alloc(32, 0); @@ -52,9 +54,9 @@ class ECPair { while (sig[0] > 0x7f) { counter++; extraData.writeUIntLE(counter, 0, 6); - sig = ecc.signWithEntropy(hash, this.__D, extraData); + sig = ecc.sign(hash, this.__D, extraData); } - return sig; + return Buffer.from(sig); } } verify(hash, signature) { diff --git a/src/index.js b/src/index.js index 6ebab9a9e..7e719593f 100644 --- a/src/index.js +++ b/src/index.js @@ -1,8 +1,8 @@ 'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); exports.TransactionBuilder = exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.bufferutils = exports.bip32 = exports.address = exports.ECPair = void 0; -const bip32 = require('bip32'); -exports.bip32 = bip32; +const bip32_1 = require('bip32'); +const ecc = require('tiny-secp256k1'); const address = require('./address'); exports.address = address; const bufferutils = require('./bufferutils'); @@ -17,6 +17,8 @@ const payments = require('./payments'); exports.payments = payments; const script = require('./script'); exports.script = script; +const bip32 = (0, bip32_1.BIP32Factory)(ecc); +exports.bip32 = bip32; var block_1 = require('./block'); Object.defineProperty(exports, 'Block', { enumerable: true, diff --git a/src/psbt.js b/src/psbt.js index b3b502927..d95f56b21 100644 --- a/src/psbt.js +++ b/src/psbt.js @@ -527,8 +527,11 @@ class Psbt { ); const partialSig = [ { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(keyPair.sign(hash), sighashType), + pubkey: Buffer.from(keyPair.publicKey), + signature: bscript.signature.encode( + Buffer.from(keyPair.sign(hash)), + sighashType, + ), }, ]; this.data.updateInput(inputIndex, { partialSig }); @@ -552,8 +555,11 @@ class Psbt { return Promise.resolve(keyPair.sign(hash)).then(signature => { const partialSig = [ { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(signature, sighashType), + pubkey: Buffer.from(keyPair.publicKey), + signature: bscript.signature.encode( + Buffer.from(signature), + sighashType, + ), }, ]; this.data.updateInput(inputIndex, { partialSig }); @@ -721,8 +727,14 @@ const isP2WSHScript = isPaymentFactory(payments.p2wsh); const isP2SHScript = isPaymentFactory(payments.p2sh); function bip32DerivationIsMine(root) { return d => { - if (!d.masterFingerprint.equals(root.fingerprint)) return false; - if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (!Buffer.from(d.masterFingerprint).equals(Buffer.from(root.fingerprint))) + return false; + if ( + !Buffer.from(root.derivePath(d.path).publicKey).equals( + Buffer.from(d.pubkey), + ) + ) + return false; return true; }; } @@ -1106,7 +1118,11 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const myDerivations = input.bip32Derivation .map(bipDv => { - if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + if ( + Buffer.from(bipDv.masterFingerprint).equals( + Buffer.from(hdKeyPair.fingerprint), + ) + ) { return bipDv; } else { return; @@ -1120,7 +1136,7 @@ function getSignersFromHD(inputIndex, inputs, hdKeyPair) { } const signers = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv.path); - if (!bipDv.pubkey.equals(node.publicKey)) { + if (!Buffer.from(bipDv.pubkey).equals(Buffer.from(node.publicKey))) { throw new Error('pubkey did not match bip32Derivation'); } return node; diff --git a/test/ecpair.spec.ts b/test/ecpair.spec.ts index a03bd30a9..2b75a868a 100644 --- a/test/ecpair.spec.ts +++ b/test/ecpair.spec.ts @@ -273,7 +273,7 @@ describe('ECPair', () => { 1, ); - assert.strictEqual(keyPair.sign(hash), signature); + assert.deepStrictEqual(keyPair.sign(hash), signature); }), ); diff --git a/test/integration/bip32.spec.ts b/test/integration/bip32.spec.ts index 3968b4e24..530c7966c 100644 --- a/test/integration/bip32.spec.ts +++ b/test/integration/bip32.spec.ts @@ -1,9 +1,10 @@ import * as assert from 'assert'; -import * as bip32 from 'bip32'; import * as bip39 from 'bip39'; import { describe, it } from 'mocha'; import * as bitcoin from '../..'; +const { bip32 } = bitcoin; + function getAddress(node: any, network?: any): string { return bitcoin.payments.p2pkh({ pubkey: node.publicKey, network }).address!; } @@ -111,7 +112,7 @@ describe('bitcoinjs-lib (BIP32)', () => { const { address } = bitcoin.payments.p2sh({ redeem: bitcoin.payments.p2wpkh({ - pubkey: child.publicKey, + pubkey: Buffer.from(child.publicKey), network: bitcoin.networks.dev, }), network: bitcoin.networks.dev, diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts index 23ad2fffa..4a5bccb9d 100644 --- a/test/integration/transactions.spec.ts +++ b/test/integration/transactions.spec.ts @@ -1,11 +1,12 @@ import * as assert from 'assert'; -import * as bip32 from 'bip32'; import { describe, it } from 'mocha'; import * as bitcoin from '../..'; import { regtestUtils } from './_regtest'; const rng = require('randombytes'); const regtest = regtestUtils.network; +const { bip32 } = bitcoin; + // See bottom of file for some helper functions used to make the payment objects needed. describe('bitcoinjs-lib (transactions with psbt)', () => { @@ -589,10 +590,10 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { it('can create (and broadcast via 3PBP) a Transaction, w/ a P2WPKH input using HD', async () => { const hdRoot = bip32.fromSeed(rng(64)); - const masterFingerprint = hdRoot.fingerprint; + const masterFingerprint = Buffer.from(hdRoot.fingerprint); const path = "m/84'/0'/0'/0/0"; const childNode = hdRoot.derivePath(path); - const pubkey = childNode.publicKey; + const pubkey = Buffer.from(childNode.publicKey); // This information should be added to your input via updateInput // You can add multiple bip32Derivation objects for multisig, but @@ -611,7 +612,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { }, ], }; - const p2wpkh = createPayment('p2wpkh', [childNode]); + const p2wpkh = createPayment('p2wpkh', [childNode as any]); const inputData = await getInputData(5e4, p2wpkh.payment, true, 'noredeem'); { const { hash, index, witnessUtxo } = inputData; @@ -628,13 +629,10 @@ describe('bitcoinjs-lib (transactions with psbt)', () => { address: regtestUtils.RANDOM_ADDRESS, value: 2e4, }) - .signInputHD(0, hdRoot); // must sign with root!!! + .signInputHD(0, hdRoot as any); // must sign with root!!! assert.strictEqual(psbt.validateSignaturesOfInput(0), true); - assert.strictEqual( - psbt.validateSignaturesOfInput(0, childNode.publicKey), - true, - ); + assert.strictEqual(psbt.validateSignaturesOfInput(0, pubkey), true); psbt.finalizeAllInputs(); const tx = psbt.extractTransaction(); diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts index d90f07920..98c9ee594 100644 --- a/test/psbt.spec.ts +++ b/test/psbt.spec.ts @@ -348,7 +348,7 @@ describe(`Psbt`, () => { await assert.doesNotReject(async () => { await psbtThatShouldsign.signInputHDAsync( f.shouldSign.inputToCheck, - bip32.fromBase58(f.shouldSign.xprv), + bip32.fromBase58(f.shouldSign.xprv) as any, (f.shouldSign as any).sighashTypes || undefined, ); }); @@ -359,7 +359,7 @@ describe(`Psbt`, () => { await assert.rejects(async () => { await psbtThatShouldThrow.signInputHDAsync( f.shouldThrow.inputToCheck, - bip32.fromBase58(f.shouldThrow.xprv), + bip32.fromBase58(f.shouldThrow.xprv) as any, (f.shouldThrow as any).sighashTypes || undefined, ); }, new RegExp(f.shouldThrow.errorMessage)); @@ -381,7 +381,7 @@ describe(`Psbt`, () => { assert.doesNotThrow(() => { psbtThatShouldsign.signInputHD( f.shouldSign.inputToCheck, - bip32.fromBase58(f.shouldSign.xprv), + bip32.fromBase58(f.shouldSign.xprv) as any, (f.shouldSign as any).sighashTypes || undefined, ); }); @@ -392,7 +392,7 @@ describe(`Psbt`, () => { assert.throws(() => { psbtThatShouldThrow.signInputHD( f.shouldThrow.inputToCheck, - bip32.fromBase58(f.shouldThrow.xprv), + bip32.fromBase58(f.shouldThrow.xprv) as any, (f.shouldThrow as any).sighashTypes || undefined, ); }, new RegExp(f.shouldThrow.errorMessage)); @@ -413,7 +413,7 @@ describe(`Psbt`, () => { const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt); await assert.doesNotReject(async () => { await psbtThatShouldsign.signAllInputsHDAsync( - bip32.fromBase58(f.shouldSign.xprv), + bip32.fromBase58(f.shouldSign.xprv) as any, (f.shouldSign as any).sighashTypes || undefined, ); }); @@ -423,7 +423,7 @@ describe(`Psbt`, () => { const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt); await assert.rejects(async () => { await psbtThatShouldThrow.signAllInputsHDAsync( - bip32.fromBase58(f.shouldThrow.xprv), + bip32.fromBase58(f.shouldThrow.xprv) as any, (f.shouldThrow as any).sighashTypes || undefined, ); }, new RegExp('No inputs were signed')); @@ -442,7 +442,7 @@ describe(`Psbt`, () => { const psbtThatShouldsign = Psbt.fromBase64(f.shouldSign.psbt); assert.doesNotThrow(() => { psbtThatShouldsign.signAllInputsHD( - bip32.fromBase58(f.shouldSign.xprv), + bip32.fromBase58(f.shouldSign.xprv) as any, (f.shouldSign as any).sighashTypes || undefined, ); }); @@ -452,7 +452,7 @@ describe(`Psbt`, () => { const psbtThatShouldThrow = Psbt.fromBase64(f.shouldThrow.psbt); assert.throws(() => { psbtThatShouldThrow.signAllInputsHD( - bip32.fromBase58(f.shouldThrow.xprv), + bip32.fromBase58(f.shouldThrow.xprv) as any, (f.shouldThrow as any).sighashTypes || undefined, ); }, new RegExp('No inputs were signed')); @@ -710,14 +710,14 @@ describe(`Psbt`, () => { index: 0, bip32Derivation: [ { - masterFingerprint: root.fingerprint, + masterFingerprint: Buffer.from(root.fingerprint), path, - pubkey: root.derivePath(path).publicKey, + pubkey: Buffer.from(root.derivePath(path).publicKey), }, ], }); - assert.strictEqual(psbt.inputHasHDKey(0, root), true); - assert.strictEqual(psbt.inputHasHDKey(0, root2), false); + assert.strictEqual(psbt.inputHasHDKey(0, root as any), true); + assert.strictEqual(psbt.inputHasHDKey(0, root2 as any), false); }); }); @@ -812,14 +812,14 @@ describe(`Psbt`, () => { value: 2000, bip32Derivation: [ { - masterFingerprint: root.fingerprint, + masterFingerprint: Buffer.from(root.fingerprint), path, - pubkey: root.derivePath(path).publicKey, + pubkey: Buffer.from(root.derivePath(path).publicKey), }, ], }); - assert.strictEqual(psbt.outputHasHDKey(0, root), true); - assert.strictEqual(psbt.outputHasHDKey(0, root2), false); + assert.strictEqual(psbt.outputHasHDKey(0, root as any), true); + assert.strictEqual(psbt.outputHasHDKey(0, root2 as any), false); }); }); diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts index 2fd6c875d..2593ec511 100644 --- a/ts_src/ecpair.ts +++ b/ts_src/ecpair.ts @@ -58,7 +58,8 @@ class ECPair implements ECPairInterface { options.compressed === undefined ? true : options.compressed; this.network = options.network || NETWORKS.prod; - if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed); + if (__Q !== undefined) + this.__Q = Buffer.from(ecc.pointCompress(__Q, this.compressed)); } get privateKey(): Buffer | undefined { @@ -67,7 +68,7 @@ class ECPair implements ECPairInterface { get publicKey(): Buffer { if (!this.__Q) - this.__Q = ecc.pointFromScalar(this.__D, this.compressed) as Buffer; + this.__Q = Buffer.from(ecc.pointFromScalar(this.__D, this.compressed)); return this.__Q; } @@ -80,7 +81,7 @@ class ECPair implements ECPairInterface { if (!this.__D) throw new Error('Missing private key'); if (lowR === undefined) lowR = this.lowR; if (lowR === false) { - return ecc.sign(hash, this.__D); + return Buffer.from(ecc.sign(hash, this.__D)); } else { let sig = ecc.sign(hash, this.__D); const extraData = Buffer.alloc(32, 0); @@ -90,9 +91,9 @@ class ECPair implements ECPairInterface { while (sig[0] > 0x7f) { counter++; extraData.writeUIntLE(counter, 0, 6); - sig = ecc.signWithEntropy(hash, this.__D, extraData); + sig = ecc.sign(hash, this.__D, extraData); } - return sig; + return Buffer.from(sig); } } diff --git a/ts_src/index.ts b/ts_src/index.ts index a41cf412d..c91e3b7fe 100644 --- a/ts_src/index.ts +++ b/ts_src/index.ts @@ -1,4 +1,5 @@ -import * as bip32 from 'bip32'; +import { BIP32Factory, BIP32Interface } from 'bip32'; +import * as ecc from 'tiny-secp256k1'; import * as address from './address'; import * as bufferutils from './bufferutils'; import * as crypto from './crypto'; @@ -7,7 +8,10 @@ import * as networks from './networks'; import * as payments from './payments'; import * as script from './script'; +const bip32 = BIP32Factory(ecc); + export { + BIP32Interface, ECPair, address, bip32, @@ -24,7 +28,6 @@ export { OPS as opcodes } from './script'; export { Transaction } from './transaction'; export { TransactionBuilder } from './transaction_builder'; -export { BIP32Interface } from 'bip32'; export { ECPairInterface, Signer, SignerAsync } from './ecpair'; export { Network } from './networks'; export { diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts index 850b4a9a1..039f2ccaf 100644 --- a/ts_src/psbt.ts +++ b/ts_src/psbt.ts @@ -538,7 +538,11 @@ export class Psbt { hdKeyPair, ); const promises = signers.map(signer => - this.signInputAsync(inputIndex, signer, sighashTypes), + this.signInputAsync( + inputIndex, + signer as Signer | SignerAsync, + sighashTypes, + ), ); return Promise.all(promises) .then(() => { @@ -627,8 +631,11 @@ export class Psbt { const partialSig = [ { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(keyPair.sign(hash), sighashType), + pubkey: Buffer.from(keyPair.publicKey), + signature: bscript.signature.encode( + Buffer.from(keyPair.sign(hash)), + sighashType, + ), }, ]; @@ -655,8 +662,11 @@ export class Psbt { return Promise.resolve(keyPair.sign(hash)).then(signature => { const partialSig = [ { - pubkey: keyPair.publicKey, - signature: bscript.signature.encode(signature, sighashType), + pubkey: Buffer.from(keyPair.publicKey), + signature: bscript.signature.encode( + Buffer.from(signature), + sighashType, + ), }, ]; @@ -763,11 +773,11 @@ interface HDSignerBase { /** * DER format compressed publicKey buffer */ - publicKey: Buffer; + publicKey: Buffer | Uint8Array; /** * The first 4 bytes of the sha256-ripemd160 of the publicKey */ - fingerprint: Buffer; + fingerprint: Buffer | Uint8Array; } interface HDSigner extends HDSignerBase { @@ -780,7 +790,7 @@ interface HDSigner extends HDSignerBase { * Input hash (the "message digest") for the signature algorithm * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ - sign(hash: Buffer): Buffer; + sign(hash: Buffer | Uint8Array): Buffer | Uint8Array; } /** @@ -788,7 +798,7 @@ interface HDSigner extends HDSignerBase { */ interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; - sign(hash: Buffer): Promise; + sign(hash: Buffer | Uint8Array): Promise; } /** @@ -930,8 +940,14 @@ function bip32DerivationIsMine( root: HDSigner, ): (d: Bip32Derivation) => boolean { return (d: Bip32Derivation): boolean => { - if (!d.masterFingerprint.equals(root.fingerprint)) return false; - if (!root.derivePath(d.path).publicKey.equals(d.pubkey)) return false; + if (!Buffer.from(d.masterFingerprint).equals(Buffer.from(root.fingerprint))) + return false; + if ( + !Buffer.from(root.derivePath(d.path).publicKey).equals( + Buffer.from(d.pubkey), + ) + ) + return false; return true; }; } @@ -1415,14 +1431,18 @@ function getSignersFromHD( inputIndex: number, inputs: PsbtInput[], hdKeyPair: HDSigner | HDSignerAsync, -): Array { +): Array { const input = checkForInput(inputs, inputIndex); if (!input.bip32Derivation || input.bip32Derivation.length === 0) { throw new Error('Need bip32Derivation to sign with HD'); } const myDerivations = input.bip32Derivation .map(bipDv => { - if (bipDv.masterFingerprint.equals(hdKeyPair.fingerprint)) { + if ( + Buffer.from(bipDv.masterFingerprint).equals( + Buffer.from(hdKeyPair.fingerprint), + ) + ) { return bipDv; } else { return; @@ -1434,9 +1454,9 @@ function getSignersFromHD( 'Need one bip32Derivation masterFingerprint to match the HDSigner fingerprint', ); } - const signers: Array = myDerivations.map(bipDv => { + const signers: Array = myDerivations.map(bipDv => { const node = hdKeyPair.derivePath(bipDv!.path); - if (!bipDv!.pubkey.equals(node.publicKey)) { + if (!Buffer.from(bipDv!.pubkey).equals(Buffer.from(node.publicKey))) { throw new Error('pubkey did not match bip32Derivation'); } return node; diff --git a/types/index.d.ts b/types/index.d.ts index 6a8cca549..117a11974 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,4 +1,4 @@ -import * as bip32 from 'bip32'; +import { BIP32Interface } from 'bip32'; import * as address from './address'; import * as bufferutils from './bufferutils'; import * as crypto from './crypto'; @@ -6,13 +6,13 @@ import * as ECPair from './ecpair'; import * as networks from './networks'; import * as payments from './payments'; import * as script from './script'; -export { ECPair, address, bip32, bufferutils, crypto, networks, payments, script, }; +declare const bip32: import("bip32").BIP32API; +export { BIP32Interface, ECPair, address, bip32, bufferutils, crypto, networks, payments, script, }; export { Block } from './block'; export { Psbt, PsbtTxInput, PsbtTxOutput } from './psbt'; export { OPS as opcodes } from './script'; export { Transaction } from './transaction'; export { TransactionBuilder } from './transaction_builder'; -export { BIP32Interface } from 'bip32'; export { ECPairInterface, Signer, SignerAsync } from './ecpair'; export { Network } from './networks'; export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments'; diff --git a/types/psbt.d.ts b/types/psbt.d.ts index 58390239c..314afd61b 100644 --- a/types/psbt.d.ts +++ b/types/psbt.d.ts @@ -116,11 +116,11 @@ interface HDSignerBase { /** * DER format compressed publicKey buffer */ - publicKey: Buffer; + publicKey: Buffer | Uint8Array; /** * The first 4 bytes of the sha256-ripemd160 of the publicKey */ - fingerprint: Buffer; + fingerprint: Buffer | Uint8Array; } interface HDSigner extends HDSignerBase { /** @@ -132,14 +132,14 @@ interface HDSigner extends HDSignerBase { * Input hash (the "message digest") for the signature algorithm * Return a 64 byte signature (32 byte r and 32 byte s in that order) */ - sign(hash: Buffer): Buffer; + sign(hash: Buffer | Uint8Array): Buffer | Uint8Array; } /** * Same as above but with async sign method */ interface HDSignerAsync extends HDSignerBase { derivePath(path: string): HDSignerAsync; - sign(hash: Buffer): Promise; + sign(hash: Buffer | Uint8Array): Promise; } /** * This function must do two things: