Skip to content

Commit 5137976

Browse files
authored
Merge pull request #1734 from bitcoinjs/feat/modular
Refactor: Remove all require statements, remove ECPair, remove tiny-secp256k1 dep
2 parents f209b0e + 84bc2ea commit 5137976

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+1448
-1154
lines changed

README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,18 @@ You can find a [Web UI](https://bitcoincore.tech/apps/bitcoinjs-ui/index.html) t
3535
## Installation
3636
``` bash
3737
npm install bitcoinjs-lib
38+
# optionally, install a key derivation library as well
39+
npm install ecpair bip32
40+
# ecpair is the ECPair class for single keys
41+
# bip32 is for generating HD keys
3842
```
3943

40-
Typically we support the [Node Maintenance LTS version](https://github.com/nodejs/Release).
41-
If in doubt, see the [.travis.yml](.travis.yml) for what versions are used by our continuous integration tests.
44+
Previous versions of the library included classes for key management (ECPair, HDNode(->"bip32")) but now these have been separated into different libraries. This lowers the bundle size significantly if you don't need to perform any crypto functions (converting private to public keys and deriving HD keys).
45+
46+
Typically we support the [Node Maintenance LTS version](https://github.com/nodejs/Release). TypeScript target will be set
47+
to the ECMAScript version in which all features are fully supported by current Active Node LTS.
48+
However, depending on adoption among other environments (browsers etc.) we may keep the target back a year or two.
49+
If in doubt, see the [main_ci.yml](.github/workflows/main_ci.yml) for what versions are used by our continuous integration tests.
4250

4351
**WARNING**: We presently don't provide any tooling to verify that the release on `npm` matches GitHub. As such, you should verify anything downloaded by `npm` against your own verified copy.
4452

package-lock.json

Lines changed: 133 additions & 65 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
"version": "5.2.0",
44
"description": "Client-side Bitcoin JavaScript library",
55
"main": "./src/index.js",
6-
"types": "./types/index.d.ts",
6+
"types": "./src/index.d.ts",
77
"engines": {
88
"node": ">=8.0.0"
99
},
@@ -18,7 +18,7 @@
1818
"audit": "NPM_AUDIT_IGNORE_DEV=1 NPM_AUDIT_IGNORE_LEVEL=low npm-audit-whitelister .npm-audit-whitelister.json",
1919
"build": "npm run clean && tsc -p ./tsconfig.json && npm run formatjs",
2020
"build:tests": "npm run clean:jstests && tsc -p ./test/tsconfig.json",
21-
"clean": "rimraf src types",
21+
"clean": "rimraf src",
2222
"clean:jstests": "rimraf 'test/**/!(ts-node-register)*.js'",
2323
"coverage-report": "npm run build && npm run nobuild:coverage-report",
2424
"coverage-html": "npm run build && npm run nobuild:coverage-html",
@@ -46,49 +46,47 @@
4646
"url": "https://github.com/bitcoinjs/bitcoinjs-lib.git"
4747
},
4848
"files": [
49-
"src",
50-
"types"
49+
"src"
5150
],
5251
"dependencies": {
5352
"bech32": "^2.0.0",
5453
"bip174": "^2.0.1",
55-
"bip32": "^2.0.4",
56-
"bip66": "^1.1.0",
57-
"bitcoin-ops": "^1.4.0",
58-
"bs58check": "^2.0.0",
54+
"bs58check": "^2.1.2",
5955
"create-hash": "^1.1.0",
60-
"create-hmac": "^1.1.3",
61-
"merkle-lib": "^2.0.10",
62-
"pushdata-bitcoin": "^1.0.1",
63-
"randombytes": "^2.0.1",
64-
"tiny-secp256k1": "^1.1.6",
6556
"typeforce": "^1.11.3",
66-
"varuint-bitcoin": "^1.0.4",
57+
"varuint-bitcoin": "^1.1.2",
6758
"wif": "^2.0.1"
6859
},
6960
"devDependencies": {
7061
"@types/bs58": "^4.0.0",
62+
"@types/bs58check": "^2.1.0",
63+
"@types/create-hash": "^1.2.2",
7164
"@types/mocha": "^5.2.7",
72-
"@types/node": "12.7.5",
65+
"@types/node": "^16.11.1",
7366
"@types/proxyquire": "^1.3.28",
67+
"@types/randombytes": "^2.0.0",
68+
"@types/wif": "^2.0.2",
69+
"bip32": "^2.0.6",
7470
"bip39": "^3.0.2",
7571
"bip65": "^1.0.1",
7672
"bip68": "^1.0.3",
7773
"bn.js": "^4.11.8",
7874
"bs58": "^4.0.0",
7975
"dhttp": "^3.0.0",
76+
"ecpair": "^1.0.0",
8077
"hoodwink": "^2.0.0",
8178
"minimaldata": "^1.0.2",
8279
"mocha": "^7.1.1",
8380
"npm-audit-whitelister": "^1.0.2",
8481
"nyc": "^15.1.0",
8582
"prettier": "1.16.4",
8683
"proxyquire": "^2.0.1",
84+
"randombytes": "^2.1.0",
8785
"regtest-client": "0.2.0",
8886
"rimraf": "^2.6.3",
8987
"ts-node": "^8.3.0",
90-
"tslint": "^5.20.1",
91-
"typescript": "3.2.2"
88+
"tslint": "^6.1.3",
89+
"typescript": "^4.4.4"
9290
},
9391
"license": "MIT"
9492
}

types/address.d.ts renamed to src/address.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// <reference types="node" />
12
import { Network } from './networks';
23
export interface Base58CheckResult {
34
hash: Buffer;

src/address.js

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
'use strict';
22
Object.defineProperty(exports, '__esModule', { value: true });
3+
exports.toOutputScript = exports.fromOutputScript = exports.toBech32 = exports.toBase58Check = exports.fromBech32 = exports.fromBase58Check = void 0;
34
const networks = require('./networks');
45
const payments = require('./payments');
56
const bscript = require('./script');
67
const types = require('./types');
7-
const { bech32, bech32m } = require('bech32');
8+
const bech32_1 = require('bech32');
89
const bs58check = require('bs58check');
9-
const typeforce = require('typeforce');
10+
const { typeforce } = types;
1011
const FUTURE_SEGWIT_MAX_SIZE = 40;
1112
const FUTURE_SEGWIT_MIN_SIZE = 2;
1213
const FUTURE_SEGWIT_MAX_VERSION = 16;
@@ -43,17 +44,17 @@ function fromBech32(address) {
4344
let result;
4445
let version;
4546
try {
46-
result = bech32.decode(address);
47+
result = bech32_1.bech32.decode(address);
4748
} catch (e) {}
4849
if (result) {
4950
version = result.words[0];
5051
if (version !== 0) throw new TypeError(address + ' uses wrong encoding');
5152
} else {
52-
result = bech32m.decode(address);
53+
result = bech32_1.bech32m.decode(address);
5354
version = result.words[0];
5455
if (version === 0) throw new TypeError(address + ' uses wrong encoding');
5556
}
56-
const data = bech32.fromWords(result.words.slice(1));
57+
const data = bech32_1.bech32.fromWords(result.words.slice(1));
5758
return {
5859
version,
5960
prefix: result.prefix,
@@ -70,11 +71,11 @@ function toBase58Check(hash, version) {
7071
}
7172
exports.toBase58Check = toBase58Check;
7273
function toBech32(data, version, prefix) {
73-
const words = bech32.toWords(data);
74+
const words = bech32_1.bech32.toWords(data);
7475
words.unshift(version);
7576
return version === 0
76-
? bech32.encode(prefix, words)
77-
: bech32m.encode(prefix, words);
77+
? bech32_1.bech32.encode(prefix, words)
78+
: bech32_1.bech32m.encode(prefix, words);
7879
}
7980
exports.toBech32 = toBech32;
8081
function fromOutputScript(output, network) {

src/bip66.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/// <reference types="node" />
2+
export declare function check(buffer: Buffer): boolean;
3+
export declare function decode(buffer: Buffer): {
4+
r: Buffer;
5+
s: Buffer;
6+
};
7+
export declare function encode(r: Buffer, s: Buffer): Buffer;

src/bip66.js

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
'use strict';
2+
// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
3+
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
4+
// NOTE: SIGHASH byte ignored AND restricted, truncate before use
5+
Object.defineProperty(exports, '__esModule', { value: true });
6+
exports.encode = exports.decode = exports.check = void 0;
7+
function check(buffer) {
8+
if (buffer.length < 8) return false;
9+
if (buffer.length > 72) return false;
10+
if (buffer[0] !== 0x30) return false;
11+
if (buffer[1] !== buffer.length - 2) return false;
12+
if (buffer[2] !== 0x02) return false;
13+
const lenR = buffer[3];
14+
if (lenR === 0) return false;
15+
if (5 + lenR >= buffer.length) return false;
16+
if (buffer[4 + lenR] !== 0x02) return false;
17+
const lenS = buffer[5 + lenR];
18+
if (lenS === 0) return false;
19+
if (6 + lenR + lenS !== buffer.length) return false;
20+
if (buffer[4] & 0x80) return false;
21+
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
22+
if (buffer[lenR + 6] & 0x80) return false;
23+
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
24+
return false;
25+
return true;
26+
}
27+
exports.check = check;
28+
function decode(buffer) {
29+
if (buffer.length < 8) throw new Error('DER sequence length is too short');
30+
if (buffer.length > 72) throw new Error('DER sequence length is too long');
31+
if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
32+
if (buffer[1] !== buffer.length - 2)
33+
throw new Error('DER sequence length is invalid');
34+
if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
35+
const lenR = buffer[3];
36+
if (lenR === 0) throw new Error('R length is zero');
37+
if (5 + lenR >= buffer.length) throw new Error('R length is too long');
38+
if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
39+
const lenS = buffer[5 + lenR];
40+
if (lenS === 0) throw new Error('S length is zero');
41+
if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
42+
if (buffer[4] & 0x80) throw new Error('R value is negative');
43+
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
44+
throw new Error('R value excessively padded');
45+
if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
46+
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
47+
throw new Error('S value excessively padded');
48+
// non-BIP66 - extract R, S values
49+
return {
50+
r: buffer.slice(4, 4 + lenR),
51+
s: buffer.slice(6 + lenR),
52+
};
53+
}
54+
exports.decode = decode;
55+
/*
56+
* Expects r and s to be positive DER integers.
57+
*
58+
* The DER format uses the most significant bit as a sign bit (& 0x80).
59+
* If the significant bit is set AND the integer is positive, a 0x00 is prepended.
60+
*
61+
* Examples:
62+
*
63+
* 0 => 0x00
64+
* 1 => 0x01
65+
* -1 => 0xff
66+
* 127 => 0x7f
67+
* -127 => 0x81
68+
* 128 => 0x0080
69+
* -128 => 0x80
70+
* 255 => 0x00ff
71+
* -255 => 0xff01
72+
* 16300 => 0x3fac
73+
* -16300 => 0xc054
74+
* 62300 => 0x00f35c
75+
* -62300 => 0xff0ca4
76+
*/
77+
function encode(r, s) {
78+
const lenR = r.length;
79+
const lenS = s.length;
80+
if (lenR === 0) throw new Error('R length is zero');
81+
if (lenS === 0) throw new Error('S length is zero');
82+
if (lenR > 33) throw new Error('R length is too long');
83+
if (lenS > 33) throw new Error('S length is too long');
84+
if (r[0] & 0x80) throw new Error('R value is negative');
85+
if (s[0] & 0x80) throw new Error('S value is negative');
86+
if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
87+
throw new Error('R value excessively padded');
88+
if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
89+
throw new Error('S value excessively padded');
90+
const signature = Buffer.allocUnsafe(6 + lenR + lenS);
91+
// 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
92+
signature[0] = 0x30;
93+
signature[1] = signature.length - 2;
94+
signature[2] = 0x02;
95+
signature[3] = r.length;
96+
r.copy(signature, 4);
97+
signature[4 + lenR] = 0x02;
98+
signature[5 + lenR] = s.length;
99+
s.copy(signature, 6 + lenR);
100+
return signature;
101+
}
102+
exports.encode = encode;

types/block.d.ts renamed to src/block.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// <reference types="node" />
12
import { Transaction } from './transaction';
23
export declare class Block {
34
static fromBuffer(buffer: Buffer): Block;

src/block.js

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
'use strict';
22
Object.defineProperty(exports, '__esModule', { value: true });
3+
exports.Block = void 0;
34
const bufferutils_1 = require('./bufferutils');
45
const bcrypto = require('./crypto');
6+
const merkle_1 = require('./merkle');
57
const transaction_1 = require('./transaction');
68
const types = require('./types');
7-
const fastMerkleRoot = require('merkle-lib/fastRoot');
8-
const typeforce = require('typeforce');
9-
const varuint = require('varuint-bitcoin');
9+
const { typeforce } = types;
1010
const errorMerkleNoTxes = new TypeError(
1111
'Cannot compute merkle root for zero transactions',
1212
);
@@ -72,7 +72,7 @@ class Block {
7272
const hashes = transactions.map(transaction =>
7373
transaction.getHash(forWitness),
7474
);
75-
const rootHash = fastMerkleRoot(hashes, bcrypto.hash256);
75+
const rootHash = (0, merkle_1.fastMerkleRoot)(hashes, bcrypto.hash256);
7676
return forWitness
7777
? bcrypto.hash256(
7878
Buffer.concat([rootHash, transactions[0].ins[0].witness[0]]),
@@ -117,15 +117,15 @@ class Block {
117117
if (headersOnly || !this.transactions) return 80;
118118
return (
119119
80 +
120-
varuint.encodingLength(this.transactions.length) +
120+
bufferutils_1.varuint.encodingLength(this.transactions.length) +
121121
this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
122122
);
123123
}
124124
getHash() {
125125
return bcrypto.hash256(this.toBuffer(true));
126126
}
127127
getId() {
128-
return bufferutils_1.reverseBuffer(this.getHash()).toString('hex');
128+
return (0, bufferutils_1.reverseBuffer)(this.getHash()).toString('hex');
129129
}
130130
getUTCDate() {
131131
const date = new Date(0); // epoch
@@ -143,8 +143,12 @@ class Block {
143143
bufferWriter.writeUInt32(this.bits);
144144
bufferWriter.writeUInt32(this.nonce);
145145
if (headersOnly || !this.transactions) return buffer;
146-
varuint.encode(this.transactions.length, buffer, bufferWriter.offset);
147-
bufferWriter.offset += varuint.encode.bytes;
146+
bufferutils_1.varuint.encode(
147+
this.transactions.length,
148+
buffer,
149+
bufferWriter.offset,
150+
);
151+
bufferWriter.offset += bufferutils_1.varuint.encode.bytes;
148152
this.transactions.forEach(tx => {
149153
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
150154
tx.toBuffer(buffer, bufferWriter.offset);
@@ -166,7 +170,7 @@ class Block {
166170
);
167171
}
168172
checkProofOfWork() {
169-
const hash = bufferutils_1.reverseBuffer(this.getHash());
173+
const hash = (0, bufferutils_1.reverseBuffer)(this.getHash());
170174
const target = Block.calculateTarget(this.bits);
171175
return hash.compare(target) <= 0;
172176
}

types/bufferutils.d.ts renamed to src/bufferutils.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/// <reference types="node" />
2+
import * as varuint from 'varuint-bitcoin';
3+
export { varuint };
14
export declare function readUInt64LE(buffer: Buffer, offset: number): number;
25
export declare function writeUInt64LE(buffer: Buffer, value: number, offset: number): number;
36
export declare function reverseBuffer(buffer: Buffer): Buffer;

0 commit comments

Comments
 (0)