@sidhujag/sysweb3-keyring 1.0.547 → 1.0.549
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{dist/cjs → cjs}/providers.js +1 -64
- package/cjs/providers.js.map +1 -0
- package/{dist/cjs → cjs}/transactions/ethereum.js +1 -16
- package/cjs/transactions/ethereum.js.map +1 -0
- package/package.json +2 -30
- package/{dist/types → types}/providers.d.ts +0 -8
- package/{dist/types → types}/transactions/ethereum.d.ts +2 -2
- package/{dist/types → types}/types.d.ts +2 -2
- package/coverage/clover.xml +0 -2875
- package/coverage/coverage-final.json +0 -29468
- package/coverage/lcov-report/base.css +0 -354
- package/coverage/lcov-report/block-navigation.js +0 -85
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -320
- package/coverage/lcov-report/prettify.css +0 -101
- package/coverage/lcov-report/prettify.js +0 -1008
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -191
- package/coverage/lcov-report/src/index.html +0 -276
- package/coverage/lcov-report/src/index.ts.html +0 -114
- package/coverage/lcov-report/src/initial-state.ts.html +0 -558
- package/coverage/lcov-report/src/keyring-manager.ts.html +0 -6279
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.html +0 -178
- package/coverage/lcov-report/src/ledger/bitcoin_client/index.ts.html +0 -144
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/appClient.ts.html +0 -1560
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/bip32.ts.html +0 -276
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/buffertools.ts.html +0 -495
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/clientCommands.ts.html +0 -1138
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/index.html +0 -363
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts.html +0 -289
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkle.ts.html +0 -486
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/merkleMap.ts.html +0 -240
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/policy.ts.html +0 -342
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/psbtv2.ts.html +0 -2388
- package/coverage/lcov-report/src/ledger/bitcoin_client/lib/varint.ts.html +0 -453
- package/coverage/lcov-report/src/ledger/consts.ts.html +0 -177
- package/coverage/lcov-report/src/ledger/index.html +0 -216
- package/coverage/lcov-report/src/ledger/index.ts.html +0 -1371
- package/coverage/lcov-report/src/ledger/utils.ts.html +0 -102
- package/coverage/lcov-report/src/signers.ts.html +0 -591
- package/coverage/lcov-report/src/storage.ts.html +0 -198
- package/coverage/lcov-report/src/transactions/ethereum.ts.html +0 -5826
- package/coverage/lcov-report/src/transactions/index.html +0 -216
- package/coverage/lcov-report/src/transactions/index.ts.html +0 -93
- package/coverage/lcov-report/src/transactions/syscoin.ts.html +0 -1521
- package/coverage/lcov-report/src/trezor/index.html +0 -176
- package/coverage/lcov-report/src/trezor/index.ts.html +0 -2655
- package/coverage/lcov-report/src/types.ts.html +0 -1443
- package/coverage/lcov-report/src/utils/derivation-paths.ts.html +0 -486
- package/coverage/lcov-report/src/utils/index.html +0 -196
- package/coverage/lcov-report/src/utils/psbt.ts.html +0 -159
- package/coverage/lcov-report/test/helpers/constants.ts.html +0 -627
- package/coverage/lcov-report/test/helpers/index.html +0 -176
- package/coverage/lcov.info +0 -4832
- package/dist/cjs/providers.js.map +0 -1
- package/dist/cjs/transactions/ethereum.js.map +0 -1
- package/dist/package.json +0 -50
- package/examples/basic-usage.js +0 -140
- package/jest.config.js +0 -32
- package/readme.md +0 -201
- package/src/declare.d.ts +0 -7
- package/src/errorUtils.ts +0 -83
- package/src/hardware-wallet-manager.ts +0 -655
- package/src/index.ts +0 -12
- package/src/initial-state.ts +0 -108
- package/src/keyring-manager.ts +0 -2698
- package/src/ledger/bitcoin_client/index.ts +0 -19
- package/src/ledger/bitcoin_client/lib/appClient.ts +0 -405
- package/src/ledger/bitcoin_client/lib/bip32.ts +0 -61
- package/src/ledger/bitcoin_client/lib/buffertools.ts +0 -134
- package/src/ledger/bitcoin_client/lib/clientCommands.ts +0 -356
- package/src/ledger/bitcoin_client/lib/constants.ts +0 -12
- package/src/ledger/bitcoin_client/lib/merkelizedPsbt.ts +0 -65
- package/src/ledger/bitcoin_client/lib/merkle.ts +0 -136
- package/src/ledger/bitcoin_client/lib/merkleMap.ts +0 -49
- package/src/ledger/bitcoin_client/lib/policy.ts +0 -91
- package/src/ledger/bitcoin_client/lib/psbtv2.ts +0 -768
- package/src/ledger/bitcoin_client/lib/varint.ts +0 -120
- package/src/ledger/consts.ts +0 -3
- package/src/ledger/index.ts +0 -685
- package/src/ledger/types.ts +0 -74
- package/src/network-utils.ts +0 -99
- package/src/providers.ts +0 -345
- package/src/signers.ts +0 -158
- package/src/storage.ts +0 -63
- package/src/transactions/__tests__/integration.test.ts +0 -303
- package/src/transactions/__tests__/syscoin.test.ts +0 -409
- package/src/transactions/ethereum.ts +0 -2503
- package/src/transactions/index.ts +0 -2
- package/src/transactions/syscoin.ts +0 -542
- package/src/trezor/index.ts +0 -1050
- package/src/types.ts +0 -366
- package/src/utils/derivation-paths.ts +0 -133
- package/src/utils/psbt.ts +0 -24
- package/src/utils.ts +0 -191
- package/test/README.md +0 -158
- package/test/__mocks__/ledger-mock.js +0 -20
- package/test/__mocks__/trezor-mock.js +0 -75
- package/test/cleanup-summary.md +0 -167
- package/test/helpers/README.md +0 -78
- package/test/helpers/constants.ts +0 -79
- package/test/helpers/setup.ts +0 -714
- package/test/integration/import-validation.spec.ts +0 -588
- package/test/unit/hardware/ledger.spec.ts +0 -869
- package/test/unit/hardware/trezor.spec.ts +0 -828
- package/test/unit/keyring-manager/account-management.spec.ts +0 -970
- package/test/unit/keyring-manager/import-watchonly.spec.ts +0 -181
- package/test/unit/keyring-manager/import-wif.spec.ts +0 -126
- package/test/unit/keyring-manager/initialization.spec.ts +0 -782
- package/test/unit/keyring-manager/key-derivation.spec.ts +0 -996
- package/test/unit/keyring-manager/security.spec.ts +0 -505
- package/test/unit/keyring-manager/state-management.spec.ts +0 -375
- package/test/unit/network/network-management.spec.ts +0 -372
- package/test/unit/transactions/ethereum-transactions.spec.ts +0 -382
- package/test/unit/transactions/syscoin-transactions.spec.ts +0 -615
- package/tsconfig.json +0 -14
- /package/{dist/README.md → README.md} +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js +0 -0
- /package/{dist/cjs → cjs}/errorUtils.js.map +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js +0 -0
- /package/{dist/cjs → cjs}/hardware-wallet-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/index.js +0 -0
- /package/{dist/cjs → cjs}/index.js.map +0 -0
- /package/{dist/cjs → cjs}/initial-state.js +0 -0
- /package/{dist/cjs → cjs}/initial-state.js.map +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js +0 -0
- /package/{dist/cjs → cjs}/keyring-manager.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/appClient.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/bip32.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/buffertools.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/clientCommands.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/constants.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkelizedPsbt.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkle.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/merkleMap.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/policy.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/psbtv2.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js +0 -0
- /package/{dist/cjs → cjs}/ledger/bitcoin_client/lib/varint.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js +0 -0
- /package/{dist/cjs → cjs}/ledger/consts.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js +0 -0
- /package/{dist/cjs → cjs}/ledger/index.js.map +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js +0 -0
- /package/{dist/cjs → cjs}/ledger/types.js.map +0 -0
- /package/{dist/cjs → cjs}/network-utils.js +0 -0
- /package/{dist/cjs → cjs}/network-utils.js.map +0 -0
- /package/{dist/cjs → cjs}/signers.js +0 -0
- /package/{dist/cjs → cjs}/signers.js.map +0 -0
- /package/{dist/cjs → cjs}/storage.js +0 -0
- /package/{dist/cjs → cjs}/storage.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/integration.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js +0 -0
- /package/{dist/cjs → cjs}/transactions/__tests__/syscoin.test.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js +0 -0
- /package/{dist/cjs → cjs}/transactions/index.js.map +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js +0 -0
- /package/{dist/cjs → cjs}/transactions/syscoin.js.map +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js +0 -0
- /package/{dist/cjs → cjs}/trezor/index.js.map +0 -0
- /package/{dist/cjs → cjs}/types.js +0 -0
- /package/{dist/cjs → cjs}/types.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js +0 -0
- /package/{dist/cjs → cjs}/utils/derivation-paths.js.map +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js +0 -0
- /package/{dist/cjs → cjs}/utils/psbt.js.map +0 -0
- /package/{dist/cjs → cjs}/utils.js +0 -0
- /package/{dist/cjs → cjs}/utils.js.map +0 -0
- /package/{dist/types → types}/errorUtils.d.ts +0 -0
- /package/{dist/types → types}/hardware-wallet-manager.d.ts +0 -0
- /package/{dist/types → types}/index.d.ts +0 -0
- /package/{dist/types → types}/initial-state.d.ts +0 -0
- /package/{dist/types → types}/keyring-manager.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/appClient.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/bip32.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/buffertools.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/clientCommands.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/constants.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkelizedPsbt.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkle.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/merkleMap.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/policy.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/psbtv2.d.ts +0 -0
- /package/{dist/types → types}/ledger/bitcoin_client/lib/varint.d.ts +0 -0
- /package/{dist/types → types}/ledger/consts.d.ts +0 -0
- /package/{dist/types → types}/ledger/index.d.ts +0 -0
- /package/{dist/types → types}/ledger/types.d.ts +0 -0
- /package/{dist/types → types}/network-utils.d.ts +0 -0
- /package/{dist/types → types}/signers.d.ts +0 -0
- /package/{dist/types → types}/storage.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/integration.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/__tests__/syscoin.test.d.ts +0 -0
- /package/{dist/types → types}/transactions/index.d.ts +0 -0
- /package/{dist/types → types}/transactions/syscoin.d.ts +0 -0
- /package/{dist/types → types}/trezor/index.d.ts +0 -0
- /package/{dist/types → types}/utils/derivation-paths.d.ts +0 -0
- /package/{dist/types → types}/utils/psbt.d.ts +0 -0
- /package/{dist/types → types}/utils.d.ts +0 -0
|
@@ -1,356 +0,0 @@
|
|
|
1
|
-
/* eslint-disable camelcase */
|
|
2
|
-
import CryptoJS from 'crypto-js';
|
|
3
|
-
|
|
4
|
-
// Helper function for SHA256 hashing (browser-compatible)
|
|
5
|
-
function sha256(data: Buffer): Buffer {
|
|
6
|
-
const wordArray = CryptoJS.lib.WordArray.create(data);
|
|
7
|
-
const hash = CryptoJS.SHA256(wordArray);
|
|
8
|
-
const hashBuffer = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex');
|
|
9
|
-
return hashBuffer;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
import { BufferReader } from './buffertools';
|
|
13
|
-
import { hashLeaf, Merkle } from './merkle';
|
|
14
|
-
import { MerkleMap } from './merkleMap';
|
|
15
|
-
import { WalletPolicy } from './policy';
|
|
16
|
-
import { createVarint, sanitizeBigintToNumber } from './varint';
|
|
17
|
-
|
|
18
|
-
enum ClientCommandCode {
|
|
19
|
-
YIELD = 0x10,
|
|
20
|
-
GET_PREIMAGE = 0x40,
|
|
21
|
-
GET_MERKLE_LEAF_PROOF = 0x41,
|
|
22
|
-
GET_MERKLE_LEAF_INDEX = 0x42,
|
|
23
|
-
GET_MORE_ELEMENTS = 0xa0,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
abstract class ClientCommand {
|
|
27
|
-
abstract code: ClientCommandCode;
|
|
28
|
-
abstract execute(request: Buffer): Buffer;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export class YieldCommand extends ClientCommand {
|
|
32
|
-
private results: Buffer[];
|
|
33
|
-
|
|
34
|
-
readonly code = ClientCommandCode.YIELD;
|
|
35
|
-
|
|
36
|
-
constructor(
|
|
37
|
-
results: Buffer[],
|
|
38
|
-
private readonly progressCallback?: () => void
|
|
39
|
-
) {
|
|
40
|
-
super();
|
|
41
|
-
this.results = results;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
execute(request: Buffer): Buffer {
|
|
45
|
-
this.results.push(Buffer.from(request.subarray(1)));
|
|
46
|
-
if (this.progressCallback) {
|
|
47
|
-
this.progressCallback();
|
|
48
|
-
}
|
|
49
|
-
return Buffer.from('');
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export class GetPreimageCommand extends ClientCommand {
|
|
54
|
-
private readonly known_preimages: ReadonlyMap<string, Buffer>;
|
|
55
|
-
private queue: Buffer[];
|
|
56
|
-
|
|
57
|
-
readonly code = ClientCommandCode.GET_PREIMAGE;
|
|
58
|
-
|
|
59
|
-
constructor(known_preimages: ReadonlyMap<string, Buffer>, queue: Buffer[]) {
|
|
60
|
-
super();
|
|
61
|
-
this.known_preimages = known_preimages;
|
|
62
|
-
this.queue = queue;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
execute(request: Buffer): Buffer {
|
|
66
|
-
const req = Buffer.from(request.subarray(1));
|
|
67
|
-
|
|
68
|
-
// we expect no more data to read
|
|
69
|
-
if (req.length != 1 + 32) {
|
|
70
|
-
throw new Error('Invalid request, unexpected trailing data');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (req[0] != 0) {
|
|
74
|
-
throw new Error('Unsupported request, the first byte should be 0');
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
// read the hash
|
|
78
|
-
const hash = Buffer.alloc(32);
|
|
79
|
-
for (let i = 0; i < 32; i++) {
|
|
80
|
-
hash[i] = req[1 + i];
|
|
81
|
-
}
|
|
82
|
-
const req_hash_hex = hash.toString('hex');
|
|
83
|
-
|
|
84
|
-
const known_preimage = this.known_preimages.get(req_hash_hex);
|
|
85
|
-
if (known_preimage != undefined) {
|
|
86
|
-
const preimage_len_varint = createVarint(known_preimage.length);
|
|
87
|
-
|
|
88
|
-
// We can send at most 255 - len(preimage_len_out) - 1 bytes in a single message;
|
|
89
|
-
// the rest will be stored in the queue for GET_MORE_ELEMENTS
|
|
90
|
-
const max_payload_size = 255 - preimage_len_varint.length - 1;
|
|
91
|
-
|
|
92
|
-
const payload_size = Math.min(max_payload_size, known_preimage.length);
|
|
93
|
-
|
|
94
|
-
if (payload_size < known_preimage.length) {
|
|
95
|
-
for (let i = payload_size; i < known_preimage.length; i++) {
|
|
96
|
-
this.queue.push(Buffer.from([known_preimage[i]]));
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return Buffer.concat([
|
|
101
|
-
preimage_len_varint,
|
|
102
|
-
Buffer.from([payload_size]),
|
|
103
|
-
Buffer.from(known_preimage.subarray(0, payload_size)),
|
|
104
|
-
]);
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
throw Error(`Requested unknown preimage for: ${req_hash_hex}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export class GetMerkleLeafProofCommand extends ClientCommand {
|
|
112
|
-
private readonly known_trees: ReadonlyMap<string, Merkle>;
|
|
113
|
-
private queue: Buffer[];
|
|
114
|
-
|
|
115
|
-
readonly code = ClientCommandCode.GET_MERKLE_LEAF_PROOF;
|
|
116
|
-
|
|
117
|
-
constructor(known_trees: ReadonlyMap<string, Merkle>, queue: Buffer[]) {
|
|
118
|
-
super();
|
|
119
|
-
this.known_trees = known_trees;
|
|
120
|
-
this.queue = queue;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
execute(request: Buffer): Buffer {
|
|
124
|
-
const req = Buffer.from(request.subarray(1));
|
|
125
|
-
|
|
126
|
-
if (req.length < 32 + 1 + 1) {
|
|
127
|
-
throw new Error('Invalid request, expected at least 34 bytes');
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const reqBuf = new BufferReader(req);
|
|
131
|
-
const hash = reqBuf.readSlice(32);
|
|
132
|
-
const hash_hex = hash.toString('hex');
|
|
133
|
-
|
|
134
|
-
let tree_size: number;
|
|
135
|
-
let leaf_index: number;
|
|
136
|
-
try {
|
|
137
|
-
tree_size = sanitizeBigintToNumber(reqBuf.readVarInt());
|
|
138
|
-
leaf_index = sanitizeBigintToNumber(reqBuf.readVarInt());
|
|
139
|
-
} catch (e) {
|
|
140
|
-
throw new Error(
|
|
141
|
-
"Invalid request, couldn't parse tree_size or leaf_index"
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const mt = this.known_trees.get(hash_hex);
|
|
146
|
-
if (!mt) {
|
|
147
|
-
throw Error(`Requested Merkle leaf proof for unknown tree: ${hash_hex}`);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (leaf_index >= tree_size || mt.size() != tree_size) {
|
|
151
|
-
throw Error('Invalid index or tree size.');
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
if (this.queue.length != 0) {
|
|
155
|
-
throw Error(
|
|
156
|
-
'This command should not execute when the queue is not empty.'
|
|
157
|
-
);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const proof = mt.getProof(leaf_index);
|
|
161
|
-
|
|
162
|
-
const n_response_elements = Math.min(
|
|
163
|
-
Math.floor((255 - 32 - 1 - 1) / 32),
|
|
164
|
-
proof.length
|
|
165
|
-
);
|
|
166
|
-
const n_leftover_elements = proof.length - n_response_elements;
|
|
167
|
-
|
|
168
|
-
// Add to the queue any proof elements that do not fit the response
|
|
169
|
-
if (n_leftover_elements > 0) {
|
|
170
|
-
this.queue.push(...proof.slice(-n_leftover_elements));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
return Buffer.concat([
|
|
174
|
-
mt.getLeafHash(leaf_index),
|
|
175
|
-
Buffer.from([proof.length]),
|
|
176
|
-
Buffer.from([n_response_elements]),
|
|
177
|
-
...proof.slice(0, n_response_elements),
|
|
178
|
-
]);
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export class GetMerkleLeafIndexCommand extends ClientCommand {
|
|
183
|
-
private readonly known_trees: ReadonlyMap<string, Merkle>;
|
|
184
|
-
|
|
185
|
-
readonly code = ClientCommandCode.GET_MERKLE_LEAF_INDEX;
|
|
186
|
-
|
|
187
|
-
constructor(known_trees: ReadonlyMap<string, Merkle>) {
|
|
188
|
-
super();
|
|
189
|
-
this.known_trees = known_trees;
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
execute(request: Buffer): Buffer {
|
|
193
|
-
const req = Buffer.from(request.subarray(1));
|
|
194
|
-
|
|
195
|
-
if (req.length != 32 + 32) {
|
|
196
|
-
throw new Error('Invalid request, unexpected trailing data');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// read the root hash
|
|
200
|
-
const root_hash = Buffer.alloc(32);
|
|
201
|
-
for (let i = 0; i < 32; i++) {
|
|
202
|
-
root_hash[i] = req.readUInt8(i);
|
|
203
|
-
}
|
|
204
|
-
const root_hash_hex = root_hash.toString('hex');
|
|
205
|
-
|
|
206
|
-
// read the leaf hash
|
|
207
|
-
const leef_hash = Buffer.alloc(32);
|
|
208
|
-
for (let i = 0; i < 32; i++) {
|
|
209
|
-
leef_hash[i] = req.readUInt8(32 + i);
|
|
210
|
-
}
|
|
211
|
-
const leef_hash_hex = leef_hash.toString('hex');
|
|
212
|
-
|
|
213
|
-
const mt = this.known_trees.get(root_hash_hex);
|
|
214
|
-
if (!mt) {
|
|
215
|
-
throw Error(
|
|
216
|
-
`Requested Merkle leaf index for unknown root: ${root_hash_hex}`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
let leaf_index = 0;
|
|
221
|
-
let found = 0;
|
|
222
|
-
for (let i = 0; i < mt.size(); i++) {
|
|
223
|
-
if (mt.getLeafHash(i).toString('hex') == leef_hash_hex) {
|
|
224
|
-
found = 1;
|
|
225
|
-
leaf_index = i;
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return Buffer.concat([Buffer.from([found]), createVarint(leaf_index)]);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export class GetMoreElementsCommand extends ClientCommand {
|
|
234
|
-
queue: Buffer[];
|
|
235
|
-
|
|
236
|
-
readonly code = ClientCommandCode.GET_MORE_ELEMENTS;
|
|
237
|
-
|
|
238
|
-
constructor(queue: Buffer[]) {
|
|
239
|
-
super();
|
|
240
|
-
this.queue = queue;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
execute(request: Buffer): Buffer {
|
|
244
|
-
if (request.length != 1) {
|
|
245
|
-
throw new Error('Invalid request, unexpected trailing data');
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
if (this.queue.length === 0) {
|
|
249
|
-
throw new Error('No elements to get');
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
// all elements should have the same length
|
|
253
|
-
const element_len = this.queue[0].length;
|
|
254
|
-
if (this.queue.some((el) => el.length != element_len)) {
|
|
255
|
-
throw new Error(
|
|
256
|
-
'The queue contains elements with different byte length, which is not expected'
|
|
257
|
-
);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
const max_elements = Math.floor(253 / element_len);
|
|
261
|
-
const n_returned_elements = Math.min(max_elements, this.queue.length);
|
|
262
|
-
|
|
263
|
-
const returned_elements = this.queue.splice(0, n_returned_elements);
|
|
264
|
-
|
|
265
|
-
return Buffer.concat([
|
|
266
|
-
Buffer.from([n_returned_elements]),
|
|
267
|
-
Buffer.from([element_len]),
|
|
268
|
-
...returned_elements,
|
|
269
|
-
]);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/**
|
|
274
|
-
* This class will dispatch a client command coming from the hardware device to
|
|
275
|
-
* the appropriate client command implementation. Those client commands
|
|
276
|
-
* typically requests data from a merkle tree or merkelized maps.
|
|
277
|
-
*
|
|
278
|
-
* A ClientCommandInterpreter is prepared by adding the merkle trees and
|
|
279
|
-
* merkelized maps it should be able to serve to the hardware device. This class
|
|
280
|
-
* doesn't know anything about the semantics of the data it holds, it just
|
|
281
|
-
* serves merkle data. It doesn't even know in what context it is being
|
|
282
|
-
* executed, ie SignPsbt, getWalletAddress, etc.
|
|
283
|
-
*
|
|
284
|
-
* If the command yelds results to the client, as signPsbt does, the yielded
|
|
285
|
-
* data will be accessible after the command completed by calling getYielded(),
|
|
286
|
-
* which will return the yields in the same order as they came in.
|
|
287
|
-
*/
|
|
288
|
-
export class ClientCommandInterpreter {
|
|
289
|
-
private readonly roots: Map<string, Merkle> = new Map();
|
|
290
|
-
private readonly preimages: Map<string, Buffer> = new Map();
|
|
291
|
-
|
|
292
|
-
private yielded: Buffer[] = [];
|
|
293
|
-
|
|
294
|
-
private queue: Buffer[] = [];
|
|
295
|
-
|
|
296
|
-
private readonly commands: Map<ClientCommandCode, ClientCommand> = new Map();
|
|
297
|
-
|
|
298
|
-
constructor(progressCallback?: () => void) {
|
|
299
|
-
const commands = [
|
|
300
|
-
new YieldCommand(this.yielded, progressCallback),
|
|
301
|
-
new GetPreimageCommand(this.preimages, this.queue),
|
|
302
|
-
new GetMerkleLeafIndexCommand(this.roots),
|
|
303
|
-
new GetMerkleLeafProofCommand(this.roots, this.queue),
|
|
304
|
-
new GetMoreElementsCommand(this.queue),
|
|
305
|
-
];
|
|
306
|
-
|
|
307
|
-
for (const cmd of commands) {
|
|
308
|
-
if (this.commands.has(cmd.code)) {
|
|
309
|
-
throw new Error(`Multiple commands with code ${cmd.code}`);
|
|
310
|
-
}
|
|
311
|
-
this.commands.set(cmd.code, cmd);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
getYielded(): readonly Buffer[] {
|
|
316
|
-
return this.yielded;
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
addKnownPreimage(preimage: Buffer): void {
|
|
320
|
-
this.preimages.set(sha256(preimage).toString('hex'), preimage);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
addKnownList(elements: readonly Buffer[]): void {
|
|
324
|
-
for (const el of elements) {
|
|
325
|
-
const preimage = Buffer.concat([Buffer.from([0]), el]);
|
|
326
|
-
this.addKnownPreimage(preimage);
|
|
327
|
-
}
|
|
328
|
-
const mt = new Merkle(elements.map((el) => hashLeaf(el)));
|
|
329
|
-
this.roots.set(mt.getRoot().toString('hex'), mt);
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
addKnownMapping(mm: MerkleMap): void {
|
|
333
|
-
this.addKnownList(mm.keys);
|
|
334
|
-
this.addKnownList(mm.values);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
addKnownWalletPolicy(wp: WalletPolicy): void {
|
|
338
|
-
this.addKnownPreimage(wp.serialize());
|
|
339
|
-
this.addKnownList(wp.keys.map((k) => Buffer.from(k, 'ascii')));
|
|
340
|
-
this.addKnownPreimage(Buffer.from(wp.descriptorTemplate));
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
execute(request: Buffer): Buffer {
|
|
344
|
-
if (request.length == 0) {
|
|
345
|
-
throw new Error('Unexpected empty command');
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
const cmdCode = request[0];
|
|
349
|
-
const cmd = this.commands.get(cmdCode);
|
|
350
|
-
if (!cmd) {
|
|
351
|
-
throw new Error(`Unexpected command code ${cmdCode}`);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
return cmd.execute(request);
|
|
355
|
-
}
|
|
356
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export const MAX_SCRIPT_BLOCK = 50;
|
|
2
|
-
export const DEFAULT_VERSION = 1;
|
|
3
|
-
export const DEFAULT_LOCKTIME = 0;
|
|
4
|
-
export const DEFAULT_SEQUENCE = 0xffffffff;
|
|
5
|
-
export const SIGHASH_ALL = 1;
|
|
6
|
-
export const OP_DUP = 0x76;
|
|
7
|
-
export const OP_HASH160 = 0xa9;
|
|
8
|
-
export const HASH_SIZE = 0x14;
|
|
9
|
-
export const OP_EQUAL = 0x87;
|
|
10
|
-
export const OP_EQUALVERIFY = 0x88;
|
|
11
|
-
export const OP_CHECKSIG = 0xac;
|
|
12
|
-
export const OP_RETURN = 0x6a;
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { MerkleMap } from './merkleMap';
|
|
2
|
-
import { PsbtV2 } from './psbtv2';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* This class merkelizes a PSBTv2, by merkelizing the different
|
|
6
|
-
* maps of the psbt. This is used during the transaction signing process,
|
|
7
|
-
* where the hardware app can request specific parts of the psbt from the
|
|
8
|
-
* client code and be sure that the response data actually belong to the psbt.
|
|
9
|
-
* The reason for this is the limited amount of memory available to the app,
|
|
10
|
-
* so it can't always store the full psbt in memory.
|
|
11
|
-
*
|
|
12
|
-
* The signing process is documented at
|
|
13
|
-
* https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/bitcoin.md#sign_psbt
|
|
14
|
-
*/
|
|
15
|
-
export class MerkelizedPsbt extends PsbtV2 {
|
|
16
|
-
public readonly globalMerkleMap: MerkleMap;
|
|
17
|
-
public inputMerkleMaps: MerkleMap[] = [];
|
|
18
|
-
public outputMerkleMaps: MerkleMap[] = [];
|
|
19
|
-
public inputMapCommitments: Buffer[];
|
|
20
|
-
public outputMapCommitments: Buffer[];
|
|
21
|
-
constructor(psbt: PsbtV2) {
|
|
22
|
-
super();
|
|
23
|
-
psbt.copy(this);
|
|
24
|
-
this.globalMerkleMap = MerkelizedPsbt.createMerkleMap(this.globalMap);
|
|
25
|
-
|
|
26
|
-
for (let i = 0; i < this.getGlobalInputCount(); i++) {
|
|
27
|
-
this.inputMerkleMaps.push(
|
|
28
|
-
MerkelizedPsbt.createMerkleMap(this.inputMaps[i])
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
this.inputMapCommitments = [...this.inputMerkleMaps.values()].map((v) =>
|
|
32
|
-
v.commitment()
|
|
33
|
-
);
|
|
34
|
-
|
|
35
|
-
for (let i = 0; i < this.getGlobalOutputCount(); i++) {
|
|
36
|
-
this.outputMerkleMaps.push(
|
|
37
|
-
MerkelizedPsbt.createMerkleMap(this.outputMaps[i])
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
this.outputMapCommitments = [...this.outputMerkleMaps.values()].map((v) =>
|
|
41
|
-
v.commitment()
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
// These public functions are for MerkelizedPsbt.
|
|
45
|
-
getGlobalSize(): number {
|
|
46
|
-
return this.globalMap.size;
|
|
47
|
-
}
|
|
48
|
-
getGlobalKeysValuesRoot(): Buffer {
|
|
49
|
-
return this.globalMerkleMap.commitment();
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
private static createMerkleMap(map: ReadonlyMap<string, Buffer>): MerkleMap {
|
|
53
|
-
const sortedKeysStrings = [...map.keys()].sort();
|
|
54
|
-
const values = sortedKeysStrings.map((k) => {
|
|
55
|
-
const v = map.get(k);
|
|
56
|
-
if (!v) {
|
|
57
|
-
throw new Error('No value for key ' + k);
|
|
58
|
-
}
|
|
59
|
-
return v;
|
|
60
|
-
});
|
|
61
|
-
const sortedKeys = sortedKeysStrings.map((k) => Buffer.from(k, 'hex'));
|
|
62
|
-
|
|
63
|
-
return new MerkleMap(sortedKeys, values);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import CryptoJS from 'crypto-js';
|
|
2
|
-
|
|
3
|
-
// Helper function for SHA256 hashing (browser-compatible)
|
|
4
|
-
function sha256(data: Buffer): Buffer {
|
|
5
|
-
const wordArray = CryptoJS.lib.WordArray.create(data);
|
|
6
|
-
const hash = CryptoJS.SHA256(wordArray);
|
|
7
|
-
const hashBuffer = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex');
|
|
8
|
-
return hashBuffer;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* This class implements the merkle tree used by Ledger Bitcoin app v2+,
|
|
13
|
-
* which is documented at
|
|
14
|
-
* https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/merkle.md
|
|
15
|
-
*/
|
|
16
|
-
export class Merkle {
|
|
17
|
-
private leaves: Buffer[];
|
|
18
|
-
private rootNode: Node;
|
|
19
|
-
private leafNodes: Node[];
|
|
20
|
-
private h: (buf: Buffer) => Buffer;
|
|
21
|
-
constructor(leaves: Buffer[], hasher: (buf: Buffer) => Buffer = sha256) {
|
|
22
|
-
this.leaves = leaves;
|
|
23
|
-
this.h = hasher;
|
|
24
|
-
const nodes = this.calculateRoot(leaves);
|
|
25
|
-
this.rootNode = nodes.root;
|
|
26
|
-
this.leafNodes = nodes.leaves;
|
|
27
|
-
}
|
|
28
|
-
getRoot(): Buffer {
|
|
29
|
-
return this.rootNode.hash;
|
|
30
|
-
}
|
|
31
|
-
size(): number {
|
|
32
|
-
return this.leaves.length;
|
|
33
|
-
}
|
|
34
|
-
getLeaves(): Buffer[] {
|
|
35
|
-
return this.leaves;
|
|
36
|
-
}
|
|
37
|
-
getLeafHash(index: number): Buffer {
|
|
38
|
-
return this.leafNodes[index].hash;
|
|
39
|
-
}
|
|
40
|
-
getProof(index: number): Buffer[] {
|
|
41
|
-
if (index >= this.leaves.length) throw Error('Index out of bounds');
|
|
42
|
-
return proveNode(this.leafNodes[index]);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
calculateRoot(leaves: Buffer[]): {
|
|
46
|
-
leaves: Node[];
|
|
47
|
-
root: Node;
|
|
48
|
-
} {
|
|
49
|
-
const n = leaves.length;
|
|
50
|
-
if (n == 0) {
|
|
51
|
-
return {
|
|
52
|
-
root: new Node(undefined, undefined, Buffer.alloc(32, 0)),
|
|
53
|
-
leaves: [],
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
if (n == 1) {
|
|
57
|
-
const newNode = new Node(undefined, undefined, leaves[0]);
|
|
58
|
-
return { root: newNode, leaves: [newNode] };
|
|
59
|
-
}
|
|
60
|
-
const leftCount = highestPowerOf2LessThan(n);
|
|
61
|
-
const leftBranch = this.calculateRoot(leaves.slice(0, leftCount));
|
|
62
|
-
const rightBranch = this.calculateRoot(leaves.slice(leftCount));
|
|
63
|
-
const leftChild = leftBranch.root;
|
|
64
|
-
const rightChild = rightBranch.root;
|
|
65
|
-
const hash = this.hashNode(leftChild.hash, rightChild.hash);
|
|
66
|
-
const node = new Node(leftChild, rightChild, hash);
|
|
67
|
-
leftChild.parent = node;
|
|
68
|
-
rightChild.parent = node;
|
|
69
|
-
return { root: node, leaves: leftBranch.leaves.concat(rightBranch.leaves) };
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
hashNode(left: Buffer, right: Buffer): Buffer {
|
|
73
|
-
return this.h(Buffer.concat([Buffer.from([1]), left, right]));
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export function hashLeaf(
|
|
78
|
-
buf: Buffer,
|
|
79
|
-
hashFunction: (buf: Buffer) => Buffer = sha256
|
|
80
|
-
): Buffer {
|
|
81
|
-
return hashConcat(Buffer.from([0]), buf, hashFunction);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function hashConcat(
|
|
85
|
-
bufA: Buffer,
|
|
86
|
-
bufB: Buffer,
|
|
87
|
-
hashFunction: (buf: Buffer) => Buffer
|
|
88
|
-
): Buffer {
|
|
89
|
-
return hashFunction(Buffer.concat([bufA, bufB]));
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
class Node {
|
|
93
|
-
leftChild?: Node;
|
|
94
|
-
rightChild?: Node;
|
|
95
|
-
parent?: Node;
|
|
96
|
-
hash: Buffer;
|
|
97
|
-
constructor(left: Node | undefined, right: Node | undefined, hash: Buffer) {
|
|
98
|
-
this.leftChild = left;
|
|
99
|
-
this.rightChild = right;
|
|
100
|
-
this.hash = hash;
|
|
101
|
-
}
|
|
102
|
-
isLeaf(): boolean {
|
|
103
|
-
return this.leftChild == undefined;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function proveNode(node: Node): Buffer[] {
|
|
108
|
-
if (!node.parent) {
|
|
109
|
-
return [];
|
|
110
|
-
}
|
|
111
|
-
if (node.parent.leftChild == node) {
|
|
112
|
-
if (!node.parent.rightChild) {
|
|
113
|
-
throw new Error('Expected right child to exist');
|
|
114
|
-
}
|
|
115
|
-
return [node.parent.rightChild.hash, ...proveNode(node.parent)];
|
|
116
|
-
} else {
|
|
117
|
-
if (!node.parent.leftChild) {
|
|
118
|
-
throw new Error('Expected left child to exist');
|
|
119
|
-
}
|
|
120
|
-
return [node.parent.leftChild.hash, ...proveNode(node.parent)];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function highestPowerOf2LessThan(n: number) {
|
|
125
|
-
if (n < 2) {
|
|
126
|
-
throw Error('Expected n >= 2');
|
|
127
|
-
}
|
|
128
|
-
if (isPowerOf2(n)) {
|
|
129
|
-
return n / 2;
|
|
130
|
-
}
|
|
131
|
-
return 1 << Math.floor(Math.log2(n));
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
function isPowerOf2(n: number): boolean {
|
|
135
|
-
return (n & (n - 1)) == 0;
|
|
136
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { hashLeaf, Merkle } from './merkle';
|
|
2
|
-
import { createVarint } from './varint';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* This implements "Merkelized Maps", documented at
|
|
6
|
-
* https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/merkle.md#merkleized-maps
|
|
7
|
-
*
|
|
8
|
-
* A merkelized map consist of two merkle trees, one for the keys of
|
|
9
|
-
* a map and one for the values of the same map, thus the two merkle
|
|
10
|
-
* trees have the same shape. The commitment is the number elements
|
|
11
|
-
* in the map followed by the keys' merkle root followed by the
|
|
12
|
-
* values' merkle root.
|
|
13
|
-
*/
|
|
14
|
-
export class MerkleMap {
|
|
15
|
-
readonly keys: readonly Buffer[];
|
|
16
|
-
readonly keysTree: Merkle;
|
|
17
|
-
readonly values: readonly Buffer[];
|
|
18
|
-
readonly valuesTree: Merkle;
|
|
19
|
-
/**
|
|
20
|
-
* @param keys Sorted list of (unhashed) keys
|
|
21
|
-
* @param values values, in corresponding order as the keys, and of equal length
|
|
22
|
-
*/
|
|
23
|
-
constructor(keys: readonly Buffer[], values: readonly Buffer[]) {
|
|
24
|
-
if (keys.length != values.length) {
|
|
25
|
-
throw new Error('keys and values should have the same length');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// Sanity check: verify that keys are actually sorted and with no duplicates
|
|
29
|
-
for (let i = 0; i < keys.length - 1; i++) {
|
|
30
|
-
if (keys[i].toString('hex') >= keys[i + 1].toString('hex')) {
|
|
31
|
-
throw new Error('keys must be in strictly increasing order');
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
this.keys = keys;
|
|
36
|
-
this.keysTree = new Merkle(keys.map((k) => hashLeaf(k)));
|
|
37
|
-
this.values = values;
|
|
38
|
-
this.valuesTree = new Merkle(values.map((v) => hashLeaf(v)));
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
commitment(): Buffer {
|
|
42
|
-
// returns a buffer between 65 and 73 (included) bytes long
|
|
43
|
-
return Buffer.concat([
|
|
44
|
-
createVarint(this.keys.length),
|
|
45
|
-
this.keysTree.getRoot(),
|
|
46
|
-
this.valuesTree.getRoot(),
|
|
47
|
-
]);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import CryptoJS from 'crypto-js';
|
|
2
|
-
|
|
3
|
-
// Helper function for SHA256 hashing (browser-compatible)
|
|
4
|
-
function sha256(data: Buffer): Buffer {
|
|
5
|
-
const wordArray = CryptoJS.lib.WordArray.create(data);
|
|
6
|
-
const hash = CryptoJS.SHA256(wordArray);
|
|
7
|
-
const hashBuffer = Buffer.from(hash.toString(CryptoJS.enc.Hex), 'hex');
|
|
8
|
-
return hashBuffer;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
import { BufferWriter } from './buffertools';
|
|
12
|
-
import { hashLeaf, Merkle } from './merkle';
|
|
13
|
-
|
|
14
|
-
const WALLET_POLICY_V2 = 2;
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* The Bitcon hardware app uses a descriptors-like thing to describe
|
|
18
|
-
* how to construct output scripts from keys. A "Wallet Policy" consists
|
|
19
|
-
* of a "Descriptor Template" and a list of "keys". A key is basically
|
|
20
|
-
* a serialized BIP32 extended public key with some added derivation path
|
|
21
|
-
* information. This is documented at
|
|
22
|
-
* https://github.com/LedgerHQ/app-bitcoin-new/blob/master/doc/wallet.md
|
|
23
|
-
*/
|
|
24
|
-
export class WalletPolicy {
|
|
25
|
-
readonly name: string;
|
|
26
|
-
readonly descriptorTemplate: string;
|
|
27
|
-
readonly keys: readonly string[];
|
|
28
|
-
/**
|
|
29
|
-
* Creates and instance of a wallet policy.
|
|
30
|
-
* @param name an ascii string, up to 16 bytes long; it must be an empty string for default wallet policies
|
|
31
|
-
* @param descriptorTemplate the wallet policy template
|
|
32
|
-
* @param keys and array of the keys, with the key derivation information
|
|
33
|
-
*/
|
|
34
|
-
constructor(
|
|
35
|
-
name: string,
|
|
36
|
-
descriptorTemplate: string,
|
|
37
|
-
keys: readonly string[]
|
|
38
|
-
) {
|
|
39
|
-
this.name = name;
|
|
40
|
-
this.descriptorTemplate = descriptorTemplate;
|
|
41
|
-
this.keys = keys;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Returns the unique 32-bytes id of this wallet policy.
|
|
46
|
-
*/
|
|
47
|
-
getId(): Buffer {
|
|
48
|
-
return sha256(this.serialize());
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/**
|
|
52
|
-
* Serializes the wallet policy for transmission via the hardware wallet protocol.
|
|
53
|
-
* @returns the serialized wallet policy
|
|
54
|
-
*/
|
|
55
|
-
serialize(): Buffer {
|
|
56
|
-
const keyBuffers = this.keys.map((k) => Buffer.from(k, 'ascii'));
|
|
57
|
-
const m = new Merkle(keyBuffers.map((k) => hashLeaf(k)));
|
|
58
|
-
|
|
59
|
-
const buf = new BufferWriter();
|
|
60
|
-
buf.writeUInt8(WALLET_POLICY_V2); // wallet version
|
|
61
|
-
|
|
62
|
-
// length of wallet name, and wallet name
|
|
63
|
-
buf.writeVarSlice(Buffer.from(this.name, 'ascii'));
|
|
64
|
-
|
|
65
|
-
// length of descriptor template
|
|
66
|
-
buf.writeVarInt(this.descriptorTemplate.length);
|
|
67
|
-
// sha256 hash of descriptor template
|
|
68
|
-
buf.writeSlice(sha256(Buffer.from(this.descriptorTemplate)));
|
|
69
|
-
|
|
70
|
-
// number of keys
|
|
71
|
-
buf.writeVarInt(this.keys.length);
|
|
72
|
-
// root of Merkle tree of keys
|
|
73
|
-
buf.writeSlice(m.getRoot());
|
|
74
|
-
return buf.buffer();
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export type DefaultDescriptorTemplate =
|
|
79
|
-
| 'pkh(@0/**)'
|
|
80
|
-
| 'sh(wpkh(@0/**))'
|
|
81
|
-
| 'wpkh(@0/**)'
|
|
82
|
-
| 'tr(@0/**)';
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Simplified class to handle default wallet policies that can be used without policy registration.
|
|
86
|
-
*/
|
|
87
|
-
export class DefaultWalletPolicy extends WalletPolicy {
|
|
88
|
-
constructor(descriptorTemplate: DefaultDescriptorTemplate, key: string) {
|
|
89
|
-
super('', descriptorTemplate, [key]);
|
|
90
|
-
}
|
|
91
|
-
}
|