quantum-resistant-rustykey 0.7.9 → 0.8.1
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/README.md +144 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,15 +14,14 @@ npm i quantum-resistant-rustykey
|
|
|
14
14
|
|
|
15
15
|
- ***Recommendation***: Await v1.0.0 (following security audit) for production/regulated deployment.
|
|
16
16
|
- includes NIST approved as well as riskier NIST 'on-ramp' variants eg SQISign
|
|
17
|
-
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
- module-lattice-based key-encapsulation mechanism
|
|
22
|
-
- **ML-KEM-512**, **ML-KEM-768**, and **ML-KEM-1024** using the same stack: [mlkem-native](https://github.com/pq-code-package/mlkem-native) built with **Emscripten**.
|
|
17
|
+
- **ML-DSA** (ML-DSA-65, ML-DSA-87)
|
|
18
|
+
- **FN-DSA** (FN-DSA-512, FN-DSA-1024)
|
|
19
|
+
- **SQIsign** (Level 1, Level 3, Level 5)
|
|
20
|
+
- **ML-KEM** (512, 768, 1024) using [mlkem-native](https://github.com/pq-code-package/mlkem-native).
|
|
23
21
|
|
|
24
22
|
### NOTE: Why we support SQISign when it is 'NIST-on-ramp' only
|
|
25
23
|
*TLDR; to help hurdle the "silent" barrier to post-quantum adoption: 1024-byte buffer limit in many existing FIDO2/WebAuthn implementations*
|
|
24
|
+
- please see our IETF standards track draft for inclusion of SQISign [cose-sqisign](https://www.ietf.org/archive/id/draft-mott-cose-sqisign-00.html)
|
|
26
25
|
|
|
27
26
|
#### WebAuthn PQC Signature size constraints
|
|
28
27
|
Dilithium variants, and Falcon-1024 are physical incompatibile with millions of existing FIDO2/WebAuthn authenticators that rely on the CTAP2 1024-byte buffer limit.
|
|
@@ -202,6 +201,78 @@ run().catch((err) => {
|
|
|
202
201
|
});
|
|
203
202
|
```
|
|
204
203
|
|
|
204
|
+
## Signatures
|
|
205
|
+
|
|
206
|
+
All signature variants expose the same API (`keypair()`, `sign()`, `verify()`, `buffer_to_string()`).
|
|
207
|
+
|
|
208
|
+
### Node.js / backend (SQISign I, SQISign V, FN-DSA-512)
|
|
209
|
+
|
|
210
|
+
```typescript
|
|
211
|
+
import {
|
|
212
|
+
loadSqisignLvl1,
|
|
213
|
+
loadSqisignLvl5,
|
|
214
|
+
loadFnDsa512,
|
|
215
|
+
} from "quantum-resistant-rustykey";
|
|
216
|
+
|
|
217
|
+
async function demo() {
|
|
218
|
+
const message = new TextEncoder().encode("RustyKey signature test");
|
|
219
|
+
|
|
220
|
+
const variants = [
|
|
221
|
+
["SQIsign-I", await loadSqisignLvl1()],
|
|
222
|
+
["SQIsign-V", await loadSqisignLvl5()],
|
|
223
|
+
["FN-DSA-512", await loadFnDsa512()],
|
|
224
|
+
] as const;
|
|
225
|
+
|
|
226
|
+
for (const [name, signer] of variants) {
|
|
227
|
+
const kp = signer.keypair();
|
|
228
|
+
const pk = await kp.get("public_key");
|
|
229
|
+
const sk = await kp.get("private_key");
|
|
230
|
+
const sig = await signer.sign(message, sk);
|
|
231
|
+
const ok = await signer.verify(sig, message, pk);
|
|
232
|
+
console.log(`${name}:`, ok ? "OK" : "FAIL");
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
demo().catch(console.error);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Browser / frontend (SQISign I, SQISign V, FN-DSA-512)
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import {
|
|
243
|
+
loadSqisignLvl1,
|
|
244
|
+
loadSqisignLvl5,
|
|
245
|
+
loadFnDsa512,
|
|
246
|
+
} from "quantum-resistant-rustykey";
|
|
247
|
+
|
|
248
|
+
const out = document.querySelector("#output") as HTMLPreElement;
|
|
249
|
+
|
|
250
|
+
async function runSignatures() {
|
|
251
|
+
const message = new TextEncoder().encode("hello from browser signatures");
|
|
252
|
+
const variants = [
|
|
253
|
+
["SQIsign-I", await loadSqisignLvl1()],
|
|
254
|
+
["SQIsign-V", await loadSqisignLvl5()],
|
|
255
|
+
["FN-DSA-512", await loadFnDsa512()],
|
|
256
|
+
] as const;
|
|
257
|
+
|
|
258
|
+
const lines: string[] = [];
|
|
259
|
+
for (const [name, signer] of variants) {
|
|
260
|
+
const kp = signer.keypair();
|
|
261
|
+
const pk = await kp.get("public_key");
|
|
262
|
+
const sk = await kp.get("private_key");
|
|
263
|
+
const sig = await signer.sign(message, sk);
|
|
264
|
+
const ok = await signer.verify(sig, message, pk);
|
|
265
|
+
lines.push(`${name}: ${ok ? "verify OK" : "verify FAILED"}`);
|
|
266
|
+
}
|
|
267
|
+
out.textContent = lines.join("\n");
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
runSignatures().catch((err) => {
|
|
271
|
+
console.error(err);
|
|
272
|
+
out.textContent = "signature demo failed";
|
|
273
|
+
});
|
|
274
|
+
```
|
|
275
|
+
|
|
205
276
|
Security note for web apps:
|
|
206
277
|
- never store private keys in `localStorage`/`sessionStorage`
|
|
207
278
|
- prefer HTTPS + short-lived keys
|
|
@@ -249,16 +320,41 @@ pnpm build
|
|
|
249
320
|
|
|
250
321
|
- Run `pnpm test` for ML-KEM-512 / 768 / 1024 round-trips.
|
|
251
322
|
|
|
252
|
-
|
|
323
|
+
### Digital Signatures (Node.js & Frontend)
|
|
253
324
|
|
|
254
|
-
|
|
325
|
+
All signature algorithms (**FN-DSA**, **ML-DSA**, and **SQIsign**) share a common interface.
|
|
255
326
|
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
|
|
327
|
+
```typescript
|
|
328
|
+
import {
|
|
329
|
+
loadFnDsa512,
|
|
330
|
+
loadMlDsa3,
|
|
331
|
+
loadSqisignLvl1
|
|
332
|
+
} from "quantum-resistant-rustykey";
|
|
333
|
+
|
|
334
|
+
async function main() {
|
|
335
|
+
// 1. Load the algorithm (e.g., FN-DSA-512)
|
|
336
|
+
const fnDsa = await loadFnDsa512();
|
|
337
|
+
|
|
338
|
+
// 2. Generate a keypair
|
|
339
|
+
const kp = fnDsa.keypair();
|
|
340
|
+
const publicKey = await kp.get("public_key");
|
|
341
|
+
const privateKey = await kp.get("private_key");
|
|
342
|
+
|
|
343
|
+
// 3. Sign a message
|
|
344
|
+
const message = "Authored by RustyKey";
|
|
345
|
+
const signature = await fnDsa.sign(message, privateKey);
|
|
346
|
+
console.log("Signature (hex):", fnDsa.buffer_to_string(signature));
|
|
347
|
+
|
|
348
|
+
// 4. Verify the signature
|
|
349
|
+
const isValid = await fnDsa.verify(signature, message, publicKey);
|
|
350
|
+
console.log("Is signature valid?", isValid);
|
|
351
|
+
}
|
|
259
352
|
```
|
|
260
353
|
|
|
261
|
-
|
|
354
|
+
> [!NOTE]
|
|
355
|
+
> **SQIsign Performance**: Level 1 signing is extremely CPU-intensive (can take seconds to minutes depending on hardware). It is recommended for "sign-once, verify-many" scenarios like certificates or firmware updates.
|
|
356
|
+
|
|
357
|
+
## Browser example (local)
|
|
262
358
|
|
|
263
359
|
## Project Structure
|
|
264
360
|
|
|
@@ -279,6 +375,42 @@ This implementation includes patches to withstand side-channel attacks. For more
|
|
|
279
375
|
|
|
280
376
|
ISC
|
|
281
377
|
|
|
378
|
+
|
|
379
|
+
## Performance Metrics
|
|
380
|
+
|
|
381
|
+
Measured on a standard development environment (Node.js/WASM). Individual results may vary based on hardware and runtime overhead.
|
|
382
|
+
|
|
383
|
+
| Algorithm | KeyGen (ms) | Sign (ms) | Verify (ms) |
|
|
384
|
+
| :--- | :---: | :---: | :---: |
|
|
385
|
+
| **FN-DSA-512** | 8.13 | 0.74 | 0.78 |
|
|
386
|
+
| **FN-DSA-1024** | 25.62 | 1.25 | 0.24 |
|
|
387
|
+
| **ML-DSA-3 (Level 3)** | 0.22 | 0.45 | 0.25 |
|
|
388
|
+
| **ML-DSA-5 (Level 5)** | 0.33 | 0.63 | 0.34 |
|
|
389
|
+
| **SQIsign L1** | 99.95 | 534.41 | 15.35 |
|
|
390
|
+
|
|
391
|
+
---
|
|
392
|
+
|
|
393
|
+
## Known Answer Tests (KAT)
|
|
394
|
+
|
|
395
|
+
To ensure implementation correctness, our WASM build is verified against official NIST and reference test vectors.
|
|
396
|
+
|
|
397
|
+
### ML-DSA-3 (Level 3 / Dilithium-3)
|
|
398
|
+
* **Msg**: `6dbbc4375136df3b07f7c70e639e223e`
|
|
399
|
+
* **PK**: `e50d03fff3b3a70961abbb92a390008dec1283f603f50cdbaaa3d00bd659bc767c3f...`
|
|
400
|
+
* **Sig**: `a0c1af32f9ba4e4beea3016b96d1c780e8b5e020bb07c24478dbdd0ec875666b5a...`
|
|
401
|
+
|
|
402
|
+
### ML-DSA-5 (Level 5 / Dilithium-5)
|
|
403
|
+
* **Msg**: `6dbbc4375136df3b07f7c70e639e223e`
|
|
404
|
+
* **PK**: `bc89b367d4288f47c71a74679d0fcffbe041de41b5da2f5fc66d8e28c589949404...`
|
|
405
|
+
* **Sig**: `47dc5764266841c1af3073fcead6a13d372979e6cca0b2952b349915f54ef66312...`
|
|
406
|
+
|
|
407
|
+
### SQIsign Level 1
|
|
408
|
+
* **Msg**: `d81c4d8d734fcbfbeade3d3f8a039faa2a2c9957e835ad55b22e75bf57bb556ac8`
|
|
409
|
+
* **PK**: `07CCD21425136F6E865E497D2D4D208F0054AD81372066E817480787AAF7B2029...`
|
|
410
|
+
* **Sig**: `84228651f271b0f39f2f19f2e8718f31ed3365ac9e5cb303afe663d0cfc11f0455...`
|
|
411
|
+
|
|
412
|
+
*Full byte-perfect vectors are included in the `src/*.test.ts` files.*
|
|
413
|
+
|
|
282
414
|
## Funding
|
|
283
415
|
|
|
284
416
|
This project was generously supported by:
|
package/package.json
CHANGED