smartledger-bsv 3.3.5 → 3.4.4

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.
Files changed (126) hide show
  1. package/CHANGELOG.md +400 -0
  2. package/README.md +235 -80
  3. package/SECURITY.md +88 -0
  4. package/anchor-entry.js +1 -0
  5. package/bin/cli.js +354 -0
  6. package/bsv-anchor.min.js +12 -0
  7. package/bsv-covenant.min.js +8 -8
  8. package/bsv-didweb.min.js +12 -0
  9. package/bsv-gdaf.min.js +9 -9
  10. package/bsv-ltp.min.js +9 -9
  11. package/bsv-mnemonic.min.js +2 -2
  12. package/bsv-shamir.min.js +3 -3
  13. package/bsv-smartcontract.min.js +9 -9
  14. package/bsv-statuslist.min.js +18 -0
  15. package/bsv-vcjwt.min.js +12 -0
  16. package/bsv.bundle.js +9 -9
  17. package/bsv.d.ts +486 -9
  18. package/bsv.min.js +8 -8
  19. package/build/webpack.anchor.config.js +17 -0
  20. package/build/webpack.didweb.config.js +17 -0
  21. package/build/webpack.statuslist.config.js +17 -0
  22. package/build/webpack.vcjwt.config.js +17 -0
  23. package/didweb-entry.js +1 -0
  24. package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +2 -2
  25. package/docs/MODULE_REFERENCE_COMPLETE.md +61 -58
  26. package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +3 -3
  27. package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
  28. package/docs/getting-started/INSTALLATION.md +30 -30
  29. package/docs/getting-started/QUICK_START.md +18 -18
  30. package/docs/migration/FROM_BSV_1_5_6.md +16 -10
  31. package/docs/technical/roadmap.md +3 -3
  32. package/gdaf-entry.js +1 -2
  33. package/index.js +68 -9
  34. package/lib/anchor/index.js +102 -0
  35. package/lib/browser-utxo-manager-es5.js +11 -4
  36. package/lib/browser-utxo-manager.js +15 -8
  37. package/lib/didweb/index.js +177 -0
  38. package/lib/ltp/claim.js +1 -0
  39. package/lib/ltp/obligation.js +1 -0
  40. package/lib/ltp/registry.js +2 -0
  41. package/lib/ltp/right.js +1 -0
  42. package/lib/smart_contract/covenant.js +10 -1
  43. package/lib/smartutxo.js +20 -12
  44. package/lib/statuslist/index.js +164 -0
  45. package/lib/transaction/transaction.js +8 -1
  46. package/lib/util/_.js +7 -1
  47. package/lib/vcjwt/index.js +189 -0
  48. package/ltp-entry.js +1 -2
  49. package/package.json +21 -15
  50. package/statuslist-entry.js +1 -0
  51. package/utilities/blockchain-state.js +32 -23
  52. package/vcjwt-entry.js +1 -0
  53. package/demos/README.md +0 -188
  54. package/demos/architecture_demo.js +0 -247
  55. package/demos/browser-test.html +0 -1208
  56. package/demos/bsv_wallet_demo.js +0 -242
  57. package/demos/complete_ltp_demo.js +0 -511
  58. package/demos/debug_tools_demo.js +0 -87
  59. package/demos/demo_features.js +0 -123
  60. package/demos/easy_interface_demo.js +0 -109
  61. package/demos/ecies_demo.js +0 -182
  62. package/demos/gdaf_core_test.js +0 -131
  63. package/demos/gdaf_demo.js +0 -237
  64. package/demos/ltp_demo.js +0 -361
  65. package/demos/ltp_primitives_demo.js +0 -403
  66. package/demos/message_demo.js +0 -209
  67. package/demos/preimage_separation_demo.js +0 -383
  68. package/demos/script_helper_demo.js +0 -289
  69. package/demos/security_demo.js +0 -287
  70. package/demos/shamir_demo.js +0 -121
  71. package/demos/simple_demo.js +0 -204
  72. package/demos/simple_p2pkh_demo.js +0 -169
  73. package/demos/simple_utxo_preimage_demo.js +0 -196
  74. package/demos/smart_contract_demo.html +0 -1347
  75. package/demos/smart_contract_demo.js +0 -910
  76. package/demos/utxo_generator_demo.js +0 -244
  77. package/demos/validation_pipeline_demo.js +0 -155
  78. package/demos/web3keys.html +0 -740
  79. package/examples/README.md +0 -200
  80. package/examples/basic/transaction-creation.js +0 -534
  81. package/examples/basic/transaction_signature_api_gap.js +0 -178
  82. package/examples/complete_workflow_demo.js +0 -783
  83. package/examples/covenants/advanced_covenant_demo.js +0 -219
  84. package/examples/covenants/covenant_interface_demo.js +0 -270
  85. package/examples/covenants/covenant_manual_signature_resolved.js +0 -212
  86. package/examples/covenants/covenant_signature_template.js +0 -117
  87. package/examples/covenants2/covenant_bidirectional_example.js +0 -262
  88. package/examples/covenants2/covenant_utils_demo.js +0 -120
  89. package/examples/covenants2/preimage_covenant_utils.js +0 -287
  90. package/examples/covenants2/production_integration.js +0 -256
  91. package/examples/data/covenant_utxos.json +0 -28
  92. package/examples/data/utxos.json +0 -26
  93. package/examples/definitive_working_demo.js +0 -261
  94. package/examples/final_working_contracts.js +0 -338
  95. package/examples/preimage/README.md +0 -178
  96. package/examples/preimage/extract_preimage_bidirectional.js +0 -421
  97. package/examples/preimage/generate_sample_preimage.js +0 -208
  98. package/examples/preimage/generate_sighash_examples.js +0 -152
  99. package/examples/preimage/parse_preimage.js +0 -117
  100. package/examples/preimage/test_preimage_extractor.js +0 -53
  101. package/examples/preimage/test_varint_extraction.js +0 -95
  102. package/examples/scripts/custom_script_helper_example.js +0 -273
  103. package/examples/scripts/custom_script_signature_test.js +0 -344
  104. package/examples/scripts/script_interpreter.js +0 -193
  105. package/examples/smart_contract/complete_workflow_demo.js +0 -343
  106. package/examples/smart_contract/covenant_builder_demo.js +0 -176
  107. package/examples/smart_contract/script_testing_integration.js +0 -198
  108. package/examples/smart_contract_templates.js +0 -718
  109. package/examples/working_smart_contracts.js +0 -348
  110. package/lib/smart_contract/test_integration.js +0 -269
  111. package/tests/browser-compatibility/README.md +0 -35
  112. package/tests/browser-compatibility/test-cdn-vs-local.html +0 -186
  113. package/tests/browser-compatibility/test-pbkdf2.html +0 -51
  114. package/tests/bundle-completeness-test.html +0 -131
  115. package/tests/bundle-demo.html +0 -476
  116. package/tests/smartcontract-test.html +0 -239
  117. package/tests/standalone-modules-test.html +0 -260
  118. package/tests/test.html +0 -612
  119. package/tests/test_builtin_verify.js +0 -117
  120. package/tests/test_debug_integration.js +0 -71
  121. package/tests/test_ecdsa_little.js +0 -70
  122. package/tests/test_shamir.js +0 -221
  123. package/tests/test_smartverify_der.js +0 -110
  124. package/tests/test_standalone_shamir.html +0 -83
  125. package/tests/unpkg-demo.html +0 -194
  126. package/utilities/blockchain-state.json +0 -118565
