@btc-vision/cli 1.0.1 → 1.0.2

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.
@@ -4,7 +4,7 @@ import * as esbuild from 'esbuild';
4
4
  import bytenode from 'bytenode';
5
5
  import { BaseCommand } from './BaseCommand.js';
6
6
  import { getManifestPath, loadManifest } from '../lib/manifest.js';
7
- import { buildOpnetBinary, computeChecksum, formatFileSize } from '../lib/binary.js';
7
+ import { buildOpnetBinary, formatFileSize } from '../lib/binary.js';
8
8
  import { CLIWallet } from '../lib/wallet.js';
9
9
  import { canSign, loadCredentials } from '../lib/credentials.js';
10
10
  export class CompileCommand extends BaseCommand {
@@ -70,8 +70,8 @@ export class CompileCommand extends BaseCommand {
70
70
  this.logger.info(`Found proto file (${formatFileSize(proto.length)})`);
71
71
  }
72
72
  let publicKey;
73
- let signature;
74
73
  let mldsaLevel;
74
+ let signFn;
75
75
  if (options.sign) {
76
76
  this.logger.info('Loading wallet for signing...');
77
77
  const credentials = loadCredentials();
@@ -85,27 +85,25 @@ export class CompileCommand extends BaseCommand {
85
85
  mldsaLevel = wallet.securityLevel;
86
86
  publicKey = wallet.mldsaPublicKey;
87
87
  this.logger.success(`Wallet loaded (MLDSA-${mldsaLevel})`);
88
- this.logger.info('Signing plugin...');
89
- const metadataBytes = Buffer.from(JSON.stringify(manifest), 'utf-8');
90
- const checksum = computeChecksum(metadataBytes, bytecode, proto);
91
- signature = wallet.signMLDSA(checksum);
92
- this.logger.success(`Plugin signed (${formatFileSize(signature.length)} signature)`);
88
+ signFn = (checksum) => wallet.signMLDSA(checksum);
93
89
  }
94
90
  else {
95
91
  this.logger.warn('Skipping signing (--no-sign)');
96
92
  mldsaLevel = 44;
97
93
  publicKey = Buffer.alloc(1312);
98
- signature = Buffer.alloc(2420);
99
94
  }
100
95
  this.logger.info('Assembling .opnet binary...');
101
- const binary = buildOpnetBinary({
96
+ const { binary, checksum } = buildOpnetBinary({
102
97
  mldsaLevel,
103
98
  publicKey,
104
- signature,
105
99
  metadata: manifest,
106
100
  bytecode,
107
101
  proto,
102
+ signFn,
108
103
  });
104
+ if (options.sign) {
105
+ this.logger.success(`Plugin signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`);
106
+ }
109
107
  this.logger.success(`Binary assembled (${formatFileSize(binary.length)})`);
110
108
  const outputPath = options.output ||
111
109
  path.join(projectDir, 'build', `${manifest.name.replace(/^@/, '').replace(/\//g, '-')}.opnet`);
@@ -121,6 +119,7 @@ export class CompileCommand extends BaseCommand {
121
119
  this.logger.log(`Plugin: ${manifest.name}@${manifest.version}`);
122
120
  this.logger.log(`Type: ${manifest.pluginType}`);
123
121
  this.logger.log(`MLDSA Level: ${mldsaLevel}`);
122
+ this.logger.log(`Checksum: sha256:${checksum.toString('hex')}`);
124
123
  this.logger.log(`Signed: ${options.sign ? 'Yes' : 'No'}`);
125
124
  this.logger.log('');
126
125
  if (!options.sign) {
@@ -112,7 +112,7 @@ export class InitCommand extends BaseCommand {
112
112
  const manifest = {
113
113
  name: config.pluginName,
114
114
  version: '1.0.0',
115
- opnetVersion: '^1.0.0',
115
+ opnetVersion: '>=0.0.1',
116
116
  main: 'dist/index.jsc',
117
117
  target: 'bytenode',
118
118
  type: 'plugin',
@@ -1,7 +1,7 @@
1
1
  import * as fs from 'fs';
2
2
  import * as crypto from 'crypto';
3
3
  import { BaseCommand } from './BaseCommand.js';
4
- import { buildOpnetBinary, computeChecksum, formatFileSize, parseOpnetBinary, } from '../lib/binary.js';
4
+ import { buildOpnetBinary, formatFileSize, parseOpnetBinary } from '../lib/binary.js';
5
5
  import { CLIWallet } from '../lib/wallet.js';
6
6
  import { canSign, loadCredentials } from '../lib/credentials.js';
7
7
  export class SignCommand extends BaseCommand {
@@ -48,20 +48,17 @@ export class SignCommand extends BaseCommand {
48
48
  this.logger.log('Use --force to re-sign with your key.');
49
49
  process.exit(1);
50
50
  }
51
- this.logger.info('Signing...');
52
- const metadataBytes = Buffer.from(parsed.rawMetadata, 'utf-8');
53
- const checksum = computeChecksum(metadataBytes, parsed.bytecode, parsed.proto ?? Buffer.alloc(0));
54
- const signature = wallet.signMLDSA(checksum);
55
- this.logger.success(`Signed (${formatFileSize(signature.length)} signature)`);
56
- this.logger.info('Rebuilding binary...');
57
- const newBinary = buildOpnetBinary({
51
+ this.logger.info('Signing and rebuilding binary...');
52
+ const signFn = (checksum) => wallet.signMLDSA(checksum);
53
+ const { binary: newBinary, checksum } = buildOpnetBinary({
58
54
  mldsaLevel: wallet.securityLevel,
59
55
  publicKey: wallet.mldsaPublicKey,
60
- signature,
61
56
  metadata: parsed.metadata,
62
57
  bytecode: parsed.bytecode,
63
58
  proto: parsed.proto ?? Buffer.alloc(0),
59
+ signFn,
64
60
  });
61
+ this.logger.success(`Signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`);
65
62
  this.logger.success(`Binary rebuilt (${formatFileSize(newBinary.length)})`);
66
63
  const outputPath = options.output || file;
67
64
  fs.writeFileSync(outputPath, newBinary);
@@ -6,11 +6,14 @@ export declare function verifyChecksum(parsed: IParsedPluginFile): boolean;
6
6
  export declare function buildOpnetBinary(options: {
7
7
  mldsaLevel: CLIMldsaLevel;
8
8
  publicKey: Buffer;
9
- signature: Buffer;
10
9
  metadata: IPluginMetadata;
11
10
  bytecode: Buffer;
12
11
  proto?: Buffer;
13
- }): Buffer;
12
+ signFn?: (checksum: Buffer) => Buffer;
13
+ }): {
14
+ binary: Buffer;
15
+ checksum: Buffer;
16
+ };
14
17
  export declare function extractMetadata(data: Buffer): IPluginMetadata | null;
15
18
  export declare function getParsedMldsaLevel(parsed: IParsedPluginFile): CLIMldsaLevel;
16
19
  export declare function formatFileSize(bytes: number): string;
@@ -91,19 +91,24 @@ export function verifyChecksum(parsed) {
91
91
  return computed.equals(parsed.checksum);
92
92
  }
93
93
  export function buildOpnetBinary(options) {
94
- const { mldsaLevel, publicKey, signature, metadata, bytecode, proto = Buffer.alloc(0), } = options;
94
+ const { mldsaLevel, publicKey, metadata, bytecode, proto = Buffer.alloc(0), signFn } = options;
95
95
  const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
96
96
  const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
97
97
  const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
98
98
  if (publicKey.length !== expectedPkSize) {
99
99
  throw new Error(`Public key size mismatch: expected ${expectedPkSize}, got ${publicKey.length}`);
100
100
  }
101
+ const tempMetadata = { ...metadata, checksum: '' };
102
+ const tempMetadataBytes = Buffer.from(JSON.stringify(tempMetadata), 'utf-8');
103
+ const checksum = computeChecksum(tempMetadataBytes, bytecode, proto);
104
+ const checksumHex = `sha256:${checksum.toString('hex')}`;
105
+ const finalMetadata = { ...metadata, checksum: checksumHex };
106
+ const metadataBytes = Buffer.from(JSON.stringify(finalMetadata), 'utf-8');
107
+ const finalChecksum = computeChecksum(metadataBytes, bytecode, proto);
108
+ const signature = signFn ? signFn(finalChecksum) : Buffer.alloc(expectedSigSize);
101
109
  if (signature.length !== expectedSigSize) {
102
110
  throw new Error(`Signature size mismatch: expected ${expectedSigSize}, got ${signature.length}`);
103
111
  }
104
- const metadataStr = JSON.stringify(metadata);
105
- const metadataBytes = Buffer.from(metadataStr, 'utf-8');
106
- const checksum = computeChecksum(metadataBytes, bytecode, proto);
107
112
  const totalSize = 8 +
108
113
  4 +
109
114
  1 +
@@ -140,8 +145,8 @@ export function buildOpnetBinary(options) {
140
145
  offset += 4;
141
146
  proto.copy(buffer, offset);
142
147
  offset += proto.length;
143
- checksum.copy(buffer, offset);
144
- return buffer;
148
+ finalChecksum.copy(buffer, offset);
149
+ return { binary: buffer, checksum: finalChecksum };
145
150
  }
146
151
  export function extractMetadata(data) {
147
152
  try {
@@ -78,7 +78,7 @@ export function createManifest(options) {
78
78
  return {
79
79
  name: options.name,
80
80
  version: '1.0.0',
81
- opnetVersion: '^1.0.0',
81
+ opnetVersion: '>=0.0.1',
82
82
  main: 'dist/index.jsc',
83
83
  target: 'bytenode',
84
84
  type: 'plugin',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@btc-vision/cli",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module",
5
5
  "description": "CLI for the OPNet plugin ecosystem - scaffolding, compilation, signing, and registry interaction",
6
6
  "author": "OP_NET",
@@ -10,7 +10,7 @@ import * as esbuild from 'esbuild';
10
10
  import bytenode from 'bytenode';
11
11
  import { BaseCommand } from './BaseCommand.js';
12
12
  import { getManifestPath, loadManifest } from '../lib/manifest.js';
13
- import { buildOpnetBinary, computeChecksum, formatFileSize } from '../lib/binary.js';
13
+ import { buildOpnetBinary, formatFileSize } from '../lib/binary.js';
14
14
  import { CLIWallet } from '../lib/wallet.js';
15
15
  import { canSign, loadCredentials } from '../lib/credentials.js';
16
16
  import { CLIMldsaLevel } from '../types/index.js';
@@ -105,8 +105,8 @@ export class CompileCommand extends BaseCommand {
105
105
 
106
106
  // Prepare signing
107
107
  let publicKey: Buffer;
108
- let signature: Buffer;
109
108
  let mldsaLevel: CLIMldsaLevel;
109
+ let signFn: ((checksum: Buffer) => Buffer) | undefined;
110
110
 
111
111
  if (options.sign) {
112
112
  this.logger.info('Loading wallet for signing...');
@@ -125,33 +125,31 @@ export class CompileCommand extends BaseCommand {
125
125
 
126
126
  this.logger.success(`Wallet loaded (MLDSA-${mldsaLevel})`);
127
127
 
128
- // Compute checksum and sign
129
- this.logger.info('Signing plugin...');
130
- const metadataBytes = Buffer.from(JSON.stringify(manifest), 'utf-8');
131
- const checksum = computeChecksum(metadataBytes, bytecode, proto);
132
-
133
- signature = wallet.signMLDSA(checksum);
134
- this.logger.success(
135
- `Plugin signed (${formatFileSize(signature.length)} signature)`,
136
- );
128
+ // Create signing function that will be called with the final checksum
129
+ signFn = (checksum: Buffer) => wallet.signMLDSA(checksum);
137
130
  } else {
138
131
  this.logger.warn('Skipping signing (--no-sign)');
139
132
  // Use dummy values for unsigned binary
140
133
  mldsaLevel = 44;
141
134
  publicKey = Buffer.alloc(1312); // MLDSA-44 public key size
142
- signature = Buffer.alloc(2420); // MLDSA-44 signature size
143
135
  }
144
136
 
145
137
  // Build .opnet binary
146
138
  this.logger.info('Assembling .opnet binary...');
147
- const binary = buildOpnetBinary({
139
+ const { binary, checksum } = buildOpnetBinary({
148
140
  mldsaLevel,
149
141
  publicKey,
150
- signature,
151
142
  metadata: manifest,
152
143
  bytecode,
153
144
  proto,
145
+ signFn,
154
146
  });
147
+
148
+ if (options.sign) {
149
+ this.logger.success(
150
+ `Plugin signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`,
151
+ );
152
+ }
155
153
  this.logger.success(`Binary assembled (${formatFileSize(binary.length)})`);
156
154
 
157
155
  // Write output
@@ -178,6 +176,7 @@ export class CompileCommand extends BaseCommand {
178
176
  this.logger.log(`Plugin: ${manifest.name}@${manifest.version}`);
179
177
  this.logger.log(`Type: ${manifest.pluginType}`);
180
178
  this.logger.log(`MLDSA Level: ${mldsaLevel}`);
179
+ this.logger.log(`Checksum: sha256:${checksum.toString('hex')}`);
181
180
  this.logger.log(`Signed: ${options.sign ? 'Yes' : 'No'}`);
182
181
  this.logger.log('');
183
182
 
@@ -185,7 +185,7 @@ export class InitCommand extends BaseCommand {
185
185
  const manifest: Record<string, unknown> = {
186
186
  name: config.pluginName,
187
187
  version: '1.0.0',
188
- opnetVersion: '^1.0.0',
188
+ opnetVersion: '>=0.0.1',
189
189
  main: 'dist/index.jsc',
190
190
  target: 'bytenode',
191
191
  type: 'plugin',
@@ -7,12 +7,7 @@
7
7
  import * as fs from 'fs';
8
8
  import * as crypto from 'crypto';
9
9
  import { BaseCommand } from './BaseCommand.js';
10
- import {
11
- buildOpnetBinary,
12
- computeChecksum,
13
- formatFileSize,
14
- parseOpnetBinary,
15
- } from '../lib/binary.js';
10
+ import { buildOpnetBinary, formatFileSize, parseOpnetBinary } from '../lib/binary.js';
16
11
  import { CLIWallet } from '../lib/wallet.js';
17
12
  import { canSign, loadCredentials } from '../lib/credentials.js';
18
13
 
@@ -77,27 +72,20 @@ export class SignCommand extends BaseCommand {
77
72
  process.exit(1);
78
73
  }
79
74
 
80
- // Compute new signature
81
- this.logger.info('Signing...');
82
- const metadataBytes = Buffer.from(parsed.rawMetadata, 'utf-8');
83
- const checksum = computeChecksum(
84
- metadataBytes,
85
- parsed.bytecode,
86
- parsed.proto ?? Buffer.alloc(0),
87
- );
88
- const signature = wallet.signMLDSA(checksum);
89
- this.logger.success(`Signed (${formatFileSize(signature.length)} signature)`);
90
-
91
- // Rebuild binary
92
- this.logger.info('Rebuilding binary...');
93
- const newBinary = buildOpnetBinary({
75
+ // Rebuild binary with signing
76
+ this.logger.info('Signing and rebuilding binary...');
77
+ const signFn = (checksum: Buffer) => wallet.signMLDSA(checksum);
78
+ const { binary: newBinary, checksum } = buildOpnetBinary({
94
79
  mldsaLevel: wallet.securityLevel,
95
80
  publicKey: wallet.mldsaPublicKey,
96
- signature,
97
81
  metadata: parsed.metadata,
98
82
  bytecode: parsed.bytecode,
99
83
  proto: parsed.proto ?? Buffer.alloc(0),
84
+ signFn,
100
85
  });
86
+ this.logger.success(
87
+ `Signed (checksum: sha256:${checksum.toString('hex').substring(0, 16)}...)`,
88
+ );
101
89
  this.logger.success(`Binary rebuilt (${formatFileSize(newBinary.length)})`);
102
90
 
103
91
  // Write output
package/src/lib/binary.ts CHANGED
@@ -184,28 +184,21 @@ export function verifyChecksum(parsed: IParsedPluginFile): boolean {
184
184
  * Build a .opnet binary file
185
185
  *
186
186
  * @param options - Build options
187
- * @returns The assembled binary
187
+ * @returns The assembled binary and the checksum that was signed
188
188
  */
189
189
  export function buildOpnetBinary(options: {
190
190
  mldsaLevel: CLIMldsaLevel;
191
191
  publicKey: Buffer;
192
- signature: Buffer;
193
192
  metadata: IPluginMetadata;
194
193
  bytecode: Buffer;
195
194
  proto?: Buffer;
196
- }): Buffer {
197
- const {
198
- mldsaLevel,
199
- publicKey,
200
- signature,
201
- metadata,
202
- bytecode,
203
- proto = Buffer.alloc(0),
204
- } = options;
195
+ signFn?: (checksum: Buffer) => Buffer;
196
+ }): { binary: Buffer; checksum: Buffer } {
197
+ const { mldsaLevel, publicKey, metadata, bytecode, proto = Buffer.alloc(0), signFn } = options;
205
198
 
206
199
  const sdkLevel = cliLevelToMLDSALevel(mldsaLevel);
207
200
 
208
- // Validate sizes
201
+ // Validate public key size
209
202
  const expectedPkSize = MLDSA_PUBLIC_KEY_SIZES[sdkLevel];
210
203
  const expectedSigSize = MLDSA_SIGNATURE_SIZES[sdkLevel];
211
204
 
@@ -215,19 +208,28 @@ export function buildOpnetBinary(options: {
215
208
  );
216
209
  }
217
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
+
218
227
  if (signature.length !== expectedSigSize) {
219
228
  throw new Error(
220
229
  `Signature size mismatch: expected ${expectedSigSize}, got ${signature.length}`,
221
230
  );
222
231
  }
223
232
 
224
- // Serialize metadata
225
- const metadataStr = JSON.stringify(metadata);
226
- const metadataBytes = Buffer.from(metadataStr, 'utf-8');
227
-
228
- // Compute checksum
229
- const checksum = computeChecksum(metadataBytes, bytecode, proto);
230
-
231
233
  // Calculate total size
232
234
  const totalSize =
233
235
  8 + // magic
@@ -291,10 +293,10 @@ export function buildOpnetBinary(options: {
291
293
  proto.copy(buffer, offset);
292
294
  offset += proto.length;
293
295
 
294
- // Checksum
295
- checksum.copy(buffer, offset);
296
+ // Checksum (use finalChecksum which was computed with metadata containing checksum hex)
297
+ finalChecksum.copy(buffer, offset);
296
298
 
297
- return buffer;
299
+ return { binary: buffer, checksum: finalChecksum };
298
300
  }
299
301
 
300
302
  /**
@@ -167,7 +167,7 @@ export function createManifest(options: {
167
167
  return {
168
168
  name: options.name,
169
169
  version: '1.0.0',
170
- opnetVersion: '^1.0.0',
170
+ opnetVersion: '>=0.0.1',
171
171
  main: 'dist/index.jsc',
172
172
  target: 'bytenode',
173
173
  type: 'plugin',