@btc-vision/bitcoin 7.0.0-beta.0 → 7.0.0-beta.1
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/README.md +112 -13
- package/benchmark-compare/BENCHMARK.md +74 -59
- package/benchmark-compare/compare.bench.ts +249 -96
- package/benchmark-compare/harness.ts +23 -25
- package/benchmark-compare/package.json +1 -0
- package/browser/address.d.ts +4 -4
- package/browser/address.d.ts.map +1 -1
- package/browser/chunks/{psbt-parallel-B-dfm5GZ.js → psbt-parallel-jZ6QcCnM.js} +3128 -2731
- package/browser/index.d.ts +1 -1
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +603 -585
- package/browser/io/base58check.d.ts +1 -25
- package/browser/io/base58check.d.ts.map +1 -1
- package/browser/io/base64.d.ts.map +1 -1
- package/browser/networks.d.ts +1 -0
- package/browser/networks.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts +17 -0
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/index.d.ts +3 -2
- package/browser/payments/index.d.ts.map +1 -1
- package/browser/payments/p2mr.d.ts +169 -0
- package/browser/payments/p2mr.d.ts.map +1 -0
- package/browser/payments/types.d.ts +11 -1
- package/browser/payments/types.d.ts.map +1 -1
- package/browser/psbt/bip371.d.ts +30 -0
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt/psbtutils.d.ts +1 -0
- package/browser/psbt/psbtutils.d.ts.map +1 -1
- package/browser/psbt.d.ts.map +1 -1
- package/browser/workers/index.js +9 -9
- package/build/address.d.ts +4 -4
- package/build/address.d.ts.map +1 -1
- package/build/address.js +11 -1
- package/build/address.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/io/base58check.d.ts +1 -25
- package/build/io/base58check.d.ts.map +1 -1
- package/build/io/base58check.js +1 -31
- package/build/io/base58check.js.map +1 -1
- package/build/io/base64.d.ts.map +1 -1
- package/build/io/base64.js +3 -0
- package/build/io/base64.js.map +1 -1
- package/build/networks.d.ts +1 -0
- package/build/networks.d.ts.map +1 -1
- package/build/networks.js +12 -0
- package/build/networks.js.map +1 -1
- package/build/payments/bip341.d.ts +17 -0
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +32 -1
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/index.d.ts +3 -2
- package/build/payments/index.d.ts.map +1 -1
- package/build/payments/index.js +2 -1
- package/build/payments/index.js.map +1 -1
- package/build/payments/p2mr.d.ts +178 -0
- package/build/payments/p2mr.d.ts.map +1 -0
- package/build/payments/p2mr.js +555 -0
- package/build/payments/p2mr.js.map +1 -0
- package/build/payments/types.d.ts +11 -1
- package/build/payments/types.d.ts.map +1 -1
- package/build/payments/types.js +1 -0
- package/build/payments/types.js.map +1 -1
- package/build/psbt/bip371.d.ts +30 -0
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +80 -15
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/psbtutils.d.ts +1 -0
- package/build/psbt/psbtutils.d.ts.map +1 -1
- package/build/psbt/psbtutils.js +2 -0
- package/build/psbt/psbtutils.js.map +1 -1
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +3 -2
- package/build/psbt.js.map +1 -1
- package/build/pubkey.js +1 -1
- package/build/pubkey.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/documentation/README.md +122 -0
- package/documentation/address.md +820 -0
- package/documentation/block.md +679 -0
- package/documentation/crypto.md +461 -0
- package/documentation/ecc.md +584 -0
- package/documentation/errors.md +656 -0
- package/documentation/io.md +942 -0
- package/documentation/networks.md +625 -0
- package/documentation/p2mr.md +380 -0
- package/documentation/payments.md +1485 -0
- package/documentation/psbt.md +1400 -0
- package/documentation/script.md +730 -0
- package/documentation/taproot.md +670 -0
- package/documentation/transaction.md +943 -0
- package/documentation/types.md +587 -0
- package/documentation/workers.md +1007 -0
- package/eslint.config.js +3 -0
- package/package.json +17 -14
- package/src/address.ts +22 -10
- package/src/index.ts +1 -0
- package/src/io/base58check.ts +1 -35
- package/src/io/base64.ts +5 -0
- package/src/networks.ts +13 -0
- package/src/payments/bip341.ts +36 -1
- package/src/payments/index.ts +4 -0
- package/src/payments/p2mr.ts +660 -0
- package/src/payments/types.ts +12 -0
- package/src/psbt/bip371.ts +84 -13
- package/src/psbt/psbtutils.ts +2 -0
- package/src/psbt.ts +4 -2
- package/src/pubkey.ts +1 -1
- package/test/bitcoin.core.spec.ts +1 -1
- package/test/fixtures/p2mr.json +270 -0
- package/test/integration/taproot.spec.ts +7 -3
- package/test/opnetTestnet.spec.ts +302 -0
- package/test/payments.spec.ts +3 -1
- package/test/psbt.spec.ts +297 -2
- package/test/tsconfig.json +2 -2
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
# P2MR (Pay-to-Merkle-Root) - BIP 360
|
|
2
|
+
|
|
3
|
+
P2MR is a SegWit version 2 output type that commits directly to the Merkle root of a script tree, removing the quantum-vulnerable key-path spend found in P2TR (Taproot). There is no internal public key or key tweaking.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Property | Value |
|
|
8
|
+
|----------|-------|
|
|
9
|
+
| SegWit version | 2 (`OP_2` = `0x52`) |
|
|
10
|
+
| Address prefix | `bc1z` (mainnet), `tb1z` (testnet), `bcrt1z` (regtest) |
|
|
11
|
+
| BIP | 360 |
|
|
12
|
+
| Bech32 encoding | bech32m |
|
|
13
|
+
| Witness program | 32-byte Merkle root |
|
|
14
|
+
| Key-path spend | None (quantum-safe) |
|
|
15
|
+
| Script-path spend | Yes |
|
|
16
|
+
|
|
17
|
+
### Comparison with P2TR
|
|
18
|
+
|
|
19
|
+
| Aspect | P2TR (BIP 341) | P2MR (BIP 360) |
|
|
20
|
+
|--------|----------------|----------------|
|
|
21
|
+
| SegWit version | 1 (`OP_1`) | 2 (`OP_2`) |
|
|
22
|
+
| Address prefix | `bc1p` | `bc1z` |
|
|
23
|
+
| Key-path spend | Yes | No |
|
|
24
|
+
| Output commitment | `tweakKey(internalPubkey, merkleRoot)` | `merkleRoot` directly |
|
|
25
|
+
| Control block | `33 + 32*m` bytes (includes internal pubkey) | `1 + 32*m` bytes (no internal pubkey) |
|
|
26
|
+
| Control byte parity bit | 0 or 1 | Always 1 |
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import {
|
|
34
|
+
payments,
|
|
35
|
+
rootHashFromPathP2MR,
|
|
36
|
+
tapBranchHash,
|
|
37
|
+
toHashTree,
|
|
38
|
+
tapleafHash,
|
|
39
|
+
findScriptPath,
|
|
40
|
+
} from '@btc-vision/bitcoin';
|
|
41
|
+
|
|
42
|
+
const { P2MR, p2mr } = payments;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Class: P2MR
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
class P2MR {
|
|
51
|
+
static readonly NAME = 'p2mr';
|
|
52
|
+
|
|
53
|
+
constructor(params: {
|
|
54
|
+
address?: string;
|
|
55
|
+
hash?: Uint8Array;
|
|
56
|
+
scriptTree?: Taptree;
|
|
57
|
+
output?: Uint8Array;
|
|
58
|
+
witness?: Uint8Array[];
|
|
59
|
+
redeem?: ScriptRedeem;
|
|
60
|
+
redeemVersion?: number;
|
|
61
|
+
network?: Network;
|
|
62
|
+
}, opts?: PaymentOpts);
|
|
63
|
+
|
|
64
|
+
// Properties
|
|
65
|
+
get name(): 'p2mr';
|
|
66
|
+
get network(): Network;
|
|
67
|
+
get address(): string | undefined;
|
|
68
|
+
get hash(): Bytes32 | undefined;
|
|
69
|
+
get output(): Script | undefined;
|
|
70
|
+
get redeem(): ScriptRedeem | undefined;
|
|
71
|
+
get redeemVersion(): number;
|
|
72
|
+
get witness(): Uint8Array[] | undefined;
|
|
73
|
+
|
|
74
|
+
// Static factory methods
|
|
75
|
+
static fromScriptTree(scriptTree: Taptree, network?: Network): P2MR;
|
|
76
|
+
static fromAddress(address: string, network?: Network): P2MR;
|
|
77
|
+
static fromOutput(output: Uint8Array, network?: Network): P2MR;
|
|
78
|
+
static fromHash(hash: Bytes32, network?: Network): P2MR;
|
|
79
|
+
|
|
80
|
+
toPayment(): P2MRPayment;
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Examples
|
|
87
|
+
|
|
88
|
+
### Creating from a Script Tree
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { P2MR } from '@btc-vision/bitcoin';
|
|
92
|
+
import * as script from '@btc-vision/bitcoin/script';
|
|
93
|
+
|
|
94
|
+
// Single-leaf script tree
|
|
95
|
+
const scriptTree = {
|
|
96
|
+
output: script.compile([script.opcodes.OP_1]),
|
|
97
|
+
};
|
|
98
|
+
const payment = P2MR.fromScriptTree(scriptTree);
|
|
99
|
+
|
|
100
|
+
console.log(payment.address); // bc1z...
|
|
101
|
+
console.log(payment.hash); // 32-byte Merkle root
|
|
102
|
+
console.log(payment.output); // OP_2 <32-byte hash>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Creating from a Multi-Leaf Script Tree
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
// Two-leaf tree
|
|
109
|
+
const scriptTree = [
|
|
110
|
+
{ output: script1 },
|
|
111
|
+
{ output: script2 },
|
|
112
|
+
];
|
|
113
|
+
const payment = P2MR.fromScriptTree(scriptTree);
|
|
114
|
+
|
|
115
|
+
// Three-leaf tree (nested)
|
|
116
|
+
const deepTree = [
|
|
117
|
+
[
|
|
118
|
+
{ output: leafA },
|
|
119
|
+
{ output: leafB },
|
|
120
|
+
],
|
|
121
|
+
{ output: leafC },
|
|
122
|
+
];
|
|
123
|
+
const deep = P2MR.fromScriptTree(deepTree);
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Creating from an Address
|
|
127
|
+
|
|
128
|
+
```typescript
|
|
129
|
+
const payment = P2MR.fromAddress('bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq');
|
|
130
|
+
console.log(payment.hash); // 32-byte Merkle root
|
|
131
|
+
console.log(payment.output); // OP_2 <32-byte hash>
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Creating from a Merkle Root Hash
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import { toBytes32 } from '@btc-vision/bitcoin';
|
|
138
|
+
|
|
139
|
+
const merkleRoot = toBytes32(rootHashBytes);
|
|
140
|
+
const payment = P2MR.fromHash(merkleRoot);
|
|
141
|
+
|
|
142
|
+
console.log(payment.address); // bc1z...
|
|
143
|
+
console.log(payment.output); // OP_2 <32-byte hash>
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Creating from an Output Script
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const payment = P2MR.fromOutput(scriptPubKey);
|
|
150
|
+
console.log(payment.hash); // 32-byte Merkle root
|
|
151
|
+
console.log(payment.address); // bc1z...
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### Script-Path Spending (Witness Construction)
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
// Define the tree and redeem script
|
|
158
|
+
const scriptTree = [
|
|
159
|
+
{ output: redeemScript },
|
|
160
|
+
{ output: otherScript },
|
|
161
|
+
];
|
|
162
|
+
const payment = new P2MR({
|
|
163
|
+
scriptTree,
|
|
164
|
+
redeem: { output: redeemScript },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
// The witness contains the script and control block
|
|
168
|
+
console.log(payment.witness);
|
|
169
|
+
// [redeemScript, controlBlock]
|
|
170
|
+
// controlBlock = [version | 0x01, ...merklePath]
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Legacy Factory Function
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
function p2mr(
|
|
177
|
+
a: Omit<P2MRPayment, 'name'>,
|
|
178
|
+
opts?: PaymentOpts
|
|
179
|
+
): P2MRPayment;
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
At least one of `address`, `output`, `hash`, `scriptTree`, or `witness` (length > 1) must be provided, otherwise `TypeError('Not enough data')` is thrown.
|
|
183
|
+
|
|
184
|
+
`PaymentOpts` supports both `validate` (default `true`) and `allowIncomplete` (default `false`).
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
import { payments } from '@btc-vision/bitcoin';
|
|
188
|
+
const { p2mr } = payments;
|
|
189
|
+
|
|
190
|
+
const payment = p2mr({ scriptTree });
|
|
191
|
+
const fromHash = p2mr({ hash: merkleRoot });
|
|
192
|
+
const fromAddress = p2mr({ address: 'bc1z...' });
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Script Structure
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
Output: OP_2 <32-byte merkle root>
|
|
201
|
+
Script-path witness: [script inputs..., script, control block]
|
|
202
|
+
Control block: [version_byte | 0x01, merkle_path_hash_1, ..., merkle_path_hash_m]
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
The control block is significantly simpler than P2TR because there is no internal public key:
|
|
206
|
+
|
|
207
|
+
| Field | Size | Description |
|
|
208
|
+
|-------|------|-------------|
|
|
209
|
+
| Control byte | 1 byte | `leaf_version \| 0x01` (parity bit always 1) |
|
|
210
|
+
| Merkle path | `32 * m` bytes | Sibling hashes from leaf to root |
|
|
211
|
+
|
|
212
|
+
The total control block length is `1 + 32*m` where `0 <= m <= 128`.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## P2MR Utilities
|
|
217
|
+
|
|
218
|
+
### rootHashFromPathP2MR
|
|
219
|
+
|
|
220
|
+
Reconstructs the Merkle root from a P2MR control block and leaf hash. Unlike `rootHashFromPath` (P2TR), the merkle path starts at offset 1 since there is no internal public key.
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { rootHashFromPathP2MR, tapleafHash, LEAF_VERSION_TAPSCRIPT } from '@btc-vision/bitcoin';
|
|
224
|
+
|
|
225
|
+
const leafHash = tapleafHash({
|
|
226
|
+
output: redeemScript,
|
|
227
|
+
version: LEAF_VERSION_TAPSCRIPT,
|
|
228
|
+
});
|
|
229
|
+
const merkleRoot = rootHashFromPathP2MR(controlBlock, leafHash);
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### tapBranchHash
|
|
233
|
+
|
|
234
|
+
Computes the `TapBranch` tagged hash of two child hashes.
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { tapBranchHash } from '@btc-vision/bitcoin';
|
|
238
|
+
|
|
239
|
+
const branchHash = tapBranchHash(leftChild, rightChild);
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Shared Taproot Utilities
|
|
243
|
+
|
|
244
|
+
P2MR reuses the same Merkle tree construction as P2TR (BIP 341):
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
import {
|
|
248
|
+
toHashTree,
|
|
249
|
+
findScriptPath,
|
|
250
|
+
tapleafHash,
|
|
251
|
+
LEAF_VERSION_TAPSCRIPT,
|
|
252
|
+
MAX_TAPTREE_DEPTH,
|
|
253
|
+
} from '@btc-vision/bitcoin';
|
|
254
|
+
|
|
255
|
+
// Build hash tree from script tree
|
|
256
|
+
const hashTree = toHashTree(scriptTree);
|
|
257
|
+
console.log(hashTree.hash); // Merkle root
|
|
258
|
+
|
|
259
|
+
// Get leaf hash for a specific script
|
|
260
|
+
const leafHash = tapleafHash({
|
|
261
|
+
output: script,
|
|
262
|
+
version: LEAF_VERSION_TAPSCRIPT,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// Find Merkle proof path
|
|
266
|
+
const path = findScriptPath(hashTree, leafHash);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Address Encoding and Decoding
|
|
272
|
+
|
|
273
|
+
P2MR addresses use bech32m encoding with witness version 2.
|
|
274
|
+
|
|
275
|
+
### Encoding (Output Script to Address)
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { address } from '@btc-vision/bitcoin';
|
|
279
|
+
|
|
280
|
+
// fromOutputScript auto-detects P2MR scripts
|
|
281
|
+
const addr = address.fromOutputScript(outputScript);
|
|
282
|
+
// Returns bc1z... for P2MR outputs
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### Decoding (Address to Output Script)
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
import { address } from '@btc-vision/bitcoin';
|
|
289
|
+
|
|
290
|
+
// toOutputScript auto-handles bc1z... addresses
|
|
291
|
+
const script = address.toOutputScript('bc1z...');
|
|
292
|
+
// Returns OP_2 <32-byte hash>
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Direct Bech32m Operations
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { fromBech32, toBech32 } from '@btc-vision/bitcoin';
|
|
299
|
+
|
|
300
|
+
// Decode
|
|
301
|
+
const decoded = fromBech32('bc1z...');
|
|
302
|
+
// decoded.version === 2
|
|
303
|
+
// decoded.data === 32-byte merkle root
|
|
304
|
+
|
|
305
|
+
// Encode
|
|
306
|
+
const encoded = toBech32(merkleRoot, 2, 'bc');
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
---
|
|
310
|
+
|
|
311
|
+
## Script Detection
|
|
312
|
+
|
|
313
|
+
```typescript
|
|
314
|
+
import { isP2MR } from '@btc-vision/bitcoin';
|
|
315
|
+
|
|
316
|
+
// Check if a script is a P2MR output
|
|
317
|
+
if (isP2MR(scriptPubKey)) {
|
|
318
|
+
console.log('This is a P2MR output');
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
## Type Definitions
|
|
325
|
+
|
|
326
|
+
### P2MRPayment
|
|
327
|
+
|
|
328
|
+
```typescript
|
|
329
|
+
interface P2MRPayment extends BasePayment {
|
|
330
|
+
readonly name: 'p2mr';
|
|
331
|
+
/** Merkle root of the script tree (= witness program). */
|
|
332
|
+
readonly hash?: Bytes32 | undefined;
|
|
333
|
+
/** Full taptree description (optional, dev-side). */
|
|
334
|
+
readonly scriptTree?: Taptree | undefined;
|
|
335
|
+
readonly redeemVersion?: number | undefined;
|
|
336
|
+
readonly redeem?: ScriptRedeem | undefined;
|
|
337
|
+
}
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### PaymentType
|
|
341
|
+
|
|
342
|
+
```typescript
|
|
343
|
+
const PaymentType = {
|
|
344
|
+
P2PK: 'p2pk',
|
|
345
|
+
P2PKH: 'p2pkh',
|
|
346
|
+
P2SH: 'p2sh',
|
|
347
|
+
P2MS: 'p2ms',
|
|
348
|
+
P2WPKH: 'p2wpkh',
|
|
349
|
+
P2WSH: 'p2wsh',
|
|
350
|
+
P2TR: 'p2tr',
|
|
351
|
+
P2MR: 'p2mr', // <-- New
|
|
352
|
+
P2OP: 'p2op',
|
|
353
|
+
Embed: 'embed',
|
|
354
|
+
} as const;
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
## Security Considerations
|
|
360
|
+
|
|
361
|
+
P2MR eliminates the quantum-vulnerable key-path spend by committing directly to a Merkle root without any elliptic curve operations in the output. This provides quantum resistance for the locking mechanism while maintaining the efficient script tree structure from Taproot.
|
|
362
|
+
|
|
363
|
+
Key security properties:
|
|
364
|
+
|
|
365
|
+
- **No key-path spend**: Unlike P2TR, there is no way to spend using a single signature against a tweaked public key. All spends must reveal a script from the tree.
|
|
366
|
+
- **Control byte parity**: The parity bit is always 1, simplifying validation.
|
|
367
|
+
- **Same Merkle tree security**: Uses identical `TapLeaf` and `TapBranch` tagged hash construction as BIP 341, benefiting from the same cryptographic analysis.
|
|
368
|
+
- **32-byte witness program**: Same length as P2TR, preventing output-based discrimination.
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## Differences from P2TR for Developers
|
|
373
|
+
|
|
374
|
+
If you are familiar with P2TR, here are the key differences when working with P2MR:
|
|
375
|
+
|
|
376
|
+
1. **No `internalPubkey` or `pubkey`**: P2MR has no concept of an internal key. The `hash` field IS the Merkle root directly.
|
|
377
|
+
2. **No `signature` getter**: There is no key-path spend, so there is no signature property.
|
|
378
|
+
3. **Simpler control block**: No 32-byte internal pubkey in the control block. Just `[version_byte, ...merkle_path]`.
|
|
379
|
+
4. **Factory methods**: Use `fromScriptTree()` and `fromHash()` instead of `fromInternalPubkey()`.
|
|
380
|
+
5. **Address prefix**: `bc1z` instead of `bc1p`.
|