@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,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ML-KEM-768 KEM algorithm implementation
|
|
3
|
+
* @module algorithms/kem/ml-kem/ml-kem-768
|
|
4
|
+
* @description
|
|
5
|
+
* ML-KEM-768 is a lattice-based key encapsulation mechanism providing NIST security level 3.
|
|
6
|
+
* It is part of the NIST FIPS 203 standard (Module-Lattice-Based Key-Encapsulation Mechanism).
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Lattice-based cryptography (Module-LWE problem)
|
|
10
|
+
* - Security Level 3 (192-bit classical, quantum-resistant)
|
|
11
|
+
* - NIST FIPS 203 standardized
|
|
12
|
+
* - IND-CCA2 security
|
|
13
|
+
* - Efficient key sizes and performance
|
|
14
|
+
*
|
|
15
|
+
* @see {@link https://csrc.nist.gov/pubs/fips/203/final} - NIST FIPS 203 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-kem-768.deno.js`
|
|
26
|
+
: `../../../../dist/ml-kem-768.min.js`;
|
|
27
|
+
|
|
28
|
+
const module = await import(modulePath);
|
|
29
|
+
return module.default;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* ML-KEM-768-INFO algorithm constants and metadata
|
|
34
|
+
* @type {{readonly name: 'ML-KEM-768', readonly identifier: 'ML-KEM-768', readonly type: 'kem', readonly securityLevel: 3, readonly standardized: true, readonly description: string, readonly keySize: {readonly publicKey: 1184, readonly secretKey: 2400, readonly ciphertext: 1088, readonly sharedSecret: 32}}}
|
|
35
|
+
*/
|
|
36
|
+
export const ML_KEM_768_INFO = {
|
|
37
|
+
name: 'ML-KEM-768',
|
|
38
|
+
identifier: 'ML-KEM-768',
|
|
39
|
+
type: 'kem',
|
|
40
|
+
securityLevel: 3,
|
|
41
|
+
standardized: true,
|
|
42
|
+
description: 'NIST FIPS 203 ML-KEM-768 (192-bit quantum security)',
|
|
43
|
+
keySize: {
|
|
44
|
+
publicKey: 1184,
|
|
45
|
+
secretKey: 2400,
|
|
46
|
+
ciphertext: 1088,
|
|
47
|
+
sharedSecret: 32
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Factory function to create an ML-KEM-768 KEM instance
|
|
53
|
+
*
|
|
54
|
+
* @async
|
|
55
|
+
* @function createMLKEM768
|
|
56
|
+
* @returns {Promise<MLKEM768>} Initialized ML-KEM-768 instance
|
|
57
|
+
* @throws {LibOQSInitError} If module initialization fails
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* import { createMLKEM768 } from '@oqs/liboqs-js';
|
|
61
|
+
*
|
|
62
|
+
* const kem = await createMLKEM768();
|
|
63
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
64
|
+
* kem.destroy();
|
|
65
|
+
*/
|
|
66
|
+
export async function createMLKEM768() {
|
|
67
|
+
const moduleFactory = await loadModule();
|
|
68
|
+
const wasmModule = await moduleFactory();
|
|
69
|
+
wasmModule._OQS_init();
|
|
70
|
+
|
|
71
|
+
const algoName = ML_KEM_768_INFO.identifier;
|
|
72
|
+
const nameLen = wasmModule.lengthBytesUTF8(algoName);
|
|
73
|
+
const namePtr = wasmModule._malloc(nameLen + 1);
|
|
74
|
+
wasmModule.stringToUTF8(algoName, namePtr, nameLen + 1);
|
|
75
|
+
|
|
76
|
+
const kemPtr = wasmModule._OQS_KEM_new(namePtr);
|
|
77
|
+
wasmModule._free(namePtr);
|
|
78
|
+
|
|
79
|
+
if (!kemPtr) {
|
|
80
|
+
throw new LibOQSInitError('ML-KEM-768', 'Failed to create KEM instance');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return new MLKEM768(wasmModule, kemPtr);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ML-KEM-768 wrapper class providing high-level KEM operations
|
|
88
|
+
*
|
|
89
|
+
* This class wraps the low-level WASM module to provide a user-friendly
|
|
90
|
+
* interface for ML-KEM-768 operations with automatic memory management
|
|
91
|
+
* and input validation.
|
|
92
|
+
*
|
|
93
|
+
* @class MLKEM768
|
|
94
|
+
* @example
|
|
95
|
+
* import { createMLKEM768 } from '@oqs/liboqs-js';
|
|
96
|
+
*
|
|
97
|
+
* const kem = await createMLKEM768();
|
|
98
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
99
|
+
* const { ciphertext, sharedSecret } = kem.encapsulate(publicKey);
|
|
100
|
+
* kem.destroy();
|
|
101
|
+
*/
|
|
102
|
+
export class MLKEM768 {
|
|
103
|
+
/** @type {Object} @private */
|
|
104
|
+
#wasmModule;
|
|
105
|
+
/** @type {number} @private */
|
|
106
|
+
#kemPtr;
|
|
107
|
+
/** @type {boolean} @private */
|
|
108
|
+
#destroyed = false;
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @param {Object} wasmModule - Emscripten WASM module
|
|
112
|
+
* @param {number} kemPtr - Pointer to KEM instance
|
|
113
|
+
* @private
|
|
114
|
+
*/
|
|
115
|
+
constructor(wasmModule, kemPtr) {
|
|
116
|
+
this.#wasmModule = wasmModule;
|
|
117
|
+
this.#kemPtr = kemPtr;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Generate a new keypair for ML-KEM-768
|
|
122
|
+
*
|
|
123
|
+
* Generates a public/private keypair using the algorithm's internal
|
|
124
|
+
* random number generator. The secret key must be kept confidential.
|
|
125
|
+
*
|
|
126
|
+
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}}
|
|
127
|
+
* @throws {LibOQSOperationError} If keypair generation fails
|
|
128
|
+
* @throws {LibOQSError} If instance has been destroyed
|
|
129
|
+
* @example
|
|
130
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
131
|
+
* // publicKey: 1184 bytes
|
|
132
|
+
* // secretKey: 2400 bytes (keep confidential!)
|
|
133
|
+
*/
|
|
134
|
+
generateKeyPair() {
|
|
135
|
+
this.#checkDestroyed();
|
|
136
|
+
|
|
137
|
+
const publicKeyPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.publicKey);
|
|
138
|
+
const secretKeyPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.secretKey);
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const result = this.#wasmModule._OQS_KEM_keypair(this.#kemPtr, publicKeyPtr, secretKeyPtr);
|
|
142
|
+
|
|
143
|
+
if (result !== 0) {
|
|
144
|
+
throw new LibOQSOperationError('keypair', 'ML-KEM-768', `Error code: ${result}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const publicKey = new Uint8Array(ML_KEM_768_INFO.keySize.publicKey);
|
|
148
|
+
const secretKey = new Uint8Array(ML_KEM_768_INFO.keySize.secretKey);
|
|
149
|
+
|
|
150
|
+
publicKey.set(this.#wasmModule.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + ML_KEM_768_INFO.keySize.publicKey));
|
|
151
|
+
secretKey.set(this.#wasmModule.HEAPU8.subarray(secretKeyPtr, secretKeyPtr + ML_KEM_768_INFO.keySize.secretKey));
|
|
152
|
+
|
|
153
|
+
return { publicKey, secretKey };
|
|
154
|
+
|
|
155
|
+
} finally {
|
|
156
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
157
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Encapsulate a shared secret using a public key
|
|
163
|
+
*
|
|
164
|
+
* Generates a random shared secret and encapsulates it using the
|
|
165
|
+
* provided public key. The shared secret can be used for symmetric
|
|
166
|
+
* encryption.
|
|
167
|
+
*
|
|
168
|
+
* @param {Uint8Array} publicKey - Recipient's public key (1184 bytes)
|
|
169
|
+
* @returns {{ciphertext: Uint8Array, sharedSecret: Uint8Array}}
|
|
170
|
+
* @throws {LibOQSValidationError} If public key is invalid
|
|
171
|
+
* @throws {LibOQSOperationError} If encapsulation fails
|
|
172
|
+
* @throws {LibOQSError} If instance has been destroyed
|
|
173
|
+
* @example
|
|
174
|
+
* const { ciphertext, sharedSecret } = kem.encapsulate(recipientPublicKey);
|
|
175
|
+
* // ciphertext: 1088 bytes (send to recipient)
|
|
176
|
+
* // sharedSecret: 32 bytes (use for symmetric encryption)
|
|
177
|
+
*/
|
|
178
|
+
encapsulate(publicKey) {
|
|
179
|
+
this.#checkDestroyed();
|
|
180
|
+
this.#validatePublicKey(publicKey);
|
|
181
|
+
|
|
182
|
+
const publicKeyPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.publicKey);
|
|
183
|
+
const ciphertextPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.ciphertext);
|
|
184
|
+
const sharedSecretPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.sharedSecret);
|
|
185
|
+
|
|
186
|
+
try {
|
|
187
|
+
this.#wasmModule.HEAPU8.set(publicKey, publicKeyPtr);
|
|
188
|
+
|
|
189
|
+
const result = this.#wasmModule._OQS_KEM_encaps(
|
|
190
|
+
this.#kemPtr,
|
|
191
|
+
ciphertextPtr,
|
|
192
|
+
sharedSecretPtr,
|
|
193
|
+
publicKeyPtr
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
if (result !== 0) {
|
|
197
|
+
throw new LibOQSOperationError('encaps', 'ML-KEM-768', `Error code: ${result}`);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const ciphertext = new Uint8Array(ML_KEM_768_INFO.keySize.ciphertext);
|
|
201
|
+
const sharedSecret = new Uint8Array(ML_KEM_768_INFO.keySize.sharedSecret);
|
|
202
|
+
|
|
203
|
+
ciphertext.set(this.#wasmModule.HEAPU8.subarray(ciphertextPtr, ciphertextPtr + ML_KEM_768_INFO.keySize.ciphertext));
|
|
204
|
+
sharedSecret.set(this.#wasmModule.HEAPU8.subarray(sharedSecretPtr, sharedSecretPtr + ML_KEM_768_INFO.keySize.sharedSecret));
|
|
205
|
+
|
|
206
|
+
return { ciphertext, sharedSecret };
|
|
207
|
+
|
|
208
|
+
} finally {
|
|
209
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
210
|
+
this.#wasmModule._free(ciphertextPtr);
|
|
211
|
+
this.#wasmModule._free(sharedSecretPtr);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Decapsulate a shared secret using a secret key
|
|
217
|
+
*
|
|
218
|
+
* Recovers the shared secret from a ciphertext using the secret key.
|
|
219
|
+
* The recovered shared secret will match the one generated during
|
|
220
|
+
* encapsulation.
|
|
221
|
+
*
|
|
222
|
+
* @param {Uint8Array} ciphertext - Ciphertext received (1088 bytes)
|
|
223
|
+
* @param {Uint8Array} secretKey - Recipient's secret key (2400 bytes)
|
|
224
|
+
* @returns {Uint8Array} Recovered shared secret (32 bytes)
|
|
225
|
+
* @throws {LibOQSValidationError} If inputs are invalid
|
|
226
|
+
* @throws {LibOQSOperationError} If decapsulation fails
|
|
227
|
+
* @throws {LibOQSError} If instance has been destroyed
|
|
228
|
+
* @example
|
|
229
|
+
* const sharedSecret = kem.decapsulate(ciphertext, mySecretKey);
|
|
230
|
+
* // sharedSecret: 32 bytes (matches sender's shared secret)
|
|
231
|
+
*/
|
|
232
|
+
decapsulate(ciphertext, secretKey) {
|
|
233
|
+
this.#checkDestroyed();
|
|
234
|
+
this.#validateCiphertext(ciphertext);
|
|
235
|
+
this.#validateSecretKey(secretKey);
|
|
236
|
+
|
|
237
|
+
const ciphertextPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.ciphertext);
|
|
238
|
+
const secretKeyPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.secretKey);
|
|
239
|
+
const sharedSecretPtr = this.#wasmModule._malloc(ML_KEM_768_INFO.keySize.sharedSecret);
|
|
240
|
+
|
|
241
|
+
try {
|
|
242
|
+
this.#wasmModule.HEAPU8.set(ciphertext, ciphertextPtr);
|
|
243
|
+
this.#wasmModule.HEAPU8.set(secretKey, secretKeyPtr);
|
|
244
|
+
|
|
245
|
+
const result = this.#wasmModule._OQS_KEM_decaps(
|
|
246
|
+
this.#kemPtr,
|
|
247
|
+
sharedSecretPtr,
|
|
248
|
+
ciphertextPtr,
|
|
249
|
+
secretKeyPtr
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
if (result !== 0) {
|
|
253
|
+
throw new LibOQSOperationError('decaps', 'ML-KEM-768', `Error code: ${result}`);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const sharedSecret = new Uint8Array(ML_KEM_768_INFO.keySize.sharedSecret);
|
|
257
|
+
sharedSecret.set(this.#wasmModule.HEAPU8.subarray(sharedSecretPtr, sharedSecretPtr + ML_KEM_768_INFO.keySize.sharedSecret));
|
|
258
|
+
|
|
259
|
+
return sharedSecret;
|
|
260
|
+
|
|
261
|
+
} finally {
|
|
262
|
+
this.#wasmModule._free(ciphertextPtr);
|
|
263
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
264
|
+
this.#wasmModule._free(sharedSecretPtr);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Clean up resources and free WASM memory
|
|
270
|
+
*
|
|
271
|
+
* This method should be called when you're done using the instance
|
|
272
|
+
* to free WASM memory. After calling destroy(), the instance cannot
|
|
273
|
+
* be used for further operations.
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* const kem = await createMLKEM768(LibOQS_ml_kem_768);
|
|
277
|
+
* // ... use kem ...
|
|
278
|
+
* kem.destroy();
|
|
279
|
+
*/
|
|
280
|
+
destroy() {
|
|
281
|
+
if (!this.#destroyed) {
|
|
282
|
+
if (this.#kemPtr) {
|
|
283
|
+
this.#wasmModule._OQS_KEM_free(this.#kemPtr);
|
|
284
|
+
this.#kemPtr = null;
|
|
285
|
+
}
|
|
286
|
+
this.#destroyed = true;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Enables automatic cleanup via `using` declarations
|
|
292
|
+
* @example
|
|
293
|
+
* using instance = await create...();
|
|
294
|
+
* // automatically cleaned up at end of scope
|
|
295
|
+
*/
|
|
296
|
+
[Symbol.dispose]() {
|
|
297
|
+
this.destroy();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get algorithm information and constants
|
|
302
|
+
* @returns {typeof ML_KEM_768_INFO} Algorithm metadata (copy of ML_KEM_768_INFO)
|
|
303
|
+
* @example
|
|
304
|
+
* const info = kem.info;
|
|
305
|
+
* console.log(info.keySize.publicKey); // 1184
|
|
306
|
+
*/
|
|
307
|
+
get info() {
|
|
308
|
+
return ML_KEM_768_INFO;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
#checkDestroyed() {
|
|
312
|
+
if (this.#destroyed) {
|
|
313
|
+
throw new LibOQSError('Instance has been destroyed', 'ML-KEM-768');
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#validatePublicKey(publicKey) {
|
|
318
|
+
if (!isUint8Array(publicKey) || publicKey.length !== ML_KEM_768_INFO.keySize.publicKey) {
|
|
319
|
+
throw new LibOQSValidationError(
|
|
320
|
+
`Invalid public key: expected ${ML_KEM_768_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
321
|
+
'ML-KEM-768'
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
#validateSecretKey(secretKey) {
|
|
327
|
+
if (!isUint8Array(secretKey) || secretKey.length !== ML_KEM_768_INFO.keySize.secretKey) {
|
|
328
|
+
throw new LibOQSValidationError(
|
|
329
|
+
`Invalid secret key: expected ${ML_KEM_768_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
330
|
+
'ML-KEM-768'
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
#validateCiphertext(ciphertext) {
|
|
336
|
+
if (!isUint8Array(ciphertext) || ciphertext.length !== ML_KEM_768_INFO.keySize.ciphertext) {
|
|
337
|
+
throw new LibOQSValidationError(
|
|
338
|
+
`Invalid ciphertext: expected ${ML_KEM_768_INFO.keySize.ciphertext} bytes, got ${ciphertext?.length ?? 'null'}`,
|
|
339
|
+
'ML-KEM-768'
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview NTRU-HPS-2048-509 KEM algorithm implementation
|
|
3
|
+
* @module algorithms/kem/ntru/ntru-hps-2048-509
|
|
4
|
+
* @description
|
|
5
|
+
* NTRU-HPS-2048-509 is a lattice-based key encapsulation mechanism from the NTRU-HPS (Highest Performance Secure) family.
|
|
6
|
+
* It provides post-quantum security based on the NTRU problem.
|
|
7
|
+
*
|
|
8
|
+
* Key features:
|
|
9
|
+
* - Lattice-based cryptography (NTRU problem)
|
|
10
|
+
* - Security Level 1 (128-bit classical, quantum-resistant)
|
|
11
|
+
* - Optimized for performance
|
|
12
|
+
* - Compact ciphertext (699 bytes)
|
|
13
|
+
*
|
|
14
|
+
* @see {@link https://ntru.org/} - NTRU specification
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { LibOQSError, LibOQSInitError, LibOQSOperationError, LibOQSValidationError } from '../../../core/errors.js';
|
|
18
|
+
import { isUint8Array } from '../../../core/validation.js';
|
|
19
|
+
|
|
20
|
+
// Dynamic module loading for cross-runtime compatibility
|
|
21
|
+
async function loadModule() {
|
|
22
|
+
const isDeno = typeof Deno !== 'undefined';
|
|
23
|
+
const modulePath = isDeno
|
|
24
|
+
? `../../../../dist/ntru-hps-2048-509.deno.js`
|
|
25
|
+
: `../../../../dist/ntru-hps-2048-509.min.js`;
|
|
26
|
+
|
|
27
|
+
const module = await import(modulePath);
|
|
28
|
+
return module.default;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* NTRU-HPS-2048-509-INFO algorithm constants and metadata
|
|
33
|
+
* @type {{readonly name: 'NTRU-HPS-2048-509', readonly identifier: 'NTRU-HPS-2048-509', readonly type: 'kem', readonly securityLevel: 1, readonly standardized: false, readonly description: string, readonly keySize: {readonly publicKey: 699, readonly secretKey: 935, readonly ciphertext: 699, readonly sharedSecret: 32}}}
|
|
34
|
+
*/
|
|
35
|
+
export const NTRU_HPS_2048_509_INFO = {
|
|
36
|
+
name: 'NTRU-HPS-2048-509',
|
|
37
|
+
identifier: 'NTRU-HPS-2048-509',
|
|
38
|
+
type: 'kem',
|
|
39
|
+
securityLevel: 1,
|
|
40
|
+
standardized: false,
|
|
41
|
+
description: 'NTRU-HPS-2048-509 NTRU-HPS (Highest Performance Secure) (NIST Level 1, 128-bit quantum security)',
|
|
42
|
+
keySize: {
|
|
43
|
+
publicKey: 699,
|
|
44
|
+
secretKey: 935,
|
|
45
|
+
ciphertext: 699,
|
|
46
|
+
sharedSecret: 32
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Factory function to create a NTRU-HPS-2048-509 KEM instance
|
|
52
|
+
*
|
|
53
|
+
* @async
|
|
54
|
+
* @function createNTRUHps2048509
|
|
55
|
+
* @returns {Promise<NTRUHps2048509>} Initialized NTRU-HPS-2048-509 instance
|
|
56
|
+
* @throws {LibOQSInitError} If module initialization fails
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* import { createNTRUHps2048509 } from '@oqs/liboqs-js';
|
|
60
|
+
*
|
|
61
|
+
* const kem = await createNTRUHps2048509();
|
|
62
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
63
|
+
* kem.destroy();
|
|
64
|
+
*/
|
|
65
|
+
export async function createNTRUHps2048509() {
|
|
66
|
+
const moduleFactory = await loadModule();
|
|
67
|
+
const wasmModule = await moduleFactory();
|
|
68
|
+
wasmModule._OQS_init();
|
|
69
|
+
|
|
70
|
+
const algoName = NTRU_HPS_2048_509_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 kemPtr = wasmModule._OQS_KEM_new(namePtr);
|
|
76
|
+
wasmModule._free(namePtr);
|
|
77
|
+
|
|
78
|
+
if (!kemPtr) {
|
|
79
|
+
throw new LibOQSInitError('NTRU-HPS-2048-509', 'Failed to create KEM instance');
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return new NTRUHps2048509(wasmModule, kemPtr);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* NTRU-HPS-2048-509 key encapsulation mechanism wrapper class
|
|
87
|
+
*
|
|
88
|
+
* @class NTRUHps2048509
|
|
89
|
+
* @description
|
|
90
|
+
* High-level wrapper for NTRU-HPS-2048-509 KEM operations. Provides secure key generation,
|
|
91
|
+
* encapsulation, and decapsulation 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 kem = await createNTRUHps2048509();
|
|
100
|
+
*
|
|
101
|
+
* // Generate keypair
|
|
102
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
103
|
+
*
|
|
104
|
+
* // Encapsulate
|
|
105
|
+
* const { ciphertext, sharedSecret: senderSecret } = kem.encapsulate(publicKey);
|
|
106
|
+
*
|
|
107
|
+
* // Decapsulate
|
|
108
|
+
* const receiverSecret = kem.decapsulate(ciphertext, secretKey);
|
|
109
|
+
*
|
|
110
|
+
* // Cleanup
|
|
111
|
+
* kem.destroy();
|
|
112
|
+
*/
|
|
113
|
+
export class NTRUHps2048509 {
|
|
114
|
+
/** @type {Object} @private */ #wasmModule;
|
|
115
|
+
/** @type {number} @private */ #kemPtr;
|
|
116
|
+
/** @type {boolean} @private */ #destroyed = false;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @private
|
|
120
|
+
* @constructor
|
|
121
|
+
* @param {Object} wasmModule - Emscripten WASM module
|
|
122
|
+
* @param {number} kemPtr - Pointer to OQS_KEM structure
|
|
123
|
+
*/
|
|
124
|
+
constructor(wasmModule, kemPtr) {
|
|
125
|
+
this.#wasmModule = wasmModule;
|
|
126
|
+
this.#kemPtr = kemPtr;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Generate a new NTRU-HPS-2048-509 keypair
|
|
131
|
+
*
|
|
132
|
+
* @async
|
|
133
|
+
* @returns {{publicKey: Uint8Array, secretKey: Uint8Array}}
|
|
134
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
135
|
+
* @throws {LibOQSOperationError} If key generation fails
|
|
136
|
+
*
|
|
137
|
+
* @example
|
|
138
|
+
* const { publicKey, secretKey } = kem.generateKeyPair();
|
|
139
|
+
* console.log('Public key:', publicKey.length); // 699 bytes
|
|
140
|
+
* console.log('Secret key:', secretKey.length); // 935 bytes
|
|
141
|
+
*/
|
|
142
|
+
generateKeyPair() {
|
|
143
|
+
this.#checkDestroyed();
|
|
144
|
+
|
|
145
|
+
const publicKey = new Uint8Array(NTRU_HPS_2048_509_INFO.keySize.publicKey);
|
|
146
|
+
const secretKey = new Uint8Array(NTRU_HPS_2048_509_INFO.keySize.secretKey);
|
|
147
|
+
|
|
148
|
+
const publicKeyPtr = this.#wasmModule._malloc(publicKey.length);
|
|
149
|
+
const secretKeyPtr = this.#wasmModule._malloc(secretKey.length);
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const result = this.#wasmModule._OQS_KEM_keypair(this.#kemPtr, publicKeyPtr, secretKeyPtr);
|
|
153
|
+
|
|
154
|
+
if (result !== 0) {
|
|
155
|
+
throw new LibOQSOperationError('generateKeyPair', 'NTRU-HPS-2048-509', 'Key generation failed');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
publicKey.set(this.#wasmModule.HEAPU8.subarray(publicKeyPtr, publicKeyPtr + publicKey.length));
|
|
159
|
+
secretKey.set(this.#wasmModule.HEAPU8.subarray(secretKeyPtr, secretKeyPtr + secretKey.length));
|
|
160
|
+
|
|
161
|
+
return { publicKey, secretKey };
|
|
162
|
+
} finally {
|
|
163
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
164
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Encapsulate a shared secret using the public key
|
|
170
|
+
*
|
|
171
|
+
* @async
|
|
172
|
+
* @param {Uint8Array} publicKey - Public key for encapsulation (699 bytes)
|
|
173
|
+
* @returns {{ciphertext: Uint8Array, sharedSecret: Uint8Array}}
|
|
174
|
+
* @returns {Uint8Array} returns.sharedSecret - Shared secret Ciphertext and shared secret
|
|
175
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
176
|
+
* @throws {LibOQSValidationError} If public key is invalid
|
|
177
|
+
* @throws {LibOQSOperationError} If encapsulation fails
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* const { ciphertext, sharedSecret } = kem.encapsulate(publicKey);
|
|
181
|
+
* console.log('Ciphertext:', ciphertext.length); // 699 bytes
|
|
182
|
+
* console.log('Shared secret:', sharedSecret.length); // 32 bytes
|
|
183
|
+
*/
|
|
184
|
+
encapsulate(publicKey) {
|
|
185
|
+
this.#checkDestroyed();
|
|
186
|
+
this.#validatePublicKey(publicKey);
|
|
187
|
+
|
|
188
|
+
const ciphertext = new Uint8Array(NTRU_HPS_2048_509_INFO.keySize.ciphertext);
|
|
189
|
+
const sharedSecret = new Uint8Array(NTRU_HPS_2048_509_INFO.keySize.sharedSecret);
|
|
190
|
+
|
|
191
|
+
const ciphertextPtr = this.#wasmModule._malloc(ciphertext.length);
|
|
192
|
+
const sharedSecretPtr = this.#wasmModule._malloc(sharedSecret.length);
|
|
193
|
+
const publicKeyPtr = this.#wasmModule._malloc(publicKey.length);
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
this.#wasmModule.HEAPU8.set(publicKey, publicKeyPtr);
|
|
197
|
+
|
|
198
|
+
const result = this.#wasmModule._OQS_KEM_encaps(
|
|
199
|
+
this.#kemPtr,
|
|
200
|
+
ciphertextPtr,
|
|
201
|
+
sharedSecretPtr,
|
|
202
|
+
publicKeyPtr
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
if (result !== 0) {
|
|
206
|
+
throw new LibOQSOperationError('encapsulate', 'NTRU-HPS-2048-509', 'Encapsulation failed');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
ciphertext.set(this.#wasmModule.HEAPU8.subarray(ciphertextPtr, ciphertextPtr + ciphertext.length));
|
|
210
|
+
sharedSecret.set(this.#wasmModule.HEAPU8.subarray(sharedSecretPtr, sharedSecretPtr + sharedSecret.length));
|
|
211
|
+
|
|
212
|
+
return { ciphertext, sharedSecret };
|
|
213
|
+
} finally {
|
|
214
|
+
this.#wasmModule._free(ciphertextPtr);
|
|
215
|
+
this.#wasmModule._free(sharedSecretPtr);
|
|
216
|
+
this.#wasmModule._free(publicKeyPtr);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Decapsulate a shared secret using the secret key
|
|
222
|
+
*
|
|
223
|
+
* @async
|
|
224
|
+
* @param {Uint8Array} ciphertext - Ciphertext to decapsulate (699 bytes)
|
|
225
|
+
* @param {Uint8Array} secretKey - Secret key for decapsulation (935 bytes)
|
|
226
|
+
* @returns {Uint8Array} Shared secret (32 bytes)
|
|
227
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
228
|
+
* @throws {LibOQSValidationError} If inputs are invalid
|
|
229
|
+
* @throws {LibOQSOperationError} If decapsulation fails
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* const sharedSecret = kem.decapsulate(ciphertext, secretKey);
|
|
233
|
+
* console.log('Shared secret:', sharedSecret.length); // 32 bytes
|
|
234
|
+
*/
|
|
235
|
+
decapsulate(ciphertext, secretKey) {
|
|
236
|
+
this.#checkDestroyed();
|
|
237
|
+
this.#validateCiphertext(ciphertext);
|
|
238
|
+
this.#validateSecretKey(secretKey);
|
|
239
|
+
|
|
240
|
+
const sharedSecret = new Uint8Array(NTRU_HPS_2048_509_INFO.keySize.sharedSecret);
|
|
241
|
+
|
|
242
|
+
const sharedSecretPtr = this.#wasmModule._malloc(sharedSecret.length);
|
|
243
|
+
const ciphertextPtr = this.#wasmModule._malloc(ciphertext.length);
|
|
244
|
+
const secretKeyPtr = this.#wasmModule._malloc(secretKey.length);
|
|
245
|
+
|
|
246
|
+
try {
|
|
247
|
+
this.#wasmModule.HEAPU8.set(ciphertext, ciphertextPtr);
|
|
248
|
+
this.#wasmModule.HEAPU8.set(secretKey, secretKeyPtr);
|
|
249
|
+
|
|
250
|
+
const result = this.#wasmModule._OQS_KEM_decaps(
|
|
251
|
+
this.#kemPtr,
|
|
252
|
+
sharedSecretPtr,
|
|
253
|
+
ciphertextPtr,
|
|
254
|
+
secretKeyPtr
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
if (result !== 0) {
|
|
258
|
+
throw new LibOQSOperationError('decapsulate', 'NTRU-HPS-2048-509', 'Decapsulation failed');
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
sharedSecret.set(this.#wasmModule.HEAPU8.subarray(sharedSecretPtr, sharedSecretPtr + sharedSecret.length));
|
|
262
|
+
|
|
263
|
+
return sharedSecret;
|
|
264
|
+
} finally {
|
|
265
|
+
this.#wasmModule._free(sharedSecretPtr);
|
|
266
|
+
this.#wasmModule._free(ciphertextPtr);
|
|
267
|
+
this.#wasmModule._free(secretKeyPtr);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Free WASM resources
|
|
273
|
+
*
|
|
274
|
+
* @description
|
|
275
|
+
* Releases all WASM memory associated with this instance.
|
|
276
|
+
* The instance cannot be used after calling destroy().
|
|
277
|
+
*
|
|
278
|
+
* @example
|
|
279
|
+
* kem.destroy();
|
|
280
|
+
* // kem is now unusable
|
|
281
|
+
*/
|
|
282
|
+
destroy() {
|
|
283
|
+
if (!this.#destroyed && this.#kemPtr) {
|
|
284
|
+
this.#wasmModule._OQS_KEM_free(this.#kemPtr);
|
|
285
|
+
this.#kemPtr = null;
|
|
286
|
+
this.#destroyed = true;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Enables automatic cleanup via `using` declarations
|
|
292
|
+
* @example
|
|
293
|
+
* using instance = await create...();
|
|
294
|
+
* // automatically cleaned up at end of scope
|
|
295
|
+
*/
|
|
296
|
+
[Symbol.dispose]() {
|
|
297
|
+
this.destroy();
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Get algorithm information
|
|
302
|
+
*
|
|
303
|
+
* @readonly
|
|
304
|
+
* @returns {typeof NTRU_HPS_2048_509_INFO} Algorithm metadata
|
|
305
|
+
*
|
|
306
|
+
* @example
|
|
307
|
+
* console.log(kem.info.name); // 'NTRU-HPS-2048-509'
|
|
308
|
+
* console.log(kem.info.securityLevel); // 1
|
|
309
|
+
* console.log(kem.info.keySize); // { publicKey: 699, secretKey: 935, ciphertext: 699, sharedSecret: 32 }
|
|
310
|
+
*/
|
|
311
|
+
get info() {
|
|
312
|
+
return NTRU_HPS_2048_509_INFO;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* @private
|
|
317
|
+
* @throws {LibOQSError} If instance is destroyed
|
|
318
|
+
*/
|
|
319
|
+
#checkDestroyed() {
|
|
320
|
+
if (this.#destroyed) {
|
|
321
|
+
throw new LibOQSError('Instance has been destroyed', 'NTRU-HPS-2048-509');
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* @private
|
|
327
|
+
* @param {Uint8Array} publicKey
|
|
328
|
+
* @throws {LibOQSValidationError} If public key size is invalid
|
|
329
|
+
*/
|
|
330
|
+
#validatePublicKey(publicKey) {
|
|
331
|
+
if (!isUint8Array(publicKey) || publicKey.length !== NTRU_HPS_2048_509_INFO.keySize.publicKey) {
|
|
332
|
+
throw new LibOQSValidationError(
|
|
333
|
+
`Invalid public key: expected ${NTRU_HPS_2048_509_INFO.keySize.publicKey} bytes, got ${publicKey?.length ?? 'null'}`,
|
|
334
|
+
'NTRU-HPS-2048-509'
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* @private
|
|
341
|
+
* @param {Uint8Array} secretKey
|
|
342
|
+
* @throws {LibOQSValidationError} If secret key size is invalid
|
|
343
|
+
*/
|
|
344
|
+
#validateSecretKey(secretKey) {
|
|
345
|
+
if (!isUint8Array(secretKey) || secretKey.length !== NTRU_HPS_2048_509_INFO.keySize.secretKey) {
|
|
346
|
+
throw new LibOQSValidationError(
|
|
347
|
+
`Invalid secret key: expected ${NTRU_HPS_2048_509_INFO.keySize.secretKey} bytes, got ${secretKey?.length ?? 'null'}`,
|
|
348
|
+
'NTRU-HPS-2048-509'
|
|
349
|
+
);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* @private
|
|
355
|
+
* @param {Uint8Array} ciphertext
|
|
356
|
+
* @throws {LibOQSValidationError} If ciphertext size is invalid
|
|
357
|
+
*/
|
|
358
|
+
#validateCiphertext(ciphertext) {
|
|
359
|
+
if (!isUint8Array(ciphertext) || ciphertext.length !== NTRU_HPS_2048_509_INFO.keySize.ciphertext) {
|
|
360
|
+
throw new LibOQSValidationError(
|
|
361
|
+
`Invalid ciphertext: expected ${NTRU_HPS_2048_509_INFO.keySize.ciphertext} bytes, got ${ciphertext?.length ?? 'null'}`,
|
|
362
|
+
'NTRU-HPS-2048-509'
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|