-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathfalcon-cli.js
More file actions
executable file
·214 lines (175 loc) · 6.81 KB
/
falcon-cli.js
File metadata and controls
executable file
·214 lines (175 loc) · 6.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
#!/usr/bin/env node
import fs from "fs";
import path from "path";
import process from "process";
import Falcon from "./index.js";
async function main() {
const args = process.argv.slice(2);
if (args.length === 0) {
printUsage();
process.exit(1);
}
// Initialize Falcon
const falcon = new Falcon();
const cmd = args[0];
try {
switch (cmd) {
case "keygen":
await handleKeygen(falcon);
break;
case "sign":
await handleSign(falcon, args);
break;
case "verify":
await handleVerify(falcon, args);
break;
case "convert":
await handleConvert(falcon, args);
break;
case "help":
printUsage();
break;
default:
console.error("Unknown command:", cmd);
printUsage();
process.exit(1);
}
} catch (error) {
console.error(`Error during ${cmd} operation:`, error.message);
process.exit(1);
}
}
function printUsage() {
console.log("Falcon Deterministic Signatures CLI");
console.log("");
console.log("Usage:");
console.log(" node falcon-cli.js keygen");
console.log(" node falcon-cli.js sign <message> <hex_sk>");
console.log(" node falcon-cli.js verify <message> <hex_sig> <hex_pk>");
console.log(" node falcon-cli.js convert <hex_compressed_sig>");
console.log("");
console.log("Options:");
console.log(" keygen Generate a new Falcon-1024 keypair");
console.log(" sign Sign a message using a secret key (produces compressed signature)");
console.log(" verify Verify a signature (compressed or CT) using a public key");
console.log(" convert Convert a compressed signature to constant-time format");
console.log(" help Show this help message");
}
async function handleKeygen(falcon) {
console.log("🔑 Generating Falcon-1024 deterministic keypair...");
// Generate keypair
const { publicKey, secretKey } = await falcon.keypair();
// Convert to hex for display
const pkHex = Falcon.bytesToHex(publicKey);
const skHex = Falcon.bytesToHex(secretKey);
// Display shortened versions for better readability
const shortenHex = (hex) => {
if (hex.length <= 40) return hex;
return hex.substring(0, 20) + '...' + hex.substring(hex.length - 20);
};
console.log("PublicKey:", shortenHex(pkHex));
console.log("SecretKey:", shortenHex(skHex));
// Store full hex values in files for reference
fs.writeFileSync("falcon_pk_hex.txt", pkHex);
fs.writeFileSync("falcon_sk_hex.txt", skHex);
// Write keys to binary files
fs.writeFileSync("falcon_pk.bin", publicKey);
fs.writeFileSync("falcon_sk.bin", secretKey);
console.log("Keygen completed successfully");
console.log(`Public key length: ${publicKey.length} bytes`);
console.log(`Secret key length: ${secretKey.length} bytes`);
console.log("Keys saved to falcon_pk.bin and falcon_sk.bin");
}
async function handleSign(falcon, args) {
if (args.length < 3) {
console.error("Error: Missing arguments for sign command");
console.log("Usage: node falcon-cli.js sign <message> <hex_sk>");
process.exit(1);
}
const message = args[1];
const secretKey = args[2]; // Already in hex format
// Sign the message (produces compressed format by default)
const signature = await falcon.sign(message, secretKey);
// Convert to hex for display
const sigHex = Falcon.bytesToHex(signature);
// Display shortened version for better readability
const shortenHex = (hex) => {
if (hex.length <= 40) return hex;
return hex.substring(0, 20) + '...' + hex.substring(hex.length - 20);
};
console.log("Signature (compressed format):", shortenHex(sigHex));
// Get the salt version
const saltVersion = await falcon.getSaltVersion(signature);
console.log(`Signature salt version: ${saltVersion}`);
// Store full hex value in file for reference
fs.writeFileSync("falcon_sig_compressed_hex.txt", sigHex);
// Write signature to binary file
fs.writeFileSync("falcon_sig_compressed.bin", signature);
console.log("Signing completed successfully");
console.log(`Signature length: ${signature.length} bytes`);
console.log("Signature saved to falcon_sig_compressed.bin");
}
async function handleVerify(falcon, args) {
if (args.length < 4) {
console.error("Error: Missing arguments for verify command");
console.log("Usage: node falcon-cli.js verify <message> <hex_sig> <hex_pk>");
process.exit(1);
}
const message = args[1];
const signature = args[2]; // Already in hex format
const publicKey = args[3]; // Already in hex format
try {
// Convert signature from hex to bytes
const sigBytes = Falcon.hexToBytes(signature);
// Determine signature type based on the header byte
const headerByte = sigBytes[0];
const isCompressed = (headerByte === 0xBA); // FALCON_DET1024_SIG_COMPRESSED_HEADER
const isCT = (headerByte === 0xDA); // FALCON_DET1024_SIG_CT_HEADER
let result;
if (isCompressed) {
console.log("Detected compressed signature format");
result = await falcon.verify(message, signature, publicKey);
} else if (isCT) {
console.log("Detected constant-time signature format");
result = await falcon.verifyConstantTime(message, signature, publicKey);
} else {
console.error(`Unknown signature format (header byte: 0x${headerByte.toString(16)})`);
process.exit(1);
}
console.log(result ? "✅ Verification success" : "❌ Verification failed");
} catch (error) {
console.error("Error during verification:", error.message);
process.exit(1);
}
}
async function handleConvert(falcon, args) {
if (args.length < 2) {
console.error("Error: Missing arguments for convert command");
console.log("Usage: node falcon-cli.js convert <hex_compressed_sig>");
process.exit(1);
}
const compressedSigHex = args[1];
try {
// Convert from compressed to CT format
const ctSignature = await falcon.convertToConstantTime(compressedSigHex);
// Convert to hex for display
const ctSigHex = Falcon.bytesToHex(ctSignature);
// Display shortened version for better readability
const shortenHex = (hex) => {
if (hex.length <= 40) return hex;
return hex.substring(0, 20) + '...' + hex.substring(hex.length - 20);
};
console.log("CT Signature:", shortenHex(ctSigHex));
// Store full hex value in file for reference
fs.writeFileSync("falcon_sig_ct_hex.txt", ctSigHex);
// Write signature to binary file
fs.writeFileSync("falcon_sig_ct.bin", ctSignature);
console.log("Conversion completed successfully");
console.log(`CT Signature length: ${ctSignature.length} bytes`);
console.log("CT Signature saved to falcon_sig_ct.bin");
} catch (error) {
console.error("Error during conversion:", error.message);
process.exit(1);
}
}
await main();