@smartledger/bsv 3.4.2 โ 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.
- package/CHANGELOG.md +336 -0
- package/README.md +72 -72
- package/SECURITY.md +88 -0
- package/bin/cli.js +13 -8
- package/bsv-covenant.min.js +4 -4
- package/bsv-gdaf.min.js +5 -5
- package/bsv-ltp.min.js +7 -7
- package/bsv-smartcontract.min.js +5 -5
- package/bsv.bundle.js +5 -5
- package/bsv.d.ts +486 -9
- package/bsv.min.js +5 -5
- package/docs/COVENANT_DEVELOPMENT_RESOLVED.md +2 -2
- package/docs/MODULE_REFERENCE_COMPLETE.md +61 -58
- package/docs/advanced/LEGAL_TOKEN_PROTOCOL.md +3 -3
- package/docs/advanced/UTXO_MANAGER_GUIDE.md +1 -1
- package/docs/getting-started/INSTALLATION.md +30 -30
- package/docs/getting-started/QUICK_START.md +18 -18
- package/docs/migration/FROM_BSV_1_5_6.md +16 -10
- package/gdaf-entry.js +1 -2
- package/index.js +20 -7
- package/lib/smart_contract/covenant.js +10 -1
- package/lib/smartutxo.js +20 -12
- package/lib/transaction/transaction.js +7 -0
- package/ltp-entry.js +1 -2
- package/package.json +3 -3
- package/utilities/blockchain-state.js +32 -23
- package/demos/README.md +0 -188
- package/demos/architecture_demo.js +0 -247
- package/demos/browser-test.html +0 -1208
- package/demos/bsv_wallet_demo.js +0 -242
- package/demos/complete_ltp_demo.js +0 -511
- package/demos/debug_tools_demo.js +0 -87
- package/demos/demo_features.js +0 -123
- package/demos/easy_interface_demo.js +0 -109
- package/demos/ecies_demo.js +0 -182
- package/demos/gdaf_demo.js +0 -237
- package/demos/ltp_demo.js +0 -361
- package/demos/ltp_primitives_demo.js +0 -403
- package/demos/message_demo.js +0 -209
- package/demos/preimage_separation_demo.js +0 -383
- package/demos/script_helper_demo.js +0 -289
- package/demos/security_demo.js +0 -287
- package/demos/shamir_demo.js +0 -121
- package/demos/simple_demo.js +0 -204
- package/demos/simple_p2pkh_demo.js +0 -169
- package/demos/simple_utxo_preimage_demo.js +0 -196
- package/demos/smart_contract_demo.html +0 -1347
- package/demos/smart_contract_demo.js +0 -910
- package/demos/utxo_generator_demo.js +0 -244
- package/demos/validation_pipeline_demo.js +0 -155
- package/demos/web3keys.html +0 -740
- package/examples/README.md +0 -200
- package/examples/basic/transaction-creation.js +0 -534
- package/examples/basic/transaction_signature_api_gap.js +0 -178
- package/examples/complete_workflow_demo.js +0 -783
- package/examples/covenants/advanced_covenant_demo.js +0 -219
- package/examples/covenants/covenant_interface_demo.js +0 -270
- package/examples/covenants/covenant_manual_signature_resolved.js +0 -212
- package/examples/covenants/covenant_signature_template.js +0 -117
- package/examples/covenants2/covenant_bidirectional_example.js +0 -262
- package/examples/covenants2/covenant_utils_demo.js +0 -120
- package/examples/covenants2/preimage_covenant_utils.js +0 -287
- package/examples/covenants2/production_integration.js +0 -256
- package/examples/data/covenant_utxos.json +0 -28
- package/examples/data/utxos.json +0 -26
- package/examples/definitive_working_demo.js +0 -261
- package/examples/final_working_contracts.js +0 -338
- package/examples/legacy/README.md +0 -11
- package/examples/legacy/smart_contract_test_integration.js +0 -269
- package/examples/legacy/test_builtin_verify.js +0 -117
- package/examples/legacy/test_debug_integration.js +0 -71
- package/examples/legacy/test_ecdsa_little.js +0 -70
- package/examples/legacy/test_shamir.js +0 -221
- package/examples/legacy/test_smartverify_der.js +0 -110
- package/examples/preimage/README.md +0 -178
- package/examples/preimage/extract_preimage_bidirectional.js +0 -421
- package/examples/preimage/generate_sample_preimage.js +0 -208
- package/examples/preimage/generate_sighash_examples.js +0 -152
- package/examples/preimage/parse_preimage.js +0 -117
- package/examples/preimage/test_preimage_extractor.js +0 -53
- package/examples/preimage/test_varint_extraction.js +0 -95
- package/examples/scripts/custom_script_helper_example.js +0 -273
- package/examples/scripts/script_interpreter.js +0 -193
- package/examples/smart_contract/complete_workflow_demo.js +0 -343
- package/examples/smart_contract/covenant_builder_demo.js +0 -176
- package/examples/smart_contract/script_testing_integration.js +0 -198
- package/examples/smart_contract_templates.js +0 -718
- package/examples/working_smart_contracts.js +0 -348
|
@@ -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");
|
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* generate_sample_preimage.js
|
|
4
|
-
* Advanced BIP-143 preimage generator with multiple realistic scenarios
|
|
5
|
-
*
|
|
6
|
-
* Generates various types of preimages for testing bidirectional extraction:
|
|
7
|
-
* - Standard P2PKH transactions
|
|
8
|
-
* - Multi-signature scenarios
|
|
9
|
-
* - Custom script patterns
|
|
10
|
-
* - Different value ranges
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
function createSamplePreimage(type = 'standard') {
|
|
14
|
-
const { Buffer } = require("buffer");
|
|
15
|
-
|
|
16
|
-
// Base fields (same for all types)
|
|
17
|
-
const baseFields = {
|
|
18
|
-
nVersion: Buffer.from([0x01, 0x00, 0x00, 0x00]), // Version 1
|
|
19
|
-
hashPrevouts: Buffer.alloc(32, 0xab), // Mock hash
|
|
20
|
-
hashSequence: Buffer.alloc(32, 0xcd), // Mock hash
|
|
21
|
-
outpoint_txid: Buffer.alloc(32, 0x12), // Mock TXID
|
|
22
|
-
outpoint_vout: Buffer.from([0x00, 0x00, 0x00, 0x00]), // Output 0
|
|
23
|
-
nSequence: Buffer.from([0xff, 0xff, 0xff, 0xff]), // Max sequence
|
|
24
|
-
hashOutputs: Buffer.alloc(32, 0xef), // Mock hash
|
|
25
|
-
nLocktime: Buffer.from([0x00, 0x00, 0x00, 0x00]), // No locktime
|
|
26
|
-
sighashType: Buffer.from([0x41, 0x00, 0x00, 0x00]) // SIGHASH_ALL | FORKID
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
let scriptVariant;
|
|
30
|
-
|
|
31
|
-
switch (type) {
|
|
32
|
-
case 'standard':
|
|
33
|
-
// Standard P2PKH (25 bytes)
|
|
34
|
-
scriptVariant = {
|
|
35
|
-
scriptLen: Buffer.from([0x19]), // 25 bytes
|
|
36
|
-
scriptCode: Buffer.from([
|
|
37
|
-
0x76, 0xa9, 0x14, // OP_DUP OP_HASH160 OP_PUSHDATA(20)
|
|
38
|
-
...Buffer.alloc(20, 0x88), // 20-byte pubkey hash
|
|
39
|
-
0x88, 0xac // OP_EQUALVERIFY OP_CHECKSIG
|
|
40
|
-
]),
|
|
41
|
-
value: Buffer.from([0x00, 0xe1, 0xf5, 0x05, 0x00, 0x00, 0x00, 0x00]) // 100000000 satoshis (1 BSV)
|
|
42
|
-
};
|
|
43
|
-
break;
|
|
44
|
-
|
|
45
|
-
case 'multisig':
|
|
46
|
-
// 2-of-3 multisig (71 bytes)
|
|
47
|
-
scriptVariant = {
|
|
48
|
-
scriptLen: Buffer.from([0x47]), // 71 bytes
|
|
49
|
-
scriptCode: Buffer.concat([
|
|
50
|
-
Buffer.from([0x52]), // OP_2 (required signatures)
|
|
51
|
-
Buffer.from([0x21]), Buffer.alloc(33, 0xaa), // First pubkey (33 bytes)
|
|
52
|
-
Buffer.from([0x21]), Buffer.alloc(33, 0xbb), // Second pubkey (33 bytes)
|
|
53
|
-
Buffer.from([0x21]), Buffer.alloc(33, 0xcc), // Third pubkey (33 bytes)
|
|
54
|
-
Buffer.from([0x53]), // OP_3 (total pubkeys)
|
|
55
|
-
Buffer.from([0xae]) // OP_CHECKMULTISIG
|
|
56
|
-
]),
|
|
57
|
-
value: Buffer.from([0x00, 0x40, 0x42, 0x0f, 0x00, 0x00, 0x00, 0x00]) // 2.56 BSV
|
|
58
|
-
};
|
|
59
|
-
break;
|
|
60
|
-
|
|
61
|
-
case 'custom':
|
|
62
|
-
// Custom script with OP_RETURN data (34 bytes)
|
|
63
|
-
scriptVariant = {
|
|
64
|
-
scriptLen: Buffer.from([0x22]), // 34 bytes
|
|
65
|
-
scriptCode: Buffer.concat([
|
|
66
|
-
Buffer.from([0x6a]), // OP_RETURN
|
|
67
|
-
Buffer.from([0x20]), // Push 32 bytes
|
|
68
|
-
Buffer.from('Hello Bitcoin SV - Custom Script Test', 'utf8').slice(0, 32)
|
|
69
|
-
]),
|
|
70
|
-
value: Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // 0 satoshis (OP_RETURN output)
|
|
71
|
-
};
|
|
72
|
-
break;
|
|
73
|
-
|
|
74
|
-
case 'large':
|
|
75
|
-
// Large script (300 bytes) to test CompactSize 3-byte varint (0xFD)
|
|
76
|
-
const scriptSize = 300;
|
|
77
|
-
scriptVariant = {
|
|
78
|
-
scriptLen: Buffer.from([0xfd, scriptSize & 0xff, (scriptSize >> 8) & 0xff]), // 3-byte varint: 0xFD + 2-byte LE
|
|
79
|
-
scriptCode: Buffer.concat([
|
|
80
|
-
Buffer.from([0x76, 0xa9, 0x14]), // OP_DUP OP_HASH160 OP_PUSHDATA(20)
|
|
81
|
-
Buffer.alloc(20, 0x99), // 20-byte pubkey hash
|
|
82
|
-
Buffer.from([0x88, 0xac]), // OP_EQUALVERIFY OP_CHECKSIG
|
|
83
|
-
Buffer.alloc(275, 0x6a) // Padding with OP_RETURN opcodes to reach 300 bytes
|
|
84
|
-
]),
|
|
85
|
-
value: Buffer.from([0x00, 0x10, 0xa5, 0xd4, 0xe8, 0x00, 0x00, 0x00]) // 10 BSV
|
|
86
|
-
};
|
|
87
|
-
break;
|
|
88
|
-
|
|
89
|
-
case 'huge':
|
|
90
|
-
// Huge script (70000 bytes) to test CompactSize 5-byte varint (0xFE)
|
|
91
|
-
const hugeSize = 70000;
|
|
92
|
-
scriptVariant = {
|
|
93
|
-
scriptLen: Buffer.from([
|
|
94
|
-
0xfe,
|
|
95
|
-
hugeSize & 0xff,
|
|
96
|
-
(hugeSize >> 8) & 0xff,
|
|
97
|
-
(hugeSize >> 16) & 0xff,
|
|
98
|
-
(hugeSize >> 24) & 0xff
|
|
99
|
-
]), // 5-byte varint: 0xFE + 4-byte LE
|
|
100
|
-
scriptCode: Buffer.concat([
|
|
101
|
-
Buffer.from([0x6a]), // OP_RETURN
|
|
102
|
-
Buffer.from([0x4c, 0xff, 0xff]), // OP_PUSHDATA2 + 65535 bytes
|
|
103
|
-
Buffer.alloc(65535, 0xaa), // Large data block
|
|
104
|
-
Buffer.alloc(hugeSize - 65539, 0xbb) // Remaining padding
|
|
105
|
-
]),
|
|
106
|
-
value: Buffer.from([0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) // 0 satoshis (data output)
|
|
107
|
-
};
|
|
108
|
-
break;
|
|
109
|
-
|
|
110
|
-
default:
|
|
111
|
-
throw new Error(`Unknown preimage type: ${type}`);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const fields = { ...baseFields, ...scriptVariant };
|
|
115
|
-
|
|
116
|
-
// Concatenate all fields
|
|
117
|
-
const preimage = Buffer.concat([
|
|
118
|
-
fields.nVersion,
|
|
119
|
-
fields.hashPrevouts,
|
|
120
|
-
fields.hashSequence,
|
|
121
|
-
fields.outpoint_txid,
|
|
122
|
-
fields.outpoint_vout,
|
|
123
|
-
fields.scriptLen,
|
|
124
|
-
fields.scriptCode,
|
|
125
|
-
fields.value,
|
|
126
|
-
fields.nSequence,
|
|
127
|
-
fields.hashOutputs,
|
|
128
|
-
fields.nLocktime,
|
|
129
|
-
fields.sighashType
|
|
130
|
-
]);
|
|
131
|
-
|
|
132
|
-
return preimage.toString('hex');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// CLI Interface
|
|
136
|
-
if (require.main === module) {
|
|
137
|
-
const type = process.argv[2] || 'standard';
|
|
138
|
-
|
|
139
|
-
if (type === '--help' || type === '-h') {
|
|
140
|
-
console.log("๐ฏ Advanced BIP-143 Preimage Generator");
|
|
141
|
-
console.log("=====================================");
|
|
142
|
-
console.log("Usage: node generate_sample_preimage.js [type]");
|
|
143
|
-
console.log("");
|
|
144
|
-
console.log("Available types:");
|
|
145
|
-
console.log(" standard - Standard P2PKH script (25 bytes, 1-byte varint) - DEFAULT");
|
|
146
|
-
console.log(" multisig - 2-of-3 multisig script (71 bytes, 1-byte varint)");
|
|
147
|
-
console.log(" custom - Custom OP_RETURN script (34 bytes, 1-byte varint)");
|
|
148
|
-
console.log(" large - Large script (300 bytes, 3-byte varint 0xFD)");
|
|
149
|
-
console.log(" huge - Huge script (70000 bytes, 5-byte varint 0xFE)");
|
|
150
|
-
console.log("");
|
|
151
|
-
console.log("Examples:");
|
|
152
|
-
console.log(" node generate_sample_preimage.js");
|
|
153
|
-
console.log(" node generate_sample_preimage.js multisig");
|
|
154
|
-
console.log(" node generate_sample_preimage.js large # Test 3-byte varint");
|
|
155
|
-
console.log(" node generate_sample_preimage.js huge # Test 5-byte varint");
|
|
156
|
-
process.exit(0);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
try {
|
|
160
|
-
console.log("๐ฏ Advanced BIP-143 Preimage Generator");
|
|
161
|
-
console.log("=====================================");
|
|
162
|
-
console.log(`๐ Type: ${type}`);
|
|
163
|
-
|
|
164
|
-
const sampleHex = createSamplePreimage(type);
|
|
165
|
-
const scriptLen = parseInt(sampleHex.substring(208, 210), 16); // Extract scriptLen byte
|
|
166
|
-
|
|
167
|
-
console.log(`๐ Generated: ${sampleHex.length / 2} bytes total`);
|
|
168
|
-
console.log(`๐ Structure: LEFT(105) + scriptCode(${scriptLen}) + RIGHT(52) bytes`);
|
|
169
|
-
console.log(`๐ฆ Preimage: ${sampleHex}`);
|
|
170
|
-
|
|
171
|
-
console.log("\n๐งช Test Commands:");
|
|
172
|
-
console.log(` node extract_preimage_bidirectional.js ${sampleHex} scriptCode`);
|
|
173
|
-
console.log(` node extract_preimage_bidirectional.js ${sampleHex} value`);
|
|
174
|
-
console.log(` npm run preimage:extract ${sampleHex} nVersion`);
|
|
175
|
-
|
|
176
|
-
console.log("\n๐ Field Analysis:");
|
|
177
|
-
console.log(` LEFT extraction: nVersion, hashPrevouts, hashSequence, outpoint_*, scriptLen`);
|
|
178
|
-
console.log(` DYNAMIC extraction: scriptCode (${scriptLen} bytes)`);
|
|
179
|
-
console.log(` RIGHT extraction: value, nSequence, hashOutputs, nLocktime, sighashType`);
|
|
180
|
-
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.error("โ Error:", error.message);
|
|
183
|
-
console.log("๐ก Use --help to see available types");
|
|
184
|
-
process.exit(1);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Export functions for programmatic use
|
|
189
|
-
function generateAllTypes() {
|
|
190
|
-
return {
|
|
191
|
-
standard: createSamplePreimage('standard'),
|
|
192
|
-
multisig: createSamplePreimage('multisig'),
|
|
193
|
-
custom: createSamplePreimage('custom'),
|
|
194
|
-
large: createSamplePreimage('large')
|
|
195
|
-
};
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
module.exports = {
|
|
199
|
-
createSamplePreimage,
|
|
200
|
-
generateAllTypes,
|
|
201
|
-
|
|
202
|
-
// Convenience functions
|
|
203
|
-
getStandardPreimage: () => createSamplePreimage('standard'),
|
|
204
|
-
getMultisigPreimage: () => createSamplePreimage('multisig'),
|
|
205
|
-
getCustomPreimage: () => createSamplePreimage('custom'),
|
|
206
|
-
getLargePreimage: () => createSamplePreimage('large'),
|
|
207
|
-
getHugePreimage: () => createSamplePreimage('huge')
|
|
208
|
-
};
|