@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.
- package/build/commands/CompileCommand.js +9 -10
- package/build/commands/InitCommand.js +1 -1
- package/build/commands/SignCommand.js +6 -9
- package/build/lib/binary.d.ts +5 -2
- package/build/lib/binary.js +11 -6
- package/build/lib/manifest.js +1 -1
- package/package.json +1 -1
- package/src/commands/CompileCommand.ts +13 -14
- package/src/commands/InitCommand.ts +1 -1
- package/src/commands/SignCommand.ts +9 -21
- package/src/lib/binary.ts +24 -22
- package/src/lib/manifest.ts +1 -1
|
@@ -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,
|
|
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
|
-
|
|
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) {
|
|
@@ -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,
|
|
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
|
|
53
|
-
const
|
|
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);
|
package/build/lib/binary.d.ts
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/build/lib/binary.js
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
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 {
|
package/build/lib/manifest.js
CHANGED
package/package.json
CHANGED
|
@@ -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,
|
|
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
|
-
//
|
|
129
|
-
|
|
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: '
|
|
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
|
-
//
|
|
81
|
-
this.logger.info('Signing...');
|
|
82
|
-
const
|
|
83
|
-
const checksum =
|
|
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
|
-
|
|
197
|
-
|
|
198
|
-
|
|
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
|
|
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
|
-
|
|
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
|
/**
|
package/src/lib/manifest.ts
CHANGED