leviathan-crypto 2.0.1 → 3.0.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/CLAUDE.md +88 -281
- package/LICENSE +4 -0
- package/README.md +275 -87
- package/dist/aes/aes-cbc.d.ts +40 -0
- package/dist/aes/aes-cbc.js +158 -0
- package/dist/aes/aes-ctr.d.ts +50 -0
- package/dist/aes/aes-ctr.js +141 -0
- package/dist/aes/aes-gcm-siv.d.ts +67 -0
- package/dist/aes/aes-gcm-siv.js +217 -0
- package/dist/aes/aes-gcm.d.ts +61 -0
- package/dist/aes/aes-gcm.js +226 -0
- package/dist/aes/cipher-suite.d.ts +21 -0
- package/dist/aes/cipher-suite.js +179 -0
- package/dist/aes/embedded.d.ts +1 -0
- package/dist/aes/embedded.js +26 -0
- package/dist/aes/generator.d.ts +14 -0
- package/dist/aes/generator.js +103 -0
- package/dist/aes/index.d.ts +58 -0
- package/dist/aes/index.js +125 -0
- package/dist/aes/ops.d.ts +60 -0
- package/dist/aes/ops.js +164 -0
- package/dist/aes/pool-worker.d.ts +1 -0
- package/dist/aes/pool-worker.js +92 -0
- package/dist/aes/types.d.ts +1 -0
- package/dist/aes/types.js +23 -0
- package/dist/aes.wasm +0 -0
- package/dist/blake3/embedded.d.ts +1 -0
- package/dist/blake3/embedded.js +26 -0
- package/dist/blake3/index.d.ts +143 -0
- package/dist/blake3/index.js +620 -0
- package/dist/blake3/types.d.ts +102 -0
- package/dist/blake3/types.js +31 -0
- package/dist/blake3/validate.d.ts +29 -0
- package/dist/blake3/validate.js +80 -0
- package/dist/blake3.wasm +0 -0
- package/dist/chacha20/cipher-suite.d.ts +10 -0
- package/dist/chacha20/cipher-suite.js +98 -13
- package/dist/chacha20/generator.d.ts +12 -0
- package/dist/chacha20/generator.js +91 -0
- package/dist/chacha20/index.d.ts +100 -3
- package/dist/chacha20/index.js +169 -35
- package/dist/chacha20/ops.d.ts +57 -6
- package/dist/chacha20/ops.js +107 -27
- package/dist/chacha20/pool-worker.js +14 -0
- package/dist/chacha20/types.d.ts +1 -32
- package/dist/cte-wasm.d.ts +1 -0
- package/dist/cte-wasm.js +3 -0
- package/dist/cte.wasm +0 -0
- package/dist/curve25519.wasm +0 -0
- package/dist/ecdsa/der.d.ts +23 -0
- package/dist/ecdsa/der.js +192 -0
- package/dist/ecdsa/ecprivatekey-der.d.ts +32 -0
- package/dist/ecdsa/ecprivatekey-der.js +230 -0
- package/dist/ecdsa/embedded.d.ts +1 -0
- package/dist/ecdsa/embedded.js +25 -0
- package/dist/ecdsa/index.d.ts +124 -0
- package/dist/ecdsa/index.js +366 -0
- package/dist/ecdsa/types.d.ts +31 -0
- package/dist/ecdsa/types.js +28 -0
- package/dist/ecdsa/validate.d.ts +18 -0
- package/dist/ecdsa/validate.js +92 -0
- package/dist/ed25519/embedded.d.ts +1 -0
- package/dist/ed25519/embedded.js +31 -0
- package/dist/ed25519/index.d.ts +70 -0
- package/dist/ed25519/index.js +308 -0
- package/dist/ed25519/types.d.ts +27 -0
- package/dist/ed25519/types.js +27 -0
- package/dist/ed25519/validate.d.ts +7 -0
- package/dist/ed25519/validate.js +77 -0
- package/dist/embedded/aes-pool-worker.d.ts +1 -0
- package/dist/embedded/aes-pool-worker.js +5 -0
- package/dist/embedded/aes.d.ts +1 -0
- package/dist/embedded/aes.js +3 -0
- package/dist/embedded/blake3.d.ts +1 -0
- package/dist/embedded/blake3.js +3 -0
- package/dist/embedded/chacha20-pool-worker.d.ts +1 -0
- package/dist/embedded/chacha20-pool-worker.js +5 -0
- package/dist/embedded/chacha20.d.ts +1 -1
- package/dist/embedded/chacha20.js +2 -2
- package/dist/embedded/curve25519.d.ts +1 -0
- package/dist/embedded/curve25519.js +3 -0
- package/dist/embedded/mldsa.d.ts +1 -0
- package/dist/embedded/mldsa.js +3 -0
- package/dist/embedded/mlkem.d.ts +1 -0
- package/dist/embedded/mlkem.js +3 -0
- package/dist/embedded/p256.d.ts +1 -0
- package/dist/embedded/p256.js +3 -0
- package/dist/embedded/serpent-pool-worker.d.ts +1 -0
- package/dist/embedded/serpent-pool-worker.js +5 -0
- package/dist/embedded/serpent.d.ts +1 -1
- package/dist/embedded/serpent.js +2 -2
- package/dist/embedded/sha2.d.ts +1 -1
- package/dist/embedded/sha2.js +2 -2
- package/dist/embedded/sha3.d.ts +1 -1
- package/dist/embedded/sha3.js +2 -2
- package/dist/embedded/slhdsa.d.ts +1 -0
- package/dist/embedded/slhdsa.js +3 -0
- package/dist/errors.d.ts +92 -1
- package/dist/errors.js +111 -1
- package/dist/fortuna.d.ts +18 -12
- package/dist/fortuna.js +166 -99
- package/dist/index.d.ts +42 -11
- package/dist/index.js +65 -20
- package/dist/init.d.ts +1 -3
- package/dist/init.js +73 -7
- package/dist/keccak/embedded.js +1 -1
- package/dist/keccak/index.d.ts +2 -0
- package/dist/keccak/index.js +4 -2
- package/dist/loader.d.ts +1 -19
- package/dist/loader.js +26 -32
- package/dist/merkle/blake3-tree.d.ts +35 -0
- package/dist/merkle/blake3-tree.js +187 -0
- package/dist/merkle/checkpoint.d.ts +58 -0
- package/dist/merkle/checkpoint.js +217 -0
- package/dist/merkle/index.d.ts +19 -0
- package/dist/merkle/index.js +37 -0
- package/dist/merkle/merkle-log.d.ts +130 -0
- package/dist/merkle/merkle-log.js +207 -0
- package/dist/merkle/merkle-verifier.d.ts +126 -0
- package/dist/merkle/merkle-verifier.js +296 -0
- package/dist/merkle/proof.d.ts +70 -0
- package/dist/merkle/proof.js +300 -0
- package/dist/merkle/sha256-tree.d.ts +33 -0
- package/dist/merkle/sha256-tree.js +145 -0
- package/dist/merkle/signed-log.d.ts +156 -0
- package/dist/merkle/signed-log.js +356 -0
- package/dist/merkle/signed-note.d.ts +309 -0
- package/dist/merkle/signed-note.js +648 -0
- package/dist/merkle/sth.d.ts +31 -0
- package/dist/merkle/sth.js +31 -0
- package/dist/merkle/storage.d.ts +40 -0
- package/dist/merkle/storage.js +71 -0
- package/dist/merkle/tree.d.ts +68 -0
- package/dist/merkle/tree.js +94 -0
- package/dist/mldsa/embedded.d.ts +1 -0
- package/dist/{kyber → mldsa}/embedded.js +5 -5
- package/dist/mldsa/expand.d.ts +53 -0
- package/dist/mldsa/expand.js +188 -0
- package/dist/mldsa/format.d.ts +16 -0
- package/dist/mldsa/format.js +68 -0
- package/dist/mldsa/hashvariant.d.ts +32 -0
- package/dist/mldsa/hashvariant.js +248 -0
- package/dist/mldsa/index.d.ts +142 -0
- package/dist/mldsa/index.js +463 -0
- package/dist/mldsa/keygen.d.ts +16 -0
- package/dist/mldsa/keygen.js +232 -0
- package/dist/mldsa/params.d.ts +21 -0
- package/dist/mldsa/params.js +55 -0
- package/dist/mldsa/sha3-helpers.d.ts +30 -0
- package/dist/mldsa/sha3-helpers.js +124 -0
- package/dist/mldsa/sign.d.ts +36 -0
- package/dist/mldsa/sign.js +380 -0
- package/dist/mldsa/types.d.ts +91 -0
- package/dist/mldsa/types.js +25 -0
- package/dist/mldsa/validate.d.ts +55 -0
- package/dist/mldsa/validate.js +125 -0
- package/dist/mldsa/verify.d.ts +29 -0
- package/dist/mldsa/verify.js +269 -0
- package/dist/mldsa.wasm +0 -0
- package/dist/mlkem/embedded.d.ts +1 -0
- package/dist/mlkem/embedded.js +27 -0
- package/dist/mlkem/indcpa.d.ts +49 -0
- package/dist/{kyber → mlkem}/indcpa.js +48 -48
- package/dist/mlkem/index.d.ts +37 -0
- package/dist/{kyber → mlkem}/index.js +41 -31
- package/dist/mlkem/kem.d.ts +21 -0
- package/dist/{kyber → mlkem}/kem.js +48 -13
- package/dist/{kyber → mlkem}/params.d.ts +4 -4
- package/dist/{kyber → mlkem}/params.js +2 -2
- package/dist/mlkem/suite.d.ts +12 -0
- package/dist/{kyber → mlkem}/suite.js +17 -12
- package/dist/{kyber → mlkem}/types.d.ts +4 -3
- package/dist/{kyber → mlkem}/types.js +1 -1
- package/dist/mlkem/validate.d.ts +23 -0
- package/dist/{kyber → mlkem}/validate.js +24 -20
- package/dist/{kyber.wasm → mlkem.wasm} +0 -0
- package/dist/p256.wasm +0 -0
- package/dist/ratchet/index.d.ts +8 -0
- package/dist/ratchet/index.js +38 -0
- package/dist/ratchet/kdf-chain.d.ts +13 -0
- package/dist/ratchet/kdf-chain.js +85 -0
- package/dist/ratchet/ratchet-keypair.d.ts +9 -0
- package/dist/ratchet/ratchet-keypair.js +61 -0
- package/dist/ratchet/root-kdf.d.ts +4 -0
- package/dist/ratchet/root-kdf.js +124 -0
- package/dist/ratchet/skipped-key-store.d.ts +14 -0
- package/dist/ratchet/skipped-key-store.js +154 -0
- package/dist/ratchet/types.d.ts +36 -0
- package/dist/ratchet/types.js +26 -0
- package/dist/serpent/cipher-suite.d.ts +10 -0
- package/dist/serpent/cipher-suite.js +144 -56
- package/dist/serpent/generator.d.ts +12 -0
- package/dist/serpent/generator.js +97 -0
- package/dist/serpent/index.d.ts +62 -1
- package/dist/serpent/index.js +97 -21
- package/dist/serpent/pool-worker.js +28 -102
- package/dist/serpent/serpent-cbc.d.ts +16 -6
- package/dist/serpent/serpent-cbc.js +58 -37
- package/dist/serpent/shared-ops.d.ts +63 -0
- package/dist/serpent/shared-ops.js +178 -0
- package/dist/serpent/types.d.ts +1 -5
- package/dist/serpent.wasm +0 -0
- package/dist/sha2/hash.d.ts +2 -0
- package/dist/sha2/hash.js +53 -0
- package/dist/sha2/hkdf.js +5 -5
- package/dist/sha2/index.d.ts +22 -1
- package/dist/sha2/index.js +80 -11
- package/dist/sha2/types.d.ts +41 -2
- package/dist/sha2.wasm +0 -0
- package/dist/sha3/hash.d.ts +2 -0
- package/dist/sha3/hash.js +53 -0
- package/dist/sha3/index.d.ts +87 -3
- package/dist/sha3/index.js +317 -19
- package/dist/sha3/kmac.d.ts +121 -0
- package/dist/sha3/kmac.js +800 -0
- package/dist/sha3.wasm +0 -0
- package/dist/shared/pkcs7.d.ts +22 -0
- package/dist/shared/pkcs7.js +84 -0
- package/dist/sign/ctx.d.ts +41 -0
- package/dist/sign/ctx.js +102 -0
- package/dist/sign/envelope.d.ts +45 -0
- package/dist/sign/envelope.js +152 -0
- package/dist/sign/hasher.d.ts +9 -0
- package/dist/sign/hasher.js +132 -0
- package/dist/sign/index.d.ts +11 -0
- package/dist/sign/index.js +34 -0
- package/dist/sign/sign-stream.d.ts +25 -0
- package/dist/sign/sign-stream.js +112 -0
- package/dist/sign/suites/ecdsa-p256.d.ts +2 -0
- package/dist/sign/suites/ecdsa-p256.js +120 -0
- package/dist/sign/suites/ed25519.d.ts +3 -0
- package/dist/sign/suites/ed25519.js +165 -0
- package/dist/sign/suites/hybrid-classical.d.ts +23 -0
- package/dist/sign/suites/hybrid-classical.js +526 -0
- package/dist/sign/suites/hybrid-pq.d.ts +4 -0
- package/dist/sign/suites/hybrid-pq.js +234 -0
- package/dist/sign/suites/mldsa.d.ts +7 -0
- package/dist/sign/suites/mldsa.js +161 -0
- package/dist/sign/suites/slhdsa.d.ts +7 -0
- package/dist/sign/suites/slhdsa.js +176 -0
- package/dist/sign/types.d.ts +106 -0
- package/dist/sign/types.js +28 -0
- package/dist/sign/verify-stream.d.ts +30 -0
- package/dist/sign/verify-stream.js +227 -0
- package/dist/slhdsa/embedded.d.ts +1 -0
- package/dist/slhdsa/embedded.js +26 -0
- package/dist/slhdsa/index.d.ts +149 -0
- package/dist/slhdsa/index.js +493 -0
- package/dist/slhdsa/params.d.ts +26 -0
- package/dist/slhdsa/params.js +70 -0
- package/dist/slhdsa/prehash.d.ts +68 -0
- package/dist/slhdsa/prehash.js +307 -0
- package/dist/slhdsa/sign.d.ts +39 -0
- package/dist/slhdsa/sign.js +116 -0
- package/dist/slhdsa/types.d.ts +129 -0
- package/dist/slhdsa/types.js +27 -0
- package/dist/slhdsa/validate.d.ts +60 -0
- package/dist/slhdsa/validate.js +127 -0
- package/dist/slhdsa/verify.d.ts +32 -0
- package/dist/slhdsa/verify.js +107 -0
- package/dist/slhdsa.wasm +0 -0
- package/dist/stream/header.js +8 -8
- package/dist/stream/index.d.ts +1 -0
- package/dist/stream/index.js +1 -0
- package/dist/stream/open-stream.js +65 -22
- package/dist/stream/seal-stream-pool.d.ts +2 -0
- package/dist/stream/seal-stream-pool.js +100 -33
- package/dist/stream/seal-stream.d.ts +1 -1
- package/dist/stream/seal-stream.js +48 -19
- package/dist/stream/seal.js +6 -6
- package/dist/stream/types.d.ts +3 -1
- package/dist/stream/types.js +1 -1
- package/dist/types.d.ts +22 -1
- package/dist/types.js +1 -1
- package/dist/utils.d.ts +9 -10
- package/dist/utils.js +84 -59
- package/dist/wasm-source.d.ts +9 -8
- package/dist/wasm-source.js +1 -1
- package/dist/x25519/embedded.d.ts +1 -0
- package/dist/x25519/embedded.js +31 -0
- package/dist/x25519/index.d.ts +43 -0
- package/dist/x25519/index.js +159 -0
- package/dist/x25519/types.d.ts +25 -0
- package/dist/x25519/types.js +27 -0
- package/dist/x25519/validate.d.ts +2 -0
- package/dist/x25519/validate.js +39 -0
- package/package.json +123 -64
- package/SECURITY.md +0 -276
- package/dist/ct-wasm.d.ts +0 -1
- package/dist/ct-wasm.js +0 -3
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +0 -323
- package/dist/docs/architecture.md +0 -932
- package/dist/docs/argon2id.md +0 -302
- package/dist/docs/chacha20.md +0 -674
- package/dist/docs/exports.md +0 -241
- package/dist/docs/fortuna.md +0 -313
- package/dist/docs/init.md +0 -302
- package/dist/docs/loader.md +0 -161
- package/dist/docs/serpent.md +0 -519
- package/dist/docs/sha2.md +0 -613
- package/dist/docs/sha3.md +0 -546
- package/dist/docs/types.md +0 -276
- package/dist/docs/utils.md +0 -367
- package/dist/embedded/kyber.d.ts +0 -1
- package/dist/embedded/kyber.js +0 -3
- package/dist/kyber/embedded.d.ts +0 -1
- package/dist/kyber/indcpa.d.ts +0 -49
- package/dist/kyber/index.d.ts +0 -38
- package/dist/kyber/kem.d.ts +0 -21
- package/dist/kyber/suite.d.ts +0 -13
- package/dist/kyber/validate.d.ts +0 -19
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/slhdsa/index.ts
|
|
23
|
+
//
|
|
24
|
+
// SLH-DSA public API, SlhDsa128f / SlhDsa192f / SlhDsa256f classes.
|
|
25
|
+
// FIPS 205, Stateless Hash-Based Digital Signature Standard.
|
|
26
|
+
//
|
|
27
|
+
// Public surface: keygen / sign / verify, plus the HashSLH-DSA family
|
|
28
|
+
// (signHash / verifyHash) and prehashed variants (signHashPrehashed /
|
|
29
|
+
// verifyHashPrehashed). Use init({ slhdsa, ... }) before constructing
|
|
30
|
+
// any class. Pure-mode usage needs only the slhdsa module; HashSLH-DSA
|
|
31
|
+
// with SHA-2 pre-hash adds sha2, with SHA-3 / SHAKE pre-hash adds sha3.
|
|
32
|
+
import { initModule, getInstance, isInitialized, _assertNotOwned } from '../init.js';
|
|
33
|
+
import { randomBytes, wipe } from '../utils.js';
|
|
34
|
+
import { SLHDSA128F, SLHDSA192F, SLHDSA256F } from './params.js';
|
|
35
|
+
import { slhSignInternalTs, signWithPrehash } from './sign.js';
|
|
36
|
+
import { slhVerifyInternalTs, verifyWithPrehash } from './verify.js';
|
|
37
|
+
import { constructMPrimePure } from './prehash.js';
|
|
38
|
+
import { validateContext, validateSigningKey, validateRnd, validateMessage, validateDigest, } from './validate.js';
|
|
39
|
+
import { algoNeedsSha2, algoNeedsSha3, digestSize, preHashMessage, } from './prehash.js';
|
|
40
|
+
export async function slhdsaInit(source) {
|
|
41
|
+
return initModule('slhdsa', source);
|
|
42
|
+
}
|
|
43
|
+
export { SLHDSA128F, SLHDSA192F, SLHDSA256F };
|
|
44
|
+
export { isInitialized };
|
|
45
|
+
/** Return the slhdsa WASM instance exports. Internal helper for tests that
|
|
46
|
+
* need raw access to the ADRS / hash / sponge primitives; consumers use
|
|
47
|
+
* the SlhDsa* classes below. */
|
|
48
|
+
export function getSlhDsaExports() {
|
|
49
|
+
return getInstance('slhdsa').exports;
|
|
50
|
+
}
|
|
51
|
+
// ── Base class ──────────────────────────────────────────────────────────────
|
|
52
|
+
export class SlhDsaBase {
|
|
53
|
+
params;
|
|
54
|
+
constructor(params) {
|
|
55
|
+
if (!isInitialized('slhdsa'))
|
|
56
|
+
throw new Error('leviathan-crypto: call init({ slhdsa: ... }) before using SlhDsa classes');
|
|
57
|
+
this.params = params;
|
|
58
|
+
}
|
|
59
|
+
get x() {
|
|
60
|
+
return getInstance('slhdsa').exports;
|
|
61
|
+
}
|
|
62
|
+
get sx() {
|
|
63
|
+
return getInstance('sha3').exports;
|
|
64
|
+
}
|
|
65
|
+
get sha2x() {
|
|
66
|
+
return getInstance('sha2').exports;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Deterministic key generation, FIPS 205 §9.1 Algorithm 18.
|
|
70
|
+
* @param seed 3n bytes laid out as `SK.seed ‖ SK.prf ‖ PK.seed`. Each
|
|
71
|
+
* component is `n` bytes (16 for 128f, 24 for 192f, 32 for
|
|
72
|
+
* 256f). The slh_keygen_internal entry consumes this layout
|
|
73
|
+
* directly.
|
|
74
|
+
*/
|
|
75
|
+
keygenDerand(seed) {
|
|
76
|
+
_assertNotOwned('slhdsa');
|
|
77
|
+
const n = this.params.n;
|
|
78
|
+
if (!(seed instanceof Uint8Array))
|
|
79
|
+
throw new TypeError('leviathan-crypto: keygen seed must be a Uint8Array');
|
|
80
|
+
if (seed.length !== 3 * n)
|
|
81
|
+
throw new RangeError(`leviathan-crypto: keygen seed must be ${3 * n} bytes (SK.seed||SK.prf||PK.seed) for `
|
|
82
|
+
+ `${this.params.paramSet} (got ${seed.length})`);
|
|
83
|
+
const x = this.x;
|
|
84
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
85
|
+
const inOff = x.getInputOffset();
|
|
86
|
+
const outOff = x.getOutOffset();
|
|
87
|
+
try {
|
|
88
|
+
this.params.wasmSelector();
|
|
89
|
+
mem.set(seed, inOff);
|
|
90
|
+
x.slhKeygenInternal();
|
|
91
|
+
const sk = mem.slice(outOff, outOff + this.params.skBytes);
|
|
92
|
+
const pk = mem.slice(outOff + this.params.skBytes, outOff + this.params.skBytes + this.params.pkBytes);
|
|
93
|
+
return { verificationKey: pk, signingKey: sk };
|
|
94
|
+
}
|
|
95
|
+
finally {
|
|
96
|
+
// INPUT held SK.seed ‖ SK.prf ‖ PK.seed; SK.seed and SK.prf are
|
|
97
|
+
// secret. Wipe the lib's staging copy unconditionally.
|
|
98
|
+
mem.fill(0, inOff, inOff + 3 * n);
|
|
99
|
+
x.wipeBuffers();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Random key generation, wraps `keygenDerand` with `randomBytes(3n)`. */
|
|
103
|
+
keygen() {
|
|
104
|
+
const seed = randomBytes(3 * this.params.n);
|
|
105
|
+
try {
|
|
106
|
+
return this.keygenDerand(seed);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
wipe(seed);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Hedged signing, FIPS 205 §3.4 / §10.2.1 Algorithm 22.
|
|
114
|
+
* Generates a fresh n-byte addrnd (opt_rand) per signature; two
|
|
115
|
+
* signatures over the same (sk, M, ctx) produce different bytes.
|
|
116
|
+
* Hedged signing is recommended over deterministic because hedged
|
|
117
|
+
* signatures remain unforgeable under fault attacks that bias the
|
|
118
|
+
* rejection-sampling stream (FIPS 205 §3.4 / §9.2).
|
|
119
|
+
*/
|
|
120
|
+
sign(sk, M, ctx = new Uint8Array(0)) {
|
|
121
|
+
_assertNotOwned('slhdsa');
|
|
122
|
+
validateSigningKey(sk, this.params);
|
|
123
|
+
validateMessage(M);
|
|
124
|
+
validateContext(ctx);
|
|
125
|
+
const MPrime = constructMPrimePure(M, ctx);
|
|
126
|
+
const optRand = randomBytes(this.params.n);
|
|
127
|
+
try {
|
|
128
|
+
return slhSignInternalTs(this.x, this.params, sk, MPrime, optRand);
|
|
129
|
+
}
|
|
130
|
+
finally {
|
|
131
|
+
wipe(optRand);
|
|
132
|
+
wipe(MPrime);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Deterministic signing, FIPS 205 §3.4. Sets opt_rand ← PK.seed so two
|
|
137
|
+
* signatures over the same (sk, M, ctx) produce identical bytes.
|
|
138
|
+
* Caller accepts the §3.4 caveat: deterministic signatures are
|
|
139
|
+
* vulnerable to fault attacks that bias secret-derived intermediates;
|
|
140
|
+
* use only when no entropy is available or determinism is a hard
|
|
141
|
+
* protocol requirement. PK.seed lives at sk[2n..3n] inside the
|
|
142
|
+
* `SK.seed ‖ SK.prf ‖ PK.seed ‖ PK.root` encoding (FIPS 205 §9.1).
|
|
143
|
+
*/
|
|
144
|
+
signDeterministic(sk, M, ctx = new Uint8Array(0)) {
|
|
145
|
+
_assertNotOwned('slhdsa');
|
|
146
|
+
validateSigningKey(sk, this.params);
|
|
147
|
+
validateMessage(M);
|
|
148
|
+
validateContext(ctx);
|
|
149
|
+
const n = this.params.n;
|
|
150
|
+
// slice() keeps optRand self-contained for WASM INPUT staging.
|
|
151
|
+
const optRand = sk.slice(2 * n, 3 * n);
|
|
152
|
+
const MPrime = constructMPrimePure(M, ctx);
|
|
153
|
+
try {
|
|
154
|
+
return slhSignInternalTs(this.x, this.params, sk, MPrime, optRand);
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
wipe(MPrime);
|
|
158
|
+
// optRand is library scratch; wipe even though contents are sk-derivable.
|
|
159
|
+
wipe(optRand);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Externally-randomised signing, testing / CAVP API. Caller supplies
|
|
164
|
+
* the n-byte opt_rand; library does not mix in additional entropy.
|
|
165
|
+
* Hard contract on the caller: opt_rand MUST come from an approved
|
|
166
|
+
* RBG and MUST NOT be reused across signatures. ACVP SLH-DSA sigGen
|
|
167
|
+
* vectors (with a supplied additionalRandomness) drive this path.
|
|
168
|
+
*/
|
|
169
|
+
signDerand(sk, M, optRand, ctx = new Uint8Array(0)) {
|
|
170
|
+
_assertNotOwned('slhdsa');
|
|
171
|
+
validateSigningKey(sk, this.params);
|
|
172
|
+
validateMessage(M);
|
|
173
|
+
validateContext(ctx);
|
|
174
|
+
validateRnd(optRand, this.params);
|
|
175
|
+
const MPrime = constructMPrimePure(M, ctx);
|
|
176
|
+
try {
|
|
177
|
+
return slhSignInternalTs(this.x, this.params, sk, MPrime, optRand);
|
|
178
|
+
}
|
|
179
|
+
finally {
|
|
180
|
+
wipe(MPrime);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Pure SLH-DSA verify, FIPS 205 §10.3 Algorithm 24 / §9.3 Algorithm 20.
|
|
185
|
+
*
|
|
186
|
+
* Returns boolean. Wrong-length pk / sig return false (FIPS 205 §3.6.2
|
|
187
|
+
* structural mismatch; same posture as ML-DSA verify). Throws
|
|
188
|
+
* `SigningError('sig-ctx-too-long')` only on the caller-side contract
|
|
189
|
+
* violation `ctx.length > 255`.
|
|
190
|
+
*/
|
|
191
|
+
verify(pk, M, sig, ctx = new Uint8Array(0)) {
|
|
192
|
+
_assertNotOwned('slhdsa');
|
|
193
|
+
validateMessage(M);
|
|
194
|
+
// FIPS 205 §3.6.2 / §10.3 Algorithm 24 line 5, wrong-length pk or σ
|
|
195
|
+
// is not a caller bug; it is a structural mismatch that cannot
|
|
196
|
+
// verify. Return false rather than throw.
|
|
197
|
+
if (!(pk instanceof Uint8Array) || pk.length !== this.params.pkBytes)
|
|
198
|
+
return false;
|
|
199
|
+
if (!(sig instanceof Uint8Array) || sig.length !== this.params.sigBytes)
|
|
200
|
+
return false;
|
|
201
|
+
validateContext(ctx);
|
|
202
|
+
const MPrime = constructMPrimePure(M, ctx);
|
|
203
|
+
try {
|
|
204
|
+
return slhVerifyInternalTs(this.x, this.params, pk, MPrime, sig);
|
|
205
|
+
}
|
|
206
|
+
finally {
|
|
207
|
+
wipe(MPrime);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// ── HashSLH-DSA, FIPS 205 §10.2.2 / §10.3 (pre-hash variant) ─────────
|
|
211
|
+
//
|
|
212
|
+
// HashSLH-DSA wraps the same Sign_internal / Verify_internal primitives
|
|
213
|
+
// pure SLH-DSA uses, but pre-hashes M and builds M' with domain-sep
|
|
214
|
+
// byte 0x01 plus the hash function's OID DER bytes; signatures
|
|
215
|
+
// produced by sign / signHash on the same key are NOT interchangeable
|
|
216
|
+
// per FIPS 205 §10.2 narrative.
|
|
217
|
+
//
|
|
218
|
+
// `ph` is the LAST positional parameter on every HashSLH-DSA method
|
|
219
|
+
// (mirrors HashML-DSA's choice). There is no sensible default; callers
|
|
220
|
+
// must select one explicitly.
|
|
221
|
+
//
|
|
222
|
+
// `init({ sha2: ... })` is required only when `ph` is a SHA-2 family
|
|
223
|
+
// algorithm. `init({ sha3: ... })` is required when `ph` is a SHA-3
|
|
224
|
+
// or SHAKE algorithm. Pure-SLH-DSA usage needs neither (slhdsa-wasm
|
|
225
|
+
// has its own embedded Keccak permutation).
|
|
226
|
+
_assertHashPrereqs(ph) {
|
|
227
|
+
// Validate ph before any other dispatch so widened-type callers
|
|
228
|
+
// (e.g. parsing a vector file via `as PreHashAlgorithm`) hit the
|
|
229
|
+
// canonical "unsupported HashSLH-DSA pre-hash" RangeError rather
|
|
230
|
+
// than a downstream sha2-not-initialized error.
|
|
231
|
+
digestSize(ph);
|
|
232
|
+
// FIPS 205 §10.2.2: "SHA-256 and SHAKE128 are only appropriate
|
|
233
|
+
// for use with SLH-DSA parameter sets that are claimed to be in
|
|
234
|
+
// security category 1." Enforce this at the public surface: a
|
|
235
|
+
// category-3 or category-5 key may not be used with SHA-256 or
|
|
236
|
+
// SHAKE128 prehash.
|
|
237
|
+
if ((ph === 'SHA2-256' || ph === 'SHAKE128') && this.params.securityCategory !== 1)
|
|
238
|
+
throw new RangeError(`leviathan-crypto: HashSLH-DSA pre-hash '${ph}' is only appropriate for security category 1 `
|
|
239
|
+
+ `(see FIPS 205 §10.2.2); ${this.params.paramSet} is security category ${this.params.securityCategory}`);
|
|
240
|
+
if (algoNeedsSha2(ph)) {
|
|
241
|
+
if (!isInitialized('sha2'))
|
|
242
|
+
throw new Error('leviathan-crypto: call init({ sha2: ... }) before HashSLH-DSA with SHA-2 pre-hash');
|
|
243
|
+
_assertNotOwned('sha2');
|
|
244
|
+
}
|
|
245
|
+
if (algoNeedsSha3(ph)) {
|
|
246
|
+
if (!isInitialized('sha3'))
|
|
247
|
+
throw new Error('leviathan-crypto: call init({ sha3: ... }) before HashSLH-DSA with SHA-3 / SHAKE pre-hash');
|
|
248
|
+
_assertNotOwned('sha3');
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Hedged HashSLH-DSA sign, FIPS 205 §10.2.2 Algorithm 23.
|
|
253
|
+
*
|
|
254
|
+
* Pre-hashes `M` with the chosen approved function `ph`, builds
|
|
255
|
+
* M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID(ph) ‖ PH_M, then drives
|
|
256
|
+
* slh_sign_internal with a fresh n-byte opt_rand (FIPS 205 §3.4
|
|
257
|
+
* recommended default; see {@link sign} for the rationale).
|
|
258
|
+
*/
|
|
259
|
+
signHash(sk, M, ph, ctx = new Uint8Array(0)) {
|
|
260
|
+
_assertNotOwned('slhdsa');
|
|
261
|
+
this._assertHashPrereqs(ph);
|
|
262
|
+
validateSigningKey(sk, this.params);
|
|
263
|
+
validateMessage(M);
|
|
264
|
+
validateContext(ctx);
|
|
265
|
+
const sha2x = algoNeedsSha2(ph) ? this.sha2x : undefined;
|
|
266
|
+
const sha3x = algoNeedsSha3(ph) ? this.sx : undefined;
|
|
267
|
+
const PH_M = preHashMessage(sha3x, sha2x, ph, M);
|
|
268
|
+
const optRand = randomBytes(this.params.n);
|
|
269
|
+
try {
|
|
270
|
+
return signWithPrehash(this.x, this.params, sk, PH_M, ph, ctx, optRand);
|
|
271
|
+
}
|
|
272
|
+
finally {
|
|
273
|
+
wipe(optRand);
|
|
274
|
+
wipe(PH_M);
|
|
275
|
+
if (sha2x)
|
|
276
|
+
sha2x.wipeBuffers();
|
|
277
|
+
if (sha3x)
|
|
278
|
+
sha3x.wipeBuffers();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Deterministic HashSLH-DSA sign, FIPS 205 §10.2.2 Algorithm 23 with
|
|
283
|
+
* opt_rand ← PK.seed (the deterministic substitute per FIPS 205 §3.4).
|
|
284
|
+
* Same fault-attack caveat as {@link signDeterministic}.
|
|
285
|
+
*/
|
|
286
|
+
signHashDeterministic(sk, M, ph, ctx = new Uint8Array(0)) {
|
|
287
|
+
_assertNotOwned('slhdsa');
|
|
288
|
+
this._assertHashPrereqs(ph);
|
|
289
|
+
validateSigningKey(sk, this.params);
|
|
290
|
+
validateMessage(M);
|
|
291
|
+
validateContext(ctx);
|
|
292
|
+
const n = this.params.n;
|
|
293
|
+
const optRand = sk.slice(2 * n, 3 * n);
|
|
294
|
+
const sha2x = algoNeedsSha2(ph) ? this.sha2x : undefined;
|
|
295
|
+
const sha3x = algoNeedsSha3(ph) ? this.sx : undefined;
|
|
296
|
+
const PH_M = preHashMessage(sha3x, sha2x, ph, M);
|
|
297
|
+
try {
|
|
298
|
+
return signWithPrehash(this.x, this.params, sk, PH_M, ph, ctx, optRand);
|
|
299
|
+
}
|
|
300
|
+
finally {
|
|
301
|
+
wipe(PH_M);
|
|
302
|
+
wipe(optRand);
|
|
303
|
+
if (sha2x)
|
|
304
|
+
sha2x.wipeBuffers();
|
|
305
|
+
if (sha3x)
|
|
306
|
+
sha3x.wipeBuffers();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Externally-randomised HashSLH-DSA sign, testing / CAVP API. Caller
|
|
311
|
+
* supplies the n-byte opt_rand (same contract as {@link signDerand}).
|
|
312
|
+
* Used to oracle ACVP HashSLH-DSA sigGen vectors with byte-identical
|
|
313
|
+
* output.
|
|
314
|
+
*/
|
|
315
|
+
signHashDerand(sk, M, ph, optRand, ctx = new Uint8Array(0)) {
|
|
316
|
+
_assertNotOwned('slhdsa');
|
|
317
|
+
this._assertHashPrereqs(ph);
|
|
318
|
+
validateSigningKey(sk, this.params);
|
|
319
|
+
validateMessage(M);
|
|
320
|
+
validateContext(ctx);
|
|
321
|
+
validateRnd(optRand, this.params);
|
|
322
|
+
const sha2x = algoNeedsSha2(ph) ? this.sha2x : undefined;
|
|
323
|
+
const sha3x = algoNeedsSha3(ph) ? this.sx : undefined;
|
|
324
|
+
const PH_M = preHashMessage(sha3x, sha2x, ph, M);
|
|
325
|
+
try {
|
|
326
|
+
return signWithPrehash(this.x, this.params, sk, PH_M, ph, ctx, optRand);
|
|
327
|
+
}
|
|
328
|
+
finally {
|
|
329
|
+
wipe(PH_M);
|
|
330
|
+
if (sha2x)
|
|
331
|
+
sha2x.wipeBuffers();
|
|
332
|
+
if (sha3x)
|
|
333
|
+
sha3x.wipeBuffers();
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* HashSLH-DSA verify, FIPS 205 §10.3 Algorithm 25.
|
|
338
|
+
*
|
|
339
|
+
* Same return / throw posture as {@link verify}: returns boolean for
|
|
340
|
+
* every signature outcome (including malformed-σ → false), throws
|
|
341
|
+
* `SigningError` only on caller-side contract violations
|
|
342
|
+
* (`ctx.length > 255`) or `RangeError` on category violations and
|
|
343
|
+
* unsupported `ph`.
|
|
344
|
+
*/
|
|
345
|
+
verifyHash(pk, M, sig, ph, ctx = new Uint8Array(0)) {
|
|
346
|
+
_assertNotOwned('slhdsa');
|
|
347
|
+
this._assertHashPrereqs(ph);
|
|
348
|
+
validateMessage(M);
|
|
349
|
+
if (!(pk instanceof Uint8Array) || pk.length !== this.params.pkBytes)
|
|
350
|
+
return false;
|
|
351
|
+
if (!(sig instanceof Uint8Array) || sig.length !== this.params.sigBytes)
|
|
352
|
+
return false;
|
|
353
|
+
validateContext(ctx);
|
|
354
|
+
const sha2x = algoNeedsSha2(ph) ? this.sha2x : undefined;
|
|
355
|
+
const sha3x = algoNeedsSha3(ph) ? this.sx : undefined;
|
|
356
|
+
const PH_M = preHashMessage(sha3x, sha2x, ph, M);
|
|
357
|
+
try {
|
|
358
|
+
return verifyWithPrehash(this.x, this.params, pk, PH_M, sig, ph, ctx);
|
|
359
|
+
}
|
|
360
|
+
finally {
|
|
361
|
+
wipe(PH_M);
|
|
362
|
+
if (sha2x)
|
|
363
|
+
sha2x.wipeBuffers();
|
|
364
|
+
if (sha3x)
|
|
365
|
+
sha3x.wipeBuffers();
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
// ── HashSLH-DSA prehashed variants, FIPS 205 §10.2.2 ──────────────────
|
|
369
|
+
//
|
|
370
|
+
// The "caller already computed PH" surface. signHash family above runs
|
|
371
|
+
// PH ← Hash(M, ph) internally; the prehashed family skips that step
|
|
372
|
+
// and accepts PH directly. Use them when M is not buffered in one
|
|
373
|
+
// place (streaming signers, protocols that already produced a digest
|
|
374
|
+
// as part of a transcript) or when a verifier prescribes a specific
|
|
375
|
+
// prehash and hands you the bytes.
|
|
376
|
+
//
|
|
377
|
+
// Wrong-size digest is a contract violation on the sign side (throws
|
|
378
|
+
// `SigningError('sig-malformed-input')`) and a structural verdict on
|
|
379
|
+
// the verify side (returns false, no throw), mirroring §3.6.2 for
|
|
380
|
+
// wrong-size pk / σ.
|
|
381
|
+
/**
|
|
382
|
+
* Hedged HashSLH-DSA sign with a caller-supplied prehash. FIPS 205
|
|
383
|
+
* §10.2.2 Algorithm 23 lines 18-25 (the post-PH path).
|
|
384
|
+
*
|
|
385
|
+
* `digest` must be exactly `digestSize(ph)` bytes; a mismatch throws
|
|
386
|
+
* `SigningError('sig-malformed-input')`. The caller owns `digest`
|
|
387
|
+
* and is responsible for wiping it; this method never mutates the
|
|
388
|
+
* buffer. Hedged variant generates a fresh n-byte opt_rand per call.
|
|
389
|
+
*/
|
|
390
|
+
signHashPrehashed(sk, digest, ph, ctx = new Uint8Array(0)) {
|
|
391
|
+
_assertNotOwned('slhdsa');
|
|
392
|
+
this._assertHashPrereqs(ph);
|
|
393
|
+
validateSigningKey(sk, this.params);
|
|
394
|
+
validateContext(ctx);
|
|
395
|
+
validateDigest(digest, ph);
|
|
396
|
+
const optRand = randomBytes(this.params.n);
|
|
397
|
+
try {
|
|
398
|
+
return signWithPrehash(this.x, this.params, sk, digest, ph, ctx, optRand);
|
|
399
|
+
}
|
|
400
|
+
finally {
|
|
401
|
+
wipe(optRand);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Deterministic HashSLH-DSA sign with a caller-supplied prehash,
|
|
406
|
+
* opt_rand ← PK.seed per FIPS 205 §3.4. Same fault-attack caveat as
|
|
407
|
+
* {@link signDeterministic}.
|
|
408
|
+
*/
|
|
409
|
+
signHashPrehashedDeterministic(sk, digest, ph, ctx = new Uint8Array(0)) {
|
|
410
|
+
_assertNotOwned('slhdsa');
|
|
411
|
+
this._assertHashPrereqs(ph);
|
|
412
|
+
validateSigningKey(sk, this.params);
|
|
413
|
+
validateContext(ctx);
|
|
414
|
+
validateDigest(digest, ph);
|
|
415
|
+
const n = this.params.n;
|
|
416
|
+
const optRand = sk.slice(2 * n, 3 * n);
|
|
417
|
+
try {
|
|
418
|
+
return signWithPrehash(this.x, this.params, sk, digest, ph, ctx, optRand);
|
|
419
|
+
}
|
|
420
|
+
finally {
|
|
421
|
+
wipe(optRand);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Externally-randomised HashSLH-DSA sign with a caller-supplied
|
|
426
|
+
* prehash, testing / CAVP API. Caller supplies the n-byte opt_rand:
|
|
427
|
+
* MUST come from an approved RBG and MUST NOT be reused across
|
|
428
|
+
* signatures.
|
|
429
|
+
*/
|
|
430
|
+
signHashPrehashedDerand(sk, digest, ph, optRand, ctx = new Uint8Array(0)) {
|
|
431
|
+
_assertNotOwned('slhdsa');
|
|
432
|
+
this._assertHashPrereqs(ph);
|
|
433
|
+
validateSigningKey(sk, this.params);
|
|
434
|
+
validateContext(ctx);
|
|
435
|
+
validateRnd(optRand, this.params);
|
|
436
|
+
validateDigest(digest, ph);
|
|
437
|
+
return signWithPrehash(this.x, this.params, sk, digest, ph, ctx, optRand);
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* HashSLH-DSA verify with a caller-supplied prehash. FIPS 205 §10.3
|
|
441
|
+
* Algorithm 25 lines 16-19 (the post-PH path).
|
|
442
|
+
*
|
|
443
|
+
* Returns boolean for every signature outcome. Wrong-length pk / σ
|
|
444
|
+
* and wrong-size `digest` all return `false` (FIPS 205 §3.6.2 /
|
|
445
|
+
* §10.3 structural mismatch). Throws on caller-side contract
|
|
446
|
+
* violations only (`ctx.length > 255`, unsupported `ph`, category
|
|
447
|
+
* mismatch).
|
|
448
|
+
*/
|
|
449
|
+
verifyHashPrehashed(pk, digest, sig, ph, ctx = new Uint8Array(0)) {
|
|
450
|
+
_assertNotOwned('slhdsa');
|
|
451
|
+
this._assertHashPrereqs(ph);
|
|
452
|
+
if (!(pk instanceof Uint8Array) || pk.length !== this.params.pkBytes)
|
|
453
|
+
return false;
|
|
454
|
+
if (!(sig instanceof Uint8Array) || sig.length !== this.params.sigBytes)
|
|
455
|
+
return false;
|
|
456
|
+
if (!(digest instanceof Uint8Array) || digest.length !== digestSize(ph))
|
|
457
|
+
return false;
|
|
458
|
+
validateContext(ctx);
|
|
459
|
+
return verifyWithPrehash(this.x, this.params, pk, digest, sig, ph, ctx);
|
|
460
|
+
}
|
|
461
|
+
dispose() {
|
|
462
|
+
// SlhDsaBase is atomic-only (no per-instance state beyond the
|
|
463
|
+
// readonly params). Every public method already runs
|
|
464
|
+
// wipeBuffers() in its own finally, so this dispose is just a
|
|
465
|
+
// final hygiene pass for defence-in-depth.
|
|
466
|
+
try {
|
|
467
|
+
this.x.wipeBuffers();
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
// dispose() is idempotent and must not throw even if the
|
|
471
|
+
// module was somehow torn down before the user finished.
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
// ── Public classes ──────────────────────────────────────────────────────────
|
|
476
|
+
/** SLH-DSA-SHAKE-128f, FIPS 205 §11.1 Table 2 (NIST security category 1). */
|
|
477
|
+
export class SlhDsa128f extends SlhDsaBase {
|
|
478
|
+
constructor() {
|
|
479
|
+
super(SLHDSA128F);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/** SLH-DSA-SHAKE-192f, FIPS 205 §11.1 Table 2 (NIST security category 3). */
|
|
483
|
+
export class SlhDsa192f extends SlhDsaBase {
|
|
484
|
+
constructor() {
|
|
485
|
+
super(SLHDSA192F);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
/** SLH-DSA-SHAKE-256f, FIPS 205 §11.1 Table 2 (NIST security category 5). */
|
|
489
|
+
export class SlhDsa256f extends SlhDsaBase {
|
|
490
|
+
constructor() {
|
|
491
|
+
super(SLHDSA256F);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface SlhDsaParams {
|
|
2
|
+
paramSet: 'SLH-DSA-SHAKE-128f' | 'SLH-DSA-SHAKE-192f' | 'SLH-DSA-SHAKE-256f';
|
|
3
|
+
n: number;
|
|
4
|
+
h: number;
|
|
5
|
+
d: number;
|
|
6
|
+
hPrime: number;
|
|
7
|
+
k: number;
|
|
8
|
+
a: number;
|
|
9
|
+
m: number;
|
|
10
|
+
pkBytes: number;
|
|
11
|
+
skBytes: number;
|
|
12
|
+
sigBytes: number;
|
|
13
|
+
securityCategory: 1 | 3 | 5;
|
|
14
|
+
/** Bind this parameter set into the WASM PARAMS slot. Called by every
|
|
15
|
+
* SlhDsaBase public method before driving slh{Keygen,Sign,Verify}Internal
|
|
16
|
+
* so the WASM dimension lookups (slhK, slhA, slhD, slhHPrime, etc.)
|
|
17
|
+
* resolve to this set. Reads the slhdsa exports lazily so the function
|
|
18
|
+
* reference can be shared across modules without baking in an instance. */
|
|
19
|
+
wasmSelector: () => void;
|
|
20
|
+
}
|
|
21
|
+
/** SLH-DSA-SHAKE-128f, FIPS 205 §11.1 Table 2 (NIST security category 1). */
|
|
22
|
+
export declare const SLHDSA128F: SlhDsaParams;
|
|
23
|
+
/** SLH-DSA-SHAKE-192f, FIPS 205 §11.1 Table 2 (NIST security category 3). */
|
|
24
|
+
export declare const SLHDSA192F: SlhDsaParams;
|
|
25
|
+
/** SLH-DSA-SHAKE-256f, FIPS 205 §11.1 Table 2 (NIST security category 5). */
|
|
26
|
+
export declare const SLHDSA256F: SlhDsaParams;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
// ▄▄▄▄▄▄▄▄▄▄
|
|
2
|
+
// ▄████████████████████▄▄ ▒ ▄▀▀ ▒ ▒ █ ▄▀▄ ▀█▀ █ ▒ ▄▀▄ █▀▄
|
|
3
|
+
// ▄██████████████████████ ▀████▄ ▓ ▓▀ ▓ ▓ ▓ ▓▄▓ ▓ ▓▀▓ ▓▄▓ ▓ ▓
|
|
4
|
+
// ▄█████████▀▀▀ ▀███████▄▄███████▌ ▀▄ ▀▄▄ ▀▄▀ ▒ ▒ ▒ ▒ ▒ █ ▒ ▒ ▒ █
|
|
5
|
+
// ▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
6
|
+
// ████████ ███▀▀ ████▀ █▀ █▀ Leviathan Crypto Library
|
|
7
|
+
// ███████▌ ▀██▀ ███
|
|
8
|
+
// ███████ ▀███ ▀██ ▀█▄ Repository & Mirror:
|
|
9
|
+
// ▀██████ ▄▄██ ▀▀ ██▄ github.com/xero/leviathan-crypto
|
|
10
|
+
// ▀█████▄ ▄██▄ ▄▀▄▀ unpkg.com/leviathan-crypto
|
|
11
|
+
// ▀████▄ ▄██▄
|
|
12
|
+
// ▐████ ▐███ Author: xero (https://x-e.ro)
|
|
13
|
+
// ▄▄██████████ ▐███ ▄▄ License: MIT
|
|
14
|
+
// ▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
15
|
+
// ▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███ This file is provided completely
|
|
16
|
+
// ▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀ free, "as is", and without
|
|
17
|
+
// ████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄ warranty of any kind. The author
|
|
18
|
+
// █████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄████ assumes absolutely no liability
|
|
19
|
+
// ▀██████▀ ▀████▄▄▄████▀ for its {ab,mis,}use.
|
|
20
|
+
// ▀█████▀▀
|
|
21
|
+
//
|
|
22
|
+
// src/ts/slhdsa/params.ts
|
|
23
|
+
//
|
|
24
|
+
// SLH-DSA (FIPS 205) parameter sets.
|
|
25
|
+
//
|
|
26
|
+
// Numeric values come from FIPS 205 §11.1 Table 2; derived sizes come from
|
|
27
|
+
// FIPS 205 §11.2 (pk = 2·n, sk = 4·n) and the §9 sigEncode algorithm:
|
|
28
|
+
//
|
|
29
|
+
// sigBytes = (1 + k·(a+1) + h + d·len) · n
|
|
30
|
+
//
|
|
31
|
+
// where w = 16 (the only approved Winternitz parameter in §11.1), so
|
|
32
|
+
// len_1 = ⌈8·n/4⌉, len_2 = 3, len = len_1 + len_2.
|
|
33
|
+
//
|
|
34
|
+
// Current scope is the SHAKE-family fast variants (128f / 192f / 256f) only;
|
|
35
|
+
// the slow variants and the SHA-2 family are explicitly out of scope.
|
|
36
|
+
//
|
|
37
|
+
// `securityCategory` (NIST PQC category 1 / 3 / 5) drives the per-set
|
|
38
|
+
// HashSLH-DSA category gate in `validate.ts` / `index.ts`. `wasmSelector`
|
|
39
|
+
// runs the corresponding `slhSetParams*` thunk on the WASM module so the
|
|
40
|
+
// PARAMS slot reflects this set before any algorithm call.
|
|
41
|
+
import { getInstance } from '../init.js';
|
|
42
|
+
function selectorFor(name) {
|
|
43
|
+
return () => {
|
|
44
|
+
getInstance('slhdsa').exports[name]();
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** SLH-DSA-SHAKE-128f, FIPS 205 §11.1 Table 2 (NIST security category 1). */
|
|
48
|
+
export const SLHDSA128F = {
|
|
49
|
+
paramSet: 'SLH-DSA-SHAKE-128f',
|
|
50
|
+
n: 16, h: 66, d: 22, hPrime: 3, k: 33, a: 6, m: 34,
|
|
51
|
+
pkBytes: 32, skBytes: 64, sigBytes: 17088,
|
|
52
|
+
securityCategory: 1,
|
|
53
|
+
wasmSelector: selectorFor('slhSetParams128f'),
|
|
54
|
+
};
|
|
55
|
+
/** SLH-DSA-SHAKE-192f, FIPS 205 §11.1 Table 2 (NIST security category 3). */
|
|
56
|
+
export const SLHDSA192F = {
|
|
57
|
+
paramSet: 'SLH-DSA-SHAKE-192f',
|
|
58
|
+
n: 24, h: 66, d: 22, hPrime: 3, k: 33, a: 8, m: 42,
|
|
59
|
+
pkBytes: 48, skBytes: 96, sigBytes: 35664,
|
|
60
|
+
securityCategory: 3,
|
|
61
|
+
wasmSelector: selectorFor('slhSetParams192f'),
|
|
62
|
+
};
|
|
63
|
+
/** SLH-DSA-SHAKE-256f, FIPS 205 §11.1 Table 2 (NIST security category 5). */
|
|
64
|
+
export const SLHDSA256F = {
|
|
65
|
+
paramSet: 'SLH-DSA-SHAKE-256f',
|
|
66
|
+
n: 32, h: 68, d: 17, hPrime: 4, k: 35, a: 9, m: 49,
|
|
67
|
+
pkBytes: 64, skBytes: 128, sigBytes: 49856,
|
|
68
|
+
securityCategory: 5,
|
|
69
|
+
wasmSelector: selectorFor('slhSetParams256f'),
|
|
70
|
+
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Sha3Exports } from '../mldsa/types.js';
|
|
2
|
+
import type { Sha2Exports } from '../sha2/types.js';
|
|
3
|
+
/** FIPS 205 §10.2.2 approved pre-hash functions, same surface as FIPS 204
|
|
4
|
+
* §5.4.1. Names follow the FIPS 204 / FIPS 205 spelling (no hyphen
|
|
5
|
+
* between SHAKE and the digit). The SHAKE entries are XOFs with fixed
|
|
6
|
+
* output lengths set by FIPS 205 §10.2.2 Algorithm 23: SHAKE128 → 256-bit
|
|
7
|
+
* (32-byte) output, SHAKE256 → 512-bit (64-byte). */
|
|
8
|
+
export type PreHashAlgorithm = 'SHA2-224' | 'SHA2-256' | 'SHA2-384' | 'SHA2-512' | 'SHA2-512/224' | 'SHA2-512/256' | 'SHA3-224' | 'SHA3-256' | 'SHA3-384' | 'SHA3-512' | 'SHAKE128' | 'SHAKE256';
|
|
9
|
+
/** Look up the FIPS 205 §10.2.2 OID DER bytes for `algo`. Returns a fresh
|
|
10
|
+
* Uint8Array each call so callers can wipe / mutate without aliasing the
|
|
11
|
+
* module-private constant. */
|
|
12
|
+
export declare function getOid(algo: PreHashAlgorithm): Uint8Array;
|
|
13
|
+
/** FIPS 205 §10.2.2 PH_M byte length for `algo`. SHAKE128 / SHAKE256 are
|
|
14
|
+
* XOFs but the spec fixes their HashSLH-DSA output to 32 / 64 bytes
|
|
15
|
+
* respectively; the SHA-3 and SHA-2 entries return their natural digest
|
|
16
|
+
* size. Used by `validateDigest` to bound the caller-supplied prehash.
|
|
17
|
+
*
|
|
18
|
+
* Duplicated from `src/ts/mldsa/hashvariant.ts:digestSize`; extraction
|
|
19
|
+
* is deferred until a third consumer materialises. */
|
|
20
|
+
export declare function digestSize(algo: PreHashAlgorithm): number;
|
|
21
|
+
/** True iff `algo` is one of the SHA-2 family pre-hashes (and therefore
|
|
22
|
+
* requires `init({ sha2: ... })`). The SHA-3 family and SHAKE variants
|
|
23
|
+
* use the `sha3` module. */
|
|
24
|
+
export declare function algoNeedsSha2(algo: PreHashAlgorithm): boolean;
|
|
25
|
+
/** True iff `algo` is a SHA-3 or SHAKE pre-hash (and therefore requires
|
|
26
|
+
* `init({ sha3: ... })`). slhdsa's own embedded Keccak permutation is
|
|
27
|
+
* used internally by `slh_sign_internal` / `slh_verify_internal`, but the
|
|
28
|
+
* HashSLH-DSA prehash dispatcher routes through the `sha3` module to keep
|
|
29
|
+
* the public surface byte-identical with `src/ts/mldsa/hashvariant.ts`
|
|
30
|
+
* (which also uses the sha3 module). */
|
|
31
|
+
export declare function algoNeedsSha3(algo: PreHashAlgorithm): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Build the HashSLH-DSA M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID ‖ PH_M.
|
|
34
|
+
*
|
|
35
|
+
* FIPS 205 §10.2.2 Algorithm 23 lines 18-19 (sign) and §10.3 Algorithm 25
|
|
36
|
+
* lines 16-17 (verify). The leading byte is 0x01 (vs 0x00 for pure
|
|
37
|
+
* SLH-DSA), domain separation across pure / pre-hash modes per FIPS 205
|
|
38
|
+
* §10.2 narrative. Caller has already validated ctx.length ≤ 255.
|
|
39
|
+
*
|
|
40
|
+
* Byte-identical to FIPS 204 §5.4 Algorithm 4 M' construction; see
|
|
41
|
+
* src/ts/mldsa/hashvariant.ts and src/ts/mldsa/format.ts:constructMPrimeHash
|
|
42
|
+
* for the ML-DSA mirror. Q7 resolution: duplicate, do not extract.
|
|
43
|
+
*/
|
|
44
|
+
export declare function constructMPrimeHash(digest: Uint8Array, ph: PreHashAlgorithm, ctx: Uint8Array): Uint8Array;
|
|
45
|
+
/**
|
|
46
|
+
* Build the pure-mode M' = 0x00 ‖ |ctx| ‖ ctx ‖ M for FIPS 205 §10.2.1
|
|
47
|
+
* Algorithm 22 line 8 (sign) and §10.3 Algorithm 24 line 8 (verify).
|
|
48
|
+
*
|
|
49
|
+
* Caller has already validated ctx.length ≤ 255. The leading byte is 0x00,
|
|
50
|
+
* which separates pure SLH-DSA signatures from HashSLH-DSA signatures (the
|
|
51
|
+
* latter prepends 0x01 via constructMPrimeHash) on the same key per the
|
|
52
|
+
* §10.2 narrative.
|
|
53
|
+
*/
|
|
54
|
+
export declare function constructMPrimePure(M: Uint8Array, ctx: Uint8Array): Uint8Array;
|
|
55
|
+
/**
|
|
56
|
+
* Pre-hash dispatcher, applies the FIPS 205 §10.2.2 hash function `algo`
|
|
57
|
+
* to message `M` and returns PH_M (the bytes that go into M' alongside
|
|
58
|
+
* the OID).
|
|
59
|
+
*
|
|
60
|
+
* `sx` is the sha3-wasm Sha3Exports, required for SHA-3 / SHAKE prehashes.
|
|
61
|
+
* `sha2x` is the sha2-wasm Sha2Exports, required for SHA-2 prehashes.
|
|
62
|
+
* Either argument may be `undefined` when the chosen `algo` does not need
|
|
63
|
+
* that module; the dispatcher throws a clear error if a required module
|
|
64
|
+
* is missing rather than NPE'ing on a member access. Pure-SLH-DSA users
|
|
65
|
+
* call neither (slhdsa-wasm has its own embedded Keccak permutation), so
|
|
66
|
+
* both modules are strictly optional.
|
|
67
|
+
*/
|
|
68
|
+
export declare function preHashMessage(sx: Sha3Exports | undefined, sha2x: Sha2Exports | undefined, algo: PreHashAlgorithm, M: Uint8Array): Uint8Array;
|