@oqs/liboqs-js 0.15.0
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/LICENSE.md +50 -0
- package/README.md +829 -0
- package/bin/cli.js +16 -0
- package/dist/classic-mceliece-348864.deno.js +0 -0
- package/dist/classic-mceliece-348864.min.js +0 -0
- package/dist/classic-mceliece-348864f.deno.js +0 -0
- package/dist/classic-mceliece-348864f.min.js +0 -0
- package/dist/classic-mceliece-460896.deno.js +0 -0
- package/dist/classic-mceliece-460896.min.js +0 -0
- package/dist/classic-mceliece-460896f.deno.js +0 -0
- package/dist/classic-mceliece-460896f.min.js +0 -0
- package/dist/classic-mceliece-6688128.deno.js +0 -0
- package/dist/classic-mceliece-6688128.min.js +0 -0
- package/dist/classic-mceliece-6688128f.deno.js +0 -0
- package/dist/classic-mceliece-6688128f.min.js +0 -0
- package/dist/classic-mceliece-6960119.deno.js +0 -0
- package/dist/classic-mceliece-6960119.min.js +0 -0
- package/dist/classic-mceliece-6960119f.deno.js +0 -0
- package/dist/classic-mceliece-6960119f.min.js +0 -0
- package/dist/classic-mceliece-8192128.deno.js +0 -0
- package/dist/classic-mceliece-8192128.min.js +0 -0
- package/dist/classic-mceliece-8192128f.deno.js +0 -0
- package/dist/classic-mceliece-8192128f.min.js +0 -0
- package/dist/cross-rsdp-128-balanced.deno.js +0 -0
- package/dist/cross-rsdp-128-balanced.min.js +0 -0
- package/dist/cross-rsdp-128-fast.deno.js +0 -0
- package/dist/cross-rsdp-128-fast.min.js +0 -0
- package/dist/cross-rsdp-128-small.deno.js +0 -0
- package/dist/cross-rsdp-128-small.min.js +0 -0
- package/dist/cross-rsdp-192-balanced.deno.js +0 -0
- package/dist/cross-rsdp-192-balanced.min.js +0 -0
- package/dist/cross-rsdp-192-fast.deno.js +0 -0
- package/dist/cross-rsdp-192-fast.min.js +0 -0
- package/dist/cross-rsdp-192-small.deno.js +0 -0
- package/dist/cross-rsdp-192-small.min.js +0 -0
- package/dist/cross-rsdp-256-balanced.deno.js +0 -0
- package/dist/cross-rsdp-256-balanced.min.js +0 -0
- package/dist/cross-rsdp-256-fast.deno.js +0 -0
- package/dist/cross-rsdp-256-fast.min.js +0 -0
- package/dist/cross-rsdp-256-small.deno.js +0 -0
- package/dist/cross-rsdp-256-small.min.js +0 -0
- package/dist/cross-rsdpg-128-balanced.deno.js +0 -0
- package/dist/cross-rsdpg-128-balanced.min.js +0 -0
- package/dist/cross-rsdpg-128-fast.deno.js +0 -0
- package/dist/cross-rsdpg-128-fast.min.js +0 -0
- package/dist/cross-rsdpg-128-small.deno.js +0 -0
- package/dist/cross-rsdpg-128-small.min.js +0 -0
- package/dist/cross-rsdpg-192-balanced.deno.js +0 -0
- package/dist/cross-rsdpg-192-balanced.min.js +0 -0
- package/dist/cross-rsdpg-192-fast.deno.js +0 -0
- package/dist/cross-rsdpg-192-fast.min.js +0 -0
- package/dist/cross-rsdpg-192-small.deno.js +0 -0
- package/dist/cross-rsdpg-192-small.min.js +0 -0
- package/dist/cross-rsdpg-256-balanced.deno.js +0 -0
- package/dist/cross-rsdpg-256-balanced.min.js +0 -0
- package/dist/cross-rsdpg-256-fast.deno.js +0 -0
- package/dist/cross-rsdpg-256-fast.min.js +0 -0
- package/dist/cross-rsdpg-256-small.deno.js +0 -0
- package/dist/cross-rsdpg-256-small.min.js +0 -0
- package/dist/falcon-1024.deno.js +0 -0
- package/dist/falcon-1024.min.js +0 -0
- package/dist/falcon-512.deno.js +0 -0
- package/dist/falcon-512.min.js +0 -0
- package/dist/falcon-padded-1024.deno.js +0 -0
- package/dist/falcon-padded-1024.min.js +0 -0
- package/dist/falcon-padded-512.deno.js +0 -0
- package/dist/falcon-padded-512.min.js +0 -0
- package/dist/frodokem-1344-aes.deno.js +0 -0
- package/dist/frodokem-1344-aes.min.js +0 -0
- package/dist/frodokem-1344-shake.deno.js +0 -0
- package/dist/frodokem-1344-shake.min.js +0 -0
- package/dist/frodokem-640-aes.deno.js +0 -0
- package/dist/frodokem-640-aes.min.js +0 -0
- package/dist/frodokem-640-shake.deno.js +0 -0
- package/dist/frodokem-640-shake.min.js +0 -0
- package/dist/frodokem-976-aes.deno.js +0 -0
- package/dist/frodokem-976-aes.min.js +0 -0
- package/dist/frodokem-976-shake.deno.js +0 -0
- package/dist/frodokem-976-shake.min.js +0 -0
- package/dist/hqc-128.deno.js +0 -0
- package/dist/hqc-128.min.js +0 -0
- package/dist/hqc-192.deno.js +0 -0
- package/dist/hqc-192.min.js +0 -0
- package/dist/hqc-256.deno.js +0 -0
- package/dist/hqc-256.min.js +0 -0
- package/dist/kyber-1024.deno.js +0 -0
- package/dist/kyber-1024.min.js +0 -0
- package/dist/kyber-512.deno.js +0 -0
- package/dist/kyber-512.min.js +0 -0
- package/dist/kyber-768.deno.js +0 -0
- package/dist/kyber-768.min.js +0 -0
- package/dist/mayo-1.deno.js +0 -0
- package/dist/mayo-1.min.js +0 -0
- package/dist/mayo-2.deno.js +0 -0
- package/dist/mayo-2.min.js +0 -0
- package/dist/mayo-3.deno.js +0 -0
- package/dist/mayo-3.min.js +0 -0
- package/dist/mayo-5.deno.js +0 -0
- package/dist/mayo-5.min.js +0 -0
- package/dist/ml-dsa-44.deno.js +0 -0
- package/dist/ml-dsa-44.min.js +0 -0
- package/dist/ml-dsa-65.deno.js +0 -0
- package/dist/ml-dsa-65.min.js +0 -0
- package/dist/ml-dsa-87.deno.js +0 -0
- package/dist/ml-dsa-87.min.js +0 -0
- package/dist/ml-kem-1024.deno.js +0 -0
- package/dist/ml-kem-1024.min.js +0 -0
- package/dist/ml-kem-512.deno.js +0 -0
- package/dist/ml-kem-512.min.js +0 -0
- package/dist/ml-kem-768.deno.js +0 -0
- package/dist/ml-kem-768.min.js +0 -0
- package/dist/ntru-hps-2048-509.deno.js +0 -0
- package/dist/ntru-hps-2048-509.min.js +0 -0
- package/dist/ntru-hps-2048-677.deno.js +0 -0
- package/dist/ntru-hps-2048-677.min.js +0 -0
- package/dist/ntru-hps-4096-1229.deno.js +0 -0
- package/dist/ntru-hps-4096-1229.min.js +0 -0
- package/dist/ntru-hps-4096-821.deno.js +0 -0
- package/dist/ntru-hps-4096-821.min.js +0 -0
- package/dist/ntru-hrss-1373.deno.js +0 -0
- package/dist/ntru-hrss-1373.min.js +0 -0
- package/dist/ntru-hrss-701.deno.js +0 -0
- package/dist/ntru-hrss-701.min.js +0 -0
- package/dist/ov-iii-pkc-skc.deno.js +0 -0
- package/dist/ov-iii-pkc-skc.min.js +0 -0
- package/dist/ov-iii-pkc.deno.js +0 -0
- package/dist/ov-iii-pkc.min.js +0 -0
- package/dist/ov-iii.deno.js +0 -0
- package/dist/ov-iii.min.js +0 -0
- package/dist/ov-ip-pkc-skc.deno.js +0 -0
- package/dist/ov-ip-pkc-skc.min.js +0 -0
- package/dist/ov-ip-pkc.deno.js +0 -0
- package/dist/ov-ip-pkc.min.js +0 -0
- package/dist/ov-ip.deno.js +0 -0
- package/dist/ov-ip.min.js +0 -0
- package/dist/ov-is-pkc-skc.deno.js +0 -0
- package/dist/ov-is-pkc-skc.min.js +0 -0
- package/dist/ov-is-pkc.deno.js +0 -0
- package/dist/ov-is-pkc.min.js +0 -0
- package/dist/ov-is.deno.js +0 -0
- package/dist/ov-is.min.js +0 -0
- package/dist/ov-v-pkc-skc.deno.js +0 -0
- package/dist/ov-v-pkc-skc.min.js +0 -0
- package/dist/ov-v-pkc.deno.js +0 -0
- package/dist/ov-v-pkc.min.js +0 -0
- package/dist/ov-v.deno.js +0 -0
- package/dist/ov-v.min.js +0 -0
- package/dist/slh-dsa-sha2-128f.deno.js +0 -0
- package/dist/slh-dsa-sha2-128f.min.js +0 -0
- package/dist/slh-dsa-sha2-128s.deno.js +0 -0
- package/dist/slh-dsa-sha2-128s.min.js +0 -0
- package/dist/slh-dsa-sha2-192f.deno.js +0 -0
- package/dist/slh-dsa-sha2-192f.min.js +0 -0
- package/dist/slh-dsa-sha2-192s.deno.js +0 -0
- package/dist/slh-dsa-sha2-192s.min.js +0 -0
- package/dist/slh-dsa-sha2-256f.deno.js +0 -0
- package/dist/slh-dsa-sha2-256f.min.js +0 -0
- package/dist/slh-dsa-sha2-256s.deno.js +0 -0
- package/dist/slh-dsa-sha2-256s.min.js +0 -0
- package/dist/slh-dsa-shake-128f.deno.js +0 -0
- package/dist/slh-dsa-shake-128f.min.js +0 -0
- package/dist/slh-dsa-shake-128s.deno.js +0 -0
- package/dist/slh-dsa-shake-128s.min.js +0 -0
- package/dist/slh-dsa-shake-192f.deno.js +0 -0
- package/dist/slh-dsa-shake-192f.min.js +0 -0
- package/dist/slh-dsa-shake-192s.deno.js +0 -0
- package/dist/slh-dsa-shake-192s.min.js +0 -0
- package/dist/slh-dsa-shake-256f.deno.js +0 -0
- package/dist/slh-dsa-shake-256f.min.js +0 -0
- package/dist/slh-dsa-shake-256s.deno.js +0 -0
- package/dist/slh-dsa-shake-256s.min.js +0 -0
- package/dist/snova-24-5-4-esk.deno.js +0 -0
- package/dist/snova-24-5-4-esk.min.js +0 -0
- package/dist/snova-24-5-4-shake-esk.deno.js +0 -0
- package/dist/snova-24-5-4-shake-esk.min.js +0 -0
- package/dist/snova-24-5-4-shake.deno.js +0 -0
- package/dist/snova-24-5-4-shake.min.js +0 -0
- package/dist/snova-24-5-4.deno.js +0 -0
- package/dist/snova-24-5-4.min.js +0 -0
- package/dist/snova-24-5-5.deno.js +0 -0
- package/dist/snova-24-5-5.min.js +0 -0
- package/dist/snova-25-8-3.deno.js +0 -0
- package/dist/snova-25-8-3.min.js +0 -0
- package/dist/snova-29-6-5.deno.js +0 -0
- package/dist/snova-29-6-5.min.js +0 -0
- package/dist/snova-37-17-2.deno.js +0 -0
- package/dist/snova-37-17-2.min.js +0 -0
- package/dist/snova-37-8-4.deno.js +0 -0
- package/dist/snova-37-8-4.min.js +0 -0
- package/dist/snova-49-11-3.deno.js +0 -0
- package/dist/snova-49-11-3.min.js +0 -0
- package/dist/snova-56-25-2.deno.js +0 -0
- package/dist/snova-56-25-2.min.js +0 -0
- package/dist/snova-60-10-4.deno.js +0 -0
- package/dist/snova-60-10-4.min.js +0 -0
- package/dist/sntrup761.deno.js +0 -0
- package/dist/sntrup761.min.js +0 -0
- package/package.json +108 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-348864.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-348864f.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-460896.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-460896f.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-6688128.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-6688128f.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-6960119.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-6960119f.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-8192128.js +336 -0
- package/src/algorithms/kem/classic-mceliece/classic-mceliece-8192128f.js +336 -0
- package/src/algorithms/kem/frodokem/efrodokem-1344-aes.js +366 -0
- package/src/algorithms/kem/frodokem/efrodokem-1344-shake.js +366 -0
- package/src/algorithms/kem/frodokem/efrodokem-640-aes.js +366 -0
- package/src/algorithms/kem/frodokem/efrodokem-640-shake.js +366 -0
- package/src/algorithms/kem/frodokem/efrodokem-976-aes.js +366 -0
- package/src/algorithms/kem/frodokem/efrodokem-976-shake.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-1344-aes.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-1344-shake.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-640-aes.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-640-shake.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-976-aes.js +366 -0
- package/src/algorithms/kem/frodokem/frodokem-976-shake.js +366 -0
- package/src/algorithms/kem/hqc/hqc-128.js +366 -0
- package/src/algorithms/kem/hqc/hqc-192.js +366 -0
- package/src/algorithms/kem/hqc/hqc-256.js +366 -0
- package/src/algorithms/kem/kyber/kyber-1024.js +349 -0
- package/src/algorithms/kem/kyber/kyber-512.js +347 -0
- package/src/algorithms/kem/kyber/kyber-768.js +348 -0
- package/src/algorithms/kem/ml-kem/ml-kem-1024.js +345 -0
- package/src/algorithms/kem/ml-kem/ml-kem-512.js +345 -0
- package/src/algorithms/kem/ml-kem/ml-kem-768.js +344 -0
- package/src/algorithms/kem/ntru/ntru-hps-2048-509.js +366 -0
- package/src/algorithms/kem/ntru/ntru-hps-2048-677.js +366 -0
- package/src/algorithms/kem/ntru/ntru-hps-4096-1229.js +366 -0
- package/src/algorithms/kem/ntru/ntru-hps-4096-821.js +366 -0
- package/src/algorithms/kem/ntru/ntru-hrss-1373.js +366 -0
- package/src/algorithms/kem/ntru/ntru-hrss-701.js +366 -0
- package/src/algorithms/kem/ntru/sntrup761.js +367 -0
- package/src/algorithms/sig/cross/cross-rsdp-128-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-128-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-128-small.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-192-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-192-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-192-small.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-256-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-256-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdp-256-small.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-128-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-128-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-128-small.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-192-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-192-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-192-small.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-256-balanced.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-256-fast.js +391 -0
- package/src/algorithms/sig/cross/cross-rsdpg-256-small.js +391 -0
- package/src/algorithms/sig/falcon/falcon-1024.js +378 -0
- package/src/algorithms/sig/falcon/falcon-512.js +379 -0
- package/src/algorithms/sig/falcon/falcon-padded-1024.js +380 -0
- package/src/algorithms/sig/falcon/falcon-padded-512.js +380 -0
- package/src/algorithms/sig/mayo/mayo-1.js +390 -0
- package/src/algorithms/sig/mayo/mayo-2.js +390 -0
- package/src/algorithms/sig/mayo/mayo-3.js +390 -0
- package/src/algorithms/sig/mayo/mayo-5.js +390 -0
- package/src/algorithms/sig/ml-dsa/ml-dsa-44.js +338 -0
- package/src/algorithms/sig/ml-dsa/ml-dsa-65.js +338 -0
- package/src/algorithms/sig/ml-dsa/ml-dsa-87.js +338 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-128f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-128s.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-192f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-192s.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-256f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-sha2-256s.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-128f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-128s.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-192f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-192s.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-256f.js +367 -0
- package/src/algorithms/sig/slh-dsa/slh-dsa-shake-256s.js +367 -0
- package/src/algorithms/sig/snova/snova-24-5-4-esk.js +391 -0
- package/src/algorithms/sig/snova/snova-24-5-4-shake-esk.js +391 -0
- package/src/algorithms/sig/snova/snova-24-5-4-shake.js +391 -0
- package/src/algorithms/sig/snova/snova-24-5-4.js +391 -0
- package/src/algorithms/sig/snova/snova-24-5-5.js +391 -0
- package/src/algorithms/sig/snova/snova-25-8-3.js +391 -0
- package/src/algorithms/sig/snova/snova-29-6-5.js +391 -0
- package/src/algorithms/sig/snova/snova-37-17-2.js +391 -0
- package/src/algorithms/sig/snova/snova-37-8-4.js +391 -0
- package/src/algorithms/sig/snova/snova-49-11-3.js +391 -0
- package/src/algorithms/sig/snova/snova-56-25-2.js +391 -0
- package/src/algorithms/sig/snova/snova-60-10-4.js +391 -0
- package/src/algorithms/sig/uov/ov-iii-pkc-skc.js +390 -0
- package/src/algorithms/sig/uov/ov-iii-pkc.js +390 -0
- package/src/algorithms/sig/uov/ov-iii.js +390 -0
- package/src/algorithms/sig/uov/ov-ip-pkc-skc.js +390 -0
- package/src/algorithms/sig/uov/ov-ip-pkc.js +390 -0
- package/src/algorithms/sig/uov/ov-ip.js +390 -0
- package/src/algorithms/sig/uov/ov-is-pkc-skc.js +390 -0
- package/src/algorithms/sig/uov/ov-is-pkc.js +390 -0
- package/src/algorithms/sig/uov/ov-is.js +390 -0
- package/src/algorithms/sig/uov/ov-v-pkc-skc.js +390 -0
- package/src/algorithms/sig/uov/ov-v-pkc.js +390 -0
- package/src/algorithms/sig/uov/ov-v.js +390 -0
- package/src/cli/algorithms.js +254 -0
- package/src/cli/commands/info.js +35 -0
- package/src/cli/commands/kem.js +91 -0
- package/src/cli/commands/list.js +30 -0
- package/src/cli/commands/sig.js +98 -0
- package/src/cli/index.js +86 -0
- package/src/cli/io.js +147 -0
- package/src/cli/parser.js +64 -0
- package/src/core/errors.js +75 -0
- package/src/core/validation.js +28 -0
- package/src/index.js +164 -0
- package/src/kem.js +60 -0
- package/src/sig.js +87 -0
- package/src/types/algorithms.d.ts +1543 -0
- package/src/types/errors.d.ts +60 -0
- package/src/types/index.d.ts +9 -0
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ML-DSA-87 signature algorithm implementation
|
|
3
|
+
* @module algorithms/sig/ml-dsa/ml-dsa-87
|
|
4
|
+
* @description
|
|
5
|
+
* ML-DSA-87 is a lattice-based digital signature algorithm providing NIST security level 5.
|
|
6
|
+
* It is part of the NIST FIPS 204 standard (Module-Lattice-Based Digital Signature Algorithm).
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Lattice-based cryptography (Module-LWE and Module-SIS problems)
|
|
10
|
+
* - Security Level 5 (256-bit classical, quantum-resistant)
|
|
11
|
+
* - NIST FIPS 204 standardized
|
|
12
|
+
* - Strong existential unforgeability under chosen message attack (SUF-CMA)
|
|
13
|
+
* - Deterministic signing with optional hedged mode
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://csrc.nist.gov/pubs/fips/204/final} - NIST FIPS 204 specification
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { LibOQSError, LibOQSInitError, LibOQSOperationError, LibOQSValidationError } from '../../../core/errors.js';
|
|
19
|
+
import { isUint8Array } from '../../../core/validation.js';
|
|
20
|
+
|
|
21
|
+
// Dynamic module loading for cross-runtime compatibility
|
|
22
|
+
async function loadModule() {
|
|
23
|
+
const isDeno = typeof Deno !== 'undefined';
|
|
24
|
+
const modulePath = isDeno
|
|
25
|
+
? `../../../../dist/ml-dsa-87.deno.js`
|
|
26
|
+
: `../../../../dist/ml-dsa-87.min.js`;
|
|
27
|
+
|
|
28
|
+
const module = await import(modulePath);
|
|
29
|
+
return module.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* ML-DSA-87-INFO algorithm constants and metadata
|
|
34
|
+
* @type {{readonly name: 'ML-DSA-87', readonly identifier: 'ML-DSA-87', readonly type: 'sig', readonly securityLevel: 5, readonly standardized: true, readonly description: string, readonly keySize: {readonly publicKey: 2592, readonly secretKey: 4896, readonly signature: 4627}}}
|
|
35
|
+
*/
|
|
36
|
+
export const ML_DSA_87_INFO = {
|
|
37
|
+
name: 'ML-DSA-87',
|
|
38
|
+
identifier: 'ML-DSA-87',
|
|
39
|
+
type: 'sig',
|
|
40
|
+
securityLevel: 5,
|
|
41
|
+
standardized: true,
|
|
42
|
+
description: 'NIST FIPS 204 ML-DSA-87 lattice-based signature (NIST Level 5, 256-bit quantum security)',
|
|
43
|
+
keySize: {
|
|
44
|
+
publicKey: 2592,
|
|
45
|
+
secretKey: 4896,
|
|
46
|
+
signature: 4627
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Load and initialize ML-DSA-87 module
|
|
52
|
+
* @returns {Promise<MLDSA87>} Initialized ML-DSA-87 instance
|
|
53
|
+
* @throws {LibOQSInitError} If initialization fails
|
|
54
|
+
* @example
|
|
55
|
+
* import { createMLDSA87 } from '@oqs/liboqs-js';
|
|
56
|
+
* const sig = await createMLDSA87();
|
|
57
|
+
*/
|
|
58
|
+
export async function createMLDSA87() {
|
|
59
|
+
const moduleFactory = await loadModule();
|
|
60
|
+
const wasmModule = await moduleFactory();
|
|
61
|
+
wasmModule._OQS_init();
|
|
62
|
+
|
|
63
|
+
const algoName = ML_DSA_87_INFO.identifier;
|
|
64
|
+
const nameLen = wasmModule.lengthBytesUTF8(algoName);
|
|
65
|
+
const namePtr = wasmModule._malloc(nameLen + 1);
|
|
66
|
+
wasmModule.stringToUTF8(algoName, namePtr, nameLen + 1);
|
|
67
|
+
|
|
68
|
+
const sigPtr = wasmModule._OQS_SIG_new(namePtr);
|
|
69
|
+
wasmModule._free(namePtr);
|
|
70
|
+
|
|
71
|
+
if (!sigPtr) {
|
|
72
|
+
throw new LibOQSInitError('ML-DSA-87', 'Failed to create SIG instance');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new MLDSA87(wasmModule, sigPtr);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ML-DSA-87 digital signature wrapper class
|
|
80
|
+
*
|
|
81
|
+
* Provides high-level interface for ML-DSA-87 digital signature operations.
|
|
82
|
+
* Automatically manages WASM memory and validates inputs.
|
|
83
|
+
*
|
|
84
|
+
* @class MLDSA87
|
|
85
|
+
* @example
|
|
86
|
+
* const sig = await createMLDSA87();
|
|
87
|
+
* const { publicKey, secretKey } = sig.generateKeyPair();
|
|
88
|
+
*
|
|
89
|
+
* const message = new TextEncoder().encode('Hello, quantum world!');
|
|
90
|
+
* const signature = sig.sign(message, secretKey);
|
|
91
|
+
*
|
|
92
|
+
* const isValid = sig.verify(message, signature, publicKey);
|
|
93
|
+
* console.log('Valid:', isValid); // true
|
|
94
|
+
*
|
|
95
|
+
* sig.destroy();
|
|
96
|
+
*/
|
|
97
|
+
export class MLDSA87 {
|
|
98
|
+
#wasmModule;
|
|
99
|
+
#sigPtr;
|
|
100
|
+
#destroyed = false;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* @param {Object} wasmModule - Emscripten WASM module
|
|
104
|
+
* @param {number} sigPtr - Pointer to OQS_SIG structure
|
|
105
|
+
* @private
|
|
106
|
+
*/
|
|
107
|
+
constructor(wasmModule, sigPtr) {
|
|
108
|
+
this.#wasmModule = wasmModule;
|
|
109
|
+
this.#sigPtr = sigPtr;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Generate a new ML-DSA-87 keypair
|
|
114
|
+
*
|
|
115
|
+
* Creates a new public/private keypair for digital signatures.
|
|
116
|
+
* The secret key must be kept confidential.
|
|
117
|
+
*
|
|
118
|
+
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}}
|
|
119
|
+
* @throws {LibOQSOperationError} If key generation fails
|
|
120
|
+
* @example
|
|
121
|
+
* const { publicKey, secretKey } = sig.generateKeyPair();
|
|
122
|
+
*/
|
|
123
|
+
generateKeyPair() {
|
|
124
|
+
this.#checkDestroyed();
|
|
125
|
+
|
|
126
|
+
const publicKey = new Uint8Array(ML_DSA_87_INFO.keySize.publicKey);
|
|
127
|
+
const secretKey = new Uint8Array(ML_DSA_87_INFO.keySize.secretKey);
|
|
128
|
+
|
|
129
|
+
const pkPtr = this.#wasmModule._malloc(publicKey.length);
|
|
130
|
+
const skPtr = this.#wasmModule._malloc(secretKey.length);
|
|
131
|
+
|
|
132
|
+
try {
|
|
133
|
+
const result = this.#wasmModule._OQS_SIG_keypair(this.#sigPtr, pkPtr, skPtr);
|
|
134
|
+
|
|
135
|
+
if (result !== 0) {
|
|
136
|
+
throw new LibOQSOperationError('generateKeyPair', 'ML-DSA-87', 'Key generation failed');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
publicKey.set(this.#wasmModule.HEAPU8.subarray(pkPtr, pkPtr + publicKey.length));
|
|
140
|
+
secretKey.set(this.#wasmModule.HEAPU8.subarray(skPtr, skPtr + secretKey.length));
|
|
141
|
+
|
|
142
|
+
return { publicKey, secretKey };
|
|
143
|
+
} finally {
|
|
144
|
+
this.#wasmModule._free(pkPtr);
|
|
145
|
+
this.#wasmModule._free(skPtr);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Sign a message using the secret key
|
|
151
|
+
*
|
|
152
|
+
* Generates a digital signature for the provided message.
|
|
153
|
+
* The signature can be verified using the corresponding public key.
|
|
154
|
+
*
|
|
155
|
+
* @param {Uint8Array} message - Message to sign (arbitrary length)
|
|
156
|
+
* @param {Uint8Array} secretKey - Secret key for signing (4896 bytes)
|
|
157
|
+
* @returns {Uint8Array} Digital signature (up to 4627 bytes)
|
|
158
|
+
* @throws {LibOQSValidationError} If inputs are invalid
|
|
159
|
+
* @throws {LibOQSOperationError} If signing fails
|
|
160
|
+
* @example
|
|
161
|
+
* const message = new TextEncoder().encode('Hello!');
|
|
162
|
+
* const signature = sig.sign(message, secretKey);
|
|
163
|
+
*/
|
|
164
|
+
sign(message, secretKey) {
|
|
165
|
+
this.#checkDestroyed();
|
|
166
|
+
this.#validateMessage(message);
|
|
167
|
+
this.#validateSecretKey(secretKey);
|
|
168
|
+
|
|
169
|
+
const signature = new Uint8Array(ML_DSA_87_INFO.keySize.signature);
|
|
170
|
+
const sigPtr = this.#wasmModule._malloc(signature.length);
|
|
171
|
+
const sigLenPtr = this.#wasmModule._malloc(8); // size_t
|
|
172
|
+
const msgPtr = this.#wasmModule._malloc(message.length);
|
|
173
|
+
const skPtr = this.#wasmModule._malloc(secretKey.length);
|
|
174
|
+
|
|
175
|
+
try {
|
|
176
|
+
this.#wasmModule.HEAPU8.set(message, msgPtr);
|
|
177
|
+
this.#wasmModule.HEAPU8.set(secretKey, skPtr);
|
|
178
|
+
this.#wasmModule.setValue(sigLenPtr, signature.length, 'i64');
|
|
179
|
+
|
|
180
|
+
const result = this.#wasmModule._OQS_SIG_sign(
|
|
181
|
+
this.#sigPtr,
|
|
182
|
+
sigPtr,
|
|
183
|
+
sigLenPtr,
|
|
184
|
+
msgPtr,
|
|
185
|
+
message.length,
|
|
186
|
+
skPtr
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (result !== 0) {
|
|
190
|
+
throw new LibOQSOperationError('sign', 'ML-DSA-87', 'Signing failed');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const actualSigLen = this.#wasmModule.getValue(sigLenPtr, 'i32');
|
|
194
|
+
const actualSignature = new Uint8Array(actualSigLen);
|
|
195
|
+
actualSignature.set(this.#wasmModule.HEAPU8.subarray(sigPtr, sigPtr + actualSigLen));
|
|
196
|
+
|
|
197
|
+
return actualSignature;
|
|
198
|
+
} finally {
|
|
199
|
+
this.#wasmModule._free(sigPtr);
|
|
200
|
+
this.#wasmModule._free(sigLenPtr);
|
|
201
|
+
this.#wasmModule._free(msgPtr);
|
|
202
|
+
this.#wasmModule._free(skPtr);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Verify a signature against a message using the public key
|
|
208
|
+
*
|
|
209
|
+
* Verifies that the signature is valid for the given message and public key.
|
|
210
|
+
*
|
|
211
|
+
* @param {Uint8Array} message - Original message that was signed
|
|
212
|
+
* @param {Uint8Array} signature - Signature to verify
|
|
213
|
+
* @param {Uint8Array} publicKey - Public key for verification (2592 bytes)
|
|
214
|
+
* @returns {boolean} True if signature is valid, false otherwise
|
|
215
|
+
* @throws {LibOQSValidationError} If inputs are invalid
|
|
216
|
+
* @example
|
|
217
|
+
* const isValid = sig.verify(message, signature, publicKey);
|
|
218
|
+
* if (isValid) {
|
|
219
|
+
* console.log('Signature is valid!');
|
|
220
|
+
* }
|
|
221
|
+
*/
|
|
222
|
+
verify(message, signature, publicKey) {
|
|
223
|
+
this.#checkDestroyed();
|
|
224
|
+
this.#validateMessage(message);
|
|
225
|
+
this.#validateSignature(signature);
|
|
226
|
+
this.#validatePublicKey(publicKey);
|
|
227
|
+
|
|
228
|
+
const msgPtr = this.#wasmModule._malloc(message.length);
|
|
229
|
+
const sigPtr = this.#wasmModule._malloc(signature.length);
|
|
230
|
+
const pkPtr = this.#wasmModule._malloc(publicKey.length);
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
this.#wasmModule.HEAPU8.set(message, msgPtr);
|
|
234
|
+
this.#wasmModule.HEAPU8.set(signature, sigPtr);
|
|
235
|
+
this.#wasmModule.HEAPU8.set(publicKey, pkPtr);
|
|
236
|
+
|
|
237
|
+
const result = this.#wasmModule._OQS_SIG_verify(
|
|
238
|
+
this.#sigPtr,
|
|
239
|
+
msgPtr,
|
|
240
|
+
message.length,
|
|
241
|
+
sigPtr,
|
|
242
|
+
signature.length,
|
|
243
|
+
pkPtr
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
return result === 0;
|
|
247
|
+
} finally {
|
|
248
|
+
this.#wasmModule._free(msgPtr);
|
|
249
|
+
this.#wasmModule._free(sigPtr);
|
|
250
|
+
this.#wasmModule._free(pkPtr);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Clean up WASM resources
|
|
256
|
+
*
|
|
257
|
+
* Frees the native signature structure. The instance cannot be used after calling destroy().
|
|
258
|
+
*
|
|
259
|
+
* @example
|
|
260
|
+
* sig.destroy();
|
|
261
|
+
*/
|
|
262
|
+
destroy() {
|
|
263
|
+
if (!this.#destroyed) {
|
|
264
|
+
if (this.#sigPtr) {
|
|
265
|
+
this.#wasmModule._OQS_SIG_free(this.#sigPtr);
|
|
266
|
+
this.#sigPtr = null;
|
|
267
|
+
}
|
|
268
|
+
this.#destroyed = true;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Enables automatic cleanup via `using` declarations
|
|
274
|
+
* @example
|
|
275
|
+
* using instance = await create...();
|
|
276
|
+
* // automatically cleaned up at end of scope
|
|
277
|
+
*/
|
|
278
|
+
[Symbol.dispose]() {
|
|
279
|
+
this.destroy();
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Get algorithm information
|
|
284
|
+
* @returns {typeof ML_DSA_87_INFO} Algorithm metadata
|
|
285
|
+
*/
|
|
286
|
+
get info() {
|
|
287
|
+
return ML_DSA_87_INFO;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#checkDestroyed() {
|
|
291
|
+
if (this.#destroyed) {
|
|
292
|
+
throw new LibOQSError('Instance has been destroyed', 'ML-DSA-87');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
#validateMessage(message) {
|
|
297
|
+
if (!ArrayBuffer.isView(message) || message.constructor.name !== 'Uint8Array') {
|
|
298
|
+
throw new LibOQSValidationError(
|
|
299
|
+
'Message must be Uint8Array',
|
|
300
|
+
'ML-DSA-87'
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#validatePublicKey(publicKey) {
|
|
306
|
+
if (!isUint8Array(publicKey) || publicKey.length !== ML_DSA_87_INFO.keySize.publicKey) {
|
|
307
|
+
throw new LibOQSValidationError(
|
|
308
|
+
`Invalid public key: expected ${ML_DSA_87_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
309
|
+
'ML-DSA-87'
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
#validateSecretKey(secretKey) {
|
|
315
|
+
if (!isUint8Array(secretKey) || secretKey.length !== ML_DSA_87_INFO.keySize.secretKey) {
|
|
316
|
+
throw new LibOQSValidationError(
|
|
317
|
+
`Invalid secret key: expected ${ML_DSA_87_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
318
|
+
'ML-DSA-87'
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#validateSignature(signature) {
|
|
324
|
+
if (!isUint8Array(signature)) {
|
|
325
|
+
throw new LibOQSValidationError(
|
|
326
|
+
'Signature must be Uint8Array',
|
|
327
|
+
'ML-DSA-87'
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
if (signature.length === 0 || signature.length > ML_DSA_87_INFO.keySize.signature) {
|
|
331
|
+
throw new LibOQSValidationError(
|
|
332
|
+
`Invalid signature length: expected up to ${ML_DSA_87_INFO.keySize.signature} bytes, got ${signature.length}`,
|
|
333
|
+
'ML-DSA-87'
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview SLH-DSA-SHA2-128f signature algorithm implementation
|
|
3
|
+
* @module algorithms/sig/slh-dsa/slh-dsa-sha2-128f
|
|
4
|
+
* @description
|
|
5
|
+
* SLH-DSA-SHA2-128f is a stateless hash-based signature scheme providing NIST security level 1.
|
|
6
|
+
* This variant uses SHA2 for hashing and is optimized for speed (fast mode).
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Stateless hash-based signatures
|
|
10
|
+
* - Security Level 1 (128-bit classical, quantum-resistant)
|
|
11
|
+
* - SHA2 hash function
|
|
12
|
+
* - Fast signing/verification
|
|
13
|
+
* - FIPS 205 standardized
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://csrc.nist.gov/pubs/fips/205/final} - FIPS 205: SLH-DSA specification
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { LibOQSError, LibOQSInitError, LibOQSOperationError, LibOQSValidationError } from '../../../core/errors.js';
|
|
19
|
+
import { isUint8Array } from '../../../core/validation.js';
|
|
20
|
+
|
|
21
|
+
// Dynamic module loading for cross-runtime compatibility
|
|
22
|
+
async function loadModule() {
|
|
23
|
+
const isDeno = typeof Deno !== 'undefined';
|
|
24
|
+
const modulePath = isDeno
|
|
25
|
+
? `../../../../dist/slh-dsa-sha2-128f.deno.js`
|
|
26
|
+
: `../../../../dist/slh-dsa-sha2-128f.min.js`;
|
|
27
|
+
|
|
28
|
+
const module = await import(modulePath);
|
|
29
|
+
return module.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* SLH-DSA-SHA2-128F-INFO algorithm constants and metadata
|
|
34
|
+
* @type {{readonly name: 'SLH-DSA-SHA2-128f', readonly identifier: 'SLH_DSA_PURE_SHA2_128F', readonly type: 'sig', readonly securityLevel: 1, readonly standardized: true, readonly description: string, readonly keySize: {readonly publicKey: 32, readonly secretKey: 64, readonly signature: 17088}}}
|
|
35
|
+
*/
|
|
36
|
+
export const SLH_DSA_SHA2_128F_INFO = {
|
|
37
|
+
name: 'SLH-DSA-SHA2-128f',
|
|
38
|
+
identifier: 'SLH_DSA_PURE_SHA2_128F',
|
|
39
|
+
type: 'sig',
|
|
40
|
+
securityLevel: 1,
|
|
41
|
+
standardized: true,
|
|
42
|
+
description: 'SLH-DSA-SHA2-128f hash-based signature (NIST Level 1, 128-bit quantum security, SHA2, fast, FIPS 205)',
|
|
43
|
+
keySize: {
|
|
44
|
+
publicKey: 32,
|
|
45
|
+
secretKey: 64,
|
|
46
|
+
signature: 17088
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Factory function to create a SLH-DSA-SHA2-128f signature instance
|
|
52
|
+
*
|
|
53
|
+
* @async
|
|
54
|
+
* @function createSlhDsaSha2128f
|
|
55
|
+
* @returns {Promise<SlhDsaSha2128f>} Initialized SLH-DSA-SHA2-128f instance
|
|
56
|
+
* @throws {LibOQSInitError} If module initialization fails
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* import { createSlhDsaSha2128f } from '@oqs/liboqs-js';
|
|
60
|
+
*
|
|
61
|
+
* const sig = await createSlhDsaSha2128f();
|
|
62
|
+
* const { publicKey, secretKey } = sig.generateKeyPair();
|
|
63
|
+
* sig.destroy();
|
|
64
|
+
*/
|
|
65
|
+
export async function createSlhDsaSha2128f() {
|
|
66
|
+
const moduleFactory = await loadModule();
|
|
67
|
+
const wasmModule = await moduleFactory();
|
|
68
|
+
wasmModule._OQS_init();
|
|
69
|
+
|
|
70
|
+
const algoName = SLH_DSA_SHA2_128F_INFO.identifier;
|
|
71
|
+
const nameLen = wasmModule.lengthBytesUTF8(algoName);
|
|
72
|
+
const namePtr = wasmModule._malloc(nameLen + 1);
|
|
73
|
+
wasmModule.stringToUTF8(algoName, namePtr, nameLen + 1);
|
|
74
|
+
|
|
75
|
+
const sigPtr = wasmModule._OQS_SIG_new(namePtr);
|
|
76
|
+
wasmModule._free(namePtr);
|
|
77
|
+
|
|
78
|
+
if (!sigPtr) {
|
|
79
|
+
throw new LibOQSInitError('SLH-DSA-SHA2-128f', 'Failed to create SIG instance');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new SlhDsaSha2128f(wasmModule, sigPtr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* SLH-DSA-SHA2-128f signature scheme wrapper class
|
|
87
|
+
*
|
|
88
|
+
* @class SlhDsaSha2128f
|
|
89
|
+
* @description
|
|
90
|
+
* High-level wrapper for SLH-DSA-SHA2-128f signature operations. Provides secure key generation,
|
|
91
|
+
* signing, and verification with automatic memory management.
|
|
92
|
+
*
|
|
93
|
+
* Memory Management:
|
|
94
|
+
* - All WASM memory is managed internally
|
|
95
|
+
* - Call destroy() when finished to free resources
|
|
96
|
+
* - Do not use instance after calling destroy()
|
|
97
|
+
*
|
|
98
|
+
* @example
|
|
99
|
+
* const sig = await createSlhDsaSha2128f();
|
|
100
|
+
*
|
|
101
|
+
* // Generate keypair
|
|
102
|
+
* const { publicKey, secretKey } = sig.generateKeyPair();
|
|
103
|
+
*
|
|
104
|
+
* // Sign message
|
|
105
|
+
* const message = new TextEncoder().encode('Hello, world!');
|
|
106
|
+
* const signature = sig.sign(message, secretKey);
|
|
107
|
+
*
|
|
108
|
+
* // Verify signature
|
|
109
|
+
* const isValid = sig.verify(message, signature, publicKey);
|
|
110
|
+
*
|
|
111
|
+
* // Cleanup
|
|
112
|
+
* sig.destroy();
|
|
113
|
+
*/
|
|
114
|
+
export class SlhDsaSha2128f {
|
|
115
|
+
/** @type {Object} @private */ #wasmModule;
|
|
116
|
+
/** @type {number} @private */ #sigPtr;
|
|
117
|
+
/** @type {boolean} @private */ #destroyed = false;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* @private
|
|
121
|
+
* @constructor
|
|
122
|
+
* @param {Object} wasmModule - Emscripten WASM module
|
|
123
|
+
* @param {number} sigPtr - Pointer to OQS_SIG structure
|
|
124
|
+
*/
|
|
125
|
+
constructor(wasmModule, sigPtr) {
|
|
126
|
+
this.#wasmModule = wasmModule;
|
|
127
|
+
this.#sigPtr = sigPtr;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Generate a new SLH-DSA-SHA2-128f keypair
|
|
132
|
+
*
|
|
133
|
+
* @async
|
|
134
|
+
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}}
|
|
135
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
136
|
+
* @throws {LibOQSOperationError} If key generation fails
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* const { publicKey, secretKey } = sig.generateKeyPair();
|
|
140
|
+
* console.log('Public key:', publicKey.length); // 32 bytes
|
|
141
|
+
* console.log('Secret key:', secretKey.length); // 64 bytes
|
|
142
|
+
*/
|
|
143
|
+
generateKeyPair() {
|
|
144
|
+
this.#checkDestroyed();
|
|
145
|
+
|
|
146
|
+
const publicKey = new Uint8Array(SLH_DSA_SHA2_128F_INFO.keySize.publicKey);
|
|
147
|
+
const secretKey = new Uint8Array(SLH_DSA_SHA2_128F_INFO.keySize.secretKey);
|
|
148
|
+
|
|
149
|
+
const publicKeyPtr = this.#wasmModule._malloc(publicKey.length);
|
|
150
|
+
const secretKeyPtr = this.#wasmModule._malloc(secretKey.length);
|
|
151
|
+
|
|
152
|
+
try {
|
|
153
|
+
const result = this.#wasmModule._OQS_SIG_keypair(this.#sigPtr, publicKeyPtr, secretKeyPtr);
|
|
154
|
+
|
|
155
|
+
if (result !== 0) {
|
|
156
|
+
throw new LibOQSOperationError('generateKeyPair', 'SLH-DSA-SHA2-128f', 'Key generation failed');
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
publicKey.set(this.#wasmModule.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + publicKey.length));
|
|
160
|
+
secretKey.set(this.#wasmModule.HEAPU8.subarray(secretKeyPtr, secretKeyPtr + secretKey.length));
|
|
161
|
+
|
|
162
|
+
return { publicKey, secretKey };
|
|
163
|
+
} finally {
|
|
164
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
165
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Sign a message using a secret key
|
|
171
|
+
*
|
|
172
|
+
* @async
|
|
173
|
+
* @param {Uint8Array} message - Message to sign (any length)
|
|
174
|
+
* @param {Uint8Array} secretKey - Secret key (64 bytes)
|
|
175
|
+
* @returns {Uint8Array} Signature (17088 bytes)
|
|
176
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
177
|
+
* @throws {LibOQSValidationError} If secret key size is invalid
|
|
178
|
+
* @throws {LibOQSOperationError} If signing fails
|
|
179
|
+
*
|
|
180
|
+
* @example
|
|
181
|
+
* const message = new TextEncoder().encode('Hello, world!');
|
|
182
|
+
* const signature = sig.sign(message, secretKey);
|
|
183
|
+
* console.log('Signature:', signature.length); // 17088 bytes
|
|
184
|
+
*/
|
|
185
|
+
sign(message, secretKey) {
|
|
186
|
+
this.#checkDestroyed();
|
|
187
|
+
this.#validateSecretKey(secretKey);
|
|
188
|
+
|
|
189
|
+
const signatureMaxLen = SLH_DSA_SHA2_128F_INFO.keySize.signature;
|
|
190
|
+
const signature = new Uint8Array(signatureMaxLen);
|
|
191
|
+
|
|
192
|
+
const messagePtr = this.#wasmModule._malloc(message.length);
|
|
193
|
+
const secretKeyPtr = this.#wasmModule._malloc(secretKey.length);
|
|
194
|
+
const signaturePtr = this.#wasmModule._malloc(signatureMaxLen);
|
|
195
|
+
const signatureLenPtr = this.#wasmModule._malloc(8);
|
|
196
|
+
|
|
197
|
+
try {
|
|
198
|
+
this.#wasmModule.HEAPU8.set(message, messagePtr);
|
|
199
|
+
this.#wasmModule.HEAPU8.set(secretKey, secretKeyPtr);
|
|
200
|
+
|
|
201
|
+
const result = this.#wasmModule._OQS_SIG_sign(
|
|
202
|
+
this.#sigPtr,
|
|
203
|
+
signaturePtr,
|
|
204
|
+
signatureLenPtr,
|
|
205
|
+
messagePtr,
|
|
206
|
+
message.length,
|
|
207
|
+
secretKeyPtr
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (result !== 0) {
|
|
211
|
+
throw new LibOQSOperationError('sign', 'SLH-DSA-SHA2-128f', 'Signing failed');
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const actualSignatureLen = this.#wasmModule.getValue(signatureLenPtr, 'i32');
|
|
215
|
+
signature.set(this.#wasmModule.HEAPU8.subarray(signaturePtr, signaturePtr + actualSignatureLen));
|
|
216
|
+
|
|
217
|
+
return signature.slice(0, actualSignatureLen);
|
|
218
|
+
} finally {
|
|
219
|
+
this.#wasmModule._free(messagePtr);
|
|
220
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
221
|
+
this.#wasmModule._free(signaturePtr);
|
|
222
|
+
this.#wasmModule._free(signatureLenPtr);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Verify a signature using a public key
|
|
228
|
+
*
|
|
229
|
+
* @async
|
|
230
|
+
* @param {Uint8Array} message - Original message (any length)
|
|
231
|
+
* @param {Uint8Array} signature - Signature to verify
|
|
232
|
+
* @param {Uint8Array} publicKey - Public key (32 bytes)
|
|
233
|
+
* @returns {boolean} True if signature is valid, false otherwise
|
|
234
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
235
|
+
* @throws {LibOQSValidationError} If public key or signature size is invalid
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* const isValid = sig.verify(message, signature, publicKey);
|
|
239
|
+
* console.log('Signature valid:', isValid);
|
|
240
|
+
*/
|
|
241
|
+
verify(message, signature, publicKey) {
|
|
242
|
+
this.#checkDestroyed();
|
|
243
|
+
this.#validatePublicKey(publicKey);
|
|
244
|
+
this.#validateSignature(signature);
|
|
245
|
+
|
|
246
|
+
const messagePtr = this.#wasmModule._malloc(message.length);
|
|
247
|
+
const signaturePtr = this.#wasmModule._malloc(signature.length);
|
|
248
|
+
const publicKeyPtr = this.#wasmModule._malloc(publicKey.length);
|
|
249
|
+
|
|
250
|
+
try {
|
|
251
|
+
this.#wasmModule.HEAPU8.set(message, messagePtr);
|
|
252
|
+
this.#wasmModule.HEAPU8.set(signature, signaturePtr);
|
|
253
|
+
this.#wasmModule.HEAPU8.set(publicKey, publicKeyPtr);
|
|
254
|
+
|
|
255
|
+
const result = this.#wasmModule._OQS_SIG_verify(
|
|
256
|
+
this.#sigPtr,
|
|
257
|
+
messagePtr,
|
|
258
|
+
message.length,
|
|
259
|
+
signaturePtr,
|
|
260
|
+
signature.length,
|
|
261
|
+
publicKeyPtr
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
return result === 0;
|
|
265
|
+
} finally {
|
|
266
|
+
this.#wasmModule._free(messagePtr);
|
|
267
|
+
this.#wasmModule._free(signaturePtr);
|
|
268
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Free WASM resources
|
|
274
|
+
*
|
|
275
|
+
* @description
|
|
276
|
+
* Releases all WASM memory associated with this instance.
|
|
277
|
+
* The instance cannot be used after calling destroy().
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* sig.destroy();
|
|
281
|
+
* // sig is now unusable
|
|
282
|
+
*/
|
|
283
|
+
destroy() {
|
|
284
|
+
if (!this.#destroyed && this.#sigPtr) {
|
|
285
|
+
this.#wasmModule._OQS_SIG_free(this.#sigPtr);
|
|
286
|
+
this.#sigPtr = null;
|
|
287
|
+
this.#destroyed = true;
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/**
|
|
292
|
+
* Enables automatic cleanup via `using` declarations
|
|
293
|
+
* @example
|
|
294
|
+
* using instance = await create...();
|
|
295
|
+
* // automatically cleaned up at end of scope
|
|
296
|
+
*/
|
|
297
|
+
[Symbol.dispose]() {
|
|
298
|
+
this.destroy();
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get algorithm information
|
|
303
|
+
*
|
|
304
|
+
* @readonly
|
|
305
|
+
* @returns {typeof SLH_DSA_SHA2_128F_INFO} Algorithm metadata
|
|
306
|
+
*
|
|
307
|
+
* @example
|
|
308
|
+
* console.log(sig.info.name); // 'SLH-DSA-SHA2-128f'
|
|
309
|
+
* console.log(sig.info.securityLevel); // 1
|
|
310
|
+
* console.log(sig.info.keySize); // { publicKey: 32, secretKey: 64, signature: 17088 }
|
|
311
|
+
*/
|
|
312
|
+
get info() {
|
|
313
|
+
return SLH_DSA_SHA2_128F_INFO;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* @private
|
|
318
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
319
|
+
*/
|
|
320
|
+
#checkDestroyed() {
|
|
321
|
+
if (this.#destroyed) {
|
|
322
|
+
throw new LibOQSError('Instance has been destroyed', 'SLH-DSA-SHA2-128f');
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* @private
|
|
328
|
+
* @param {Uint8Array} publicKey
|
|
329
|
+
* @throws {LibOQSValidationError} If public key size is invalid
|
|
330
|
+
*/
|
|
331
|
+
#validatePublicKey(publicKey) {
|
|
332
|
+
if (!isUint8Array(publicKey) || publicKey.length !== SLH_DSA_SHA2_128F_INFO.keySize.publicKey) {
|
|
333
|
+
throw new LibOQSValidationError(
|
|
334
|
+
`Invalid public key: expected ${SLH_DSA_SHA2_128F_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
335
|
+
'SLH-DSA-SHA2-128f'
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @private
|
|
342
|
+
* @param {Uint8Array} secretKey
|
|
343
|
+
* @throws {LibOQSValidationError} If secret key size is invalid
|
|
344
|
+
*/
|
|
345
|
+
#validateSecretKey(secretKey) {
|
|
346
|
+
if (!isUint8Array(secretKey) || secretKey.length !== SLH_DSA_SHA2_128F_INFO.keySize.secretKey) {
|
|
347
|
+
throw new LibOQSValidationError(
|
|
348
|
+
`Invalid secret key: expected ${SLH_DSA_SHA2_128F_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
349
|
+
'SLH-DSA-SHA2-128f'
|
|
350
|
+
);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* @private
|
|
356
|
+
* @param {Uint8Array} signature
|
|
357
|
+
* @throws {LibOQSValidationError} If signature size is invalid
|
|
358
|
+
*/
|
|
359
|
+
#validateSignature(signature) {
|
|
360
|
+
if (!isUint8Array(signature) || signature.length === 0 || signature.length > SLH_DSA_SHA2_128F_INFO.keySize.signature) {
|
|
361
|
+
throw new LibOQSValidationError(
|
|
362
|
+
`Invalid signature: expected 0 < length <= ${SLH_DSA_SHA2_128F_INFO.keySize.signature} bytes, got ${signature?.length ?? 'null'}`,
|
|
363
|
+
'SLH-DSA-SHA2-128f'
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|