@btc-vision/cli 1.0.5 → 1.0.7

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 (51) hide show
  1. package/build/index.js +3 -4
  2. package/build/lib/config.js +1 -6
  3. package/build/lib/ipfs.d.ts +0 -2
  4. package/build/lib/ipfs.js +29 -32
  5. package/build/lib/wallet.js +1 -1
  6. package/package.json +4 -1
  7. package/.gitattributes +0 -2
  8. package/.github/dependabot.yml +0 -9
  9. package/.github/workflows/ci.yml +0 -48
  10. package/.prettierrc.json +0 -12
  11. package/CONTRIBUTING.md +0 -56
  12. package/NOTICE +0 -17
  13. package/SECURITY.md +0 -35
  14. package/eslint.config.js +0 -41
  15. package/gulpfile.js +0 -41
  16. package/src/commands/AcceptCommand.ts +0 -224
  17. package/src/commands/BaseCommand.ts +0 -59
  18. package/src/commands/CompileCommand.ts +0 -195
  19. package/src/commands/ConfigCommand.ts +0 -117
  20. package/src/commands/DeprecateCommand.ts +0 -193
  21. package/src/commands/InfoCommand.ts +0 -293
  22. package/src/commands/InitCommand.ts +0 -541
  23. package/src/commands/InstallCommand.ts +0 -179
  24. package/src/commands/KeygenCommand.ts +0 -157
  25. package/src/commands/ListCommand.ts +0 -169
  26. package/src/commands/LoginCommand.ts +0 -197
  27. package/src/commands/LogoutCommand.ts +0 -76
  28. package/src/commands/PublishCommand.ts +0 -340
  29. package/src/commands/ScopeRegisterCommand.ts +0 -164
  30. package/src/commands/SearchCommand.ts +0 -140
  31. package/src/commands/SignCommand.ts +0 -110
  32. package/src/commands/TransferCommand.ts +0 -363
  33. package/src/commands/UndeprecateCommand.ts +0 -167
  34. package/src/commands/UpdateCommand.ts +0 -200
  35. package/src/commands/VerifyCommand.ts +0 -228
  36. package/src/commands/WhoamiCommand.ts +0 -113
  37. package/src/index.ts +0 -88
  38. package/src/lib/PackageRegistry.abi.json +0 -765
  39. package/src/lib/PackageRegistry.abi.ts +0 -365
  40. package/src/lib/binary.ts +0 -338
  41. package/src/lib/config.ts +0 -265
  42. package/src/lib/credentials.ts +0 -176
  43. package/src/lib/ipfs.ts +0 -382
  44. package/src/lib/manifest.ts +0 -195
  45. package/src/lib/provider.ts +0 -121
  46. package/src/lib/registry.ts +0 -467
  47. package/src/lib/transaction.ts +0 -205
  48. package/src/lib/wallet.ts +0 -262
  49. package/src/types/PackageRegistry.ts +0 -344
  50. package/src/types/index.ts +0 -147
  51. package/tsconfig.json +0 -25
