@btc-vision/cli 1.0.4 → 1.0.6

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 (46) hide show
  1. package/package.json +7 -4
  2. package/.gitattributes +0 -2
  3. package/.github/dependabot.yml +0 -9
  4. package/.github/workflows/ci.yml +0 -48
  5. package/.prettierrc.json +0 -12
  6. package/CONTRIBUTING.md +0 -56
  7. package/NOTICE +0 -17
  8. package/SECURITY.md +0 -35
  9. package/eslint.config.js +0 -41
  10. package/gulpfile.js +0 -41
  11. package/src/commands/AcceptCommand.ts +0 -224
  12. package/src/commands/BaseCommand.ts +0 -59
  13. package/src/commands/CompileCommand.ts +0 -195
  14. package/src/commands/ConfigCommand.ts +0 -117
  15. package/src/commands/DeprecateCommand.ts +0 -193
  16. package/src/commands/InfoCommand.ts +0 -293
  17. package/src/commands/InitCommand.ts +0 -541
  18. package/src/commands/InstallCommand.ts +0 -179
  19. package/src/commands/KeygenCommand.ts +0 -157
  20. package/src/commands/ListCommand.ts +0 -169
  21. package/src/commands/LoginCommand.ts +0 -197
  22. package/src/commands/LogoutCommand.ts +0 -76
  23. package/src/commands/PublishCommand.ts +0 -340
  24. package/src/commands/ScopeRegisterCommand.ts +0 -164
  25. package/src/commands/SearchCommand.ts +0 -140
  26. package/src/commands/SignCommand.ts +0 -110
  27. package/src/commands/TransferCommand.ts +0 -363
  28. package/src/commands/UndeprecateCommand.ts +0 -167
  29. package/src/commands/UpdateCommand.ts +0 -200
  30. package/src/commands/VerifyCommand.ts +0 -228
  31. package/src/commands/WhoamiCommand.ts +0 -113
  32. package/src/index.ts +0 -88
  33. package/src/lib/PackageRegistry.abi.json +0 -765
  34. package/src/lib/PackageRegistry.abi.ts +0 -365
  35. package/src/lib/binary.ts +0 -338
  36. package/src/lib/config.ts +0 -265
  37. package/src/lib/credentials.ts +0 -176
  38. package/src/lib/ipfs.ts +0 -382
  39. package/src/lib/manifest.ts +0 -195
  40. package/src/lib/provider.ts +0 -121
  41. package/src/lib/registry.ts +0 -467
  42. package/src/lib/transaction.ts +0 -205
  43. package/src/lib/wallet.ts +0 -262
  44. package/src/types/PackageRegistry.ts +0 -344
  45. package/src/types/index.ts +0 -147
  46. 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
- }