@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-44 signature algorithm implementation
|
|
3
|
+
* @module algorithms/sig/ml-dsa/ml-dsa-44
|
|
4
|
+
* @description
|
|
5
|
+
* ML-DSA-44 is a lattice-based digital signature algorithm providing NIST security level 2.
|
|
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 2 (128-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-44.deno.js`
|
|
26
|
+
: `../../../../dist/ml-dsa-44.min.js`;
|
|
27
|
+
|
|
28
|
+
const module = await import(modulePath);
|
|
29
|
+
return module.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* ML-DSA-44-INFO algorithm constants and metadata
|
|
34
|
+
* @type {{readonly name: 'ML-DSA-44', readonly identifier: 'ML-DSA-44', readonly type: 'sig', readonly securityLevel: 2, readonly standardized: true, readonly description: string, readonly keySize: {readonly publicKey: 1312, readonly secretKey: 2560, readonly signature: 2420}}}
|
|
35
|
+
*/
|
|
36
|
+
export const ML_DSA_44_INFO = {
|
|
37
|
+
name: 'ML-DSA-44',
|
|
38
|
+
identifier: 'ML-DSA-44',
|
|
39
|
+
type: 'sig',
|
|
40
|
+
securityLevel: 2,
|
|
41
|
+
standardized: true,
|
|
42
|
+
description: 'NIST FIPS 204 ML-DSA-44 lattice-based signature (NIST Level 2, 128-bit quantum security)',
|
|
43
|
+
keySize: {
|
|
44
|
+
publicKey: 1312,
|
|
45
|
+
secretKey: 2560,
|
|
46
|
+
signature: 2420
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Load and initialize ML-DSA-44 module
|
|
52
|
+
* @returns {Promise<MLDSA44>} Initialized ML-DSA-44 instance
|
|
53
|
+
* @throws {LibOQSInitError} If initialization fails
|
|
54
|
+
* @example
|
|
55
|
+
* import { createMLDSA44 } from '@oqs/liboqs-js';
|
|
56
|
+
* const sig = await createMLDSA44();
|
|
57
|
+
*/
|
|
58
|
+
export async function createMLDSA44() {
|
|
59
|
+
const moduleFactory = await loadModule();
|
|
60
|
+
const wasmModule = await moduleFactory();
|
|
61
|
+
wasmModule._OQS_init();
|
|
62
|
+
|
|
63
|
+
const algoName = ML_DSA_44_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-44', 'Failed to create SIG instance');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new MLDSA44(wasmModule, sigPtr);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ML-DSA-44 digital signature wrapper class
|
|
80
|
+
*
|
|
81
|
+
* Provides high-level interface for ML-DSA-44 digital signature operations.
|
|
82
|
+
* Automatically manages WASM memory and validates inputs.
|
|
83
|
+
*
|
|
84
|
+
* @class MLDSA44
|
|
85
|
+
* @example
|
|
86
|
+
* const sig = await createMLDSA44();
|
|
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 MLDSA44 {
|
|
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-44 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_44_INFO.keySize.publicKey);
|
|
127
|
+
const secretKey = new Uint8Array(ML_DSA_44_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-44', '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 (2560 bytes)
|
|
157
|
+
* @returns {Uint8Array} Digital signature (up to 2420 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_44_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-44', '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 (1312 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_44_INFO} Algorithm metadata
|
|
285
|
+
*/
|
|
286
|
+
get info() {
|
|
287
|
+
return ML_DSA_44_INFO;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#checkDestroyed() {
|
|
291
|
+
if (this.#destroyed) {
|
|
292
|
+
throw new LibOQSError('Instance has been destroyed', 'ML-DSA-44');
|
|
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-44'
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#validatePublicKey(publicKey) {
|
|
306
|
+
if (!isUint8Array(publicKey) || publicKey.length !== ML_DSA_44_INFO.keySize.publicKey) {
|
|
307
|
+
throw new LibOQSValidationError(
|
|
308
|
+
`Invalid public key: expected ${ML_DSA_44_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
309
|
+
'ML-DSA-44'
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
#validateSecretKey(secretKey) {
|
|
315
|
+
if (!isUint8Array(secretKey) || secretKey.length !== ML_DSA_44_INFO.keySize.secretKey) {
|
|
316
|
+
throw new LibOQSValidationError(
|
|
317
|
+
`Invalid secret key: expected ${ML_DSA_44_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
318
|
+
'ML-DSA-44'
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#validateSignature(signature) {
|
|
324
|
+
if (!isUint8Array(signature)) {
|
|
325
|
+
throw new LibOQSValidationError(
|
|
326
|
+
'Signature must be Uint8Array',
|
|
327
|
+
'ML-DSA-44'
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
if (signature.length === 0 || signature.length > ML_DSA_44_INFO.keySize.signature) {
|
|
331
|
+
throw new LibOQSValidationError(
|
|
332
|
+
`Invalid signature length: expected up to ${ML_DSA_44_INFO.keySize.signature} bytes, got ${signature.length}`,
|
|
333
|
+
'ML-DSA-44'
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ML-DSA-65 signature algorithm implementation
|
|
3
|
+
* @module algorithms/sig/ml-dsa/ml-dsa-65
|
|
4
|
+
* @description
|
|
5
|
+
* ML-DSA-65 is a lattice-based digital signature algorithm providing NIST security level 3.
|
|
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 3 (192-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-65.deno.js`
|
|
26
|
+
: `../../../../dist/ml-dsa-65.min.js`;
|
|
27
|
+
|
|
28
|
+
const module = await import(modulePath);
|
|
29
|
+
return module.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* ML-DSA-65-INFO algorithm constants and metadata
|
|
34
|
+
* @type {{readonly name: 'ML-DSA-65', readonly identifier: 'ML-DSA-65', readonly type: 'sig', readonly securityLevel: 3, readonly standardized: true, readonly description: string, readonly keySize: {readonly publicKey: 1952, readonly secretKey: 4032, readonly signature: 3309}}}
|
|
35
|
+
*/
|
|
36
|
+
export const ML_DSA_65_INFO = {
|
|
37
|
+
name: 'ML-DSA-65',
|
|
38
|
+
identifier: 'ML-DSA-65',
|
|
39
|
+
type: 'sig',
|
|
40
|
+
securityLevel: 3,
|
|
41
|
+
standardized: true,
|
|
42
|
+
description: 'NIST FIPS 204 ML-DSA-65 lattice-based signature (NIST Level 3, 192-bit quantum security)',
|
|
43
|
+
keySize: {
|
|
44
|
+
publicKey: 1952,
|
|
45
|
+
secretKey: 4032,
|
|
46
|
+
signature: 3309
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Load and initialize ML-DSA-65 module
|
|
52
|
+
* @returns {Promise<MLDSA65>} Initialized ML-DSA-65 instance
|
|
53
|
+
* @throws {LibOQSInitError} If initialization fails
|
|
54
|
+
* @example
|
|
55
|
+
* import { createMLDSA65 } from '@oqs/liboqs-js';
|
|
56
|
+
* const sig = await createMLDSA65();
|
|
57
|
+
*/
|
|
58
|
+
export async function createMLDSA65() {
|
|
59
|
+
const moduleFactory = await loadModule();
|
|
60
|
+
const wasmModule = await moduleFactory();
|
|
61
|
+
wasmModule._OQS_init();
|
|
62
|
+
|
|
63
|
+
const algoName = ML_DSA_65_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-65', 'Failed to create SIG instance');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return new MLDSA65(wasmModule, sigPtr);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* ML-DSA-65 digital signature wrapper class
|
|
80
|
+
*
|
|
81
|
+
* Provides high-level interface for ML-DSA-65 digital signature operations.
|
|
82
|
+
* Automatically manages WASM memory and validates inputs.
|
|
83
|
+
*
|
|
84
|
+
* @class MLDSA65
|
|
85
|
+
* @example
|
|
86
|
+
* const sig = await createMLDSA65();
|
|
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 MLDSA65 {
|
|
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-65 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_65_INFO.keySize.publicKey);
|
|
127
|
+
const secretKey = new Uint8Array(ML_DSA_65_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-65', '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 (4032 bytes)
|
|
157
|
+
* @returns {Uint8Array} Digital signature (up to 3309 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_65_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-65', '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 (1952 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_65_INFO} Algorithm metadata
|
|
285
|
+
*/
|
|
286
|
+
get info() {
|
|
287
|
+
return ML_DSA_65_INFO;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#checkDestroyed() {
|
|
291
|
+
if (this.#destroyed) {
|
|
292
|
+
throw new LibOQSError('Instance has been destroyed', 'ML-DSA-65');
|
|
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-65'
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
#validatePublicKey(publicKey) {
|
|
306
|
+
if (!isUint8Array(publicKey) || publicKey.length !== ML_DSA_65_INFO.keySize.publicKey) {
|
|
307
|
+
throw new LibOQSValidationError(
|
|
308
|
+
`Invalid public key: expected ${ML_DSA_65_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
309
|
+
'ML-DSA-65'
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
#validateSecretKey(secretKey) {
|
|
315
|
+
if (!isUint8Array(secretKey) || secretKey.length !== ML_DSA_65_INFO.keySize.secretKey) {
|
|
316
|
+
throw new LibOQSValidationError(
|
|
317
|
+
`Invalid secret key: expected ${ML_DSA_65_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
318
|
+
'ML-DSA-65'
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#validateSignature(signature) {
|
|
324
|
+
if (!isUint8Array(signature)) {
|
|
325
|
+
throw new LibOQSValidationError(
|
|
326
|
+
'Signature must be Uint8Array',
|
|
327
|
+
'ML-DSA-65'
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
if (signature.length === 0 || signature.length > ML_DSA_65_INFO.keySize.signature) {
|
|
331
|
+
throw new LibOQSValidationError(
|
|
332
|
+
`Invalid signature length: expected up to ${ML_DSA_65_INFO.keySize.signature} bytes, got ${signature.length}`,
|
|
333
|
+
'ML-DSA-65'
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|