@@ -1,365 +0,0 @@
1
- /**
2
- * PackageRegistry Contract ABI
3
- *
4
- * Auto-generated from PackageRegistry.abi.json
5
- */
6
-
7
- import { BitcoinAbiTypes, BitcoinInterfaceAbi } from 'opnet';
8
- import { ABIDataTypes } from '@btc-vision/transaction';
9
-
10
- export const PACKAGE_REGISTRY_ABI: BitcoinInterfaceAbi = [
11
- // Functions
12
- {
13
- name: 'setTreasuryAddress',
14
- type: BitcoinAbiTypes.Function,
15
- inputs: [{ name: 'treasuryAddress', type: ABIDataTypes.STRING }],
16
- outputs: [],
17
- },
18
- {
19
- name: 'setScopePrice',
20
- type: BitcoinAbiTypes.Function,
21
- inputs: [{ name: 'priceSats', type: ABIDataTypes.UINT64 }],
22
- outputs: [],
23
- },
24
- {
25
- name: 'setPackagePrice',
26
- type: BitcoinAbiTypes.Function,
27
- inputs: [{ name: 'priceSats', type: ABIDataTypes.UINT64 }],
28
- outputs: [],
29
- },
30
- {
31
- name: 'registerScope',
32
- type: BitcoinAbiTypes.Function,
33
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
34
- outputs: [],
35
- },
36
- {
37
- name: 'initiateScopeTransfer',
38
- type: BitcoinAbiTypes.Function,
39
- inputs: [
40
- { name: 'scopeName', type: ABIDataTypes.STRING },
41
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
42
- ],
43
- outputs: [],
44
- },
45
- {
46
- name: 'acceptScopeTransfer',
47
- type: BitcoinAbiTypes.Function,
48
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
49
- outputs: [],
50
- },
51
- {
52
- name: 'cancelScopeTransfer',
53
- type: BitcoinAbiTypes.Function,
54
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
55
- outputs: [],
56
- },
57
- {
58
- name: 'registerPackage',
59
- type: BitcoinAbiTypes.Function,
60
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
61
- outputs: [],
62
- },
63
- {
64
- name: 'publishVersion',
65
- type: BitcoinAbiTypes.Function,
66
- inputs: [
67
- { name: 'packageName', type: ABIDataTypes.STRING },
68
- { name: 'version', type: ABIDataTypes.STRING },
69
- { name: 'ipfsCid', type: ABIDataTypes.STRING },
70
- { name: 'checksum', type: ABIDataTypes.BYTES32 },
71
- { name: 'signature', type: ABIDataTypes.BYTES },
72
- { name: 'mldsaLevel', type: ABIDataTypes.UINT8 },
73
- { name: 'opnetVersionRange', type: ABIDataTypes.STRING },
74
- { name: 'pluginType', type: ABIDataTypes.UINT8 },
75
- { name: 'permissionsHash', type: ABIDataTypes.BYTES32 },
76
- { name: 'dependencies', type: ABIDataTypes.BYTES },
77
- ],
78
- outputs: [],
79
- },
80
- {
81
- name: 'deprecateVersion',
82
- type: BitcoinAbiTypes.Function,
83
- inputs: [
84
- { name: 'packageName', type: ABIDataTypes.STRING },
85
- { name: 'version', type: ABIDataTypes.STRING },
86
- { name: 'reason', type: ABIDataTypes.STRING },
87
- ],
88
- outputs: [],
89
- },
90
- {
91
- name: 'undeprecateVersion',
92
- type: BitcoinAbiTypes.Function,
93
- inputs: [
94
- { name: 'packageName', type: ABIDataTypes.STRING },
95
- { name: 'version', type: ABIDataTypes.STRING },
96
- ],
97
- outputs: [],
98
- },
99
- {
100
- name: 'initiateTransfer',
101
- type: BitcoinAbiTypes.Function,
102
- inputs: [
103
- { name: 'packageName', type: ABIDataTypes.STRING },
104
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
105
- ],
106
- outputs: [],
107
- },
108
- {
109
- name: 'acceptTransfer',
110
- type: BitcoinAbiTypes.Function,
111
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
112
- outputs: [],
113
- },
114
- {
115
- name: 'cancelTransfer',
116
- type: BitcoinAbiTypes.Function,
117
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
118
- outputs: [],
119
- },
120
- {
121
- name: 'getScope',
122
- type: BitcoinAbiTypes.Function,
123
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
124
- outputs: [
125
- { name: 'exists', type: ABIDataTypes.BOOL },
126
- { name: 'owner', type: ABIDataTypes.ADDRESS },
127
- { name: 'createdAt', type: ABIDataTypes.UINT64 },
128
- ],
129
- },
130
- {
131
- name: 'getScopeOwner',
132
- type: BitcoinAbiTypes.Function,
133
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
134
- outputs: [{ name: 'owner', type: ABIDataTypes.ADDRESS }],
135
- },
136
- {
137
- name: 'getPackage',
138
- type: BitcoinAbiTypes.Function,
139
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
140
- outputs: [
141
- { name: 'exists', type: ABIDataTypes.BOOL },
142
- { name: 'owner', type: ABIDataTypes.ADDRESS },
143
- { name: 'createdAt', type: ABIDataTypes.UINT64 },
144
- { name: 'versionCount', type: ABIDataTypes.UINT256 },
145
- { name: 'latestVersion', type: ABIDataTypes.STRING },
146
- ],
147
- },
148
- {
149
- name: 'getOwner',
150
- type: BitcoinAbiTypes.Function,
151
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
152
- outputs: [{ name: 'owner', type: ABIDataTypes.ADDRESS }],
153
- },
154
- {
155
- name: 'getVersion',
156
- type: BitcoinAbiTypes.Function,
157
- inputs: [
158
- { name: 'packageName', type: ABIDataTypes.STRING },
159
- { name: 'version', type: ABIDataTypes.STRING },
160
- ],
161
- outputs: [
162
- { name: 'exists', type: ABIDataTypes.BOOL },
163
- { name: 'ipfsCid', type: ABIDataTypes.STRING },
164
- { name: 'checksum', type: ABIDataTypes.BYTES32 },
165
- { name: 'sigHash', type: ABIDataTypes.BYTES32 },
166
- { name: 'mldsaLevel', type: ABIDataTypes.UINT8 },
167
- { name: 'opnetVersionRange', type: ABIDataTypes.STRING },
168
- { name: 'pluginType', type: ABIDataTypes.UINT8 },
169
- { name: 'permissionsHash', type: ABIDataTypes.BYTES32 },
170
- { name: 'depsHash', type: ABIDataTypes.BYTES32 },
171
- { name: 'publisher', type: ABIDataTypes.ADDRESS },
172
- { name: 'publishedAt', type: ABIDataTypes.UINT64 },
173
- { name: 'deprecated', type: ABIDataTypes.BOOL },
174
- ],
175
- },
176
- {
177
- name: 'isDeprecated',
178
- type: BitcoinAbiTypes.Function,
179
- inputs: [
180
- { name: 'packageName', type: ABIDataTypes.STRING },
181
- { name: 'version', type: ABIDataTypes.STRING },
182
- ],
183
- outputs: [{ name: 'deprecated', type: ABIDataTypes.BOOL }],
184
- },
185
- {
186
- name: 'isImmutable',
187
- type: BitcoinAbiTypes.Function,
188
- inputs: [
189
- { name: 'packageName', type: ABIDataTypes.STRING },
190
- { name: 'version', type: ABIDataTypes.STRING },
191
- ],
192
- outputs: [{ name: 'immutable', type: ABIDataTypes.BOOL }],
193
- },
194
- {
195
- name: 'getPendingTransfer',
196
- type: BitcoinAbiTypes.Function,
197
- inputs: [{ name: 'packageName', type: ABIDataTypes.STRING }],
198
- outputs: [
199
- { name: 'pendingOwner', type: ABIDataTypes.ADDRESS },
200
- { name: 'initiatedAt', type: ABIDataTypes.UINT64 },
201
- ],
202
- },
203
- {
204
- name: 'getPendingScopeTransfer',
205
- type: BitcoinAbiTypes.Function,
206
- inputs: [{ name: 'scopeName', type: ABIDataTypes.STRING }],
207
- outputs: [
208
- { name: 'pendingOwner', type: ABIDataTypes.ADDRESS },
209
- { name: 'initiatedAt', type: ABIDataTypes.UINT64 },
210
- ],
211
- },
212
- {
213
- name: 'getTreasuryAddress',
214
- type: BitcoinAbiTypes.Function,
215
- inputs: [],
216
- outputs: [{ name: 'treasuryAddress', type: ABIDataTypes.STRING }],
217
- },
218
- {
219
- name: 'getScopePrice',
220
- type: BitcoinAbiTypes.Function,
221
- inputs: [],
222
- outputs: [{ name: 'priceSats', type: ABIDataTypes.UINT64 }],
223
- },
224
- {
225
- name: 'getPackagePrice',
226
- type: BitcoinAbiTypes.Function,
227
- inputs: [],
228
- outputs: [{ name: 'priceSats', type: ABIDataTypes.UINT64 }],
229
- },
230
- // Events
231
- {
232
- name: 'TreasuryAddressChanged',
233
- type: BitcoinAbiTypes.Event,
234
- values: [
235
- { name: 'previousAddressHash', type: ABIDataTypes.UINT256 },
236
- { name: 'newAddressHash', type: ABIDataTypes.UINT256 },
237
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
238
- ],
239
- },
240
- {
241
- name: 'ScopePriceChanged',
242
- type: BitcoinAbiTypes.Event,
243
- values: [
244
- { name: 'oldPrice', type: ABIDataTypes.UINT64 },
245
- { name: 'newPrice', type: ABIDataTypes.UINT64 },
246
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
247
- ],
248
- },
249
- {
250
- name: 'PackagePriceChanged',
251
- type: BitcoinAbiTypes.Event,
252
- values: [
253
- { name: 'oldPrice', type: ABIDataTypes.UINT64 },
254
- { name: 'newPrice', type: ABIDataTypes.UINT64 },
255
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
256
- ],
257
- },
258
- {
259
- name: 'ScopeRegistered',
260
- type: BitcoinAbiTypes.Event,
261
- values: [
262
- { name: 'scopeHash', type: ABIDataTypes.UINT256 },
263
- { name: 'owner', type: ABIDataTypes.ADDRESS },
264
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
265
- ],
266
- },
267
- {
268
- name: 'ScopeTransferInitiated',
269
- type: BitcoinAbiTypes.Event,
270
- values: [
271
- { name: 'scopeHash', type: ABIDataTypes.UINT256 },
272
- { name: 'currentOwner', type: ABIDataTypes.ADDRESS },
273
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
274
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
275
- ],
276
- },
277
- {
278
- name: 'ScopeTransferCompleted',
279
- type: BitcoinAbiTypes.Event,
280
- values: [
281
- { name: 'scopeHash', type: ABIDataTypes.UINT256 },
282
- { name: 'previousOwner', type: ABIDataTypes.ADDRESS },
283
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
284
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
285
- ],
286
- },
287
- {
288
- name: 'ScopeTransferCancelled',
289
- type: BitcoinAbiTypes.Event,
290
- values: [
291
- { name: 'scopeHash', type: ABIDataTypes.UINT256 },
292
- { name: 'owner', type: ABIDataTypes.ADDRESS },
293
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
294
- ],
295
- },
296
- {
297
- name: 'PackageRegistered',
298
- type: BitcoinAbiTypes.Event,
299
- values: [
300
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
301
- { name: 'owner', type: ABIDataTypes.ADDRESS },
302
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
303
- ],
304
- },
305
- {
306
- name: 'VersionPublished',
307
- type: BitcoinAbiTypes.Event,
308
- values: [
309
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
310
- { name: 'versionHash', type: ABIDataTypes.UINT256 },
311
- { name: 'publisher', type: ABIDataTypes.ADDRESS },
312
- { name: 'checksum', type: ABIDataTypes.UINT256 },
313
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
314
- { name: 'mldsaLevel', type: ABIDataTypes.UINT8 },
315
- { name: 'pluginType', type: ABIDataTypes.UINT8 },
316
- ],
317
- },
318
- {
319
- name: 'VersionDeprecated',
320
- type: BitcoinAbiTypes.Event,
321
- values: [
322
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
323
- { name: 'versionHash', type: ABIDataTypes.UINT256 },
324
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
325
- ],
326
- },
327
- {
328
- name: 'VersionUndeprecated',
329
- type: BitcoinAbiTypes.Event,
330
- values: [
331
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
332
- { name: 'versionHash', type: ABIDataTypes.UINT256 },
333
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
334
- ],
335
- },
336
- {
337
- name: 'PackageTransferInitiated',
338
- type: BitcoinAbiTypes.Event,
339
- values: [
340
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
341
- { name: 'currentOwner', type: ABIDataTypes.ADDRESS },
342
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
343
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
344
- ],
345
- },
346
- {
347
- name: 'PackageTransferCompleted',
348
- type: BitcoinAbiTypes.Event,
349
- values: [
350
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
351
- { name: 'previousOwner', type: ABIDataTypes.ADDRESS },
352
- { name: 'newOwner', type: ABIDataTypes.ADDRESS },
353
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
354
- ],
355
- },
356
- {
357
- name: 'PackageTransferCancelled',
358
- type: BitcoinAbiTypes.Event,
359
- values: [
360
- { name: 'packageHash', type: ABIDataTypes.UINT256 },
361
- { name: 'owner', type: ABIDataTypes.ADDRESS },
362
- { name: 'timestamp', type: ABIDataTypes.UINT64 },
363
- ],
364
- },
365
- ];
package/src/lib/binary.ts DELETED
@@ -1,338 +0,0 @@
1
- /**
2
- * .opnet Binary Format Parser/Writer
3
- *
4
- * Implements the OIP-0003 binary format for compiled plugins.
5
- *
6
- * @module lib/binary
7
- */
8
-
9
- import * as crypto from 'crypto';
10
- import {
11
- IParsedPluginFile,
12
- IPluginMetadata,
13
- MLDSA_PUBLIC_KEY_SIZES,
14
- MLDSA_SIGNATURE_SIZES,
15
- MLDSALevel,
16
- PLUGIN_FORMAT_VERSION,
17
- PLUGIN_MAGIC_BYTES,
18
- } from '@btc-vision/plugin-sdk';
19
-
20
- import { cliLevelToMLDSALevel, CLIMldsaLevel, mldsaLevelToCLI } from '../types/index.js';
21
-
22
- /**
23
- * Parse a .opnet binary file
24
- *
25
- * @param data - The binary file contents
26
- * @returns Parsed binary structure
27
- * @throws Error if the binary is malformed
28
- */
29
- export function parseOpnetBinary(data: Buffer): IParsedPluginFile {
30
- let offset = 0;
31
-
32
- // Check minimum size
33
- if (data.length < 8 + 4 + 1) {
34
- throw new Error('Binary too small: missing header');
35
- }
36
-
37
- // Magic bytes (8 bytes)
38
- const magic = data.subarray(offset, offset + 8);
39
- offset += 8;
40
-
41
- if (!magic.equals(PLUGIN_MAGIC_BYTES)) {
42
- throw new Error(
43
- `Invalid magic bytes: expected ${PLUGIN_MAGIC_BYTES.toString('hex')}, got ${magic.toString('hex')}`,
44
- );
45
- }
46
-
47
- // Format version (uint32 LE)
48
- const formatVersion = data.readUInt32LE(offset);
49
- offset += 4;
50
-
51
- if (formatVersion !== PLUGIN_FORMAT_VERSION) {
52
- throw new Error(
53
- `Unsupported format version: ${formatVersion} (expected ${PLUGIN_FORMAT_VERSION})`,
54
- );
55
- }
56
-
57
- // MLDSA level (uint8)
58
- const mldsaLevelValue = data.readUInt8(offset);
59
- offset += 1;
60
-
61
- if (mldsaLevelValue > 2) {
62
- throw new Error(`Invalid MLDSA level: ${mldsaLevelValue} (must be 0, 1, or 2)`);
63
- }
64
-
65
- const mldsaLevel = mldsaLevelValue as MLDSALevel;
66
-
67
- // Get sizes based on level
68
- const publicKeySize = MLDSA_PUBLIC_KEY_SIZES[mldsaLevel];
69
- const signatureSize = MLDSA_SIGNATURE_SIZES[mldsaLevel];
70
-
71
- // Check we have enough data
72
- const minSize = offset + publicKeySize + signatureSize + 4 + 4 + 4 + 32;
73
- if (data.length < minSize) {
74
- throw new Error(`Binary truncated: expected at least ${minSize} bytes, got ${data.length}`);
75
- }
76
-
77
- // Public key
78
- const publicKey = Buffer.from(data.subarray(offset, offset + publicKeySize));
79
- offset += publicKeySize;
80
-
81
- // Signature
82
- const signature = Buffer.from(data.subarray(offset, offset + signatureSize));
83
- offset += signatureSize;
84
-
85
- // Metadata length (uint32 LE)
86
- const metadataLength = data.readUInt32LE(offset);
87
- offset += 4;
88
-
89
- if (offset + metadataLength > data.length) {
90
- throw new Error(`Metadata section truncated at offset ${offset}`);
91
- }
92
-
93
- // Metadata
94
- const metadataBytes = data.subarray(offset, offset + metadataLength);
95
- offset += metadataLength;
96
-
97
- let rawMetadata: string;
98
- let metadata: IPluginMetadata;
99
- try {
100
- rawMetadata = metadataBytes.toString('utf-8');
101
- metadata = JSON.parse(rawMetadata) as IPluginMetadata;
102
- } catch {
103
- throw new Error('Malformed JSON metadata');
104
- }
105
-
106
- // Bytecode length (uint32 LE)
107
- const bytecodeLength = data.readUInt32LE(offset);
108
- offset += 4;
109
-
110
- if (offset + bytecodeLength > data.length) {
111
- throw new Error(`Bytecode section truncated at offset ${offset}`);
112
- }
113
-
114
- // Bytecode
115
- const bytecode = Buffer.from(data.subarray(offset, offset + bytecodeLength));
116
- offset += bytecodeLength;
117
-
118
- // Proto length (uint32 LE)
119
- const protoLength = data.readUInt32LE(offset);
120
- offset += 4;
121
-
122
- if (offset + protoLength > data.length) {
123
- throw new Error(`Proto section truncated at offset ${offset}`);
124
- }
125
-
126
- // Proto
127
- const proto =
128
- protoLength > 0 ? Buffer.from(data.subarray(offset, offset + protoLength)) : undefined;
129
- offset += protoLength;
130
-
131
- // Checksum (32 bytes)
132
- if (offset + 32 > data.length) {
133
- throw new Error('Checksum truncated');
134
- }
135
-
136
- const checksum = Buffer.from(data.subarray(offset, offset + 32));
137
-
138
- return {
139
- formatVersion,
140
- mldsaLevel,
141
- publicKey,
142
- signature,
143
- metadata,
144
- rawMetadata,
145
- bytecode,
146
- proto,
147
- checksum,
148
- };
149
- }
150
-
151
- /**
152
- * Compute the checksum for plugin data
153
- *
154
- * @param metadata - JSON metadata bytes
155
- * @param bytecode - V8 bytecode bytes
156
- * @param proto - Proto bytes (can be empty)
157
- * @returns SHA-256 hash
158
- */
159
- export function computeChecksum(metadata: Buffer, bytecode: Buffer, proto: Buffer): Buffer {
160
- const hash = crypto.createHash('sha256');
161
- hash.update(metadata);
162
- hash.update(bytecode);
163
- hash.update(proto);
164
- return hash.digest();
165
- }
166
-
167
- /**
168
- * Verify the checksum of parsed binary
169
- *
170
- * @param parsed - The parsed binary structure
171
- * @returns True if checksum matches
172
- */
173
- export function verifyChecksum(parsed: IParsedPluginFile): boolean {
174
- const metadataBytes = Buffer.from(parsed.rawMetadata, 'utf-8');
175
- const computed = computeChecksum(
176
- metadataBytes,
177
- parsed.bytecode,
178
- parsed.proto ?? Buffer.alloc(0),
179
- );
180
- return computed.equals(parsed.checksum);
181
- }
182
-
183
- /**
184
- * Build a .opnet binary file
185
- *
186
- * @param options - Build options
187
- * @returns The assembled binary and the checksum that was signed
188
- */
189
- export function buildOpnetBinary(options: {
190
- mldsaLevel: CLIMldsaLevel;
191
- publicKey: Buffer;
192
- metadata: IPluginMetadata;
193
- bytecode: Buffer;
194
- proto?: Buffer;
195
- signFn?: (checksum: Buffer) => Buffer;
196
- }): { binary: Buffer; checksum: Buffer } {
197
- const { mldsaLevel, publicKey, metadata, bytecode, proto = Buffer.alloc(0), signFn } = options;
198
-
199
- const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
200
-
201
- // Validate public key size
202
- const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
203
- const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
204
-
205
- if (publicKey.length !== expectedPkSize) {
206
- throw new Error(
207
- `Public key size mismatch: expected ${expectedPkSize}, got ${publicKey.length}`,
208
- );
209
- }
210
-
211
- // First pass: compute checksum without the checksum field set
212
- const tempMetadata = { ...metadata, checksum: '' };
213
- const tempMetadataBytes = Buffer.from(JSON.stringify(tempMetadata), 'utf-8');
214
- const checksum = computeChecksum(tempMetadataBytes, bytecode, proto);
215
- const checksumHex = `sha256:${checksum.toString('hex')}`;
216
-
217
- // Second pass: serialize metadata with checksum included
218
- const finalMetadata = { ...metadata, checksum: checksumHex };
219
- const metadataBytes = Buffer.from(JSON.stringify(finalMetadata), 'utf-8');
220
-
221
- // Recompute checksum with the final metadata (includes checksum field)
222
- const finalChecksum = computeChecksum(metadataBytes, bytecode, proto);
223
-
224
- // Sign the final checksum (this is what gets verified)
225
- const signature = signFn ? signFn(finalChecksum) : Buffer.alloc(expectedSigSize);
226
-
227
- if (signature.length !== expectedSigSize) {
228
- throw new Error(
229
- `Signature size mismatch: expected ${expectedSigSize}, got ${signature.length}`,
230
- );
231
- }
232
-
233
- // Calculate total size
234
- const totalSize =
235
- 8 + // magic
236
- 4 + // version
237
- 1 + // mldsa level
238
- publicKey.length +
239
- signature.length +
240
- 4 +
241
- metadataBytes.length + // metadata
242
- 4 +
243
- bytecode.length + // bytecode
244
- 4 +
245
- proto.length + // proto
246
- 32; // checksum
247
-
248
- // Build buffer
249
- const buffer = Buffer.alloc(totalSize);
250
- let offset = 0;
251
-
252
- // Magic bytes
253
- PLUGIN_MAGIC_BYTES.copy(buffer, offset);
254
- offset += 8;
255
-
256
- // Format version
257
- buffer.writeUInt32LE(PLUGIN_FORMAT_VERSION, offset);
258
- offset += 4;
259
-
260
- // MLDSA level (enum value 0, 1, or 2)
261
- buffer.writeUInt8(sdkLevel, offset);
262
- offset += 1;
263
-
264
- // Public key
265
- publicKey.copy(buffer, offset);
266
- offset += publicKey.length;
267
-
268
- // Signature
269
- signature.copy(buffer, offset);
270
- offset += signature.length;
271
-
272
- // Metadata length
273
- buffer.writeUInt32LE(metadataBytes.length, offset);
274
- offset += 4;
275
-
276
- // Metadata
277
- metadataBytes.copy(buffer, offset);
278
- offset += metadataBytes.length;
279
-
280
- // Bytecode length
281
- buffer.writeUInt32LE(bytecode.length, offset);
282
- offset += 4;
283
-
284
- // Bytecode
285
- bytecode.copy(buffer, offset);
286
- offset += bytecode.length;
287
-
288
- // Proto length
289
- buffer.writeUInt32LE(proto.length, offset);
290
- offset += 4;
291
-
292
- // Proto
293
- proto.copy(buffer, offset);
294
- offset += proto.length;
295
-
296
- // Checksum (use finalChecksum which was computed with metadata containing checksum hex)
297
- finalChecksum.copy(buffer, offset);
298
-
299
- return { binary: buffer, checksum: finalChecksum };
300
- }
301
-
302
- /**
303
- * Extract just the metadata from a .opnet file without full validation
304
- *
305
- * @param data - The binary file contents
306
- * @returns The parsed metadata or null if invalid
307
- */
308
- export function extractMetadata(data: Buffer): IPluginMetadata | null {
309
- try {
310
- const parsed = parseOpnetBinary(data);
311
- return parsed.metadata;
312
- } catch {
313
- return null;
314
- }
315
- }
316
-
317
- /**
318
- * Get the CLI MLDSA level from parsed binary
319
- */
320
- export function getParsedMldsaLevel(parsed: IParsedPluginFile): CLIMldsaLevel {
321
- return mldsaLevelToCLI(parsed.mldsaLevel);
322
- }
323
-
324
- /**
325
- * Get file size formatted as human-readable string
326
- *
327
- * @param bytes - File size in bytes
328
- * @returns Formatted string (e.g., "1.5 MB")
329
- */
330
- export function formatFileSize(bytes: number): string {
331
- if (bytes < 1024) {
332
- return `${bytes} B`;
333
- } else if (bytes < 1024 * 1024) {
334
- return `${(bytes / 1024).toFixed(1)} KB`;
335
- } else {
336
- return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
337
- }
338
- }