diff --git a/package-lock.json b/package-lock.json
index a1ba1ec..f932d24 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5,12 +5,12 @@
"requires": true,
"dependencies": {
"@babel/code-frame": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.8.3.tgz",
- "integrity": "sha512-a9gxpmdXtZEInkCSHUJDLHZVBgb1QS0jhss4cPP93EW7s+uC5bikET2twEF3KV+7rDblJcmNvTR7VJejqd2C2g==",
+ "version": "7.15.8",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.15.8.tgz",
+ "integrity": "sha512-2IAnmn8zbvC/jKYhq5Ki9I+DwjlrtMPUCH/CpHvqI4dNnlwHwsxoIhlc8WcYY5LSYknXQtAlFYuHfqAFCvQ4Wg==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.8.3"
+ "@babel/highlight": "^7.14.5"
}
},
"@babel/core": {
@@ -196,14 +196,22 @@
}
},
"@babel/highlight": {
- "version": "7.8.3",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.8.3.tgz",
- "integrity": "sha512-PX4y5xQUvy0fnEVHrYOarRPXVWafSjTW9T0Hab8gVIawpl2Sj0ORyrygANq+KjcNlSSTw0YCLSNA8OyZ1I4yEg==",
+ "version": "7.14.5",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
+ "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
"dev": true,
"requires": {
+ "@babel/helper-validator-identifier": "^7.14.5",
"chalk": "^2.0.0",
- "esutils": "^2.0.2",
"js-tokens": "^4.0.0"
+ },
+ "dependencies": {
+ "@babel/helper-validator-identifier": {
+ "version": "7.15.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz",
+ "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==",
+ "dev": true
+ }
}
},
"@babel/parser": {
@@ -383,6 +391,24 @@
"@types/base-x": "*"
}
},
+ "@types/bs58check": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@types/bs58check/-/bs58check-2.1.0.tgz",
+ "integrity": "sha512-OxsysnJQh82vy9DRbOcw9m2j/WiyqZLn0YBhKxdQ+aCwoHj+tWzyCgpwAkr79IfDXZKxc6h7k89T9pwS78CqTQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/create-hash": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@types/create-hash/-/create-hash-1.2.2.tgz",
+ "integrity": "sha512-Fg8/kfMJObbETFU/Tn+Y0jieYewryLrbKwLCEIwPyklZZVY2qB+64KFjhplGSw+cseZosfFXctXO+PyIYD8iZQ==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@types/mocha": {
"version": "5.2.7",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
@@ -390,9 +416,9 @@
"dev": true
},
"@types/node": {
- "version": "12.7.5",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
- "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
+ "version": "16.11.1",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.1.tgz",
+ "integrity": "sha512-PYGcJHL9mwl1Ek3PLiYgyEKtwTMmkMw4vbiyz/ps3pfdRYLVv+SN7qHVAImrjdAXxgluDEw6Ph4lyv+m9UpRmA==",
"dev": true
},
"@types/proxyquire": {
@@ -401,6 +427,24 @@
"integrity": "sha512-SQaNzWQ2YZSr7FqAyPPiA3FYpux2Lqh3HWMZQk47x3xbMCqgC/w0dY3dw9rGqlweDDkrySQBcaScXWeR+Yb11Q==",
"dev": true
},
+ "@types/randombytes": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/@types/randombytes/-/randombytes-2.0.0.tgz",
+ "integrity": "sha512-bz8PhAVlwN72vqefzxa14DKNT8jK/mV66CSjwdVQM/k3Th3EPKfUtdMniwZgMedQTFuywAsfjnZsg+pEnltaMA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
+ "@types/wif": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/@types/wif/-/wif-2.0.2.tgz",
+ "integrity": "sha512-IiIuBeJzlh4LWJ7kVTrX0nwB60OG0vvGTaWC/SgSbVFw7uYUTF6gEuvDZ1goWkeirekJDD58Y8g7NljQh2fNkA==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"aggregate-error": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz",
@@ -557,14 +601,6 @@
"integrity": "sha512-RQ1nc7xtnLa5XltnCqkoR2zmhuz498RjMJwrLKQzOE049D1HUqnYfon7cVSbwS5UGm0/EQlC2CH+NY3MyITA4Q==",
"dev": true
},
- "bip66": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz",
- "integrity": "sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI=",
- "requires": {
- "safe-buffer": "^5.0.1"
- }
- },
"bip68": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/bip68/-/bip68-1.0.4.tgz",
@@ -574,7 +610,8 @@
"bitcoin-ops": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/bitcoin-ops/-/bitcoin-ops-1.4.1.tgz",
- "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow=="
+ "integrity": "sha512-pef6gxZFztEhaE9RY9HmWVmiIHqCb2OyS4HPKkpc6CIiiOa3Qmuoylxc5P2EkU3w+5eTSifI9SEZC88idAIGow==",
+ "dev": true
},
"bn.js": {
"version": "4.11.8",
@@ -888,18 +925,42 @@
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
- "elliptic": {
- "version": "6.5.3",
- "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz",
- "integrity": "sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw==",
+ "ecpair": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/ecpair/-/ecpair-1.0.0.tgz",
+ "integrity": "sha512-1L+P/ivLC3eKHgqcX1M9tFYQWXDoqwJ3zQnN7zDaTtLpiCQKpFTaAZvnsPC5PkWB4q3EPFAHffCLvjfCqRjuwQ==",
+ "dev": true,
"requires": {
- "bn.js": "^4.4.0",
- "brorand": "^1.0.1",
+ "randombytes": "^2.0.1",
+ "tiny-secp256k1": "^1.1.6",
+ "typeforce": "^1.11.3",
+ "wif": "^2.0.1"
+ }
+ },
+ "elliptic": {
+ "version": "6.5.4",
+ "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz",
+ "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==",
+ "requires": {
+ "bn.js": "^4.11.9",
+ "brorand": "^1.1.0",
"hash.js": "^1.0.0",
- "hmac-drbg": "^1.0.0",
- "inherits": "^2.0.1",
- "minimalistic-assert": "^1.0.0",
- "minimalistic-crypto-utils": "^1.0.0"
+ "hmac-drbg": "^1.0.1",
+ "inherits": "^2.0.4",
+ "minimalistic-assert": "^1.0.1",
+ "minimalistic-crypto-utils": "^1.0.1"
+ },
+ "dependencies": {
+ "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=="
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ }
}
},
"emoji-regex": {
@@ -956,12 +1017,6 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
- "esutils": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
- "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
- "dev": true
- },
"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",
@@ -1549,11 +1604,6 @@
"integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
"dev": true
},
- "merkle-lib": {
- "version": "2.0.10",
- "resolved": "https://registry.npmjs.org/merkle-lib/-/merkle-lib-2.0.10.tgz",
- "integrity": "sha1-grjbrnXieneFOItz+ddyXQ9vMyY="
- },
"minimaldata": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/minimaldata/-/minimaldata-1.0.2.tgz",
@@ -2091,6 +2141,7 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/pushdata-bitcoin/-/pushdata-bitcoin-1.0.1.tgz",
"integrity": "sha1-FZMdPNlnreUiBvUjqnMxrvfUOvc=",
+ "dev": true,
"requires": {
"bitcoin-ops": "^1.3.0"
}
@@ -2446,15 +2497,15 @@
}
},
"tslib": {
- "version": "1.11.1",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz",
- "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==",
+ "version": "1.14.1",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
"dev": true
},
"tslint": {
- "version": "5.20.1",
- "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
- "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
+ "version": "6.1.3",
+ "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz",
+ "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
@@ -2465,10 +2516,10 @@
"glob": "^7.1.1",
"js-yaml": "^3.13.1",
"minimatch": "^3.0.4",
- "mkdirp": "^0.5.1",
+ "mkdirp": "^0.5.3",
"resolve": "^1.3.2",
"semver": "^5.3.0",
- "tslib": "^1.8.0",
+ "tslib": "^1.13.0",
"tsutils": "^2.29.0"
},
"dependencies": {
@@ -2510,9 +2561,9 @@
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
},
"typescript": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.2.2.tgz",
- "integrity": "sha512-VCj5UiSyHBjwfYacmDuc/NOk4QQixbE+Wn7MFJuS0nRuPQbof132Pw4u53dm264O8LPc2MVsc7RJNml5szurkg==",
+ "version": "4.4.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
+ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==",
"dev": true
},
"uuid": {
@@ -2522,9 +2573,9 @@
"dev": true
},
"varuint-bitcoin": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.0.tgz",
- "integrity": "sha512-jCEPG+COU/1Rp84neKTyDJQr478/hAfVp5xxYn09QEH0yBjbmPeMfuuQIrp+BUD83hybtYZKhr5elV3bvdV1bA==",
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz",
+ "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==",
"requires": {
"safe-buffer": "^5.1.1"
}
diff --git a/package.json b/package.json
index 887dff8..03df9d5 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"version": "5.2.0",
"description": "Client-side Bitcoin JavaScript library",
"main": "./src/index.js",
- "types": "./types/index.d.ts",
+ "types": "./src/index.d.ts",
"engines": {
"node": ">=8.0.0"
},
@@ -18,7 +18,7 @@
"audit": "NPM_AUDIT_IGNORE_DEV=1 NPM_AUDIT_IGNORE_LEVEL=low npm-audit-whitelister .npm-audit-whitelister.json",
"build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs",
"build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json",
- "clean": "rimraf src types",
+ "clean": "rimraf src",
"clean:jstests": "rimraf 'test/**/!(ts-node-register)*.js'",
"coverage-report": "npm run build && npm run nobuild:coverage-report",
"coverage-html": "npm run build && npm run nobuild:coverage-html",
@@ -46,37 +46,36 @@
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
},
"files": [
- "src",
- "types"
+ "src"
],
"dependencies": {
"bech32": "^2.0.0",
"bip174": "^2.0.1",
"bip32": "^2.0.4",
- "bip66": "^1.1.0",
- "bitcoin-ops": "^1.4.0",
- "bs58check": "^2.0.0",
+ "bs58check": "^2.1.2",
"create-hash": "^1.1.0",
"create-hmac": "^1.1.3",
- "merkle-lib": "^2.0.10",
- "pushdata-bitcoin": "^1.0.1",
"randombytes": "^2.0.1",
- "tiny-secp256k1": "^1.1.6",
"typeforce": "^1.11.3",
- "varuint-bitcoin": "^1.0.4",
+ "varuint-bitcoin": "^1.1.2",
"wif": "^2.0.1"
},
"devDependencies": {
"@types/bs58": "^4.0.0",
+ "@types/bs58check": "^2.1.0",
+ "@types/create-hash": "^1.2.2",
"@types/mocha": "^5.2.7",
- "@types/node": "12.7.5",
+ "@types/node": "^16.11.1",
"@types/proxyquire": "^1.3.28",
+ "@types/randombytes": "^2.0.0",
+ "@types/wif": "^2.0.2",
"bip39": "^3.0.2",
"bip65": "^1.0.1",
"bip68": "^1.0.3",
"bn.js": "^4.11.8",
"bs58": "^4.0.0",
"dhttp": "^3.0.0",
+ "ecpair": "^1.0.0",
"hoodwink": "^2.0.0",
"minimaldata": "^1.0.2",
"mocha": "^7.1.1",
@@ -87,8 +86,8 @@
"regtest-client": "0.2.0",
"rimraf": "^2.6.3",
"ts-node": "^8.3.0",
- "tslint": "^5.20.1",
- "typescript": "3.2.2"
+ "tslint": "^6.1.3",
+ "typescript": "^4.4.4"
},
"license": "MIT"
}
diff --git a/types/address.d.ts b/src/address.d.ts
similarity index 95%
rename from types/address.d.ts
rename to src/address.d.ts
index 5c7ed5a..be0e00a 100644
--- a/types/address.d.ts
+++ b/src/address.d.ts
@@ -1,3 +1,4 @@
+///
import { Network } from './networks';
export interface Base58CheckResult {
hash: Buffer;
diff --git a/src/address.js b/src/address.js
index 1709c37..12938fc 100644
--- a/src/address.js
+++ b/src/address.js
@@ -1,12 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.toBase58Check = exports.fromBech32 = exports.fromBase58Check = void 0;
const networks = require('./networks');
const payments = require('./payments');
const bscript = require('./script');
const types = require('./types');
-const { bech32, bech32m } = require('bech32');
+const bech32_1 = require('bech32');
const bs58check = require('bs58check');
-const typeforce = require('typeforce');
+const { typeforce } = types;
const FUTURE_SEGWIT_MAX_SIZE = 40;
const FUTURE_SEGWIT_MIN_SIZE = 2;
const FUTURE_SEGWIT_MAX_VERSION = 16;
@@ -43,17 +44,17 @@ function fromBech32(address) {
let result;
let version;
try {
- result = bech32.decode(address);
+ result = bech32_1.bech32.decode(address);
} catch (e) {}
if (result) {
version = result.words[0];
if (version !== 0) throw new TypeError(address + ' uses wrong encoding');
} else {
- result = bech32m.decode(address);
+ result = bech32_1.bech32m.decode(address);
version = result.words[0];
if (version === 0) throw new TypeError(address + ' uses wrong encoding');
}
- const data = bech32.fromWords(result.words.slice(1));
+ const data = bech32_1.bech32.fromWords(result.words.slice(1));
return {
version,
prefix: result.prefix,
@@ -70,11 +71,11 @@ function toBase58Check(hash, version) {
}
exports.toBase58Check = toBase58Check;
function toBech32(data, version, prefix) {
- const words = bech32.toWords(data);
+ const words = bech32_1.bech32.toWords(data);
words.unshift(version);
return version === 0
- ? bech32.encode(prefix, words)
- : bech32m.encode(prefix, words);
+ ? bech32_1.bech32.encode(prefix, words)
+ : bech32_1.bech32m.encode(prefix, words);
}
exports.toBech32 = toBech32;
function fromOutputScript(output, network) {
diff --git a/src/bip66.d.ts b/src/bip66.d.ts
new file mode 100644
index 0000000..547c57f
--- /dev/null
+++ b/src/bip66.d.ts
@@ -0,0 +1,7 @@
+///
+export declare function check(buffer: Buffer): boolean;
+export declare function decode(buffer: Buffer): {
+ r: Buffer;
+ s: Buffer;
+};
+export declare function encode(r: Buffer, s: Buffer): Buffer;
diff --git a/src/bip66.js b/src/bip66.js
new file mode 100644
index 0000000..0070f99
--- /dev/null
+++ b/src/bip66.js
@@ -0,0 +1,102 @@
+'use strict';
+// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
+// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
+// NOTE: SIGHASH byte ignored AND restricted, truncate before use
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.encode = exports.decode = exports.check = void 0;
+function check(buffer) {
+ if (buffer.length < 8) return false;
+ if (buffer.length > 72) return false;
+ if (buffer[0] !== 0x30) return false;
+ if (buffer[1] !== buffer.length - 2) return false;
+ if (buffer[2] !== 0x02) return false;
+ const lenR = buffer[3];
+ if (lenR === 0) return false;
+ if (5 + lenR >= buffer.length) return false;
+ if (buffer[4 + lenR] !== 0x02) return false;
+ const lenS = buffer[5 + lenR];
+ if (lenS === 0) return false;
+ if (6 + lenR + lenS !== buffer.length) return false;
+ if (buffer[4] & 0x80) return false;
+ if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
+ if (buffer[lenR + 6] & 0x80) return false;
+ if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
+ return false;
+ return true;
+}
+exports.check = check;
+function decode(buffer) {
+ if (buffer.length < 8) throw new Error('DER sequence length is too short');
+ if (buffer.length > 72) throw new Error('DER sequence length is too long');
+ if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
+ if (buffer[1] !== buffer.length - 2)
+ throw new Error('DER sequence length is invalid');
+ if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
+ const lenR = buffer[3];
+ if (lenR === 0) throw new Error('R length is zero');
+ if (5 + lenR >= buffer.length) throw new Error('R length is too long');
+ if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
+ const lenS = buffer[5 + lenR];
+ if (lenS === 0) throw new Error('S length is zero');
+ if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
+ if (buffer[4] & 0x80) throw new Error('R value is negative');
+ if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
+ throw new Error('R value excessively padded');
+ if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
+ if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
+ throw new Error('S value excessively padded');
+ // non-BIP66 - extract R, S values
+ return {
+ r: buffer.slice(4, 4 + lenR),
+ s: buffer.slice(6 + lenR),
+ };
+}
+exports.decode = decode;
+/*
+ * Expects r and s to be positive DER integers.
+ *
+ * The DER format uses the most significant bit as a sign bit (& 0x80).
+ * If the significant bit is set AND the integer is positive, a 0x00 is prepended.
+ *
+ * Examples:
+ *
+ * 0 => 0x00
+ * 1 => 0x01
+ * -1 => 0xff
+ * 127 => 0x7f
+ * -127 => 0x81
+ * 128 => 0x0080
+ * -128 => 0x80
+ * 255 => 0x00ff
+ * -255 => 0xff01
+ * 16300 => 0x3fac
+ * -16300 => 0xc054
+ * 62300 => 0x00f35c
+ * -62300 => 0xff0ca4
+ */
+function encode(r, s) {
+ const lenR = r.length;
+ const lenS = s.length;
+ if (lenR === 0) throw new Error('R length is zero');
+ if (lenS === 0) throw new Error('S length is zero');
+ if (lenR > 33) throw new Error('R length is too long');
+ if (lenS > 33) throw new Error('S length is too long');
+ if (r[0] & 0x80) throw new Error('R value is negative');
+ if (s[0] & 0x80) throw new Error('S value is negative');
+ if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
+ throw new Error('R value excessively padded');
+ if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
+ throw new Error('S value excessively padded');
+ const signature = Buffer.allocUnsafe(6 + lenR + lenS);
+ // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
+ signature[0] = 0x30;
+ signature[1] = signature.length - 2;
+ signature[2] = 0x02;
+ signature[3] = r.length;
+ r.copy(signature, 4);
+ signature[4 + lenR] = 0x02;
+ signature[5 + lenR] = s.length;
+ s.copy(signature, 6 + lenR);
+ return signature;
+}
+exports.encode = encode;
diff --git a/types/block.d.ts b/src/block.d.ts
similarity index 96%
rename from types/block.d.ts
rename to src/block.d.ts
index 7d8309c..1d90c13 100644
--- a/types/block.d.ts
+++ b/src/block.d.ts
@@ -1,3 +1,4 @@
+///
import { Transaction } from './transaction';
export declare class Block {
static fromBuffer(buffer: Buffer): Block;
diff --git a/src/block.js b/src/block.js
index cb3ee4b..4e6ca84 100644
--- a/src/block.js
+++ b/src/block.js
@@ -1,12 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.Block = void 0;
const bufferutils_1 = require('./bufferutils');
const bcrypto = require('./crypto');
+const merkle_1 = require('./merkle');
const transaction_1 = require('./transaction');
const types = require('./types');
-const fastMerkleRoot = require('merkle-lib/fastRoot');
-const typeforce = require('typeforce');
-const varuint = require('varuint-bitcoin');
+const { typeforce } = types;
const errorMerkleNoTxes = new TypeError(
'Cannot compute merkle root for zero transactions',
);
@@ -14,16 +14,6 @@ const errorWitnessNotSegwit = new TypeError(
'Cannot compute witness commit for non-segwit block',
);
class Block {
- constructor() {
- this.version = 1;
- this.prevHash = undefined;
- this.merkleRoot = undefined;
- this.timestamp = 0;
- this.witnessCommit = undefined;
- this.bits = 0;
- this.nonce = 0;
- this.transactions = undefined;
- }
static fromBuffer(buffer) {
if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
const bufferReader = new bufferutils_1.BufferReader(buffer);
@@ -72,13 +62,21 @@ class Block {
const hashes = transactions.map(transaction =>
transaction.getHash(forWitness),
);
- const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
+ const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256);
return forWitness
? bcrypto.hash256(
Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]),
)
: rootHash;
}
+ version = 1;
+ prevHash = undefined;
+ merkleRoot = undefined;
+ timestamp = 0;
+ witnessCommit = undefined;
+ bits = 0;
+ nonce = 0;
+ transactions = undefined;
getWitnessCommit() {
if (!txesHaveWitnessCommit(this.transactions)) return null;
// The merkle root for the witness data is in an OP_RETURN output.
@@ -117,7 +115,7 @@ class Block {
if (headersOnly || !this.transactions) return 80;
return (
80 +
- varuint.encodingLength(this.transactions.length) +
+ bufferutils_1.varuint.encodingLength(this.transactions.length) +
this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
);
}
@@ -125,7 +123,7 @@ class Block {
return bcrypto.hash256(this.toBuffer(true));
}
getId() {
- return bufferutils_1.reverseBuffer(this.getHash()).toString('hex');
+ return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex');
}
getUTCDate() {
const date = new Date(0); // epoch
@@ -143,8 +141,12 @@ class Block {
bufferWriter.writeUInt32(this.bits);
bufferWriter.writeUInt32(this.nonce);
if (headersOnly || !this.transactions) return buffer;
- varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
- bufferWriter.offset += varuint.encode.bytes;
+ bufferutils_1.varuint.encode(
+ this.transactions.length,
+ buffer,
+ bufferWriter.offset,
+ );
+ bufferWriter.offset += bufferutils_1.varuint.encode.bytes;
this.transactions.forEach(tx => {
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
tx.toBuffer(buffer, bufferWriter.offset);
@@ -166,7 +168,7 @@ class Block {
);
}
checkProofOfWork() {
- const hash = bufferutils_1.reverseBuffer(this.getHash());
+ const hash = (0, bufferutils_1.reverseBuffer)(this.getHash());
const target = Block.calculateTarget(this.bits);
return hash.compare(target) <= 0;
}
diff --git a/types/bufferutils.d.ts b/src/bufferutils.d.ts
similarity index 92%
rename from types/bufferutils.d.ts
rename to src/bufferutils.d.ts
index 95a48ba..40f89b3 100644
--- a/types/bufferutils.d.ts
+++ b/src/bufferutils.d.ts
@@ -1,3 +1,6 @@
+///
+import * as varuint from 'varuint-bitcoin';
+export { varuint };
export declare function readUInt64LE(buffer: Buffer, offset: number): number;
export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number;
export declare function reverseBuffer(buffer: Buffer): Buffer;
diff --git a/src/bufferutils.js b/src/bufferutils.js
index a68fd31..933bebc 100644
--- a/src/bufferutils.js
+++ b/src/bufferutils.js
@@ -1,8 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.BufferReader = exports.BufferWriter = exports.cloneBuffer = exports.reverseBuffer = exports.writeUInt64LE = exports.readUInt64LE = exports.varuint = void 0;
const types = require('./types');
-const typeforce = require('typeforce');
+const { typeforce } = types;
const varuint = require('varuint-bitcoin');
+exports.varuint = varuint;
// https://github.com/feross/buffer/blob/master/index.js#L1127
function verifuint(value, max) {
if (typeof value !== 'number')
@@ -51,6 +53,8 @@ exports.cloneBuffer = cloneBuffer;
* Helper class for serialization of bitcoin data types into a pre-allocated buffer.
*/
class BufferWriter {
+ buffer;
+ offset;
constructor(buffer, offset = 0) {
this.buffer = buffer;
this.offset = offset;
@@ -92,6 +96,8 @@ exports.BufferWriter = BufferWriter;
* Helper class for reading of bitcoin data types from a buffer.
*/
class BufferReader {
+ buffer;
+ offset;
constructor(buffer, offset = 0) {
this.buffer = buffer;
this.offset = offset;
diff --git a/types/crypto.d.ts b/src/crypto.d.ts
similarity index 90%
rename from types/crypto.d.ts
rename to src/crypto.d.ts
index 5d93acd..1743681 100644
--- a/types/crypto.d.ts
+++ b/src/crypto.d.ts
@@ -1,3 +1,4 @@
+///
export declare function ripemd160(buffer: Buffer): Buffer;
export declare function sha1(buffer: Buffer): Buffer;
export declare function sha256(buffer: Buffer): Buffer;
diff --git a/src/crypto.js b/src/crypto.js
index e7dd596..f53b041 100644
--- a/src/crypto.js
+++ b/src/crypto.js
@@ -1,5 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.hash256 = exports.hash160 = exports.sha256 = exports.sha1 = exports.ripemd160 = void 0;
const createHash = require('create-hash');
function ripemd160(buffer) {
try {
diff --git a/src/ecpair.js b/src/ecpair.js
deleted file mode 100644
index 91fe3a9..0000000
--- a/src/ecpair.js
+++ /dev/null
@@ -1,107 +0,0 @@
-'use strict';
-Object.defineProperty(exports, '__esModule', { value: true });
-const NETWORKS = require('./networks');
-const types = require('./types');
-const ecc = require('tiny-secp256k1');
-const randomBytes = require('randombytes');
-const typeforce = require('typeforce');
-const wif = require('wif');
-const isOptions = typeforce.maybe(
- typeforce.compile({
- compressed: types.maybe(types.Boolean),
- network: types.maybe(types.Network),
- }),
-);
-class ECPair {
- constructor(__D, __Q, options) {
- this.__D = __D;
- this.__Q = __Q;
- this.lowR = false;
- if (options === undefined) options = {};
- this.compressed =
- options.compressed === undefined ? true : options.compressed;
- this.network = options.network || NETWORKS.bitcoin;
- if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed);
- }
- get privateKey() {
- return this.__D;
- }
- get publicKey() {
- if (!this.__Q) this.__Q = ecc.pointFromScalar(this.__D, this.compressed);
- return this.__Q;
- }
- toWIF() {
- if (!this.__D) throw new Error('Missing private key');
- return wif.encode(this.network.wif, this.__D, this.compressed);
- }
- sign(hash, lowR) {
- if (!this.__D) throw new Error('Missing private key');
- if (lowR === undefined) lowR = this.lowR;
- if (lowR === false) {
- return ecc.sign(hash, this.__D);
- } else {
- let sig = ecc.sign(hash, this.__D);
- const extraData = Buffer.alloc(32, 0);
- let counter = 0;
- // if first try is lowR, skip the loop
- // for second try and on, add extra entropy counting up
- while (sig[0] > 0x7f) {
- counter++;
- extraData.writeUIntLE(counter, 0, 6);
- sig = ecc.signWithEntropy(hash, this.__D, extraData);
- }
- return sig;
- }
- }
- verify(hash, signature) {
- return ecc.verify(hash, this.publicKey, signature);
- }
-}
-function fromPrivateKey(buffer, options) {
- typeforce(types.Buffer256bit, buffer);
- if (!ecc.isPrivate(buffer))
- throw new TypeError('Private key not in range [1, n)');
- typeforce(isOptions, options);
- return new ECPair(buffer, undefined, options);
-}
-exports.fromPrivateKey = fromPrivateKey;
-function fromPublicKey(buffer, options) {
- typeforce(ecc.isPoint, buffer);
- typeforce(isOptions, options);
- return new ECPair(undefined, buffer, options);
-}
-exports.fromPublicKey = fromPublicKey;
-function fromWIF(wifString, network) {
- const decoded = wif.decode(wifString);
- const version = decoded.version;
- // list of networks?
- if (types.Array(network)) {
- network = network
- .filter(x => {
- return version === x.wif;
- })
- .pop();
- if (!network) throw new Error('Unknown network version');
- // otherwise, assume a network object (or default to bitcoin)
- } else {
- network = network || NETWORKS.bitcoin;
- if (version !== network.wif) throw new Error('Invalid network version');
- }
- return fromPrivateKey(decoded.privateKey, {
- compressed: decoded.compressed,
- network: network,
- });
-}
-exports.fromWIF = fromWIF;
-function makeRandom(options) {
- typeforce(isOptions, options);
- if (options === undefined) options = {};
- const rng = options.rng || randomBytes;
- let d;
- do {
- d = rng(32);
- typeforce(types.Buffer256bit, d);
- } while (!ecc.isPrivate(d));
- return fromPrivateKey(d, options);
-}
-exports.makeRandom = makeRandom;
diff --git a/types/index.d.ts b/src/index.d.ts
similarity index 63%
rename from types/index.d.ts
rename to src/index.d.ts
index f63a986..1086e4b 100644
--- a/types/index.d.ts
+++ b/src/index.d.ts
@@ -1,18 +1,15 @@
import * as bip32 from 'bip32';
import * as address from './address';
import * as crypto from './crypto';
-import * as ECPair from './ecpair';
import * as networks from './networks';
import * as payments from './payments';
import * as script from './script';
-export { ECPair, address, bip32, crypto, networks, payments, script };
+export { address, bip32, crypto, networks, payments, script };
export { Block } from './block';
-export { Psbt, PsbtTxInput, PsbtTxOutput } from './psbt';
-export { OPS as opcodes } from './script';
+export { Psbt, PsbtTxInput, PsbtTxOutput, Signer, SignerAsync, HDSigner, HDSignerAsync, } from './psbt';
+export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
export { BIP32Interface } from 'bip32';
-export { ECPairInterface, Signer, SignerAsync } from './ecpair';
export { Network } from './networks';
export { Payment, PaymentCreator, PaymentOpts, Stack, StackElement, } from './payments';
-export { OpCode } from './script';
export { Input as TxInput, Output as TxOutput } from './transaction';
diff --git a/src/index.js b/src/index.js
index e27b98a..a643df8 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,13 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.Transaction = exports.opcodes = exports.Psbt = exports.Block = exports.script = exports.payments = exports.networks = exports.crypto = exports.bip32 = exports.address = void 0;
const bip32 = require('bip32');
exports.bip32 = bip32;
const address = require('./address');
exports.address = address;
const crypto = require('./crypto');
exports.crypto = crypto;
-const ECPair = require('./ecpair');
-exports.ECPair = ECPair;
const networks = require('./networks');
exports.networks = networks;
const payments = require('./payments');
@@ -15,10 +14,30 @@ exports.payments = payments;
const script = require('./script');
exports.script = script;
var block_1 = require('./block');
-exports.Block = block_1.Block;
+Object.defineProperty(exports, 'Block', {
+ enumerable: true,
+ get: function() {
+ return block_1.Block;
+ },
+});
var psbt_1 = require('./psbt');
-exports.Psbt = psbt_1.Psbt;
-var script_1 = require('./script');
-exports.opcodes = script_1.OPS;
+Object.defineProperty(exports, 'Psbt', {
+ enumerable: true,
+ get: function() {
+ return psbt_1.Psbt;
+ },
+});
+var ops_1 = require('./ops');
+Object.defineProperty(exports, 'opcodes', {
+ enumerable: true,
+ get: function() {
+ return ops_1.OPS;
+ },
+});
var transaction_1 = require('./transaction');
-exports.Transaction = transaction_1.Transaction;
+Object.defineProperty(exports, 'Transaction', {
+ enumerable: true,
+ get: function() {
+ return transaction_1.Transaction;
+ },
+});
diff --git a/src/merkle.d.ts b/src/merkle.d.ts
new file mode 100644
index 0000000..d602201
--- /dev/null
+++ b/src/merkle.d.ts
@@ -0,0 +1,2 @@
+///
+export declare function fastMerkleRoot(values: Buffer[], digestFn: (b: Buffer) => Buffer): Buffer;
diff --git a/src/merkle.js b/src/merkle.js
new file mode 100644
index 0000000..e93f9ca
--- /dev/null
+++ b/src/merkle.js
@@ -0,0 +1,22 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.fastMerkleRoot = void 0;
+function fastMerkleRoot(values, digestFn) {
+ if (!Array.isArray(values)) throw TypeError('Expected values Array');
+ if (typeof digestFn !== 'function')
+ throw TypeError('Expected digest Function');
+ let length = values.length;
+ const results = values.concat();
+ while (length > 1) {
+ let j = 0;
+ for (let i = 0; i < length; i += 2, ++j) {
+ const left = results[i];
+ const right = i + 1 === length ? left : results[i + 1];
+ const data = Buffer.concat([left, right]);
+ results[j] = digestFn(data);
+ }
+ length = j;
+ }
+ return results[0];
+}
+exports.fastMerkleRoot = fastMerkleRoot;
diff --git a/types/networks.d.ts b/src/networks.d.ts
similarity index 100%
rename from types/networks.d.ts
rename to src/networks.d.ts
diff --git a/src/networks.js b/src/networks.js
index 0c31fe1..ea710f8 100644
--- a/src/networks.js
+++ b/src/networks.js
@@ -1,5 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.testnet = exports.regtest = exports.bitcoin = void 0;
exports.bitcoin = {
messagePrefix: '\x18Bitcoin Signed Message:\n',
bech32: 'bc',
diff --git a/src/ops.d.ts b/src/ops.d.ts
new file mode 100644
index 0000000..cda7a84
--- /dev/null
+++ b/src/ops.d.ts
@@ -0,0 +1,7 @@
+declare const OPS: {
+ [key: string]: number;
+};
+declare const REVERSE_OPS: {
+ [key: number]: string;
+};
+export { OPS, REVERSE_OPS };
diff --git a/src/ops.js b/src/ops.js
new file mode 100644
index 0000000..9d629cd
--- /dev/null
+++ b/src/ops.js
@@ -0,0 +1,130 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.REVERSE_OPS = exports.OPS = void 0;
+const OPS = {
+ OP_FALSE: 0,
+ OP_0: 0,
+ OP_PUSHDATA1: 76,
+ OP_PUSHDATA2: 77,
+ OP_PUSHDATA4: 78,
+ OP_1NEGATE: 79,
+ OP_RESERVED: 80,
+ OP_TRUE: 81,
+ OP_1: 81,
+ OP_2: 82,
+ OP_3: 83,
+ OP_4: 84,
+ OP_5: 85,
+ OP_6: 86,
+ OP_7: 87,
+ OP_8: 88,
+ OP_9: 89,
+ OP_10: 90,
+ OP_11: 91,
+ OP_12: 92,
+ OP_13: 93,
+ OP_14: 94,
+ OP_15: 95,
+ OP_16: 96,
+ OP_NOP: 97,
+ OP_VER: 98,
+ OP_IF: 99,
+ OP_NOTIF: 100,
+ OP_VERIF: 101,
+ OP_VERNOTIF: 102,
+ OP_ELSE: 103,
+ OP_ENDIF: 104,
+ OP_VERIFY: 105,
+ OP_RETURN: 106,
+ OP_TOALTSTACK: 107,
+ OP_FROMALTSTACK: 108,
+ OP_2DROP: 109,
+ OP_2DUP: 110,
+ OP_3DUP: 111,
+ OP_2OVER: 112,
+ OP_2ROT: 113,
+ OP_2SWAP: 114,
+ OP_IFDUP: 115,
+ OP_DEPTH: 116,
+ OP_DROP: 117,
+ OP_DUP: 118,
+ OP_NIP: 119,
+ OP_OVER: 120,
+ OP_PICK: 121,
+ OP_ROLL: 122,
+ OP_ROT: 123,
+ OP_SWAP: 124,
+ OP_TUCK: 125,
+ OP_CAT: 126,
+ OP_SUBSTR: 127,
+ OP_LEFT: 128,
+ OP_RIGHT: 129,
+ OP_SIZE: 130,
+ OP_INVERT: 131,
+ OP_AND: 132,
+ OP_OR: 133,
+ OP_XOR: 134,
+ OP_EQUAL: 135,
+ OP_EQUALVERIFY: 136,
+ OP_RESERVED1: 137,
+ OP_RESERVED2: 138,
+ OP_1ADD: 139,
+ OP_1SUB: 140,
+ OP_2MUL: 141,
+ OP_2DIV: 142,
+ OP_NEGATE: 143,
+ OP_ABS: 144,
+ OP_NOT: 145,
+ OP_0NOTEQUAL: 146,
+ OP_ADD: 147,
+ OP_SUB: 148,
+ OP_MUL: 149,
+ OP_DIV: 150,
+ OP_MOD: 151,
+ OP_LSHIFT: 152,
+ OP_RSHIFT: 153,
+ OP_BOOLAND: 154,
+ OP_BOOLOR: 155,
+ OP_NUMEQUAL: 156,
+ OP_NUMEQUALVERIFY: 157,
+ OP_NUMNOTEQUAL: 158,
+ OP_LESSTHAN: 159,
+ OP_GREATERTHAN: 160,
+ OP_LESSTHANOREQUAL: 161,
+ OP_GREATERTHANOREQUAL: 162,
+ OP_MIN: 163,
+ OP_MAX: 164,
+ OP_WITHIN: 165,
+ OP_RIPEMD160: 166,
+ OP_SHA1: 167,
+ OP_SHA256: 168,
+ OP_HASH160: 169,
+ OP_HASH256: 170,
+ OP_CODESEPARATOR: 171,
+ OP_CHECKSIG: 172,
+ OP_CHECKSIGVERIFY: 173,
+ OP_CHECKMULTISIG: 174,
+ OP_CHECKMULTISIGVERIFY: 175,
+ OP_NOP1: 176,
+ OP_NOP2: 177,
+ OP_CHECKLOCKTIMEVERIFY: 177,
+ OP_NOP3: 178,
+ OP_CHECKSEQUENCEVERIFY: 178,
+ OP_NOP4: 179,
+ OP_NOP5: 180,
+ OP_NOP6: 181,
+ OP_NOP7: 182,
+ OP_NOP8: 183,
+ OP_NOP9: 184,
+ OP_NOP10: 185,
+ OP_PUBKEYHASH: 253,
+ OP_PUBKEY: 254,
+ OP_INVALIDOPCODE: 255,
+};
+exports.OPS = OPS;
+const REVERSE_OPS = {};
+exports.REVERSE_OPS = REVERSE_OPS;
+for (const op of Object.keys(OPS)) {
+ const code = OPS[op];
+ REVERSE_OPS[code] = op;
+}
diff --git a/types/payments/embed.d.ts b/src/payments/embed.d.ts
similarity index 100%
rename from types/payments/embed.d.ts
rename to src/payments/embed.d.ts
diff --git a/src/payments/embed.js b/src/payments/embed.js
index 19df35d..4b7218f 100644
--- a/src/payments/embed.js
+++ b/src/payments/embed.js
@@ -1,9 +1,10 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2data = void 0;
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
const OPS = bscript.OPS;
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
@@ -15,11 +16,13 @@ function stacksEqual(a, b) {
function p2data(a, opts) {
if (!a.data && !a.output) throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- output: typef.maybe(typef.Buffer),
- data: typef.maybe(typef.arrayOf(typef.Buffer)),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ data: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
},
a,
);
@@ -38,7 +41,7 @@ function p2data(a, opts) {
if (a.output) {
const chunks = bscript.decompile(a.output);
if (chunks[0] !== OPS.OP_RETURN) throw new TypeError('Output is invalid');
- if (!chunks.slice(1).every(typef.Buffer))
+ if (!chunks.slice(1).every(types_1.typeforce.Buffer))
throw new TypeError('Output is invalid');
if (a.data && !stacksEqual(a.data, o.data))
throw new TypeError('Data mismatch');
diff --git a/types/payments/index.d.ts b/src/payments/index.d.ts
similarity index 97%
rename from types/payments/index.d.ts
rename to src/payments/index.d.ts
index 922e0bf..1edf071 100644
--- a/types/payments/index.d.ts
+++ b/src/payments/index.d.ts
@@ -1,3 +1,4 @@
+///
import { Network } from '../networks';
import { p2data as embed } from './embed';
import { p2ms } from './p2ms';
diff --git a/src/payments/index.js b/src/payments/index.js
index ddab977..c23c529 100644
--- a/src/payments/index.js
+++ b/src/payments/index.js
@@ -1,18 +1,54 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2wsh = exports.p2wpkh = exports.p2sh = exports.p2pkh = exports.p2pk = exports.p2ms = exports.embed = void 0;
const embed_1 = require('./embed');
-exports.embed = embed_1.p2data;
+Object.defineProperty(exports, 'embed', {
+ enumerable: true,
+ get: function() {
+ return embed_1.p2data;
+ },
+});
const p2ms_1 = require('./p2ms');
-exports.p2ms = p2ms_1.p2ms;
+Object.defineProperty(exports, 'p2ms', {
+ enumerable: true,
+ get: function() {
+ return p2ms_1.p2ms;
+ },
+});
const p2pk_1 = require('./p2pk');
-exports.p2pk = p2pk_1.p2pk;
+Object.defineProperty(exports, 'p2pk', {
+ enumerable: true,
+ get: function() {
+ return p2pk_1.p2pk;
+ },
+});
const p2pkh_1 = require('./p2pkh');
-exports.p2pkh = p2pkh_1.p2pkh;
+Object.defineProperty(exports, 'p2pkh', {
+ enumerable: true,
+ get: function() {
+ return p2pkh_1.p2pkh;
+ },
+});
const p2sh_1 = require('./p2sh');
-exports.p2sh = p2sh_1.p2sh;
+Object.defineProperty(exports, 'p2sh', {
+ enumerable: true,
+ get: function() {
+ return p2sh_1.p2sh;
+ },
+});
const p2wpkh_1 = require('./p2wpkh');
-exports.p2wpkh = p2wpkh_1.p2wpkh;
+Object.defineProperty(exports, 'p2wpkh', {
+ enumerable: true,
+ get: function() {
+ return p2wpkh_1.p2wpkh;
+ },
+});
const p2wsh_1 = require('./p2wsh');
-exports.p2wsh = p2wsh_1.p2wsh;
+Object.defineProperty(exports, 'p2wsh', {
+ enumerable: true,
+ get: function() {
+ return p2wsh_1.p2wsh;
+ },
+});
// TODO
// witness commitment
diff --git a/types/payments/lazy.d.ts b/src/payments/lazy.d.ts
similarity index 100%
rename from types/payments/lazy.d.ts
rename to src/payments/lazy.d.ts
diff --git a/src/payments/lazy.js b/src/payments/lazy.js
index 1a71521..e620c72 100644
--- a/src/payments/lazy.js
+++ b/src/payments/lazy.js
@@ -1,5 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.value = exports.prop = void 0;
function prop(object, name, f) {
Object.defineProperty(object, name, {
configurable: true,
diff --git a/types/payments/p2ms.d.ts b/src/payments/p2ms.d.ts
similarity index 100%
rename from types/payments/p2ms.d.ts
rename to src/payments/p2ms.d.ts
diff --git a/src/payments/p2ms.js b/src/payments/p2ms.js
index 9fed788..0b7e72d 100644
--- a/src/payments/p2ms.js
+++ b/src/payments/p2ms.js
@@ -1,11 +1,11 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2ms = void 0;
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
const OPS = bscript.OPS;
-const typef = require('typeforce');
-const ecc = require('tiny-secp256k1');
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
@@ -30,15 +30,19 @@ function p2ms(a, opts) {
(opts.allowIncomplete && x === OPS.OP_0) !== undefined
);
}
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- m: typef.maybe(typef.Number),
- n: typef.maybe(typef.Number),
- output: typef.maybe(typef.Buffer),
- pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)),
- signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)),
- input: typef.maybe(typef.Buffer),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ m: types_1.typeforce.maybe(types_1.typeforce.Number),
+ n: types_1.typeforce.maybe(types_1.typeforce.Number),
+ output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ pubkeys: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.isPoint),
+ ),
+ signatures: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(isAcceptableSignature),
+ ),
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
},
a,
);
@@ -101,14 +105,15 @@ function p2ms(a, opts) {
if (opts.validate) {
if (a.output) {
decode(a.output);
- if (!typef.Number(chunks[0])) throw new TypeError('Output is invalid');
- if (!typef.Number(chunks[chunks.length - 2]))
+ if (!types_1.typeforce.Number(chunks[0]))
+ throw new TypeError('Output is invalid');
+ if (!types_1.typeforce.Number(chunks[chunks.length - 2]))
throw new TypeError('Output is invalid');
if (chunks[chunks.length - 1] !== OPS.OP_CHECKMULTISIG)
throw new TypeError('Output is invalid');
if (o.m <= 0 || o.n > 16 || o.m > o.n || o.n !== chunks.length - 3)
throw new TypeError('Output is invalid');
- if (!o.pubkeys.every(x => ecc.isPoint(x)))
+ if (!o.pubkeys.every(x => (0, types_1.isPoint)(x)))
throw new TypeError('Output is invalid');
if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
if (a.n !== undefined && a.n !== o.n) throw new TypeError('n mismatch');
diff --git a/types/payments/p2pk.d.ts b/src/payments/p2pk.d.ts
similarity index 100%
rename from types/payments/p2pk.d.ts
rename to src/payments/p2pk.d.ts
diff --git a/src/payments/p2pk.js b/src/payments/p2pk.js
index 702669e..2849530 100644
--- a/src/payments/p2pk.js
+++ b/src/payments/p2pk.js
@@ -1,24 +1,24 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2pk = void 0;
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
// input: {signature}
// output: {pubKey} OP_CHECKSIG
function p2pk(a, opts) {
if (!a.input && !a.output && !a.pubkey && !a.input && !a.signature)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- output: typef.maybe(typef.Buffer),
- pubkey: typef.maybe(ecc.isPoint),
- signature: typef.maybe(bscript.isCanonicalScriptSignature),
- input: typef.maybe(typef.Buffer),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ pubkey: types_1.typeforce.maybe(types_1.isPoint),
+ signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
},
a,
);
@@ -52,7 +52,7 @@ function p2pk(a, opts) {
if (a.output) {
if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG)
throw new TypeError('Output is invalid');
- if (!ecc.isPoint(o.pubkey))
+ if (!(0, types_1.isPoint)(o.pubkey))
throw new TypeError('Output pubkey is invalid');
if (a.pubkey && !a.pubkey.equals(o.pubkey))
throw new TypeError('Pubkey mismatch');
diff --git a/types/payments/p2pkh.d.ts b/src/payments/p2pkh.d.ts
similarity index 100%
rename from types/payments/p2pkh.d.ts
rename to src/payments/p2pkh.d.ts
diff --git a/src/payments/p2pkh.js b/src/payments/p2pkh.js
index 94c801f..8edc8ba 100644
--- a/src/payments/p2pkh.js
+++ b/src/payments/p2pkh.js
@@ -1,28 +1,28 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2pkh = void 0;
const bcrypto = require('../crypto');
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
-const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
const bs58check = require('bs58check');
+const OPS = bscript.OPS;
// input: {signature} {pubkey}
// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
function p2pkh(a, opts) {
if (!a.address && !a.hash && !a.output && !a.pubkey && !a.input)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- address: typef.maybe(typef.String),
- hash: typef.maybe(typef.BufferN(20)),
- output: typef.maybe(typef.BufferN(25)),
- pubkey: typef.maybe(ecc.isPoint),
- signature: typef.maybe(bscript.isCanonicalScriptSignature),
- input: typef.maybe(typef.Buffer),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ address: types_1.typeforce.maybe(types_1.typeforce.String),
+ hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
+ output: types_1.typeforce.maybe(types_1.typeforce.BufferN(25)),
+ pubkey: types_1.typeforce.maybe(types_1.isPoint),
+ signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
},
a,
);
@@ -116,7 +116,7 @@ function p2pkh(a, opts) {
if (chunks.length !== 2) throw new TypeError('Input is invalid');
if (!bscript.isCanonicalScriptSignature(chunks[0]))
throw new TypeError('Input has invalid signature');
- if (!ecc.isPoint(chunks[1]))
+ if (!(0, types_1.isPoint)(chunks[1]))
throw new TypeError('Input has invalid pubkey');
if (a.signature && !a.signature.equals(chunks[0]))
throw new TypeError('Signature mismatch');
diff --git a/types/payments/p2sh.d.ts b/src/payments/p2sh.d.ts
similarity index 100%
rename from types/payments/p2sh.d.ts
rename to src/payments/p2sh.d.ts
diff --git a/src/payments/p2sh.js b/src/payments/p2sh.js
index 0f46403..8710bf1 100644
--- a/src/payments/p2sh.js
+++ b/src/payments/p2sh.js
@@ -1,12 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2sh = void 0;
const bcrypto = require('../crypto');
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
-const OPS = bscript.OPS;
const bs58check = require('bs58check');
+const OPS = bscript.OPS;
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
return a.every((x, i) => {
@@ -20,20 +21,24 @@ function p2sh(a, opts) {
if (!a.address && !a.hash && !a.output && !a.redeem && !a.input)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- address: typef.maybe(typef.String),
- hash: typef.maybe(typef.BufferN(20)),
- output: typef.maybe(typef.BufferN(23)),
- redeem: typef.maybe({
- network: typef.maybe(typef.Object),
- output: typef.maybe(typef.Buffer),
- input: typef.maybe(typef.Buffer),
- witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ address: types_1.typeforce.maybe(types_1.typeforce.String),
+ hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
+ output: types_1.typeforce.maybe(types_1.typeforce.BufferN(23)),
+ redeem: types_1.typeforce.maybe({
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
}),
- input: typef.maybe(typef.Buffer),
- witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
},
a,
);
diff --git a/types/payments/p2wpkh.d.ts b/src/payments/p2wpkh.d.ts
similarity index 100%
rename from types/payments/p2wpkh.d.ts
rename to src/payments/p2wpkh.d.ts
diff --git a/src/payments/p2wpkh.js b/src/payments/p2wpkh.js
index 9e9e685..168e08f 100644
--- a/src/payments/p2wpkh.js
+++ b/src/payments/p2wpkh.js
@@ -1,13 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2wpkh = void 0;
const bcrypto = require('../crypto');
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
+const bech32_1 = require('bech32');
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
-const { bech32 } = require('bech32');
const EMPTY_BUFFER = Buffer.alloc(0);
// witness: {signature} {pubKey}
// input: <>
@@ -16,23 +16,25 @@ function p2wpkh(a, opts) {
if (!a.address && !a.hash && !a.output && !a.pubkey && !a.witness)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- address: typef.maybe(typef.String),
- hash: typef.maybe(typef.BufferN(20)),
- input: typef.maybe(typef.BufferN(0)),
- network: typef.maybe(typef.Object),
- output: typef.maybe(typef.BufferN(22)),
- pubkey: typef.maybe(ecc.isPoint),
- signature: typef.maybe(bscript.isCanonicalScriptSignature),
- witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ address: types_1.typeforce.maybe(types_1.typeforce.String),
+ hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(20)),
+ input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ output: types_1.typeforce.maybe(types_1.typeforce.BufferN(22)),
+ pubkey: types_1.typeforce.maybe(types_1.isPoint),
+ signature: types_1.typeforce.maybe(bscript.isCanonicalScriptSignature),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
},
a,
);
const _address = lazy.value(() => {
- const result = bech32.decode(a.address);
+ const result = bech32_1.bech32.decode(a.address);
const version = result.words.shift();
- const data = bech32.fromWords(result.words);
+ const data = bech32_1.bech32.fromWords(result.words);
return {
version,
prefix: result.prefix,
@@ -43,9 +45,9 @@ function p2wpkh(a, opts) {
const o = { name: 'p2wpkh', network };
lazy.prop(o, 'address', () => {
if (!o.hash) return;
- const words = bech32.toWords(o.hash);
+ const words = bech32_1.bech32.toWords(o.hash);
words.unshift(0x00);
- return bech32.encode(network.bech32, words);
+ return bech32_1.bech32.encode(network.bech32, words);
});
lazy.prop(o, 'hash', () => {
if (a.output) return a.output.slice(2, 22);
@@ -107,14 +109,14 @@ function p2wpkh(a, opts) {
if (hash.length > 0 && !hash.equals(pkh))
throw new TypeError('Hash mismatch');
else hash = pkh;
- if (!ecc.isPoint(a.pubkey) || a.pubkey.length !== 33)
+ if (!(0, types_1.isPoint)(a.pubkey) || a.pubkey.length !== 33)
throw new TypeError('Invalid pubkey for p2wpkh');
}
if (a.witness) {
if (a.witness.length !== 2) throw new TypeError('Witness is invalid');
if (!bscript.isCanonicalScriptSignature(a.witness[0]))
throw new TypeError('Witness has invalid signature');
- if (!ecc.isPoint(a.witness[1]) || a.witness[1].length !== 33)
+ if (!(0, types_1.isPoint)(a.witness[1]) || a.witness[1].length !== 33)
throw new TypeError('Witness has invalid pubkey');
if (a.signature && !a.signature.equals(a.witness[0]))
throw new TypeError('Signature mismatch');
diff --git a/types/payments/p2wsh.d.ts b/src/payments/p2wsh.d.ts
similarity index 100%
rename from types/payments/p2wsh.d.ts
rename to src/payments/p2wsh.d.ts
diff --git a/src/payments/p2wsh.js b/src/payments/p2wsh.js
index 20432a9..66ee1da 100644
--- a/src/payments/p2wsh.js
+++ b/src/payments/p2wsh.js
@@ -1,13 +1,13 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.p2wsh = void 0;
const bcrypto = require('../crypto');
const networks_1 = require('../networks');
const bscript = require('../script');
+const types_1 = require('../types');
const lazy = require('./lazy');
-const typef = require('typeforce');
+const bech32_1 = require('bech32');
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
-const { bech32 } = require('bech32');
const EMPTY_BUFFER = Buffer.alloc(0);
function stacksEqual(a, b) {
if (a.length !== b.length) return false;
@@ -20,7 +20,7 @@ function chunkHasUncompressedPubkey(chunk) {
Buffer.isBuffer(chunk) &&
chunk.length === 65 &&
chunk[0] === 0x04 &&
- ecc.isPoint(chunk)
+ (0, types_1.isPoint)(chunk)
) {
return true;
} else {
@@ -34,27 +34,31 @@ function p2wsh(a, opts) {
if (!a.address && !a.hash && !a.output && !a.redeem && !a.witness)
throw new TypeError('Not enough data');
opts = Object.assign({ validate: true }, opts || {});
- typef(
+ (0, types_1.typeforce)(
{
- network: typef.maybe(typef.Object),
- address: typef.maybe(typef.String),
- hash: typef.maybe(typef.BufferN(32)),
- output: typef.maybe(typef.BufferN(34)),
- redeem: typef.maybe({
- input: typef.maybe(typef.Buffer),
- network: typef.maybe(typef.Object),
- output: typef.maybe(typef.Buffer),
- witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ address: types_1.typeforce.maybe(types_1.typeforce.String),
+ hash: types_1.typeforce.maybe(types_1.typeforce.BufferN(32)),
+ output: types_1.typeforce.maybe(types_1.typeforce.BufferN(34)),
+ redeem: types_1.typeforce.maybe({
+ input: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ network: types_1.typeforce.maybe(types_1.typeforce.Object),
+ output: types_1.typeforce.maybe(types_1.typeforce.Buffer),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
}),
- input: typef.maybe(typef.BufferN(0)),
- witness: typef.maybe(typef.arrayOf(typef.Buffer)),
+ input: types_1.typeforce.maybe(types_1.typeforce.BufferN(0)),
+ witness: types_1.typeforce.maybe(
+ types_1.typeforce.arrayOf(types_1.typeforce.Buffer),
+ ),
},
a,
);
const _address = lazy.value(() => {
- const result = bech32.decode(a.address);
+ const result = bech32_1.bech32.decode(a.address);
const version = result.words.shift();
- const data = bech32.fromWords(result.words);
+ const data = bech32_1.bech32.fromWords(result.words);
return {
version,
prefix: result.prefix,
@@ -71,9 +75,9 @@ function p2wsh(a, opts) {
const o = { network };
lazy.prop(o, 'address', () => {
if (!o.hash) return;
- const words = bech32.toWords(o.hash);
+ const words = bech32_1.bech32.toWords(o.hash);
words.unshift(0x00);
- return bech32.encode(network.bech32, words);
+ return bech32_1.bech32.encode(network.bech32, words);
});
lazy.prop(o, 'hash', () => {
if (a.output) return a.output.slice(2);
diff --git a/types/psbt.d.ts b/src/psbt.d.ts
similarity index 88%
rename from types/psbt.d.ts
rename to src/psbt.d.ts
index e7a79eb..8603a69 100644
--- a/types/psbt.d.ts
+++ b/src/psbt.d.ts
@@ -1,6 +1,6 @@
+///
import { Psbt as PsbtBase } from 'bip174';
import { KeyValue, PsbtGlobalUpdate, PsbtInput, PsbtInputUpdate, PsbtOutput, PsbtOutputUpdate } from 'bip174/src/lib/interfaces';
-import { Signer, SignerAsync } from './ecpair';
import { Network } from './networks';
import { Transaction } from './transaction';
export interface TransactionInput {
@@ -18,6 +18,7 @@ export interface TransactionOutput {
export interface PsbtTxOutput extends TransactionOutput {
address: string | undefined;
}
+export declare type ValidateSigFunction = (pubkey: Buffer, msghash: Buffer, signature: Buffer) => boolean;
/**
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
* There are 6 roles that this class fulfills. (Explained in BIP174)
@@ -58,11 +59,13 @@ export declare class Psbt {
private __CACHE;
private opts;
constructor(opts?: PsbtOptsOptional, data?: PsbtBase);
- readonly inputCount: number;
- version: number;
- locktime: number;
- readonly txInputs: PsbtTxInput[];
- readonly txOutputs: PsbtTxOutput[];
+ get inputCount(): number;
+ get version(): number;
+ set version(version: number);
+ get locktime(): number;
+ set locktime(locktime: number);
+ get txInputs(): PsbtTxInput[];
+ get txOutputs(): PsbtTxOutput[];
combine(...those: Psbt[]): this;
clone(): Psbt;
setMaximumFeeRate(satoshiPerByte: number): void;
@@ -83,8 +86,8 @@ export declare class Psbt {
inputHasHDKey(inputIndex: number, root: HDSigner): boolean;
outputHasPubkey(outputIndex: number, pubkey: Buffer): boolean;
outputHasHDKey(outputIndex: number, root: HDSigner): boolean;
- validateSignaturesOfAllInputs(): boolean;
- validateSignaturesOfInput(inputIndex: number, pubkey?: Buffer): boolean;
+ validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean;
+ validateSignaturesOfInput(inputIndex: number, validator: ValidateSigFunction, pubkey?: Buffer): boolean;
signAllInputsHD(hdKeyPair: HDSigner, sighashTypes?: number[]): this;
signAllInputsHDAsync(hdKeyPair: HDSigner | HDSignerAsync, sighashTypes?: number[]): Promise;
signInputHD(inputIndex: number, hdKeyPair: HDSigner, sighashTypes?: number[]): this;
@@ -129,7 +132,7 @@ interface HDSignerBase {
*/
fingerprint: Buffer;
}
-interface HDSigner extends HDSignerBase {
+export interface HDSigner extends HDSignerBase {
/**
* The path string must match /^m(\/\d+'?)+$/
* ex. m/44'/0'/0'/1/23 levels with ' must be hard derivations
@@ -144,10 +147,22 @@ interface HDSigner extends HDSignerBase {
/**
* Same as above but with async sign method
*/
-interface HDSignerAsync extends HDSignerBase {
+export interface HDSignerAsync extends HDSignerBase {
derivePath(path: string): HDSignerAsync;
sign(hash: Buffer): Promise;
}
+export interface Signer {
+ publicKey: Buffer;
+ network?: any;
+ sign(hash: Buffer, lowR?: boolean): Buffer;
+ getPublicKey?(): Buffer;
+}
+export interface SignerAsync {
+ publicKey: Buffer;
+ network?: any;
+ sign(hash: Buffer, lowR?: boolean): Promise;
+ getPublicKey?(): Buffer;
+}
/**
* This function must do two things:
* 1. Check if the `input` can be finalized. If it can not be finalized, throw.
diff --git a/src/psbt.js b/src/psbt.js
index 6381669..84aa5b8 100644
--- a/src/psbt.js
+++ b/src/psbt.js
@@ -1,12 +1,12 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.Psbt = void 0;
const bip174_1 = require('bip174');
const varuint = require('bip174/src/lib/converter/varint');
const utils_1 = require('bip174/src/lib/utils');
const address_1 = require('./address');
const bufferutils_1 = require('./bufferutils');
const crypto_1 = require('./crypto');
-const ecpair_1 = require('./ecpair');
const networks_1 = require('./networks');
const payments = require('./payments');
const bscript = require('./script');
@@ -25,7 +25,7 @@ const DEFAULT_OPTS = {
* THIS IS NOT TO BE RELIED ON.
* It is only here as a last ditch effort to prevent sending a 500 BTC fee etc.
*/
- maximumFeeRate: 5000,
+ maximumFeeRate: 5000, // satoshi per byte
};
/**
* Psbt class can parse and generate a PSBT binary based off of the BIP174.
@@ -60,6 +60,23 @@ const DEFAULT_OPTS = {
* Transaction object. Such as fee rate not being larger than maximumFeeRate etc.
*/
class Psbt {
+ data;
+ static fromBase64(data, opts = {}) {
+ const buffer = Buffer.from(data, 'base64');
+ return this.fromBuffer(buffer, opts);
+ }
+ static fromHex(data, opts = {}) {
+ const buffer = Buffer.from(data, 'hex');
+ return this.fromBuffer(buffer, opts);
+ }
+ static fromBuffer(buffer, opts = {}) {
+ const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
+ const psbt = new Psbt(opts, psbtBase);
+ checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
+ return psbt;
+ }
+ __CACHE;
+ opts;
constructor(opts = {}, data = new bip174_1.Psbt(new PsbtTransaction())) {
this.data = data;
// set defaults
@@ -69,6 +86,8 @@ class Psbt {
__NON_WITNESS_UTXO_BUF_CACHE: [],
__TX_IN_CACHE: {},
__TX: this.data.globalMap.unsignedTx.tx,
+ // Psbt's predecesor (TransactionBuilder - now removed) behavior
+ // was to not confirm input values before signing.
// Even though we highly encourage people to get
// the full parent transaction to verify values, the ability to
// sign non-segwit inputs without the full transaction was often
@@ -87,20 +106,6 @@ class Psbt {
dpew(this, '__CACHE', false, true);
dpew(this, 'opts', false, true);
}
- static fromBase64(data, opts = {}) {
- const buffer = Buffer.from(data, 'base64');
- return this.fromBuffer(buffer, opts);
- }
- static fromHex(data, opts = {}) {
- const buffer = Buffer.from(data, 'hex');
- return this.fromBuffer(buffer, opts);
- }
- static fromBuffer(buffer, opts = {}) {
- const psbtBase = bip174_1.Psbt.fromBuffer(buffer, transactionFromBuffer);
- const psbt = new Psbt(opts, psbtBase);
- checkTxForDupeIns(psbt.__CACHE.__TX, psbt.__CACHE);
- return psbt;
- }
get inputCount() {
return this.data.inputs.length;
}
@@ -118,7 +123,7 @@ class Psbt {
}
get txInputs() {
return this.__CACHE.__TX.ins.map(input => ({
- hash: bufferutils_1.cloneBuffer(input.hash),
+ hash: (0, bufferutils_1.cloneBuffer)(input.hash),
index: input.index,
sequence: input.sequence,
}));
@@ -127,10 +132,13 @@ class Psbt {
return this.__CACHE.__TX.outs.map(output => {
let address;
try {
- address = address_1.fromOutputScript(output.script, this.opts.network);
+ address = (0, address_1.fromOutputScript)(
+ output.script,
+ this.opts.network,
+ );
} catch (_) {}
return {
- script: bufferutils_1.cloneBuffer(output.script),
+ script: (0, bufferutils_1.cloneBuffer)(output.script),
value: output.value,
address,
};
@@ -229,7 +237,7 @@ class Psbt {
const { address } = outputData;
if (typeof address === 'string') {
const { network } = this.opts;
- const script = address_1.toOutputScript(address, network);
+ const script = (0, address_1.toOutputScript)(address, network);
outputData = Object.assign(outputData, { script });
}
const c = this.__CACHE;
@@ -262,12 +270,12 @@ class Psbt {
return getTxCacheValue('__FEE', 'fee', this.data.inputs, this.__CACHE);
}
finalizeAllInputs() {
- utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
+ (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
range(this.data.inputs.length).forEach(idx => this.finalizeInput(idx));
return this;
}
finalizeInput(inputIndex, finalScriptsFunc = getFinalScripts) {
- const input = utils_1.checkForInput(this.data.inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
const { script, isP2SH, isP2WSH, isSegwit } = getScriptFromInput(
inputIndex,
input,
@@ -292,7 +300,7 @@ class Psbt {
return this;
}
getInputType(inputIndex) {
- const input = utils_1.checkForInput(this.data.inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
const script = getScriptFromUtxo(inputIndex, input, this.__CACHE);
const result = getMeaningfulScript(
script,
@@ -307,39 +315,41 @@ class Psbt {
return type + mainType;
}
inputHasPubkey(inputIndex, pubkey) {
- const input = utils_1.checkForInput(this.data.inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
return pubkeyInInput(pubkey, input, inputIndex, this.__CACHE);
}
inputHasHDKey(inputIndex, root) {
- const input = utils_1.checkForInput(this.data.inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(this.data.inputs, inputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!input.bip32Derivation && input.bip32Derivation.some(derivationIsMine)
);
}
outputHasPubkey(outputIndex, pubkey) {
- const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
+ const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
return pubkeyInOutput(pubkey, output, outputIndex, this.__CACHE);
}
outputHasHDKey(outputIndex, root) {
- const output = utils_1.checkForOutput(this.data.outputs, outputIndex);
+ const output = (0, utils_1.checkForOutput)(this.data.outputs, outputIndex);
const derivationIsMine = bip32DerivationIsMine(root);
return (
!!output.bip32Derivation && output.bip32Derivation.some(derivationIsMine)
);
}
- validateSignaturesOfAllInputs() {
- utils_1.checkForInput(this.data.inputs, 0); // making sure we have at least one
+ validateSignaturesOfAllInputs(validator) {
+ (0, utils_1.checkForInput)(this.data.inputs, 0); // making sure we have at least one
const results = range(this.data.inputs.length).map(idx =>
- this.validateSignaturesOfInput(idx),
+ this.validateSignaturesOfInput(idx, validator),
);
return results.reduce((final, res) => res === true && final, true);
}
- validateSignaturesOfInput(inputIndex, pubkey) {
+ validateSignaturesOfInput(inputIndex, validator, pubkey) {
const input = this.data.inputs[inputIndex];
const partialSig = (input || {}).partialSig;
if (!input || !partialSig || partialSig.length < 1)
throw new Error('No signatures to validate');
+ if (typeof validator !== 'function')
+ throw new Error('Need validator function to validate signatures');
const mySigs = pubkey
? partialSig.filter(sig => sig.pubkey.equals(pubkey))
: partialSig;
@@ -363,8 +373,7 @@ class Psbt {
hashCache = hash;
scriptCache = script;
checkScriptForPubkey(pSig.pubkey, script, 'verify');
- const keypair = ecpair_1.fromPublicKey(pSig.pubkey);
- results.push(keypair.verify(hash, sig.signature));
+ results.push(validator(pSig.pubkey, hash, sig.signature));
}
return results.every(res => res === true);
}
@@ -616,6 +625,7 @@ const transactionFromBuffer = buffer => new PsbtTransaction(buffer);
* It contains a bitcoinjs-lib Transaction object.
*/
class PsbtTransaction {
+ tx;
constructor(buffer = Buffer.from([2, 0, 0, 0, 0, 0, 0, 0, 0, 0])) {
this.tx = transaction_1.Transaction.fromBuffer(buffer);
checkTxEmpty(this.tx);
@@ -641,7 +651,7 @@ class PsbtTransaction {
}
const hash =
typeof input.hash === 'string'
- ? bufferutils_1.reverseBuffer(Buffer.from(input.hash, 'hex'))
+ ? (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash, 'hex'))
: input.hash;
this.tx.addInput(hash, input.index, input.sequence);
}
@@ -684,8 +694,7 @@ function hasSigs(neededSigs, partialSig, pubkeys) {
if (pubkeys) {
sigs = pubkeys
.map(pkey => {
- const pubkey = ecpair_1.fromPublicKey(pkey, { compressed: true })
- .publicKey;
+ const pubkey = compressPubkey(pkey);
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
})
.filter(v => !!v);
@@ -816,7 +825,7 @@ function checkTxForDupeIns(tx, cache) {
}
function checkTxInputCache(cache, input) {
const key =
- bufferutils_1.reverseBuffer(Buffer.from(input.hash)).toString('hex') +
+ (0, bufferutils_1.reverseBuffer)(Buffer.from(input.hash)).toString('hex') +
':' +
input.index;
if (cache.__TX_IN_CACHE[key]) throw new Error('Duplicate input detected.');
@@ -911,7 +920,7 @@ function getHashAndSighashType(
cache,
sighashTypes,
) {
- const input = utils_1.checkForInput(inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(inputs, inputIndex);
const { hash, sighashType, script } = getHashForSig(
inputIndex,
input,
@@ -997,7 +1006,8 @@ function getHashForSig(inputIndex, input, cache, forValidate, sighashTypes) {
console.warn(
'Warning: Signing non-segwit inputs without the full parent transaction ' +
'means there is a chance that a miner could feed you incorrect information ' +
- 'to trick you into paying large fees. You are not ' +
+ "to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
+ '(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
'*********************',
@@ -1094,7 +1104,7 @@ function getScriptFromInput(inputIndex, input, cache) {
return res;
}
function getSignersFromHD(inputIndex, inputs, hdKeyPair) {
- const input = utils_1.checkForInput(inputs, inputIndex);
+ const input = (0, utils_1.checkForInput)(inputs, inputIndex);
if (!input.bip32Derivation || input.bip32Derivation.length === 0) {
throw new Error('Need bip32Derivation to sign with HD');
}
@@ -1321,6 +1331,15 @@ function redeemFromFinalWitnessScript(finalScript) {
if (!sDecomp) return;
return lastItem;
}
+function compressPubkey(pubkey) {
+ if (pubkey.length === 65) {
+ const parity = pubkey[64] & 1;
+ const newKey = pubkey.slice(0, 33);
+ newKey[0] = 2 | parity;
+ return newKey;
+ }
+ return pubkey.slice();
+}
function isPubkeyLike(buf) {
return buf.length === 33 && bscript.isCanonicalPubKey(buf);
}
@@ -1376,7 +1395,7 @@ function checkInvalidP2WSH(script) {
}
}
function pubkeyInScript(pubkey, script) {
- const pubkeyHash = crypto_1.hash160(pubkey);
+ const pubkeyHash = (0, crypto_1.hash160)(pubkey);
const decompiled = bscript.decompile(script);
if (decompiled === null) throw new Error('Unknown script error');
return decompiled.some(element => {
diff --git a/src/push_data.d.ts b/src/push_data.d.ts
new file mode 100644
index 0000000..07c2f91
--- /dev/null
+++ b/src/push_data.d.ts
@@ -0,0 +1,8 @@
+///
+export declare function encodingLength(i: number): number;
+export declare function encode(buffer: Buffer, num: number, offset: number): number;
+export declare function decode(buffer: Buffer, offset: number): {
+ opcode: number;
+ number: number;
+ size: number;
+} | null;
diff --git a/src/push_data.js b/src/push_data.js
new file mode 100644
index 0000000..16b6147
--- /dev/null
+++ b/src/push_data.js
@@ -0,0 +1,61 @@
+'use strict';
+Object.defineProperty(exports, '__esModule', { value: true });
+exports.decode = exports.encode = exports.encodingLength = void 0;
+const ops_1 = require('./ops');
+function encodingLength(i) {
+ return i < ops_1.OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5;
+}
+exports.encodingLength = encodingLength;
+function encode(buffer, num, offset) {
+ const size = encodingLength(num);
+ // ~6 bit
+ if (size === 1) {
+ buffer.writeUInt8(num, offset);
+ // 8 bit
+ } else if (size === 2) {
+ buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA1, offset);
+ buffer.writeUInt8(num, offset + 1);
+ // 16 bit
+ } else if (size === 3) {
+ buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA2, offset);
+ buffer.writeUInt16LE(num, offset + 1);
+ // 32 bit
+ } else {
+ buffer.writeUInt8(ops_1.OPS.OP_PUSHDATA4, offset);
+ buffer.writeUInt32LE(num, offset + 1);
+ }
+ return size;
+}
+exports.encode = encode;
+function decode(buffer, offset) {
+ const opcode = buffer.readUInt8(offset);
+ let num;
+ let size;
+ // ~6 bit
+ if (opcode < ops_1.OPS.OP_PUSHDATA1) {
+ num = opcode;
+ size = 1;
+ // 8 bit
+ } else if (opcode === ops_1.OPS.OP_PUSHDATA1) {
+ if (offset + 2 > buffer.length) return null;
+ num = buffer.readUInt8(offset + 1);
+ size = 2;
+ // 16 bit
+ } else if (opcode === ops_1.OPS.OP_PUSHDATA2) {
+ if (offset + 3 > buffer.length) return null;
+ num = buffer.readUInt16LE(offset + 1);
+ size = 3;
+ // 32 bit
+ } else {
+ if (offset + 5 > buffer.length) return null;
+ if (opcode !== ops_1.OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode');
+ num = buffer.readUInt32LE(offset + 1);
+ size = 5;
+ }
+ return {
+ opcode,
+ number: num,
+ size,
+ };
+}
+exports.decode = decode;
diff --git a/types/script.d.ts b/src/script.d.ts
similarity index 90%
rename from types/script.d.ts
rename to src/script.d.ts
index 4b04615..261ecf4 100644
--- a/types/script.d.ts
+++ b/src/script.d.ts
@@ -1,10 +1,9 @@
+///
+import { OPS } from './ops';
import { Stack } from './payments';
import * as scriptNumber from './script_number';
import * as scriptSignature from './script_signature';
-export declare type OpCode = number;
-export declare const OPS: {
- [index: string]: number;
-};
+export { OPS };
export declare function isPushOnly(value: Stack): boolean;
export declare function compile(chunks: Buffer | Stack): Buffer;
export declare function decompile(buffer: Buffer | Array): Array | null;
diff --git a/src/script.js b/src/script.js
index 39859dc..5e5e17b 100644
--- a/src/script.js
+++ b/src/script.js
@@ -1,21 +1,26 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.signature = exports.number = exports.isCanonicalScriptSignature = exports.isDefinedHashType = exports.isCanonicalPubKey = exports.toStack = exports.fromASM = exports.toASM = exports.decompile = exports.compile = exports.isPushOnly = exports.OPS = void 0;
+const bip66 = require('./bip66');
+const ops_1 = require('./ops');
+Object.defineProperty(exports, 'OPS', {
+ enumerable: true,
+ get: function() {
+ return ops_1.OPS;
+ },
+});
+const pushdata = require('./push_data');
const scriptNumber = require('./script_number');
const scriptSignature = require('./script_signature');
const types = require('./types');
-const bip66 = require('bip66');
-const ecc = require('tiny-secp256k1');
-const pushdata = require('pushdata-bitcoin');
-const typeforce = require('typeforce');
-exports.OPS = require('bitcoin-ops');
-const REVERSE_OPS = require('bitcoin-ops/map');
-const OP_INT_BASE = exports.OPS.OP_RESERVED; // OP_1 - 1
+const { typeforce } = types;
+const OP_INT_BASE = ops_1.OPS.OP_RESERVED; // OP_1 - 1
function isOPInt(value) {
return (
types.Number(value) &&
- (value === exports.OPS.OP_0 ||
- (value >= exports.OPS.OP_1 && value <= exports.OPS.OP_16) ||
- value === exports.OPS.OP_1NEGATE)
+ (value === ops_1.OPS.OP_0 ||
+ (value >= ops_1.OPS.OP_1 && value <= ops_1.OPS.OP_16) ||
+ value === ops_1.OPS.OP_1NEGATE)
);
}
function isPushOnlyChunk(value) {
@@ -26,10 +31,10 @@ function isPushOnly(value) {
}
exports.isPushOnly = isPushOnly;
function asMinimalOP(buffer) {
- if (buffer.length === 0) return exports.OPS.OP_0;
+ if (buffer.length === 0) return ops_1.OPS.OP_0;
if (buffer.length !== 1) return;
if (buffer[0] >= 1 && buffer[0] <= 16) return OP_INT_BASE + buffer[0];
- if (buffer[0] === 0x81) return exports.OPS.OP_1NEGATE;
+ if (buffer[0] === 0x81) return ops_1.OPS.OP_1NEGATE;
}
function chunksIsBuffer(buf) {
return Buffer.isBuffer(buf);
@@ -90,7 +95,7 @@ function decompile(buffer) {
while (i < buffer.length) {
const opcode = buffer[i];
// data chunk
- if (opcode > exports.OPS.OP_0 && opcode <= exports.OPS.OP_PUSHDATA4) {
+ if (opcode > ops_1.OPS.OP_0 && opcode <= ops_1.OPS.OP_PUSHDATA4) {
const d = pushdata.decode(buffer, i);
// did reading a pushDataInt fail?
if (d === null) return null;
@@ -128,7 +133,7 @@ function toASM(chunks) {
chunk = op;
}
// opcode!
- return REVERSE_OPS[chunk];
+ return ops_1.REVERSE_OPS[chunk];
})
.join(' ');
}
@@ -138,7 +143,7 @@ function fromASM(asm) {
return compile(
asm.split(' ').map(chunkStr => {
// opcode?
- if (exports.OPS[chunkStr] !== undefined) return exports.OPS[chunkStr];
+ if (ops_1.OPS[chunkStr] !== undefined) return ops_1.OPS[chunkStr];
typeforce(types.Hex, chunkStr);
// data!
return Buffer.from(chunkStr, 'hex');
@@ -151,13 +156,13 @@ function toStack(chunks) {
typeforce(isPushOnly, chunks);
return chunks.map(op => {
if (singleChunkIsBuffer(op)) return op;
- if (op === exports.OPS.OP_0) return Buffer.allocUnsafe(0);
+ if (op === ops_1.OPS.OP_0) return Buffer.allocUnsafe(0);
return scriptNumber.encode(op - OP_INT_BASE);
});
}
exports.toStack = toStack;
function isCanonicalPubKey(buffer) {
- return ecc.isPoint(buffer);
+ return types.isPoint(buffer);
}
exports.isCanonicalPubKey = isCanonicalPubKey;
function isDefinedHashType(hashType) {
diff --git a/types/script_number.d.ts b/src/script_number.d.ts
similarity index 83%
rename from types/script_number.d.ts
rename to src/script_number.d.ts
index cf535fc..015bb89 100644
--- a/types/script_number.d.ts
+++ b/src/script_number.d.ts
@@ -1,2 +1,3 @@
+///
export declare function decode(buffer: Buffer, maxLength?: number, minimal?: boolean): number;
export declare function encode(_number: number): Buffer;
diff --git a/src/script_number.js b/src/script_number.js
index 3f313af..8220a10 100644
--- a/src/script_number.js
+++ b/src/script_number.js
@@ -1,5 +1,6 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.encode = exports.decode = void 0;
function decode(buffer, maxLength, minimal) {
maxLength = maxLength || 4;
minimal = minimal === undefined ? true : minimal;
diff --git a/types/script_signature.d.ts b/src/script_signature.d.ts
similarity index 88%
rename from types/script_signature.d.ts
rename to src/script_signature.d.ts
index fbf18d5..2057dd9 100644
--- a/types/script_signature.d.ts
+++ b/src/script_signature.d.ts
@@ -1,3 +1,4 @@
+///
interface ScriptSignature {
signature: Buffer;
hashType: number;
diff --git a/src/script_signature.js b/src/script_signature.js
index fb52fe9..638e5f2 100644
--- a/src/script_signature.js
+++ b/src/script_signature.js
@@ -1,8 +1,9 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.encode = exports.decode = void 0;
+const bip66 = require('./bip66');
const types = require('./types');
-const bip66 = require('bip66');
-const typeforce = require('typeforce');
+const { typeforce } = types;
const ZERO = Buffer.alloc(1, 0);
function toDER(x) {
let i = 0;
diff --git a/types/transaction.d.ts b/src/transaction.d.ts
similarity index 98%
rename from types/transaction.d.ts
rename to src/transaction.d.ts
index 6846ea5..c4de954 100644
--- a/types/transaction.d.ts
+++ b/src/transaction.d.ts
@@ -1,3 +1,4 @@
+///
export interface Output {
script: Buffer;
value: number;
diff --git a/src/transaction.js b/src/transaction.js
index 8db57c3..e4ebf6f 100644
--- a/src/transaction.js
+++ b/src/transaction.js
@@ -1,20 +1,20 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
+exports.Transaction = void 0;
const bufferutils_1 = require('./bufferutils');
const bcrypto = require('./crypto');
const bscript = require('./script');
const script_1 = require('./script');
const types = require('./types');
-const typeforce = require('typeforce');
-const varuint = require('varuint-bitcoin');
+const { typeforce } = types;
function varSliceSize(someScript) {
const length = someScript.length;
- return varuint.encodingLength(length) + length;
+ return bufferutils_1.varuint.encodingLength(length) + length;
}
function vectorSize(someVector) {
const length = someVector.length;
return (
- varuint.encodingLength(length) +
+ bufferutils_1.varuint.encodingLength(length) +
someVector.reduce((sum, witness) => {
return sum + varSliceSize(witness);
}, 0)
@@ -39,12 +39,13 @@ function isOutput(out) {
return out.value !== undefined;
}
class Transaction {
- constructor() {
- this.version = 1;
- this.locktime = 0;
- this.ins = [];
- this.outs = [];
- }
+ static DEFAULT_SEQUENCE = 0xffffffff;
+ static SIGHASH_ALL = 0x01;
+ static SIGHASH_NONE = 0x02;
+ static SIGHASH_SINGLE = 0x03;
+ static SIGHASH_ANYONECANPAY = 0x80;
+ static ADVANCED_TRANSACTION_MARKER = 0x00;
+ static ADVANCED_TRANSACTION_FLAG = 0x01;
static fromBuffer(buffer, _NO_STRICT) {
const bufferReader = new bufferutils_1.BufferReader(buffer);
const tx = new Transaction();
@@ -101,6 +102,10 @@ class Transaction {
}
return true;
}
+ version = 1;
+ locktime = 0;
+ ins = [];
+ outs = [];
isCoinbase() {
return (
this.ins.length === 1 && Transaction.isCoinbaseHash(this.ins[0].hash)
@@ -157,8 +162,8 @@ class Transaction {
const hasWitnesses = _ALLOW_WITNESS && this.hasWitnesses();
return (
(hasWitnesses ? 10 : 8) +
- varuint.encodingLength(this.ins.length) +
- varuint.encodingLength(this.outs.length) +
+ bufferutils_1.varuint.encodingLength(this.ins.length) +
+ bufferutils_1.varuint.encodingLength(this.outs.length) +
this.ins.reduce((sum, input) => {
return sum + 40 + varSliceSize(input.script);
}, 0) +
@@ -336,7 +341,9 @@ class Transaction {
}
getId() {
// transaction hash's are displayed in reverse order
- return bufferutils_1.reverseBuffer(this.getHash(false)).toString('hex');
+ return (0, bufferutils_1.reverseBuffer)(this.getHash(false)).toString(
+ 'hex',
+ );
}
toBuffer(buffer, initialOffset) {
return this.__toBuffer(buffer, initialOffset, true);
@@ -392,11 +399,4 @@ class Transaction {
return buffer;
}
}
-Transaction.DEFAULT_SEQUENCE = 0xffffffff;
-Transaction.SIGHASH_ALL = 0x01;
-Transaction.SIGHASH_NONE = 0x02;
-Transaction.SIGHASH_SINGLE = 0x03;
-Transaction.SIGHASH_ANYONECANPAY = 0x80;
-Transaction.ADVANCED_TRANSACTION_MARKER = 0x00;
-Transaction.ADVANCED_TRANSACTION_FLAG = 0x01;
exports.Transaction = Transaction;
diff --git a/types/types.d.ts b/src/types.d.ts
similarity index 86%
rename from types/types.d.ts
rename to src/types.d.ts
index e7c588d..5a8505d 100644
--- a/types/types.d.ts
+++ b/src/types.d.ts
@@ -1,3 +1,6 @@
+///
+export declare const typeforce: any;
+export declare function isPoint(p: Buffer | number | undefined | null): boolean;
export declare function UInt31(value: number): boolean;
export declare function BIP32Path(value: string): boolean;
export declare namespace BIP32Path {
diff --git a/src/types.js b/src/types.js
index 8bcee2c..a6d1efa 100644
--- a/src/types.js
+++ b/src/types.js
@@ -1,13 +1,39 @@
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
-const typeforce = require('typeforce');
+exports.oneOf = exports.Null = exports.BufferN = exports.Function = exports.UInt32 = exports.UInt8 = exports.tuple = exports.maybe = exports.Hex = exports.Buffer = exports.String = exports.Boolean = exports.Array = exports.Number = exports.Hash256bit = exports.Hash160bit = exports.Buffer256bit = exports.Network = exports.ECPoint = exports.Satoshi = exports.Signer = exports.BIP32Path = exports.UInt31 = exports.isPoint = exports.typeforce = void 0;
+const buffer_1 = require('buffer');
+exports.typeforce = require('typeforce');
+const ZERO32 = buffer_1.Buffer.alloc(32, 0);
+const EC_P = buffer_1.Buffer.from(
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
+ 'hex',
+);
+function isPoint(p) {
+ if (!buffer_1.Buffer.isBuffer(p)) return false;
+ if (p.length < 33) return false;
+ const t = p[0];
+ const x = p.slice(1, 33);
+ if (x.compare(ZERO32) === 0) return false;
+ if (x.compare(EC_P) >= 0) return false;
+ if ((t === 0x02 || t === 0x03) && p.length === 33) {
+ return true;
+ }
+ const y = p.slice(33);
+ if (y.compare(ZERO32) === 0) return false;
+ if (y.compare(EC_P) >= 0) return false;
+ if (t === 0x04 && p.length === 65) return true;
+ return false;
+}
+exports.isPoint = isPoint;
const UINT31_MAX = Math.pow(2, 31) - 1;
function UInt31(value) {
- return typeforce.UInt32(value) && value <= UINT31_MAX;
+ return exports.typeforce.UInt32(value) && value <= UINT31_MAX;
}
exports.UInt31 = UInt31;
function BIP32Path(value) {
- return typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/);
+ return (
+ exports.typeforce.String(value) && !!value.match(/^(m\/)?(\d+'?\/)*\d+'?$/)
+ );
}
exports.BIP32Path = BIP32Path;
BIP32Path.toJSON = () => {
@@ -15,7 +41,7 @@ BIP32Path.toJSON = () => {
};
function Signer(obj) {
return (
- (typeforce.Buffer(obj.publicKey) ||
+ (exports.typeforce.Buffer(obj.publicKey) ||
typeof obj.getPublicKey === 'function') &&
typeof obj.sign === 'function'
);
@@ -23,36 +49,39 @@ function Signer(obj) {
exports.Signer = Signer;
const SATOSHI_MAX = 21 * 1e14;
function Satoshi(value) {
- return typeforce.UInt53(value) && value <= SATOSHI_MAX;
+ return exports.typeforce.UInt53(value) && value <= SATOSHI_MAX;
}
exports.Satoshi = Satoshi;
// external dependent types
-exports.ECPoint = typeforce.quacksLike('Point');
+exports.ECPoint = exports.typeforce.quacksLike('Point');
// exposed, external API
-exports.Network = typeforce.compile({
- messagePrefix: typeforce.oneOf(typeforce.Buffer, typeforce.String),
+exports.Network = exports.typeforce.compile({
+ messagePrefix: exports.typeforce.oneOf(
+ exports.typeforce.Buffer,
+ exports.typeforce.String,
+ ),
bip32: {
- public: typeforce.UInt32,
- private: typeforce.UInt32,
+ public: exports.typeforce.UInt32,
+ private: exports.typeforce.UInt32,
},
- pubKeyHash: typeforce.UInt8,
- scriptHash: typeforce.UInt8,
- wif: typeforce.UInt8,
+ pubKeyHash: exports.typeforce.UInt8,
+ scriptHash: exports.typeforce.UInt8,
+ wif: exports.typeforce.UInt8,
});
-exports.Buffer256bit = typeforce.BufferN(32);
-exports.Hash160bit = typeforce.BufferN(20);
-exports.Hash256bit = typeforce.BufferN(32);
-exports.Number = typeforce.Number; // tslint:disable-line variable-name
-exports.Array = typeforce.Array;
-exports.Boolean = typeforce.Boolean; // tslint:disable-line variable-name
-exports.String = typeforce.String; // tslint:disable-line variable-name
-exports.Buffer = typeforce.Buffer;
-exports.Hex = typeforce.Hex;
-exports.maybe = typeforce.maybe;
-exports.tuple = typeforce.tuple;
-exports.UInt8 = typeforce.UInt8;
-exports.UInt32 = typeforce.UInt32;
-exports.Function = typeforce.Function;
-exports.BufferN = typeforce.BufferN;
-exports.Null = typeforce.Null;
-exports.oneOf = typeforce.oneOf;
+exports.Buffer256bit = exports.typeforce.BufferN(32);
+exports.Hash160bit = exports.typeforce.BufferN(20);
+exports.Hash256bit = exports.typeforce.BufferN(32);
+exports.Number = exports.typeforce.Number; // tslint:disable-line variable-name
+exports.Array = exports.typeforce.Array;
+exports.Boolean = exports.typeforce.Boolean; // tslint:disable-line variable-name
+exports.String = exports.typeforce.String; // tslint:disable-line variable-name
+exports.Buffer = exports.typeforce.Buffer;
+exports.Hex = exports.typeforce.Hex;
+exports.maybe = exports.typeforce.maybe;
+exports.tuple = exports.typeforce.tuple;
+exports.UInt8 = exports.typeforce.UInt8;
+exports.UInt32 = exports.typeforce.UInt32;
+exports.Function = exports.typeforce.Function;
+exports.BufferN = exports.typeforce.BufferN;
+exports.Null = exports.typeforce.Null;
+exports.oneOf = exports.typeforce.oneOf;
diff --git a/test/bitcoin.core.spec.ts b/test/bitcoin.core.spec.ts
index 0263266..9040416 100644
--- a/test/bitcoin.core.spec.ts
+++ b/test/bitcoin.core.spec.ts
@@ -88,49 +88,6 @@ describe('Bitcoin-core', () => {
});
});
- // base58KeysValid
- describe('ECPair', () => {
- base58KeysValid.forEach(f => {
- const strng = f[0] as string;
- const hex = f[1];
- const params = f[2] as any;
-
- if (!params.isPrivkey) return;
-
- const network = params.isTestnet
- ? bitcoin.networks.testnet
- : bitcoin.networks.bitcoin;
- const keyPair = bitcoin.ECPair.fromWIF(strng, network);
-
- it('fromWIF imports ' + strng, () => {
- assert.strictEqual(keyPair.privateKey!.toString('hex'), hex);
- assert.strictEqual(keyPair.compressed, params.isCompressed);
- });
-
- it('toWIF exports ' + hex + ' to ' + strng, () => {
- assert.strictEqual(keyPair.toWIF(), strng);
- });
- });
- });
-
- // base58KeysInvalid
- describe('ECPair.fromWIF', () => {
- const allowedNetworks = [
- bitcoin.networks.bitcoin,
- bitcoin.networks.testnet,
- ];
-
- base58KeysInvalid.forEach(f => {
- const strng = f[0];
-
- it('throws on ' + strng, () => {
- assert.throws(() => {
- bitcoin.ECPair.fromWIF(strng, allowedNetworks);
- }, /(Invalid|Unknown) (checksum|compression flag|network version|WIF length)/);
- });
- });
- });
-
describe('Block.fromHex', () => {
blocksValid.forEach(f => {
it('can parse ' + f.id, () => {
diff --git a/test/ecpair.spec.ts b/test/ecpair.spec.ts
deleted file mode 100644
index 0b54ecc..0000000
--- a/test/ecpair.spec.ts
+++ /dev/null
@@ -1,341 +0,0 @@
-import * as assert from 'assert';
-import { beforeEach, describe, it } from 'mocha';
-import * as proxyquire from 'proxyquire';
-import { ECPair, ECPairInterface, networks as NETWORKS } from '..';
-import * as fixtures from './fixtures/ecpair.json';
-const hoodwink = require('hoodwink');
-const tinysecp = require('tiny-secp256k1');
-
-const NETWORKS_LIST = Object.values(NETWORKS);
-const ZERO = Buffer.alloc(32, 0);
-const ONE = Buffer.from(
- '0000000000000000000000000000000000000000000000000000000000000001',
- 'hex',
-);
-const GROUP_ORDER = Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141',
- 'hex',
-);
-const GROUP_ORDER_LESS_1 = Buffer.from(
- 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140',
- 'hex',
-);
-
-describe('ECPair', () => {
- describe('getPublicKey', () => {
- let keyPair: ECPairInterface;
-
- beforeEach(() => {
- keyPair = ECPair.fromPrivateKey(ONE);
- });
-
- it(
- 'calls pointFromScalar lazily',
- hoodwink(() => {
- assert.strictEqual((keyPair as any).__Q, undefined);
-
- // .publicKey forces the memoization
- assert.strictEqual(
- keyPair.publicKey.toString('hex'),
- '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
- );
- assert.strictEqual(
- (keyPair as any).__Q.toString('hex'),
- '0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798',
- );
- }),
- );
- });
-
- describe('fromPrivateKey', () => {
- it('defaults to compressed', () => {
- const keyPair = ECPair.fromPrivateKey(ONE);
-
- assert.strictEqual(keyPair.compressed, true);
- });
-
- it('supports the uncompressed option', () => {
- const keyPair = ECPair.fromPrivateKey(ONE, {
- compressed: false,
- });
-
- assert.strictEqual(keyPair.compressed, false);
- });
-
- it('supports the network option', () => {
- const keyPair = ECPair.fromPrivateKey(ONE, {
- compressed: false,
- network: NETWORKS.testnet,
- });
-
- assert.strictEqual(keyPair.network, NETWORKS.testnet);
- });
-
- fixtures.valid.forEach(f => {
- it('derives public key for ' + f.WIF, () => {
- const d = Buffer.from(f.d, 'hex');
- const keyPair = ECPair.fromPrivateKey(d, {
- compressed: f.compressed,
- });
-
- assert.strictEqual(keyPair.publicKey.toString('hex'), f.Q);
- });
- });
-
- fixtures.invalid.fromPrivateKey.forEach(f => {
- it('throws ' + f.exception, () => {
- const d = Buffer.from(f.d, 'hex');
- assert.throws(() => {
- ECPair.fromPrivateKey(d, (f as any).options);
- }, new RegExp(f.exception));
- });
- });
- });
-
- describe('fromPublicKey', () => {
- fixtures.invalid.fromPublicKey.forEach(f => {
- it('throws ' + f.exception, () => {
- const Q = Buffer.from(f.Q, 'hex');
- assert.throws(() => {
- ECPair.fromPublicKey(Q, (f as any).options);
- }, new RegExp(f.exception));
- });
- });
- });
-
- describe('fromWIF', () => {
- fixtures.valid.forEach(f => {
- it('imports ' + f.WIF + ' (' + f.network + ')', () => {
- const network = (NETWORKS as any)[f.network];
- const keyPair = ECPair.fromWIF(f.WIF, network);
-
- assert.strictEqual(keyPair.privateKey!.toString('hex'), f.d);
- assert.strictEqual(keyPair.compressed, f.compressed);
- assert.strictEqual(keyPair.network, network);
- });
- });
-
- fixtures.valid.forEach(f => {
- it('imports ' + f.WIF + ' (via list of networks)', () => {
- const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST);
-
- assert.strictEqual(keyPair.privateKey!.toString('hex'), f.d);
- assert.strictEqual(keyPair.compressed, f.compressed);
- assert.strictEqual(keyPair.network, (NETWORKS as any)[f.network]);
- });
- });
-
- fixtures.invalid.fromWIF.forEach(f => {
- it('throws on ' + f.WIF, () => {
- assert.throws(() => {
- const networks = f.network
- ? (NETWORKS as any)[f.network]
- : NETWORKS_LIST;
-
- ECPair.fromWIF(f.WIF, networks);
- }, new RegExp(f.exception));
- });
- });
- });
-
- describe('toWIF', () => {
- fixtures.valid.forEach(f => {
- it('exports ' + f.WIF, () => {
- const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST);
- const result = keyPair.toWIF();
- assert.strictEqual(result, f.WIF);
- });
- });
- it('throws if no private key is found', () => {
- assert.throws(() => {
- const keyPair = ECPair.makeRandom();
- delete (keyPair as any).__D;
- keyPair.toWIF();
- }, /Missing private key/);
- });
- });
-
- describe('makeRandom', () => {
- const d = Buffer.alloc(32, 4);
- const exWIF = 'KwMWvwRJeFqxYyhZgNwYuYjbQENDAPAudQx5VEmKJrUZcq6aL2pv';
-
- describe('uses randombytes RNG', () => {
- it('generates a ECPair', () => {
- const stub = {
- randombytes: (): Buffer => {
- return d;
- },
- };
- const ProxiedECPair = proxyquire('../src/ecpair', stub);
-
- const keyPair = ProxiedECPair.makeRandom();
- assert.strictEqual(keyPair.toWIF(), exWIF);
- });
- });
-
- it('allows a custom RNG to be used', () => {
- const keyPair = ECPair.makeRandom({
- rng: (size): Buffer => {
- return d.slice(0, size);
- },
- });
-
- assert.strictEqual(keyPair.toWIF(), exWIF);
- });
-
- it('retains the same defaults as ECPair constructor', () => {
- const keyPair = ECPair.makeRandom();
-
- assert.strictEqual(keyPair.compressed, true);
- assert.strictEqual(keyPair.network, NETWORKS.bitcoin);
- });
-
- it('supports the options parameter', () => {
- const keyPair = ECPair.makeRandom({
- compressed: false,
- network: NETWORKS.testnet,
- });
-
- assert.strictEqual(keyPair.compressed, false);
- assert.strictEqual(keyPair.network, NETWORKS.testnet);
- });
-
- it('throws if d is bad length', () => {
- function rng(): Buffer {
- return Buffer.alloc(28);
- }
-
- assert.throws(() => {
- ECPair.makeRandom({ rng });
- }, /Expected Buffer\(Length: 32\), got Buffer\(Length: 28\)/);
- });
-
- it(
- 'loops until d is within interval [1, n) : 1',
- hoodwink(function(this: any): void {
- const rng = this.stub(() => {
- if (rng.calls === 0) return ZERO; // 0
- return ONE; // >0
- }, 2);
-
- ECPair.makeRandom({ rng });
- }),
- );
-
- it(
- 'loops until d is within interval [1, n) : n - 1',
- hoodwink(function(this: any): void {
- const rng = this.stub(() => {
- if (rng.calls === 0) return ZERO; // <1
- if (rng.calls === 1) return GROUP_ORDER; // >n-1
- return GROUP_ORDER_LESS_1; // n-1
- }, 3);
-
- ECPair.makeRandom({ rng });
- }),
- );
- });
-
- describe('.network', () => {
- fixtures.valid.forEach(f => {
- it('returns ' + f.network + ' for ' + f.WIF, () => {
- const network = (NETWORKS as any)[f.network];
- const keyPair = ECPair.fromWIF(f.WIF, NETWORKS_LIST);
-
- assert.strictEqual(keyPair.network, network);
- });
- });
- });
-
- describe('tinysecp wrappers', () => {
- let keyPair: ECPairInterface;
- let hash: Buffer;
- let signature: Buffer;
-
- beforeEach(() => {
- keyPair = ECPair.makeRandom();
- hash = ZERO;
- signature = Buffer.alloc(64, 1);
- });
-
- describe('signing', () => {
- it(
- 'wraps tinysecp.sign',
- hoodwink(function(this: any): void {
- this.mock(
- tinysecp,
- 'sign',
- (h: any, d: any) => {
- assert.strictEqual(h, hash);
- assert.strictEqual(d, keyPair.privateKey);
- return signature;
- },
- 1,
- );
-
- assert.strictEqual(keyPair.sign(hash), signature);
- }),
- );
-
- it('throws if no private key is found', () => {
- delete (keyPair as any).__D;
-
- assert.throws(() => {
- keyPair.sign(hash);
- }, /Missing private key/);
- });
- });
-
- describe('verify', () => {
- it(
- 'wraps tinysecp.verify',
- hoodwink(function(this: any): void {
- this.mock(
- tinysecp,
- 'verify',
- (h: any, q: any, s: any) => {
- assert.strictEqual(h, hash);
- assert.strictEqual(q, keyPair.publicKey);
- assert.strictEqual(s, signature);
- return true;
- },
- 1,
- );
-
- assert.strictEqual(keyPair.verify(hash, signature), true);
- }),
- );
- });
- });
- describe('optional low R signing', () => {
- const sig = Buffer.from(
- '95a6619140fca3366f1d3b013b0367c4f86e39508a50fdce' +
- 'e5245fbb8bd60aa6086449e28cf15387cf9f85100bfd0838624ca96759e59f65c10a00' +
- '16b86f5229',
- 'hex',
- );
- const sigLowR = Buffer.from(
- '6a2660c226e8055afad317eeba918a304be79208d505' +
- '3bc5ea4a5e4c5892b4a061c717c5284ae5202d721c0e49b4717b79966280906b1d3b52' +
- '95d1fdde963c35',
- 'hex',
- );
- const lowRKeyPair = ECPair.fromWIF(
- 'L3nThUzbAwpUiBAjR5zCu66ybXSPMr2zZ3ikp' + 'ScpTPiYTxBynfZu',
- );
- const dataToSign = Buffer.from(
- 'b6c5c548a7f6164c8aa7af5350901626ebd69f9ae' + '2c1ecf8871f5088ec204cfe',
- 'hex',
- );
-
- it('signs with normal R by default', () => {
- const signed = lowRKeyPair.sign(dataToSign);
- assert.deepStrictEqual(sig, signed);
- });
-
- it('signs with low R when true is passed', () => {
- const signed = lowRKeyPair.sign(dataToSign, true);
- assert.deepStrictEqual(sigLowR, signed);
- });
- });
-});
diff --git a/test/integration/addresses.spec.ts b/test/integration/addresses.spec.ts
index d8feb7c..2b24ef5 100644
--- a/test/integration/addresses.spec.ts
+++ b/test/integration/addresses.spec.ts
@@ -1,4 +1,5 @@
import * as assert from 'assert';
+import { ECPair } from 'ecpair';
import { describe, it } from 'mocha';
import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
@@ -10,7 +11,7 @@ describe('bitcoinjs-lib (addresses)', () => {
'can generate a random address [and support the retrieval of ' +
'transactions for that address (via 3PBP)]',
async () => {
- const keyPair = bitcoin.ECPair.makeRandom();
+ const keyPair = ECPair.makeRandom();
const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey });
// bitcoin P2PKH addresses start with a '1'
@@ -29,7 +30,7 @@ describe('bitcoinjs-lib (addresses)', () => {
);
it('can import an address via WIF', () => {
- const keyPair = bitcoin.ECPair.fromWIF(
+ const keyPair = ECPair.fromWIF(
'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
);
const { address } = bitcoin.payments.p2pkh({ pubkey: keyPair.publicKey });
@@ -51,7 +52,7 @@ describe('bitcoinjs-lib (addresses)', () => {
});
it('can generate a SegWit address', () => {
- const keyPair = bitcoin.ECPair.fromWIF(
+ const keyPair = ECPair.fromWIF(
'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
);
const { address } = bitcoin.payments.p2wpkh({ pubkey: keyPair.publicKey });
@@ -60,7 +61,7 @@ describe('bitcoinjs-lib (addresses)', () => {
});
it('can generate a SegWit address (via P2SH)', () => {
- const keyPair = bitcoin.ECPair.fromWIF(
+ const keyPair = ECPair.fromWIF(
'KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn',
);
const { address } = bitcoin.payments.p2sh({
@@ -103,7 +104,7 @@ describe('bitcoinjs-lib (addresses)', () => {
// examples using other network information
it('can generate a Testnet address', () => {
- const keyPair = bitcoin.ECPair.makeRandom({ network: TESTNET });
+ const keyPair = ECPair.makeRandom({ network: TESTNET });
const { address } = bitcoin.payments.p2pkh({
pubkey: keyPair.publicKey,
network: TESTNET,
@@ -130,7 +131,7 @@ describe('bitcoinjs-lib (addresses)', () => {
wif: 0xb0,
};
- const keyPair = bitcoin.ECPair.makeRandom({ network: LITECOIN });
+ const keyPair = ECPair.makeRandom({ network: LITECOIN });
const { address } = bitcoin.payments.p2pkh({
pubkey: keyPair.publicKey,
network: LITECOIN,
diff --git a/test/integration/cltv.spec.ts b/test/integration/cltv.spec.ts
index d5141c7..4b2eb66 100644
--- a/test/integration/cltv.spec.ts
+++ b/test/integration/cltv.spec.ts
@@ -1,4 +1,5 @@
import * as assert from 'assert';
+import { ECPair } from 'ecpair';
import { before, describe, it } from 'mocha';
import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
@@ -13,11 +14,11 @@ function idToHash(txid: string): Buffer {
return Buffer.from(txid, 'hex').reverse();
}
-const alice = bitcoin.ECPair.fromWIF(
+const alice = ECPair.fromWIF(
'cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe',
regtest,
);
-const bob = bitcoin.ECPair.fromWIF(
+const bob = ECPair.fromWIF(
'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x',
regtest,
);
diff --git a/test/integration/csv.spec.ts b/test/integration/csv.spec.ts
index 6f11a90..81b0943 100644
--- a/test/integration/csv.spec.ts
+++ b/test/integration/csv.spec.ts
@@ -1,5 +1,6 @@
import * as assert from 'assert';
import { PsbtInput } from 'bip174/src/lib/interfaces';
+import { ECPair } from 'ecpair';
import { before, describe, it } from 'mocha';
import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
@@ -15,19 +16,19 @@ function idToHash(txid: string): Buffer {
return Buffer.from(txid, 'hex').reverse();
}
-const alice = bitcoin.ECPair.fromWIF(
+const alice = ECPair.fromWIF(
'cScfkGjbzzoeewVWmU2hYPUHeVGJRDdFt7WhmrVVGkxpmPP8BHWe',
regtest,
);
-const bob = bitcoin.ECPair.fromWIF(
+const bob = ECPair.fromWIF(
'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsLwjHXA9x',
regtest,
);
-const charles = bitcoin.ECPair.fromWIF(
+const charles = ECPair.fromWIF(
'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMSb4Ubnf',
regtest,
);
-const dave = bitcoin.ECPair.fromWIF(
+const dave = ECPair.fromWIF(
'cMkopUXKWsEzAjfa1zApksGRwjVpJRB3831qM9W4gKZsMwS4pqnx',
regtest,
);
diff --git a/test/integration/payments.spec.ts b/test/integration/payments.spec.ts
index 58f48f5..ea7294e 100644
--- a/test/integration/payments.spec.ts
+++ b/test/integration/payments.spec.ts
@@ -1,10 +1,11 @@
+import { ECPair } from 'ecpair';
import { describe, it } from 'mocha';
import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
const NETWORK = regtestUtils.network;
const keyPairs = [
- bitcoin.ECPair.makeRandom({ network: NETWORK }),
- bitcoin.ECPair.makeRandom({ network: NETWORK }),
+ ECPair.makeRandom({ network: NETWORK }),
+ ECPair.makeRandom({ network: NETWORK }),
];
async function buildAndSign(
diff --git a/test/integration/transactions.spec.ts b/test/integration/transactions.spec.ts
index 9c98bb4..d4788dc 100644
--- a/test/integration/transactions.spec.ts
+++ b/test/integration/transactions.spec.ts
@@ -1,16 +1,23 @@
import * as assert from 'assert';
import * as bip32 from 'bip32';
+import { ECPair } from 'ecpair';
import { describe, it } from 'mocha';
import * as bitcoin from '../..';
import { regtestUtils } from './_regtest';
const rng = require('randombytes');
const regtest = regtestUtils.network;
+const validator = (
+ pubkey: Buffer,
+ msghash: Buffer,
+ signature: Buffer,
+): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
+
// See bottom of file for some helper functions used to make the payment objects needed.
describe('bitcoinjs-lib (transactions with psbt)', () => {
it('can create a 1-to-1 Transaction', () => {
- const alice = bitcoin.ECPair.fromWIF(
+ const alice = ECPair.fromWIF(
'L2uPYXe17xSTqbCjZvL2DsyXPCbXspvcu5mHLDYUgzdUbZGSKrSr',
);
const psbt = new bitcoin.Psbt();
@@ -59,7 +66,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
value: 80000,
});
psbt.signInput(0, alice);
- psbt.validateSignaturesOfInput(0);
+ psbt.validateSignaturesOfInput(0, validator);
psbt.finalizeAllInputs();
assert.strictEqual(
psbt.extractTransaction().toHex(),
@@ -147,8 +154,8 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
// Finalizer wants to check all signatures are valid before finalizing.
// If the finalizer wants to check for specific pubkeys, the second arg
// can be passed. See the first multisig example below.
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
- assert.strictEqual(psbt.validateSignaturesOfInput(1), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(1, validator), true);
// This step it new. Since we separate the signing operation and
// the creation of the scriptSig and witness stack, we are able to
@@ -183,7 +190,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
})
.signInput(0, alice1.keys[0]);
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
psbt.finalizeAllInputs();
// build and broadcast to the RegTest network
@@ -215,13 +222,13 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
.signInput(0, multisig.keys[0])
.signInput(0, multisig.keys[2]);
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
assert.strictEqual(
- psbt.validateSignaturesOfInput(0, multisig.keys[0].publicKey),
+ psbt.validateSignaturesOfInput(0, validator, multisig.keys[0].publicKey),
true,
);
assert.throws(() => {
- psbt.validateSignaturesOfInput(0, multisig.keys[3].publicKey);
+ psbt.validateSignaturesOfInput(0, validator, multisig.keys[3].publicKey);
}, new RegExp('No signatures for this pubkey'));
psbt.finalizeAllInputs();
@@ -330,7 +337,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
})
.signInput(0, p2wpkh.keys[0]);
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
@@ -398,7 +405,7 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
})
.signInput(0, p2wsh.keys[0]);
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
psbt.finalizeAllInputs();
const tx = psbt.extractTransaction();
@@ -472,13 +479,13 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
.signInput(0, p2sh.keys[2])
.signInput(0, p2sh.keys[3]);
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
assert.strictEqual(
- psbt.validateSignaturesOfInput(0, p2sh.keys[3].publicKey),
+ psbt.validateSignaturesOfInput(0, validator, p2sh.keys[3].publicKey),
true,
);
assert.throws(() => {
- psbt.validateSignaturesOfInput(0, p2sh.keys[1].publicKey);
+ psbt.validateSignaturesOfInput(0, validator, p2sh.keys[1].publicKey);
}, new RegExp('No signatures for this pubkey'));
psbt.finalizeAllInputs();
@@ -534,10 +541,10 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
'can create (and broadcast via 3PBP) a Transaction, w/ a ' +
'P2SH(P2MS(2 of 2)) input with nonWitnessUtxo',
async () => {
- const myKey = bitcoin.ECPair.makeRandom({ network: regtest });
+ const myKey = ECPair.makeRandom({ network: regtest });
const myKeys = [
myKey,
- bitcoin.ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }),
+ ECPair.fromPrivateKey(myKey.privateKey!, { network: regtest }),
];
const p2sh = createPayment('p2sh-p2ms(2 of 2)', myKeys);
const inputData = await getInputData(5e4, p2sh.payment, false, 'p2sh');
@@ -603,9 +610,9 @@ describe('bitcoinjs-lib (transactions with psbt)', () => {
})
.signInputHD(0, hdRoot); // must sign with root!!!
- assert.strictEqual(psbt.validateSignaturesOfInput(0), true);
+ assert.strictEqual(psbt.validateSignaturesOfInput(0, validator), true);
assert.strictEqual(
- psbt.validateSignaturesOfInput(0, childNode.publicKey),
+ psbt.validateSignaturesOfInput(0, validator, childNode.publicKey),
true,
);
psbt.finalizeAllInputs();
@@ -638,11 +645,11 @@ function createPayment(_type: string, myKeys?: any[], network?: any): any {
throw new Error('Need n keys for multisig');
}
while (!myKeys && n > 1) {
- keys.push(bitcoin.ECPair.makeRandom({ network }));
+ keys.push(ECPair.makeRandom({ network }));
n--;
}
}
- if (!myKeys) keys.push(bitcoin.ECPair.makeRandom({ network }));
+ if (!myKeys) keys.push(ECPair.makeRandom({ network }));
let payment: any;
splitType.forEach(type => {
diff --git a/test/psbt.spec.ts b/test/psbt.spec.ts
index f203324..1c6cb09 100644
--- a/test/psbt.spec.ts
+++ b/test/psbt.spec.ts
@@ -1,10 +1,10 @@
import * as assert from 'assert';
import * as crypto from 'crypto';
+import { ECPair } from 'ecpair';
import { describe, it } from 'mocha';
import {
bip32,
- ECPair,
networks as NETWORKS,
payments,
Psbt,
@@ -14,6 +14,12 @@ import {
import * as preFixtures from './fixtures/psbt.json';
+const validator = (
+ pubkey: Buffer,
+ msghash: Buffer,
+ signature: Buffer,
+): boolean => ECPair.fromPublicKey(pubkey).verify(msghash, signature);
+
const initBuffers = (object: any): typeof preFixtures =>
JSON.parse(JSON.stringify(object), (_, value) => {
const regex = new RegExp(/^Buffer.from\(['"](.*)['"], ['"](.*)['"]\)$/);
@@ -896,7 +902,7 @@ describe(`Psbt`, () => {
const notAClone = Object.assign(new Psbt(), psbt); // references still active
const clone = psbt.clone();
- assert.strictEqual(psbt.validateSignaturesOfAllInputs(), true);
+ assert.strictEqual(psbt.validateSignaturesOfAllInputs(validator), true);
assert.strictEqual(clone.toBase64(), psbt.toBase64());
assert.strictEqual(clone.toBase64(), notAClone.toBase64());
@@ -923,20 +929,27 @@ describe(`Psbt`, () => {
it('Correctly validates a signature', () => {
const psbt = Psbt.fromBase64(f.psbt);
- assert.strictEqual(psbt.validateSignaturesOfInput(f.index), true);
+ assert.strictEqual(
+ psbt.validateSignaturesOfInput(f.index, validator),
+ true,
+ );
assert.throws(() => {
- psbt.validateSignaturesOfInput(f.nonExistantIndex);
+ psbt.validateSignaturesOfInput(f.nonExistantIndex, validator);
}, new RegExp('No signatures to validate'));
});
it('Correctly validates a signature against a pubkey', () => {
const psbt = Psbt.fromBase64(f.psbt);
assert.strictEqual(
- psbt.validateSignaturesOfInput(f.index, f.pubkey as any),
+ psbt.validateSignaturesOfInput(f.index, validator, f.pubkey as any),
true,
);
assert.throws(() => {
- psbt.validateSignaturesOfInput(f.index, f.incorrectPubkey as any);
+ psbt.validateSignaturesOfInput(
+ f.index,
+ validator,
+ f.incorrectPubkey as any,
+ );
}, new RegExp('No signatures for this pubkey'));
});
});
@@ -985,7 +998,7 @@ describe(`Psbt`, () => {
assert.throws(() => {
psbt.setVersion(3);
}, new RegExp('Can not modify transaction, signatures exist.'));
- psbt.validateSignaturesOfInput(0);
+ psbt.validateSignaturesOfInput(0, validator);
psbt.finalizeAllInputs();
assert.throws(() => {
psbt.setVersion(3);
diff --git a/test/tsconfig.json b/test/tsconfig.json
index e29620d..4e4f529 100644
--- a/test/tsconfig.json
+++ b/test/tsconfig.json
@@ -1,6 +1,6 @@
{
"compilerOptions": {
- "target": "ES2017",
+ "target": "ESNEXT",
"module": "commonjs",
"outDir": "../",
"declaration": false,
diff --git a/ts_src/address.ts b/ts_src/address.ts
index 11be51b..d8111a7 100644
--- a/ts_src/address.ts
+++ b/ts_src/address.ts
@@ -3,10 +3,9 @@ import * as networks from './networks';
import * as payments from './payments';
import * as bscript from './script';
import * as types from './types';
-
-const { bech32, bech32m } = require('bech32');
-const bs58check = require('bs58check');
-const typeforce = require('typeforce');
+import { bech32, bech32m } from 'bech32';
+import * as bs58check from 'bs58check';
+const { typeforce } = types;
export interface Base58CheckResult {
hash: Buffer;
diff --git a/ts_src/bip66.ts b/ts_src/bip66.ts
new file mode 100644
index 0000000..ab76a4f
--- /dev/null
+++ b/ts_src/bip66.ts
@@ -0,0 +1,111 @@
+// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
+// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
+// NOTE: SIGHASH byte ignored AND restricted, truncate before use
+
+export function check(buffer: Buffer): boolean {
+ if (buffer.length < 8) return false;
+ if (buffer.length > 72) return false;
+ if (buffer[0] !== 0x30) return false;
+ if (buffer[1] !== buffer.length - 2) return false;
+ if (buffer[2] !== 0x02) return false;
+
+ const lenR = buffer[3];
+ if (lenR === 0) return false;
+ if (5 + lenR >= buffer.length) return false;
+ if (buffer[4 + lenR] !== 0x02) return false;
+
+ const lenS = buffer[5 + lenR];
+ if (lenS === 0) return false;
+ if (6 + lenR + lenS !== buffer.length) return false;
+
+ if (buffer[4] & 0x80) return false;
+ if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
+
+ if (buffer[lenR + 6] & 0x80) return false;
+ if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
+ return false;
+ return true;
+}
+
+export function decode(buffer: Buffer): { r: Buffer; s: Buffer } {
+ if (buffer.length < 8) throw new Error('DER sequence length is too short');
+ if (buffer.length > 72) throw new Error('DER sequence length is too long');
+ if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
+ if (buffer[1] !== buffer.length - 2)
+ throw new Error('DER sequence length is invalid');
+ if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
+
+ const lenR = buffer[3];
+ if (lenR === 0) throw new Error('R length is zero');
+ if (5 + lenR >= buffer.length) throw new Error('R length is too long');
+ if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
+
+ const lenS = buffer[5 + lenR];
+ if (lenS === 0) throw new Error('S length is zero');
+ if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
+
+ if (buffer[4] & 0x80) throw new Error('R value is negative');
+ if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
+ throw new Error('R value excessively padded');
+
+ if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
+ if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
+ throw new Error('S value excessively padded');
+
+ // non-BIP66 - extract R, S values
+ return {
+ r: buffer.slice(4, 4 + lenR),
+ s: buffer.slice(6 + lenR),
+ };
+}
+
+/*
+ * Expects r and s to be positive DER integers.
+ *
+ * The DER format uses the most significant bit as a sign bit (& 0x80).
+ * If the significant bit is set AND the integer is positive, a 0x00 is prepended.
+ *
+ * Examples:
+ *
+ * 0 => 0x00
+ * 1 => 0x01
+ * -1 => 0xff
+ * 127 => 0x7f
+ * -127 => 0x81
+ * 128 => 0x0080
+ * -128 => 0x80
+ * 255 => 0x00ff
+ * -255 => 0xff01
+ * 16300 => 0x3fac
+ * -16300 => 0xc054
+ * 62300 => 0x00f35c
+ * -62300 => 0xff0ca4
+ */
+export function encode(r: Buffer, s: Buffer): Buffer {
+ const lenR = r.length;
+ const lenS = s.length;
+ if (lenR === 0) throw new Error('R length is zero');
+ if (lenS === 0) throw new Error('S length is zero');
+ if (lenR > 33) throw new Error('R length is too long');
+ if (lenS > 33) throw new Error('S length is too long');
+ if (r[0] & 0x80) throw new Error('R value is negative');
+ if (s[0] & 0x80) throw new Error('S value is negative');
+ if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
+ throw new Error('R value excessively padded');
+ if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
+ throw new Error('S value excessively padded');
+
+ const signature = Buffer.allocUnsafe(6 + lenR + lenS);
+
+ // 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
+ signature[0] = 0x30;
+ signature[1] = signature.length - 2;
+ signature[2] = 0x02;
+ signature[3] = r.length;
+ r.copy(signature, 4);
+ signature[4 + lenR] = 0x02;
+ signature[5 + lenR] = s.length;
+ s.copy(signature, 6 + lenR);
+
+ return signature;
+}
diff --git a/ts_src/block.ts b/ts_src/block.ts
index 2760e5e..c73477e 100644
--- a/ts_src/block.ts
+++ b/ts_src/block.ts
@@ -1,11 +1,14 @@
-import { BufferReader, BufferWriter, reverseBuffer } from './bufferutils';
+import {
+ BufferReader,
+ BufferWriter,
+ reverseBuffer,
+ varuint,
+} from './bufferutils';
import * as bcrypto from './crypto';
+import { fastMerkleRoot } from './merkle';
import { Transaction } from './transaction';
import * as types from './types';
-
-const fastMerkleRoot = require('merkle-lib/fastRoot');
-const typeforce = require('typeforce');
-const varuint = require('varuint-bitcoin');
+const { typeforce } = types;
const errorMerkleNoTxes = new TypeError(
'Cannot compute merkle root for zero transactions',
diff --git a/ts_src/bufferutils.ts b/ts_src/bufferutils.ts
index 9005f2a..43171c4 100644
--- a/ts_src/bufferutils.ts
+++ b/ts_src/bufferutils.ts
@@ -1,7 +1,7 @@
import * as types from './types';
-
-const typeforce = require('typeforce');
-const varuint = require('varuint-bitcoin');
+const { typeforce } = types;
+import * as varuint from 'varuint-bitcoin';
+export { varuint };
// https://github.com/feross/buffer/blob/master/index.js#L1127
function verifuint(value: number, max: number): void {
diff --git a/ts_src/crypto.ts b/ts_src/crypto.ts
index 1cb5a69..7f69c40 100644
--- a/ts_src/crypto.ts
+++ b/ts_src/crypto.ts
@@ -1,4 +1,4 @@
-const createHash = require('create-hash');
+import * as createHash from 'create-hash';
export function ripemd160(buffer: Buffer): Buffer {
try {
diff --git a/ts_src/ecpair.ts b/ts_src/ecpair.ts
deleted file mode 100644
index 3c7eb1c..0000000
--- a/ts_src/ecpair.ts
+++ /dev/null
@@ -1,161 +0,0 @@
-import { Network } from './networks';
-import * as NETWORKS from './networks';
-import * as types from './types';
-const ecc = require('tiny-secp256k1');
-const randomBytes = require('randombytes');
-const typeforce = require('typeforce');
-const wif = require('wif');
-
-const isOptions = typeforce.maybe(
- typeforce.compile({
- compressed: types.maybe(types.Boolean),
- network: types.maybe(types.Network),
- }),
-);
-
-interface ECPairOptions {
- compressed?: boolean;
- network?: Network;
- rng?(arg0: number): Buffer;
-}
-
-export interface Signer {
- publicKey: Buffer;
- network?: any;
- sign(hash: Buffer, lowR?: boolean): Buffer;
- getPublicKey?(): Buffer;
-}
-
-export interface SignerAsync {
- publicKey: Buffer;
- network?: any;
- sign(hash: Buffer, lowR?: boolean): Promise;
- getPublicKey?(): Buffer;
-}
-
-export interface ECPairInterface extends Signer {
- compressed: boolean;
- network: Network;
- lowR: boolean;
- privateKey?: Buffer;
- toWIF(): string;
- verify(hash: Buffer, signature: Buffer): boolean;
-}
-
-class ECPair implements ECPairInterface {
- compressed: boolean;
- network: Network;
- lowR: boolean;
-
- constructor(
- private __D?: Buffer,
- private __Q?: Buffer,
- options?: ECPairOptions,
- ) {
- this.lowR = false;
- if (options === undefined) options = {};
- this.compressed =
- options.compressed === undefined ? true : options.compressed;
- this.network = options.network || NETWORKS.bitcoin;
-
- if (__Q !== undefined) this.__Q = ecc.pointCompress(__Q, this.compressed);
- }
-
- get privateKey(): Buffer | undefined {
- return this.__D;
- }
-
- get publicKey(): Buffer {
- if (!this.__Q)
- this.__Q = ecc.pointFromScalar(this.__D, this.compressed) as Buffer;
- return this.__Q;
- }
-
- toWIF(): string {
- if (!this.__D) throw new Error('Missing private key');
- return wif.encode(this.network.wif, this.__D, this.compressed);
- }
-
- sign(hash: Buffer, lowR?: boolean): Buffer {
- if (!this.__D) throw new Error('Missing private key');
- if (lowR === undefined) lowR = this.lowR;
- if (lowR === false) {
- return ecc.sign(hash, this.__D);
- } else {
- let sig = ecc.sign(hash, this.__D);
- const extraData = Buffer.alloc(32, 0);
- let counter = 0;
- // if first try is lowR, skip the loop
- // for second try and on, add extra entropy counting up
- while (sig[0] > 0x7f) {
- counter++;
- extraData.writeUIntLE(counter, 0, 6);
- sig = ecc.signWithEntropy(hash, this.__D, extraData);
- }
- return sig;
- }
- }
-
- verify(hash: Buffer, signature: Buffer): boolean {
- return ecc.verify(hash, this.publicKey, signature);
- }
-}
-
-function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair {
- typeforce(types.Buffer256bit, buffer);
- if (!ecc.isPrivate(buffer))
- throw new TypeError('Private key not in range [1, n)');
- typeforce(isOptions, options);
-
- return new ECPair(buffer, undefined, options);
-}
-
-function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair {
- typeforce(ecc.isPoint, buffer);
- typeforce(isOptions, options);
- return new ECPair(undefined, buffer, options);
-}
-
-function fromWIF(wifString: string, network?: Network | Network[]): ECPair {
- const decoded = wif.decode(wifString);
- const version = decoded.version;
-
- // list of networks?
- if (types.Array(network)) {
- network = (network as Network[])
- .filter((x: Network) => {
- return version === x.wif;
- })
- .pop() as Network;
-
- if (!network) throw new Error('Unknown network version');
-
- // otherwise, assume a network object (or default to bitcoin)
- } else {
- network = network || NETWORKS.bitcoin;
-
- if (version !== (network as Network).wif)
- throw new Error('Invalid network version');
- }
-
- return fromPrivateKey(decoded.privateKey, {
- compressed: decoded.compressed,
- network: network as Network,
- });
-}
-
-function makeRandom(options?: ECPairOptions): ECPair {
- typeforce(isOptions, options);
- if (options === undefined) options = {};
- const rng = options.rng || randomBytes;
-
- let d;
- do {
- d = rng(32);
- typeforce(types.Buffer256bit, d);
- } while (!ecc.isPrivate(d));
-
- return fromPrivateKey(d, options);
-}
-
-export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF };
diff --git a/ts_src/index.ts b/ts_src/index.ts
index c425d96..66b2f9c 100644
--- a/ts_src/index.ts
+++ b/ts_src/index.ts
@@ -1,20 +1,26 @@
import * as bip32 from 'bip32';
import * as address from './address';
import * as crypto from './crypto';
-import * as ECPair from './ecpair';
import * as networks from './networks';
import * as payments from './payments';
import * as script from './script';
-export { ECPair, address, bip32, crypto, networks, payments, script };
+export { address, bip32, crypto, networks, payments, script };
export { Block } from './block';
-export { Psbt, PsbtTxInput, PsbtTxOutput } from './psbt';
-export { OPS as opcodes } from './script';
+export {
+ Psbt,
+ PsbtTxInput,
+ PsbtTxOutput,
+ Signer,
+ SignerAsync,
+ HDSigner,
+ HDSignerAsync,
+} from './psbt';
+export { OPS as opcodes } from './ops';
export { Transaction } from './transaction';
export { BIP32Interface } from 'bip32';
-export { ECPairInterface, Signer, SignerAsync } from './ecpair';
export { Network } from './networks';
export {
Payment,
@@ -23,5 +29,4 @@ export {
Stack,
StackElement,
} from './payments';
-export { OpCode } from './script';
export { Input as TxInput, Output as TxOutput } from './transaction';
diff --git a/ts_src/merkle.ts b/ts_src/merkle.ts
new file mode 100644
index 0000000..8ff8c3f
--- /dev/null
+++ b/ts_src/merkle.ts
@@ -0,0 +1,27 @@
+export function fastMerkleRoot(
+ values: Buffer[],
+ digestFn: (b: Buffer) => Buffer,
+): Buffer {
+ if (!Array.isArray(values)) throw TypeError('Expected values Array');
+ if (typeof digestFn !== 'function')
+ throw TypeError('Expected digest Function');
+
+ let length = values.length;
+ const results = values.concat();
+
+ while (length > 1) {
+ let j = 0;
+
+ for (let i = 0; i < length; i += 2, ++j) {
+ const left = results[i];
+ const right = i + 1 === length ? left : results[i + 1];
+ const data = Buffer.concat([left, right]);
+
+ results[j] = digestFn(data);
+ }
+
+ length = j;
+ }
+
+ return results[0];
+}
diff --git a/ts_src/ops.ts b/ts_src/ops.ts
new file mode 100644
index 0000000..8e2c41c
--- /dev/null
+++ b/ts_src/ops.ts
@@ -0,0 +1,141 @@
+const OPS: { [key: string]: number } = {
+ OP_FALSE: 0,
+ OP_0: 0,
+ OP_PUSHDATA1: 76,
+ OP_PUSHDATA2: 77,
+ OP_PUSHDATA4: 78,
+ OP_1NEGATE: 79,
+ OP_RESERVED: 80,
+ OP_TRUE: 81,
+ OP_1: 81,
+ OP_2: 82,
+ OP_3: 83,
+ OP_4: 84,
+ OP_5: 85,
+ OP_6: 86,
+ OP_7: 87,
+ OP_8: 88,
+ OP_9: 89,
+ OP_10: 90,
+ OP_11: 91,
+ OP_12: 92,
+ OP_13: 93,
+ OP_14: 94,
+ OP_15: 95,
+ OP_16: 96,
+
+ OP_NOP: 97,
+ OP_VER: 98,
+ OP_IF: 99,
+ OP_NOTIF: 100,
+ OP_VERIF: 101,
+ OP_VERNOTIF: 102,
+ OP_ELSE: 103,
+ OP_ENDIF: 104,
+ OP_VERIFY: 105,
+ OP_RETURN: 106,
+
+ OP_TOALTSTACK: 107,
+ OP_FROMALTSTACK: 108,
+ OP_2DROP: 109,
+ OP_2DUP: 110,
+ OP_3DUP: 111,
+ OP_2OVER: 112,
+ OP_2ROT: 113,
+ OP_2SWAP: 114,
+ OP_IFDUP: 115,
+ OP_DEPTH: 116,
+ OP_DROP: 117,
+ OP_DUP: 118,
+ OP_NIP: 119,
+ OP_OVER: 120,
+ OP_PICK: 121,
+ OP_ROLL: 122,
+ OP_ROT: 123,
+ OP_SWAP: 124,
+ OP_TUCK: 125,
+
+ OP_CAT: 126,
+ OP_SUBSTR: 127,
+ OP_LEFT: 128,
+ OP_RIGHT: 129,
+ OP_SIZE: 130,
+
+ OP_INVERT: 131,
+ OP_AND: 132,
+ OP_OR: 133,
+ OP_XOR: 134,
+ OP_EQUAL: 135,
+ OP_EQUALVERIFY: 136,
+ OP_RESERVED1: 137,
+ OP_RESERVED2: 138,
+
+ OP_1ADD: 139,
+ OP_1SUB: 140,
+ OP_2MUL: 141,
+ OP_2DIV: 142,
+ OP_NEGATE: 143,
+ OP_ABS: 144,
+ OP_NOT: 145,
+ OP_0NOTEQUAL: 146,
+ OP_ADD: 147,
+ OP_SUB: 148,
+ OP_MUL: 149,
+ OP_DIV: 150,
+ OP_MOD: 151,
+ OP_LSHIFT: 152,
+ OP_RSHIFT: 153,
+
+ OP_BOOLAND: 154,
+ OP_BOOLOR: 155,
+ OP_NUMEQUAL: 156,
+ OP_NUMEQUALVERIFY: 157,
+ OP_NUMNOTEQUAL: 158,
+ OP_LESSTHAN: 159,
+ OP_GREATERTHAN: 160,
+ OP_LESSTHANOREQUAL: 161,
+ OP_GREATERTHANOREQUAL: 162,
+ OP_MIN: 163,
+ OP_MAX: 164,
+
+ OP_WITHIN: 165,
+
+ OP_RIPEMD160: 166,
+ OP_SHA1: 167,
+ OP_SHA256: 168,
+ OP_HASH160: 169,
+ OP_HASH256: 170,
+ OP_CODESEPARATOR: 171,
+ OP_CHECKSIG: 172,
+ OP_CHECKSIGVERIFY: 173,
+ OP_CHECKMULTISIG: 174,
+ OP_CHECKMULTISIGVERIFY: 175,
+
+ OP_NOP1: 176,
+
+ OP_NOP2: 177,
+ OP_CHECKLOCKTIMEVERIFY: 177,
+
+ OP_NOP3: 178,
+ OP_CHECKSEQUENCEVERIFY: 178,
+
+ OP_NOP4: 179,
+ OP_NOP5: 180,
+ OP_NOP6: 181,
+ OP_NOP7: 182,
+ OP_NOP8: 183,
+ OP_NOP9: 184,
+ OP_NOP10: 185,
+
+ OP_PUBKEYHASH: 253,
+ OP_PUBKEY: 254,
+ OP_INVALIDOPCODE: 255,
+};
+
+const REVERSE_OPS: { [key: number]: string } = {};
+for (const op of Object.keys(OPS)) {
+ const code = OPS[op];
+ REVERSE_OPS[code] = op;
+}
+
+export { OPS, REVERSE_OPS };
diff --git a/ts_src/payments/embed.ts b/ts_src/payments/embed.ts
index c54e279..c479b89 100644
--- a/ts_src/payments/embed.ts
+++ b/ts_src/payments/embed.ts
@@ -1,9 +1,9 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { typeforce as typef } from '../types';
import { Payment, PaymentOpts, Stack } from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
const OPS = bscript.OPS;
function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
diff --git a/ts_src/payments/p2ms.ts b/ts_src/payments/p2ms.ts
index 7cd6f10..eaa1440 100644
--- a/ts_src/payments/p2ms.ts
+++ b/ts_src/payments/p2ms.ts
@@ -1,10 +1,9 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { isPoint, typeforce as typef } from '../types';
import { Payment, PaymentOpts, Stack } from './index';
import * as lazy from './lazy';
const OPS = bscript.OPS;
-const typef = require('typeforce');
-const ecc = require('tiny-secp256k1');
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
@@ -41,7 +40,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment {
m: typef.maybe(typef.Number),
n: typef.maybe(typef.Number),
output: typef.maybe(typef.Buffer),
- pubkeys: typef.maybe(typef.arrayOf(ecc.isPoint)),
+ pubkeys: typef.maybe(typef.arrayOf(isPoint)),
signatures: typef.maybe(typef.arrayOf(isAcceptableSignature)),
input: typef.maybe(typef.Buffer),
@@ -119,7 +118,7 @@ export function p2ms(a: Payment, opts?: PaymentOpts): Payment {
if (o.m! <= 0 || o.n! > 16 || o.m! > o.n! || o.n !== chunks.length - 3)
throw new TypeError('Output is invalid');
- if (!o.pubkeys!.every(x => ecc.isPoint(x)))
+ if (!o.pubkeys!.every(x => isPoint(x)))
throw new TypeError('Output is invalid');
if (a.m !== undefined && a.m !== o.m) throw new TypeError('m mismatch');
diff --git a/ts_src/payments/p2pk.ts b/ts_src/payments/p2pk.ts
index b4fdbc5..7273f53 100644
--- a/ts_src/payments/p2pk.ts
+++ b/ts_src/payments/p2pk.ts
@@ -1,10 +1,9 @@
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { isPoint, typeforce as typef } from '../types';
import { Payment, PaymentOpts, StackFunction } from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
// input: {signature}
// output: {pubKey} OP_CHECKSIG
@@ -17,7 +16,7 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment {
{
network: typef.maybe(typef.Object),
output: typef.maybe(typef.Buffer),
- pubkey: typef.maybe(ecc.isPoint),
+ pubkey: typef.maybe(isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
input: typef.maybe(typef.Buffer),
@@ -58,8 +57,7 @@ export function p2pk(a: Payment, opts?: PaymentOpts): Payment {
if (a.output) {
if (a.output[a.output.length - 1] !== OPS.OP_CHECKSIG)
throw new TypeError('Output is invalid');
- if (!ecc.isPoint(o.pubkey))
- throw new TypeError('Output pubkey is invalid');
+ if (!isPoint(o.pubkey)) throw new TypeError('Output pubkey is invalid');
if (a.pubkey && !a.pubkey.equals(o.pubkey!))
throw new TypeError('Pubkey mismatch');
}
diff --git a/ts_src/payments/p2pkh.ts b/ts_src/payments/p2pkh.ts
index 6503093..3b5bd6f 100644
--- a/ts_src/payments/p2pkh.ts
+++ b/ts_src/payments/p2pkh.ts
@@ -1,13 +1,11 @@
import * as bcrypto from '../crypto';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { isPoint, typeforce as typef } from '../types';
import { Payment, PaymentOpts, StackFunction } from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
+import * as bs58check from 'bs58check';
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
-
-const bs58check = require('bs58check');
// input: {signature} {pubkey}
// output: OP_DUP OP_HASH160 {hash160(pubkey)} OP_EQUALVERIFY OP_CHECKSIG
@@ -23,7 +21,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment {
hash: typef.maybe(typef.BufferN(20)),
output: typef.maybe(typef.BufferN(25)),
- pubkey: typef.maybe(ecc.isPoint),
+ pubkey: typef.maybe(isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
input: typef.maybe(typef.Buffer),
},
@@ -31,7 +29,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment {
);
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address);
+ const payload = bs58check.decode(a.address!);
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
@@ -129,8 +127,7 @@ export function p2pkh(a: Payment, opts?: PaymentOpts): Payment {
if (chunks.length !== 2) throw new TypeError('Input is invalid');
if (!bscript.isCanonicalScriptSignature(chunks[0] as Buffer))
throw new TypeError('Input has invalid signature');
- if (!ecc.isPoint(chunks[1]))
- throw new TypeError('Input has invalid pubkey');
+ if (!isPoint(chunks[1])) throw new TypeError('Input has invalid pubkey');
if (a.signature && !a.signature.equals(chunks[0] as Buffer))
throw new TypeError('Signature mismatch');
diff --git a/ts_src/payments/p2sh.ts b/ts_src/payments/p2sh.ts
index 3b53fdc..9be5a8c 100644
--- a/ts_src/payments/p2sh.ts
+++ b/ts_src/payments/p2sh.ts
@@ -1,6 +1,7 @@
import * as bcrypto from '../crypto';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { typeforce as typef } from '../types';
import {
Payment,
PaymentFunction,
@@ -9,11 +10,9 @@ import {
StackFunction,
} from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
+import * as bs58check from 'bs58check';
const OPS = bscript.OPS;
-const bs58check = require('bs58check');
-
function stacksEqual(a: Buffer[], b: Buffer[]): boolean {
if (a.length !== b.length) return false;
@@ -58,7 +57,7 @@ export function p2sh(a: Payment, opts?: PaymentOpts): Payment {
const o: Payment = { network };
const _address = lazy.value(() => {
- const payload = bs58check.decode(a.address);
+ const payload = bs58check.decode(a.address!);
const version = payload.readUInt8(0);
const hash = payload.slice(1);
return { version, hash };
diff --git a/ts_src/payments/p2wpkh.ts b/ts_src/payments/p2wpkh.ts
index 3d8f86f..a4497fe 100644
--- a/ts_src/payments/p2wpkh.ts
+++ b/ts_src/payments/p2wpkh.ts
@@ -1,13 +1,11 @@
import * as bcrypto from '../crypto';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { isPoint, typeforce as typef } from '../types';
import { Payment, PaymentOpts } from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
+import { bech32 } from 'bech32';
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
-
-const { bech32 } = require('bech32');
const EMPTY_BUFFER = Buffer.alloc(0);
@@ -26,7 +24,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment {
input: typef.maybe(typef.BufferN(0)),
network: typef.maybe(typef.Object),
output: typef.maybe(typef.BufferN(22)),
- pubkey: typef.maybe(ecc.isPoint),
+ pubkey: typef.maybe(isPoint),
signature: typef.maybe(bscript.isCanonicalScriptSignature),
witness: typef.maybe(typef.arrayOf(typef.Buffer)),
},
@@ -34,7 +32,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment {
);
const _address = lazy.value(() => {
- const result = bech32.decode(a.address);
+ const result = bech32.decode(a.address!);
const version = result.words.shift();
const data = bech32.fromWords(result.words);
return {
@@ -118,7 +116,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment {
if (hash.length > 0 && !hash.equals(pkh))
throw new TypeError('Hash mismatch');
else hash = pkh;
- if (!ecc.isPoint(a.pubkey) || a.pubkey.length !== 33)
+ if (!isPoint(a.pubkey) || a.pubkey.length !== 33)
throw new TypeError('Invalid pubkey for p2wpkh');
}
@@ -126,7 +124,7 @@ export function p2wpkh(a: Payment, opts?: PaymentOpts): Payment {
if (a.witness.length !== 2) throw new TypeError('Witness is invalid');
if (!bscript.isCanonicalScriptSignature(a.witness[0]))
throw new TypeError('Witness has invalid signature');
- if (!ecc.isPoint(a.witness[1]) || a.witness[1].length !== 33)
+ if (!isPoint(a.witness[1]) || a.witness[1].length !== 33)
throw new TypeError('Witness has invalid pubkey');
if (a.signature && !a.signature.equals(a.witness[0]))
diff --git a/ts_src/payments/p2wsh.ts b/ts_src/payments/p2wsh.ts
index e28cd57..00860e0 100644
--- a/ts_src/payments/p2wsh.ts
+++ b/ts_src/payments/p2wsh.ts
@@ -1,13 +1,11 @@
import * as bcrypto from '../crypto';
import { bitcoin as BITCOIN_NETWORK } from '../networks';
import * as bscript from '../script';
+import { isPoint, typeforce as typef } from '../types';
import { Payment, PaymentOpts, StackElement, StackFunction } from './index';
import * as lazy from './lazy';
-const typef = require('typeforce');
+import { bech32 } from 'bech32';
const OPS = bscript.OPS;
-const ecc = require('tiny-secp256k1');
-
-const { bech32 } = require('bech32');
const EMPTY_BUFFER = Buffer.alloc(0);
@@ -24,7 +22,7 @@ function chunkHasUncompressedPubkey(chunk: StackElement): boolean {
Buffer.isBuffer(chunk) &&
chunk.length === 65 &&
chunk[0] === 0x04 &&
- ecc.isPoint(chunk)
+ isPoint(chunk)
) {
return true;
} else {
@@ -61,7 +59,7 @@ export function p2wsh(a: Payment, opts?: PaymentOpts): Payment {
);
const _address = lazy.value(() => {
- const result = bech32.decode(a.address);
+ const result = bech32.decode(a.address!);
const version = result.words.shift();
const data = bech32.fromWords(result.words);
return {
diff --git a/ts_src/psbt.ts b/ts_src/psbt.ts
index c23fa1f..b9af10f 100644
--- a/ts_src/psbt.ts
+++ b/ts_src/psbt.ts
@@ -16,11 +16,6 @@ import { checkForInput, checkForOutput } from 'bip174/src/lib/utils';
import { fromOutputScript, toOutputScript } from './address';
import { cloneBuffer, reverseBuffer } from './bufferutils';
import { hash160 } from './crypto';
-import {
- fromPublicKey as ecPairFromPublicKey,
- Signer,
- SignerAsync,
-} from './ecpair';
import { bitcoin as btcNetwork, Network } from './networks';
import * as payments from './payments';
import * as bscript from './script';
@@ -45,6 +40,13 @@ export interface PsbtTxOutput extends TransactionOutput {
address: string | undefined;
}
+// msghash is 32 byte hash of preimage, signature is 64 byte compact signature (r,s 32 bytes each)
+export type ValidateSigFunction = (
+ pubkey: Buffer,
+ msghash: Buffer,
+ signature: Buffer,
+) => boolean;
+
/**
* These are the default arguments for a Psbt instance.
*/
@@ -416,19 +418,25 @@ export class Psbt {
);
}
- validateSignaturesOfAllInputs(): boolean {
+ validateSignaturesOfAllInputs(validator: ValidateSigFunction): boolean {
checkForInput(this.data.inputs, 0); // making sure we have at least one
const results = range(this.data.inputs.length).map(idx =>
- this.validateSignaturesOfInput(idx),
+ this.validateSignaturesOfInput(idx, validator),
);
return results.reduce((final, res) => res === true && final, true);
}
- validateSignaturesOfInput(inputIndex: number, pubkey?: Buffer): boolean {
+ validateSignaturesOfInput(
+ inputIndex: number,
+ validator: ValidateSigFunction,
+ pubkey?: Buffer,
+ ): boolean {
const input = this.data.inputs[inputIndex];
const partialSig = (input || {}).partialSig;
if (!input || !partialSig || partialSig.length < 1)
throw new Error('No signatures to validate');
+ if (typeof validator !== 'function')
+ throw new Error('Need validator function to validate signatures');
const mySigs = pubkey
? partialSig.filter(sig => sig.pubkey.equals(pubkey))
: partialSig;
@@ -452,8 +460,7 @@ export class Psbt {
hashCache = hash;
scriptCache = script;
checkScriptForPubkey(pSig.pubkey, script, 'verify');
- const keypair = ecPairFromPublicKey(pSig.pubkey);
- results.push(keypair.verify(hash, sig.signature));
+ results.push(validator(pSig.pubkey, hash, sig.signature));
}
return results.every(res => res === true);
}
@@ -780,7 +787,7 @@ interface HDSignerBase {
fingerprint: Buffer;
}
-interface HDSigner extends HDSignerBase {
+export interface HDSigner extends HDSignerBase {
/**
* The path string must match /^m(\/\d+'?)+$/
* ex. m/44'/0'/0'/1/23 levels with ' must be hard derivations
@@ -796,11 +803,25 @@ interface HDSigner extends HDSignerBase {
/**
* Same as above but with async sign method
*/
-interface HDSignerAsync extends HDSignerBase {
+export interface HDSignerAsync extends HDSignerBase {
derivePath(path: string): HDSignerAsync;
sign(hash: Buffer): Promise;
}
+export interface Signer {
+ publicKey: Buffer;
+ network?: any;
+ sign(hash: Buffer, lowR?: boolean): Buffer;
+ getPublicKey?(): Buffer;
+}
+
+export interface SignerAsync {
+ publicKey: Buffer;
+ network?: any;
+ sign(hash: Buffer, lowR?: boolean): Promise;
+ getPublicKey?(): Buffer;
+}
+
/**
* This function is needed to pass to the bip174 base class's fromBuffer.
* It takes the "transaction buffer" portion of the psbt buffer and returns a
@@ -903,8 +924,7 @@ function hasSigs(
if (pubkeys) {
sigs = pubkeys
.map(pkey => {
- const pubkey = ecPairFromPublicKey(pkey, { compressed: true })
- .publicKey;
+ const pubkey = compressPubkey(pkey);
return partialSig.find(pSig => pSig.pubkey.equals(pubkey));
})
.filter(v => !!v);
@@ -1305,7 +1325,7 @@ function getHashForSig(
console.warn(
'Warning: Signing non-segwit inputs without the full parent transaction ' +
'means there is a chance that a miner could feed you incorrect information ' +
- 'to trick you into paying large fees. This behavior is the same as Psbt\'s predecesor ' +
+ "to trick you into paying large fees. This behavior is the same as Psbt's predecesor " +
'(TransactionBuilder - now removed) when signing non-segwit scripts. You are not ' +
'able to export this Psbt with toBuffer|toBase64|toHex since it is not ' +
'BIP174 compliant.\n*********************\nPROCEED WITH CAUTION!\n' +
@@ -1714,6 +1734,16 @@ function redeemFromFinalWitnessScript(
return lastItem;
}
+function compressPubkey(pubkey: Buffer): Buffer {
+ if (pubkey.length === 65) {
+ const parity = pubkey[64] & 1;
+ const newKey = pubkey.slice(0, 33);
+ newKey[0] = 2 | parity;
+ return newKey;
+ }
+ return pubkey.slice();
+}
+
function isPubkeyLike(buf: Buffer): boolean {
return buf.length === 33 && bscript.isCanonicalPubKey(buf);
}
diff --git a/ts_src/push_data.ts b/ts_src/push_data.ts
new file mode 100644
index 0000000..56bb02a
--- /dev/null
+++ b/ts_src/push_data.ts
@@ -0,0 +1,76 @@
+import { OPS } from './ops';
+
+export function encodingLength(i: number): number {
+ return i < OPS.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5;
+}
+
+export function encode(buffer: Buffer, num: number, offset: number): number {
+ const size = encodingLength(num);
+
+ // ~6 bit
+ if (size === 1) {
+ buffer.writeUInt8(num, offset);
+
+ // 8 bit
+ } else if (size === 2) {
+ buffer.writeUInt8(OPS.OP_PUSHDATA1, offset);
+ buffer.writeUInt8(num, offset + 1);
+
+ // 16 bit
+ } else if (size === 3) {
+ buffer.writeUInt8(OPS.OP_PUSHDATA2, offset);
+ buffer.writeUInt16LE(num, offset + 1);
+
+ // 32 bit
+ } else {
+ buffer.writeUInt8(OPS.OP_PUSHDATA4, offset);
+ buffer.writeUInt32LE(num, offset + 1);
+ }
+
+ return size;
+}
+
+export function decode(
+ buffer: Buffer,
+ offset: number,
+): {
+ opcode: number;
+ number: number;
+ size: number;
+} | null {
+ const opcode = buffer.readUInt8(offset);
+ let num: number;
+ let size: number;
+
+ // ~6 bit
+ if (opcode < OPS.OP_PUSHDATA1) {
+ num = opcode;
+ size = 1;
+
+ // 8 bit
+ } else if (opcode === OPS.OP_PUSHDATA1) {
+ if (offset + 2 > buffer.length) return null;
+ num = buffer.readUInt8(offset + 1);
+ size = 2;
+
+ // 16 bit
+ } else if (opcode === OPS.OP_PUSHDATA2) {
+ if (offset + 3 > buffer.length) return null;
+ num = buffer.readUInt16LE(offset + 1);
+ size = 3;
+
+ // 32 bit
+ } else {
+ if (offset + 5 > buffer.length) return null;
+ if (opcode !== OPS.OP_PUSHDATA4) throw new Error('Unexpected opcode');
+
+ num = buffer.readUInt32LE(offset + 1);
+ size = 5;
+ }
+
+ return {
+ opcode,
+ number: num,
+ size,
+ };
+}
diff --git a/ts_src/script.ts b/ts_src/script.ts
index 951f48b..5d20ebc 100644
--- a/ts_src/script.ts
+++ b/ts_src/script.ts
@@ -1,17 +1,14 @@
+import * as bip66 from './bip66';
+import { OPS, REVERSE_OPS } from './ops';
import { Stack } from './payments';
+import * as pushdata from './push_data';
import * as scriptNumber from './script_number';
import * as scriptSignature from './script_signature';
import * as types from './types';
-const bip66 = require('bip66');
-const ecc = require('tiny-secp256k1');
-const pushdata = require('pushdata-bitcoin');
-const typeforce = require('typeforce');
+const { typeforce } = types;
-export type OpCode = number;
-export const OPS = require('bitcoin-ops') as { [index: string]: OpCode };
-
-const REVERSE_OPS = require('bitcoin-ops/map') as { [index: number]: string };
const OP_INT_BASE = OPS.OP_RESERVED; // OP_1 - 1
+export { OPS };
function isOPInt(value: number): boolean {
return (
@@ -194,7 +191,7 @@ export function toStack(chunks: Buffer | Array): Buffer[] {
}
export function isCanonicalPubKey(buffer: Buffer): boolean {
- return ecc.isPoint(buffer);
+ return types.isPoint(buffer);
}
export function isDefinedHashType(hashType: number): boolean {
diff --git a/ts_src/script_signature.ts b/ts_src/script_signature.ts
index af9930e..df206e8 100644
--- a/ts_src/script_signature.ts
+++ b/ts_src/script_signature.ts
@@ -1,7 +1,6 @@
+import * as bip66 from './bip66';
import * as types from './types';
-const bip66 = require('bip66');
-
-const typeforce = require('typeforce');
+const { typeforce } = types;
const ZERO = Buffer.alloc(1, 0);
function toDER(x: Buffer): Buffer {
diff --git a/ts_src/transaction.ts b/ts_src/transaction.ts
index b1ac302..c5dde9a 100644
--- a/ts_src/transaction.ts
+++ b/ts_src/transaction.ts
@@ -1,11 +1,14 @@
-import { BufferReader, BufferWriter, reverseBuffer } from './bufferutils';
+import {
+ BufferReader,
+ BufferWriter,
+ reverseBuffer,
+ varuint,
+} from './bufferutils';
import * as bcrypto from './crypto';
import * as bscript from './script';
import { OPS as opcodes } from './script';
import * as types from './types';
-
-const typeforce = require('typeforce');
-const varuint = require('varuint-bitcoin');
+const { typeforce } = types;
function varSliceSize(someScript: Buffer): number {
const length = someScript.length;
diff --git a/ts_src/types.ts b/ts_src/types.ts
index 2e41267..c035b40 100644
--- a/ts_src/types.ts
+++ b/ts_src/types.ts
@@ -1,4 +1,29 @@
-const typeforce = require('typeforce');
+import { Buffer as NBuffer } from 'buffer';
+export const typeforce = require('typeforce');
+
+const ZERO32 = NBuffer.alloc(32, 0);
+const EC_P = NBuffer.from(
+ 'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f',
+ 'hex',
+);
+export function isPoint(p: Buffer | number | undefined | null): boolean {
+ if (!NBuffer.isBuffer(p)) return false;
+ if (p.length < 33) return false;
+
+ const t = p[0];
+ const x = p.slice(1, 33);
+ if (x.compare(ZERO32) === 0) return false;
+ if (x.compare(EC_P) >= 0) return false;
+ if ((t === 0x02 || t === 0x03) && p.length === 33) {
+ return true;
+ }
+
+ const y = p.slice(33);
+ if (y.compare(ZERO32) === 0) return false;
+ if (y.compare(EC_P) >= 0) return false;
+ if (t === 0x04 && p.length === 65) return true;
+ return false;
+}
const UINT31_MAX: number = Math.pow(2, 31) - 1;
export function UInt31(value: number): boolean {
diff --git a/tsconfig.json b/tsconfig.json
index f770a45..3c74061 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,10 +1,9 @@
{
"compilerOptions": {
- "target": "ES2015",
+ "target": "ESNEXT",
"module": "commonjs",
"outDir": "./src",
"declaration": true,
- "declarationDir": "./types",
"rootDir": "./ts_src",
"types": [
"node"
diff --git a/tslint.json b/tslint.json
index d42da60..90e513d 100644
--- a/tslint.json
+++ b/tslint.json
@@ -2,7 +2,8 @@
"defaultSeverity": "error",
"extends": ["tslint:recommended"],
"rules": {
- "arrow-parens": [true, "ban-single-arg-parens"],
+ "array-type": false,
+ "arrow-parens": false,
"curly": false,
"indent": [
true,
@@ -25,7 +26,6 @@
"typedef": [
true,
"call-signature",
- "arrow-call-signature",
"property-declaration"
],
"variable-name": [
diff --git a/types/ecpair.d.ts b/types/ecpair.d.ts
deleted file mode 100644
index 447c608..0000000
--- a/types/ecpair.d.ts
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Network } from './networks';
-interface ECPairOptions {
- compressed?: boolean;
- network?: Network;
- rng?(arg0: number): Buffer;
-}
-export interface Signer {
- publicKey: Buffer;
- network?: any;
- sign(hash: Buffer, lowR?: boolean): Buffer;
- getPublicKey?(): Buffer;
-}
-export interface SignerAsync {
- publicKey: Buffer;
- network?: any;
- sign(hash: Buffer, lowR?: boolean): Promise;
- getPublicKey?(): Buffer;
-}
-export interface ECPairInterface extends Signer {
- compressed: boolean;
- network: Network;
- lowR: boolean;
- privateKey?: Buffer;
- toWIF(): string;
- verify(hash: Buffer, signature: Buffer): boolean;
-}
-declare class ECPair implements ECPairInterface {
- private __D?;
- private __Q?;
- compressed: boolean;
- network: Network;
- lowR: boolean;
- constructor(__D?: Buffer | undefined, __Q?: Buffer | undefined, options?: ECPairOptions);
- readonly privateKey: Buffer | undefined;
- readonly publicKey: Buffer;
- toWIF(): string;
- sign(hash: Buffer, lowR?: boolean): Buffer;
- verify(hash: Buffer, signature: Buffer): boolean;
-}
-declare function fromPrivateKey(buffer: Buffer, options?: ECPairOptions): ECPair;
-declare function fromPublicKey(buffer: Buffer, options?: ECPairOptions): ECPair;
-declare function fromWIF(wifString: string, network?: Network | Network[]): ECPair;
-declare function makeRandom(options?: ECPairOptions): ECPair;
-export { makeRandom, fromPrivateKey, fromPublicKey, fromWIF };