@@ -1,178 +0,0 @@
1
- # BIP-143 Preimage Tools
2
-
3
- This directory contains tools and examples for working with Bitcoin BIP-143 transaction preimages.
4
-
5
- ## Files
6
-
7
- ### `extract_preimage_bidirectional.js`
8
- **Advanced bidirectional preimage field extractor with optimal ASM generation**
9
-
10
- Intelligently extracts any BIP-143 preimage field using the most efficient strategy:
11
- - **LEFT extraction** for early fields (nVersion, hashPrevouts, etc.)
12
- - **RIGHT extraction** for late fields (value, nLocktime, sighashType, etc.)
13
- - **DYNAMIC extraction** for variable-length scriptCode
14
-
15
- #### Features
16
- - āœ… Complete BIP-143 specification compliance
17
- - āœ… Optimal operation count for each field
18
- - āœ… Generates production-ready Bitcoin Script ASM
19
- - āœ… Handles variable scriptCode dynamically
20
- - āœ… Robust error handling and validation
21
- - āœ… Field interpretation (satoshis, version numbers, etc.)
22
-
23
- #### Usage
24
- ```bash
25
- # Extract any preimage field
26
- node extract_preimage_bidirectional.js <preimage_hex> <field_name>
27
-
28
- # Examples
29
- node extract_preimage_bidirectional.js 01000000ab12cd... scriptCode
30
- node extract_preimage_bidirectional.js 01000000ab12cd... value
31
- node extract_preimage_bidirectional.js 01000000ab12cd... sighashType
32
- ```
33
-
34
- #### Available Fields
35
-
36
- **LEFT Fields (fixed offsets from start):**
37
- - `nVersion` (4 bytes) - Transaction version
38
- - `hashPrevouts` (32 bytes) - Hash of all input outpoints
39
- - `hashSequence` (32 bytes) - Hash of all input sequences
40
- - `outpoint_txid` (32 bytes) - Current input's previous transaction ID
41
- - `outpoint_vout` (4 bytes) - Current input's previous output index
42
- - `scriptLen` (1 byte) - Length of the scriptCode
43
-
44
- **DYNAMIC Field (uses internal length):**
45
- - `scriptCode` (variable) - The script being executed
46
-
47
- **RIGHT Fields (fixed offsets from end):**
48
- - `value` (8 bytes) - Input amount in satoshis
49
- - `nSequence` (4 bytes) - Current input's sequence number
50
- - `hashOutputs` (32 bytes) - Hash of all outputs
51
- - `nLocktime` (4 bytes) - Transaction lock time
52
- - `sighashType` (4 bytes) - Signature hash type
53
-
54
- #### Integration with Covenant Framework
55
-
56
- The generated ASM can be used directly in covenant locking scripts:
57
-
58
- ```javascript
59
- const { CovenantInterface } = require('../../lib/covenant-interface');
60
-
61
- // Use bidirectional extraction in covenant
62
- const covenant = new CovenantInterface();
63
- const script = covenant.createAdvancedCovenant({
64
- type: 'custom',
65
- rules: {
66
- // Insert generated ASM for preimage field extraction
67
- extractValue: `
68
- # Generated by extract_preimage_bidirectional.js
69
- OP_SIZE
70
- 52 OP_SUB
71
- OP_SPLIT
72
- OP_DROP
73
- 8 OP_SPLIT
74
- OP_DROP
75
- `
76
- }
77
- });
78
- ```
79
-
80
- #### BIP-143 Structure Reference
81
-
82
- ```
83
- Total: LEFT(105) + scriptCode(variable) + RIGHT(52) bytes
84
-
85
- LEFT ZONE (105 bytes): DYNAMIC: RIGHT ZONE (52 bytes):
86
- ā”œā”€ nVersion (4) ā”œā”€ scriptCode ā”œā”€ value (8)
87
- ā”œā”€ hashPrevouts (32) └─ (scriptLen bytes) ā”œā”€ nSequence (4)
88
- ā”œā”€ hashSequence (32) ā”œā”€ hashOutputs (32)
89
- ā”œā”€ outpoint_txid (32) ā”œā”€ nLocktime (4)
90
- ā”œā”€ outpoint_vout (4) └─ sighashType (4)
91
- └─ scriptLen (1)
92
- ```
93
-
94
- ## See Also
95
- - `../../docs/preimage.md` - BIP-143 technical specification
96
- - `../../docs/ADVANCED_COVENANT_DEVELOPMENT.md` - Covenant implementation guide
97
- - `../covenants/` - Complete covenant examples using preimage extraction
98
- - `../../lib/covenant-interface.js` - CovenantPreimage class implementation
99
-
100
- ### `generate_sighash_examples.js`
101
- **SIGHASH flag preimage generator demonstrating "zero hash" behavior**
102
-
103
- Explains why multi-input transactions appear to have "extra zeros" - they're not bugs but required by BIP-143 SIGHASH rules:
104
-
105
- #### Features
106
- - āœ… Complete SIGHASH flag support (ALL, NONE, SINGLE, ANYONECANPAY)
107
- - āœ… Demonstrates zero hash field behavior
108
- - āœ… Educational tool for multi-input transaction analysis
109
- - āœ… Integration with bidirectional extractor
110
-
111
- #### Usage
112
- ```bash
113
- # Generate SIGHASH examples
114
- node generate_sighash_examples.js [sighash_type]
115
-
116
- # Examples showing zero hash behavior
117
- node generate_sighash_examples.js ALL_ANYONECANPAY_FORKID # Zero hashPrevouts + hashSequence
118
- node generate_sighash_examples.js NONE_FORKID # Zero hashOutputs
119
- node generate_sighash_examples.js NONE_ANYONECANPAY_FORKID # Zero all hash fields
120
- ```
121
-
122
- #### SIGHASH Flag Behavior
123
- | SIGHASH Type | hashPrevouts | hashSequence | hashOutputs | Use Case |
124
- |--------------|-------------|-------------|-------------|-----------|
125
- | ALL_FORKID | Normal | Normal | Normal | Standard signing |
126
- | NONE_FORKID | Normal | Normal | **Zero** | Blank check |
127
- | SINGLE_FORKID | Normal | Normal | **Zero** | One-to-one |
128
- | ALL_ANYONECANPAY_FORKID | **Zero** | **Zero** | Normal | Crowdfunding |
129
- | NONE_ANYONECANPAY_FORKID | **Zero** | **Zero** | **Zero** | Maximum flexibility |
130
-
131
- ### `test_varint_extraction.js`
132
- **Comprehensive CompactSize varint test suite**
133
-
134
- Validates proper parsing of 1-3 byte CompactSize varints in real-world scenarios:
135
- - 1-byte encoding: 0-252 bytes (most common)
136
- - 3-byte encoding: 253-65535 bytes (large scripts)
137
- - 5-byte encoding: 65536+ bytes (huge scripts)
138
-
139
- ## 🧠 **Understanding the "Extra Zero" Mystery**
140
-
141
- ### The Problem
142
- Developers often see patterns like this in BSV preimages and think it's a bug:
143
- ```
144
- ...1976a914000000000000...
145
- ```
146
-
147
- ### The Reality
148
- These zeros are **intentional** and required by Bitcoin's BIP-143 specification:
149
-
150
- 1. **CompactSize Varint Encoding**
151
- - Scripts ≄253 bytes use 3-byte encoding: `0xFD + 2-byte length`
152
- - This adds "extra bytes" that look like zeros to developers expecting 1-byte
153
-
154
- 2. **SIGHASH Flag Behavior**
155
- - `ANYONECANPAY`: Zeros out `hashPrevouts` and `hashSequence` (64 zero bytes)
156
- - `NONE`: Zeros out `hashOutputs` (32 zero bytes)
157
- - `SINGLE`: Zeros out `hashOutputs` for unmatched outputs
158
-
159
- 3. **Multi-Input Concatenation Issues**
160
- - Wrong byte boundary slicing between inputs
161
- - Reusing preimage buffers without proper re-serialization
162
-
163
- ### The Solution
164
- Our bidirectional extractor handles all these cases:
165
- - āœ… **Auto-detects** CompactSize varint size (1-3 bytes)
166
- - āœ… **Warns about** zero hashes with SIGHASH flag context
167
- - āœ… **Validates** preimage structure against BIP-143
168
- - āœ… **Generates** optimal ASM regardless of complexity
169
-
170
- ## Performance Notes
171
-
172
- The enhanced bidirectional strategy minimizes script operations:
173
- - **LEFT fields**: Direct offset splitting (2-3 operations)
174
- - **RIGHT fields**: Size-based splitting (3-4 operations)
175
- - **scriptCode**: Dynamic extraction using CompactSize varint (3-4 operations)
176
- - **Zero hash detection**: Automatic with contextual warnings
177
-
178
- This is significantly more efficient than linear parsing and handles all BIP-143 edge cases that break traditional parsers.
@@ -1,421 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * extract_preimage_bidirectional.js
4
- * ---------------------------------------------------------------------
5
- * Extract any part of the transaction preimage intelligently by slicing
6
- * from either LEFT or RIGHT based on what is known.
7
- * Handles variable scriptCode length via dynamic slicing.
8
- *
9
- * Part of the Preimage Covenant Tools - implements bidirectional slicing
10
- * strategy for optimal preimage field extraction in Bitcoin Script.
11
- *
12
- * Usage:
13
- * node extract_preimage_bidirectional.js <raw_preimage_hex> <field_name>
14
- *
15
- * Example:
16
- * node extract_preimage_bidirectional.js 01000000ab12... scriptCode
17
- */
18
-
19
- const { Buffer } = require("buffer");
20
-
21
- // Fixed field definitions - LEFT side (known offsets from start)
22
- const LEFT_FIXED_FIELDS = [
23
- { name: "nVersion", len: 4 },
24
- { name: "hashPrevouts", len: 32 },
25
- { name: "hashSequence", len: 32 },
26
- { name: "outpoint_txid", len: 32 },
27
- { name: "outpoint_vout", len: 4 },
28
- // Note: scriptLen is VARIABLE (1-3 bytes CompactSize varint) - handled separately
29
- ];
30
-
31
- // Fixed field definitions - RIGHT side (known offsets from end)
32
- const RIGHT_FIXED_FIELDS = [
33
- { name: "value", len: 8 },
34
- { name: "nSequence", len: 4 },
35
- { name: "hashOutputs", len: 32 },
36
- { name: "nLocktime", len: 4 },
37
- { name: "sighashType", len: 4 },
38
- ];
39
-
40
- // Calculate total bytes on each side
41
- const LEFT_FIXED_TOTAL = LEFT_FIXED_FIELDS.reduce((a, f) => a + f.len, 0); // 104 bytes (without scriptLen varint)
42
- const RIGHT_TOTAL = RIGHT_FIXED_FIELDS.reduce((a, f) => a + f.len, 0); // 52 bytes
43
-
44
- // CompactSize varint decoder for scriptLen
45
- function decodeCompactSize(buf, offset) {
46
- if (offset >= buf.length) return { value: 0, size: 1 };
47
-
48
- const firstByte = buf[offset];
49
-
50
- if (firstByte < 0xfd) {
51
- // 1-byte encoding: 0-252
52
- return { value: firstByte, size: 1 };
53
- } else if (firstByte === 0xfd) {
54
- // 3-byte encoding: 0xfd + 2 bytes little-endian
55
- if (offset + 2 >= buf.length) return { value: 0, size: 1 };
56
- const value = buf.readUInt16LE(offset + 1);
57
- return { value, size: 3 };
58
- } else if (firstByte === 0xfe) {
59
- // 5-byte encoding: 0xfe + 4 bytes little-endian
60
- if (offset + 4 >= buf.length) return { value: 0, size: 1 };
61
- const value = buf.readUInt32LE(offset + 1);
62
- return { value, size: 5 };
63
- } else {
64
- // 0xff = 9-byte encoding (not used for script lengths)
65
- throw new Error('Invalid CompactSize varint: 8-byte integers not supported for scriptLen');
66
- }
67
- }
68
-
69
- // Helper functions
70
- function safeSlice(buf, start, end) {
71
- if (start >= buf.length) return Buffer.alloc(0);
72
- if (end > buf.length) end = buf.length;
73
- return buf.slice(start, end);
74
- }
75
-
76
- function parsePreimage(hex) {
77
- const buf = Buffer.from(hex, "hex");
78
- let offset = 0;
79
- const parsed = {};
80
-
81
- // Parse LEFT fixed fields (104 bytes)
82
- for (const f of LEFT_FIXED_FIELDS) {
83
- const part = safeSlice(buf, offset, offset + f.len);
84
- parsed[f.name] = part.toString("hex");
85
- offset += f.len;
86
- }
87
-
88
- // Parse CompactSize varint for scriptLen
89
- const scriptLenInfo = decodeCompactSize(buf, offset);
90
- parsed.scriptLen = scriptLenInfo.value;
91
- parsed.scriptLenSize = scriptLenInfo.size; // Track varint encoding size
92
- parsed.scriptLenRaw = safeSlice(buf, offset, offset + scriptLenInfo.size).toString("hex");
93
- offset += scriptLenInfo.size;
94
-
95
- // Parse variable scriptCode using decoded scriptLen
96
- const scriptCode = safeSlice(buf, offset, offset + parsed.scriptLen);
97
- parsed.scriptCode = scriptCode.toString("hex");
98
- offset += parsed.scriptLen;
99
-
100
- // Parse RIGHT fields
101
- for (const f of RIGHT_FIXED_FIELDS) {
102
- const part = safeSlice(buf, offset, offset + f.len);
103
- parsed[f.name] = part.toString("hex");
104
- offset += f.len;
105
- }
106
-
107
- // Add structure info for analysis
108
- parsed._structure = {
109
- leftFixed: LEFT_FIXED_TOTAL,
110
- scriptLenVarint: scriptLenInfo.size,
111
- scriptCode: parsed.scriptLen,
112
- rightFixed: RIGHT_TOTAL,
113
- totalCalculated: LEFT_FIXED_TOTAL + scriptLenInfo.size + parsed.scriptLen + RIGHT_TOTAL,
114
- totalActual: buf.length
115
- };
116
-
117
- return parsed;
118
- }
119
-
120
- function generateBidirectionalASM(field, preimageLength, parsed) {
121
- console.log(`\n🧠 Bidirectional Analysis for "${field}"`);
122
- console.log('='.repeat(60));
123
-
124
- // Determine extraction strategy
125
- const rightFields = RIGHT_FIXED_FIELDS.map(f => f.name);
126
- const leftFields = LEFT_FIXED_FIELDS.map(f => f.name);
127
-
128
- const isRightField = rightFields.includes(field);
129
- const isLeftField = leftFields.includes(field);
130
- const isDynamic = field === 'scriptCode';
131
- const isScriptLen = field === 'scriptLen';
132
-
133
- if (isRightField) {
134
- return generateRightExtractionASM(field, preimageLength);
135
- } else if (isLeftField) {
136
- return generateLeftExtractionASM(field);
137
- } else if (isDynamic) {
138
- return generateDynamicExtractionASM(field, parsed);
139
- } else if (isScriptLen) {
140
- return generateScriptLenExtractionASM(parsed);
141
- } else {
142
- throw new Error(`Unknown field: ${field}`);
143
- }
144
- }
145
-
146
- function generateRightExtractionASM(field, preimageLength) {
147
- // Calculate offset from end
148
- let offsetFromEnd = 0;
149
- let targetLen = 0;
150
-
151
- for (const f of RIGHT_FIXED_FIELDS) {
152
- if (f.name === field) {
153
- targetLen = f.len;
154
- break;
155
- }
156
- offsetFromEnd += f.len;
157
- }
158
-
159
- console.log(`šŸ“ Strategy: Extract from RIGHT side`);
160
- console.log(` - Total preimage: ${preimageLength} bytes`);
161
- console.log(` - Right zone: ${RIGHT_TOTAL} bytes`);
162
- console.log(` - Offset from end: ${offsetFromEnd} bytes`);
163
- console.log(` - Field length: ${targetLen} bytes`);
164
-
165
- const asm = [
166
- `# šŸ”„ Extract ${field} from RIGHT side (bidirectional strategy)`,
167
- `OP_SIZE # Push preimage size: [preimage, size]`,
168
- `${RIGHT_TOTAL - offsetFromEnd} OP_SUB # Calculate split point: [preimage, split_point]`,
169
- `OP_SPLIT # Split: [left_part, right_part]`,
170
- `OP_DROP # Drop left: [right_part]`,
171
- `${targetLen} OP_SPLIT # Extract field: [remaining, ${field}]`,
172
- `OP_DROP # Clean up: [${field}]`,
173
- `# āœ… Result: ${field} is now on top of stack`
174
- ].join('\n');
175
-
176
- return asm;
177
- }
178
-
179
- function generateLeftExtractionASM(field) {
180
- // Calculate offset from start
181
- let offsetFromStart = 0;
182
- let targetLen = 0;
183
-
184
- for (const f of LEFT_FIXED_FIELDS) {
185
- if (f.name === field) {
186
- targetLen = f.len;
187
- break;
188
- }
189
- offsetFromStart += f.len;
190
- }
191
-
192
- console.log(`šŸ“ Strategy: Extract from LEFT side`);
193
- console.log(` - Left fixed zone: ${LEFT_FIXED_TOTAL} bytes`);
194
- console.log(` - Offset from start: ${offsetFromStart} bytes`);
195
- console.log(` - Field length: ${targetLen} bytes`);
196
-
197
- const asm = [
198
- `# šŸ”„ Extract ${field} from LEFT side (bidirectional strategy)`,
199
- `${offsetFromStart} OP_SPLIT # Skip to field: [prefix, remainder]`,
200
- `OP_DROP # Drop prefix: [remainder]`,
201
- `${targetLen} OP_SPLIT # Extract field: [${field}, suffix]`,
202
- `OP_DROP # Clean up: [${field}]`,
203
- `# āœ… Result: ${field} is now on top of stack`
204
- ].join('\n');
205
-
206
- return asm;
207
- }
208
-
209
- function generateDynamicExtractionASM(field, parsed) {
210
- const leftZone = LEFT_FIXED_TOTAL + parsed.scriptLenSize;
211
-
212
- console.log(`šŸ“ Strategy: Extract DYNAMIC field (uses CompactSize varint)`);
213
- console.log(` - Left fixed zone: ${LEFT_FIXED_TOTAL} bytes`);
214
- console.log(` - ScriptLen varint: ${parsed.scriptLenSize} bytes (${parsed.scriptLenRaw})`);
215
- console.log(` - Script length: ${parsed.scriptLen} bytes`);
216
- console.log(` - Skip zone total: ${leftZone} bytes`);
217
-
218
- const asm = [
219
- `# šŸŽÆ Extract ${field} DYNAMICALLY with CompactSize varint support`,
220
- `${leftZone} OP_SPLIT # Skip left zone + scriptLen varint: [left_zone, remainder]`,
221
- `OP_DROP # Drop left: [remainder]`,
222
- `${parsed.scriptLen} OP_SPLIT # Extract scriptCode: [scriptCode, right_zone]`,
223
- `OP_DROP # Clean up: [scriptCode]`,
224
- `# āœ… Result: scriptCode extracted with ${parsed.scriptLenSize}-byte varint awareness`
225
- ].join('\n');
226
-
227
- return asm;
228
- }
229
-
230
- function generateScriptLenExtractionASM(parsed) {
231
- console.log(`šŸ“ Strategy: Extract CompactSize scriptLen varint`);
232
- console.log(` - Left fixed zone: ${LEFT_FIXED_TOTAL} bytes`);
233
- console.log(` - Varint encoding: ${parsed.scriptLenSize} bytes`);
234
- console.log(` - Raw varint: ${parsed.scriptLenRaw}`);
235
- console.log(` - Decoded value: ${parsed.scriptLen}`);
236
-
237
- const asm = [
238
- `# šŸŽÆ Extract scriptLen CompactSize varint (${parsed.scriptLenSize} bytes)`,
239
- `${LEFT_FIXED_TOTAL} OP_SPLIT # Skip left fixed fields: [left_zone, remainder]`,
240
- `OP_DROP # Drop left: [remainder]`,
241
- `${parsed.scriptLenSize} OP_SPLIT # Extract varint: [scriptLen_varint, suffix]`,
242
- `OP_DROP # Clean up: [scriptLen_varint]`,
243
- `# āœ… Result: CompactSize varint (decode off-chain to get ${parsed.scriptLen})`
244
- ].join('\n');
245
-
246
- return asm;
247
- }
248
-
249
- function simulateExtraction(buf, field) {
250
- console.log(`\nšŸŽ¬ Simulating stack execution for "${field}"`);
251
- console.log('='.repeat(60));
252
-
253
- const parsed = parsePreimage(buf.toString('hex'));
254
-
255
- if (parsed[field] !== undefined) {
256
- const value = parsed[field];
257
- console.log(`šŸ“¦ Extracted value: ${value}`);
258
-
259
- // Add interpretations with CompactSize awareness
260
- if (field === 'nVersion') {
261
- const version = Buffer.from(value, 'hex').readUInt32LE(0);
262
- console.log(` šŸ“ Interpreted: Version ${version}`);
263
- } else if (field === 'value') {
264
- if (value.length === 16) { // 8 bytes = 16 hex chars
265
- const satoshis = Buffer.from(value, 'hex').readBigUInt64LE(0);
266
- console.log(` šŸ“ Interpreted: ${satoshis} satoshis`);
267
- }
268
- } else if (field === 'sighashType') {
269
- const sighashInt = Buffer.from(value, 'hex').readUInt32LE(0);
270
- const types = {
271
- 1: 'SIGHASH_ALL',
272
- 65: 'SIGHASH_ALL | FORKID',
273
- 2: 'SIGHASH_NONE',
274
- 66: 'SIGHASH_NONE | FORKID',
275
- 3: 'SIGHASH_SINGLE',
276
- 67: 'SIGHASH_SINGLE | FORKID',
277
- 129: 'SIGHASH_ALL | ANYONECANPAY',
278
- 193: 'SIGHASH_ALL | ANYONECANPAY | FORKID'
279
- };
280
- console.log(` šŸ“ Interpreted: ${types[sighashInt] || `Custom (${sighashInt})`}`);
281
- } else if (field === 'outpoint_vout') {
282
- const vout = Buffer.from(value, 'hex').readUInt32LE(0);
283
- console.log(` šŸ“ Interpreted: Output index ${vout}`);
284
- } else if (field === 'scriptLen') {
285
- console.log(` šŸ“ Interpreted: CompactSize varint (${parsed.scriptLenSize} bytes)`);
286
- console.log(` šŸ“ Raw varint: ${parsed.scriptLenRaw}`);
287
- console.log(` šŸ“ Decoded value: ${parsed.scriptLen} bytes`);
288
-
289
- if (parsed.scriptLenSize === 1) {
290
- console.log(` šŸ’” Standard encoding: value < 253 (0xFD)`);
291
- } else if (parsed.scriptLenSize === 3) {
292
- console.log(` šŸ’” Extended encoding: 0xFD + 2-byte little-endian`);
293
- } else if (parsed.scriptLenSize === 5) {
294
- console.log(` šŸ’” Long encoding: 0xFE + 4-byte little-endian`);
295
- }
296
- } else if (field === 'scriptCode') {
297
- const scriptBuf = Buffer.from(value, 'hex');
298
- if (scriptBuf.length === 25 && scriptBuf[0] === 0x76 && scriptBuf[1] === 0xa9) {
299
- console.log(` šŸ“ Interpreted: Standard P2PKH script (25 bytes)`);
300
- } else if (scriptBuf.length > 70 && scriptBuf[0] >= 0x51 && scriptBuf[0] <= 0x60) {
301
- console.log(` šŸ“ Interpreted: Multisig script (${scriptBuf.length} bytes)`);
302
- } else if (scriptBuf.length > 0 && scriptBuf[0] === 0x6a) {
303
- console.log(` šŸ“ Interpreted: OP_RETURN data script (${scriptBuf.length} bytes)`);
304
- } else {
305
- console.log(` šŸ“ Interpreted: Custom script (${scriptBuf.length} bytes)`);
306
- }
307
- } else if (['hashPrevouts', 'hashSequence', 'hashOutputs'].includes(field)) {
308
- if (value === '00'.repeat(32)) {
309
- console.log(` āš ļø Zero hash detected - check SIGHASH flags (ANYONECANPAY, NONE, SINGLE)`);
310
- } else {
311
- console.log(` šŸ“ Interpreted: 32-byte hash (${value.substring(0, 16)}...)`);
312
- }
313
- }
314
- } else {
315
- console.log(`āŒ Field "${field}" not found in parsed preimage`);
316
- }
317
- }
318
-
319
- // CLI Interface
320
- if (process.argv.length < 4) {
321
- console.log("🧠 Bidirectional Preimage Field Extractor v2.0");
322
- console.log("=============================================");
323
- console.log("✨ Now with CompactSize varint support for multi-input transactions!");
324
- console.log("");
325
- console.log("Usage: node extract_preimage_bidirectional.js <preimage_hex> <field_name>");
326
- console.log("");
327
- console.log("šŸ”„ LEFT Fields (fixed offsets from start):");
328
- LEFT_FIXED_FIELDS.forEach(f => {
329
- console.log(` - ${f.name.padEnd(16)} (${f.len} bytes)`);
330
- });
331
- console.log(" - scriptLen (1-3 bytes CompactSize varint)");
332
- console.log("");
333
- console.log("šŸŽÆ DYNAMIC Field (uses CompactSize scriptLen):");
334
- console.log(` - scriptCode (variable, decoded from scriptLen varint)`);
335
- console.log("");
336
- console.log("šŸ”„ RIGHT Fields (fixed offsets from end):");
337
- RIGHT_FIXED_FIELDS.forEach(f => {
338
- console.log(` - ${f.name.padEnd(16)} (${f.len} bytes)`);
339
- });
340
- console.log("");
341
- console.log("šŸ“– CompactSize Encoding:");
342
- console.log(" < 253 (0xFD) → 1 byte");
343
- console.log(" 253-65535 → 3 bytes (0xFD + 2-byte LE)");
344
- console.log(" 65536-4294967295 → 5 bytes (0xFE + 4-byte LE)");
345
- console.log("");
346
- console.log("Examples:");
347
- console.log(" node extract_preimage_bidirectional.js 01000000ab12cd... scriptCode");
348
- console.log(" node extract_preimage_bidirectional.js 01000000ab12cd... scriptLen");
349
- console.log(" node extract_preimage_bidirectional.js 01000000ab12cd... value");
350
- process.exit(1);
351
- }
352
-
353
- const hex = process.argv[2];
354
- const field = process.argv[3];
355
-
356
- // Validate input
357
- if (!/^[0-9a-fA-F]+$/.test(hex)) {
358
- console.error("āŒ Invalid hex string. Please provide a valid hexadecimal preimage.");
359
- process.exit(1);
360
- }
361
-
362
- if (hex.length < 200) {
363
- console.error("āŒ Preimage too short. Expected at least 100+ bytes for valid BIP-143 preimage.");
364
- process.exit(1);
365
- }
366
-
367
- try {
368
- const buf = Buffer.from(hex, "hex");
369
- const parsed = parsePreimage(hex);
370
-
371
- console.log(`\nšŸ” Bidirectional Preimage Analysis`);
372
- console.log('='.repeat(60));
373
- console.log(`šŸ“Š Total preimage: ${buf.length} bytes (${hex.length} hex chars)`);
374
- console.log(`šŸ“‹ Structure: LEFT(${parsed._structure.leftFixed}) + scriptLen(${parsed._structure.scriptLenVarint}) + scriptCode(${parsed._structure.scriptCode}) + RIGHT(${parsed._structure.rightFixed}) = ${parsed._structure.totalCalculated} bytes`);
375
-
376
- // Validate structure with CompactSize awareness
377
- if (buf.length !== parsed._structure.totalCalculated) {
378
- console.log(`āš ļø Size mismatch: expected ${parsed._structure.totalCalculated}, got ${buf.length}`);
379
- console.log(`šŸ’” Check: CompactSize varint encoding, script serialization, SIGHASH flags`);
380
- } else {
381
- console.log(`āœ… Structure validated: Perfect BIP-143 compliance`);
382
- }
383
-
384
- // Show CompactSize details
385
- if (parsed.scriptLenSize > 1) {
386
- console.log(`šŸ” CompactSize Details: ${parsed.scriptLen} bytes encoded as ${parsed.scriptLenSize}-byte varint (${parsed.scriptLenRaw})`);
387
- }
388
-
389
- // Generate and display ASM
390
- const asm = generateBidirectionalASM(field, buf.length, parsed);
391
- console.log(`\nšŸ“œ Generated ASM:`);
392
- console.log(asm);
393
-
394
- // Simulate extraction
395
- simulateExtraction(buf, field);
396
-
397
- } catch (error) {
398
- console.error("āŒ Error:", error.message);
399
- if (error.message.includes('Invalid hex')) {
400
- console.error("šŸ’” Tip: Make sure your preimage is valid hexadecimal");
401
- } else if (error.message.includes('Unknown field')) {
402
- console.error("šŸ’” Tip: Check available fields with --help");
403
- }
404
- process.exit(1);
405
- }
406
-
407
- // Add helpful footer
408
- console.log("\n" + "=".repeat(60));
409
- console.log("šŸŽÆ Enhanced Bidirectional Strategy Benefits:");
410
- console.log(" āœ… Optimal extraction direction for each field");
411
- console.log(" āœ… CompactSize varint scriptLen support (1-3 bytes)");
412
- console.log(" āœ… Handles multi-input transaction preimages");
413
- console.log(" āœ… SIGHASH flag awareness (zero hash detection)");
414
- console.log(" āœ… Self-contained (no external context needed)");
415
- console.log(" āœ… Generates minimal ASM operations");
416
- console.log("");
417
- console.log("šŸ”— Integration with Covenant Tools:");
418
- console.log(" - Use generated ASM in covenant locking scripts");
419
- console.log(" - Verify preimage components with dynamic extraction");
420
- console.log(" - Build advanced covenant patterns with field isolation");
421
- console.log("šŸ“– See DOCUMENTATION.md for complete covenant implementation");