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,234 @@
|
|
|
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/sign/suites/hybrid-pq.ts
|
|
23
|
+
//
|
|
24
|
+
// MldsaSlhdsaHybridSuite factory (internal). Three exported PQ-only
|
|
25
|
+
// hybrid consts:
|
|
26
|
+
// 0x30 MlDsa44SlhDsa128fSuite (cat-1)
|
|
27
|
+
// 0x31 MlDsa65SlhDsa192fSuite (cat-3)
|
|
28
|
+
// 0x32 MlDsa87SlhDsa256fSuite (cat-5)
|
|
29
|
+
//
|
|
30
|
+
// Wire is leviathan-defined (no composite-sigs entry covers PQ-only
|
|
31
|
+
// pairs); ML-DSA first, no length prefixes (per-hybrid sizes catalog-
|
|
32
|
+
// fixed).
|
|
33
|
+
//
|
|
34
|
+
// Both halves sign the same prehash digest under the same effective_ctx.
|
|
35
|
+
// FIPS 204 §5.4 Alg 4 and FIPS 205 §10.2 Alg 22 produce byte-identical
|
|
36
|
+
// M' = toByte(1,1) || toByte(|ctx|,1) || ctx || OID(ph) || PH_M given a
|
|
37
|
+
// common (digest, ph, ctx); SHAKE128 / SHAKE256 share OIDs across the
|
|
38
|
+
// two specs (FIPS 204 §5.4.1 Table 1 = FIPS 205 §10.2 Table 11).
|
|
39
|
+
//
|
|
40
|
+
// verifyPrehashed ALWAYS runs both sub-verifies before AND-reduce
|
|
41
|
+
// (constant-time gate). Per-hybrid ctxDomain prevents cross-suite and
|
|
42
|
+
// cross-hybrid forgery.
|
|
43
|
+
//
|
|
44
|
+
// Wire layout, M' construction, ctxDomain table, constant-time
|
|
45
|
+
// discipline, and threat model:
|
|
46
|
+
// docs/signaturesuite.md#pq-only-hybrid-composite-encoding.
|
|
47
|
+
import { concat } from '../../utils.js';
|
|
48
|
+
import { wipe, utf8ToBytes } from '../../utils.js';
|
|
49
|
+
import { SigningError } from '../../errors.js';
|
|
50
|
+
import { MlDsa44, MlDsa65, MlDsa87, MLDSA44, MLDSA65, MLDSA87, } from '../../mldsa/index.js';
|
|
51
|
+
import { SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from '../../slhdsa/index.js';
|
|
52
|
+
import { buildEffectiveCtx, CTX_DOMAIN_MAX } from '../ctx.js';
|
|
53
|
+
import { createRunningHash } from '../hasher.js';
|
|
54
|
+
// Lowercase public sign-surface → uppercase ML-DSA-side algorithm name.
|
|
55
|
+
// Mirrors prehashAlgoToMldsa in ctx.ts but only covers the two SHAKE
|
|
56
|
+
// entries actually used by hybrid suites; the hybrid catalog is locked
|
|
57
|
+
// to shake-128 (cat-1) and shake-256 (cat-3 / cat-5).
|
|
58
|
+
function prehashAlgoToMldsaLocal(algo) {
|
|
59
|
+
switch (algo) {
|
|
60
|
+
case 'shake-128': return 'SHAKE128';
|
|
61
|
+
case 'shake-256': return 'SHAKE256';
|
|
62
|
+
case 'sha-256': return 'SHA2-256';
|
|
63
|
+
case 'sha-512': return 'SHA2-512';
|
|
64
|
+
case 'sha3-256': return 'SHA3-256';
|
|
65
|
+
case 'sha3-512': return 'SHA3-512';
|
|
66
|
+
default: {
|
|
67
|
+
const _exhaustive = algo;
|
|
68
|
+
throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function prehashAlgoToSlhdsaLocal(algo) {
|
|
73
|
+
switch (algo) {
|
|
74
|
+
case 'shake-128': return 'SHAKE128';
|
|
75
|
+
case 'shake-256': return 'SHAKE256';
|
|
76
|
+
case 'sha-256': return 'SHA2-256';
|
|
77
|
+
case 'sha-512': return 'SHA2-512';
|
|
78
|
+
case 'sha3-256': return 'SHA3-256';
|
|
79
|
+
case 'sha3-512': return 'SHA3-512';
|
|
80
|
+
default: {
|
|
81
|
+
const _exhaustive = algo;
|
|
82
|
+
throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ── Factory ─────────────────────────────────────────────────────────────────
|
|
87
|
+
function MldsaSlhdsaHybridSuite(MlDsaClass, mldsaParams, SlhDsaClass, slhdsaParams, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
|
|
88
|
+
if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
|
|
89
|
+
throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
|
|
90
|
+
const pkSize = mldsaParams.pkBytes + slhdsaParams.pkBytes;
|
|
91
|
+
const skSize = mldsaParams.skBytes + slhdsaParams.skBytes;
|
|
92
|
+
const sigMaxSize = mldsaParams.sigBytes + slhdsaParams.sigBytes;
|
|
93
|
+
const wasmModules = Object.freeze(['mldsa', 'sha3', 'slhdsa']);
|
|
94
|
+
const mldsaHashAlgo = prehashAlgoToMldsaLocal(prehashAlgorithm);
|
|
95
|
+
const slhdsaHashAlgo = prehashAlgoToSlhdsaLocal(prehashAlgorithm);
|
|
96
|
+
return {
|
|
97
|
+
formatEnum,
|
|
98
|
+
formatName,
|
|
99
|
+
ctxDomain,
|
|
100
|
+
pkSize,
|
|
101
|
+
skSize,
|
|
102
|
+
sigMaxSize,
|
|
103
|
+
wasmModules,
|
|
104
|
+
prehashAlgorithm,
|
|
105
|
+
prehashSize,
|
|
106
|
+
sign(sk, msg, ctx) {
|
|
107
|
+
const h = createRunningHash(prehashAlgorithm);
|
|
108
|
+
try {
|
|
109
|
+
h.update(msg);
|
|
110
|
+
const digest = h.finalize();
|
|
111
|
+
try {
|
|
112
|
+
return this.signPrehashed(sk, digest, ctx);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
wipe(digest);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
h.dispose();
|
|
120
|
+
throw e;
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
verify(pk, msg, sig, ctx) {
|
|
124
|
+
const h = createRunningHash(prehashAlgorithm);
|
|
125
|
+
try {
|
|
126
|
+
h.update(msg);
|
|
127
|
+
const digest = h.finalize();
|
|
128
|
+
try {
|
|
129
|
+
return this.verifyPrehashed(pk, digest, sig, ctx);
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
wipe(digest);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch (e) {
|
|
136
|
+
h.dispose();
|
|
137
|
+
throw e;
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
keygen() {
|
|
141
|
+
const mldsaInst = new MlDsaClass();
|
|
142
|
+
let mldsaKp;
|
|
143
|
+
try {
|
|
144
|
+
mldsaKp = mldsaInst.keygen();
|
|
145
|
+
}
|
|
146
|
+
finally {
|
|
147
|
+
mldsaInst.dispose();
|
|
148
|
+
}
|
|
149
|
+
const slhdsaInst = new SlhDsaClass();
|
|
150
|
+
let slhdsaKp;
|
|
151
|
+
try {
|
|
152
|
+
slhdsaKp = slhdsaInst.keygen();
|
|
153
|
+
}
|
|
154
|
+
finally {
|
|
155
|
+
slhdsaInst.dispose();
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
pk: concat(mldsaKp.verificationKey, slhdsaKp.verificationKey),
|
|
159
|
+
sk: concat(mldsaKp.signingKey, slhdsaKp.signingKey),
|
|
160
|
+
};
|
|
161
|
+
},
|
|
162
|
+
signPrehashed(sk, digest, ctx) {
|
|
163
|
+
if (digest.length !== prehashSize)
|
|
164
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != ${prehashSize} for ${formatName}`);
|
|
165
|
+
if (sk.length !== skSize)
|
|
166
|
+
throw new SigningError('sig-key-size', `sk length ${sk.length} != ${skSize} for ${formatName}`);
|
|
167
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
168
|
+
const skMldsa = sk.subarray(0, mldsaParams.skBytes);
|
|
169
|
+
const skSlhdsa = sk.subarray(mldsaParams.skBytes);
|
|
170
|
+
const mldsaInst = new MlDsaClass();
|
|
171
|
+
let sigMldsa;
|
|
172
|
+
try {
|
|
173
|
+
sigMldsa = mldsaInst.signHashPrehashed(skMldsa, digest, mldsaHashAlgo, effectiveCtx);
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
mldsaInst.dispose();
|
|
177
|
+
}
|
|
178
|
+
const slhdsaInst = new SlhDsaClass();
|
|
179
|
+
let sigSlhdsa;
|
|
180
|
+
try {
|
|
181
|
+
sigSlhdsa = slhdsaInst.signHashPrehashed(skSlhdsa, digest, slhdsaHashAlgo, effectiveCtx);
|
|
182
|
+
}
|
|
183
|
+
finally {
|
|
184
|
+
slhdsaInst.dispose();
|
|
185
|
+
}
|
|
186
|
+
try {
|
|
187
|
+
return concat(sigMldsa, sigSlhdsa);
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
wipe(effectiveCtx);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
verifyPrehashed(pk, digest, sig, ctx) {
|
|
194
|
+
if (pk.length !== pkSize)
|
|
195
|
+
return false;
|
|
196
|
+
if (sig.length !== sigMaxSize)
|
|
197
|
+
return false;
|
|
198
|
+
if (digest.length !== prehashSize)
|
|
199
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != ${prehashSize} for ${formatName}`);
|
|
200
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
201
|
+
const pkMldsa = pk.subarray(0, mldsaParams.pkBytes);
|
|
202
|
+
const pkSlhdsa = pk.subarray(mldsaParams.pkBytes);
|
|
203
|
+
const sigMldsa = sig.subarray(0, mldsaParams.sigBytes);
|
|
204
|
+
const sigSlhdsa = sig.subarray(mldsaParams.sigBytes);
|
|
205
|
+
let mldsaOk;
|
|
206
|
+
let slhdsaOk;
|
|
207
|
+
try {
|
|
208
|
+
const mldsaInst = new MlDsaClass();
|
|
209
|
+
try {
|
|
210
|
+
mldsaOk = mldsaInst.verifyHashPrehashed(pkMldsa, digest, sigMldsa, mldsaHashAlgo, effectiveCtx);
|
|
211
|
+
}
|
|
212
|
+
finally {
|
|
213
|
+
mldsaInst.dispose();
|
|
214
|
+
}
|
|
215
|
+
const slhdsaInst = new SlhDsaClass();
|
|
216
|
+
try {
|
|
217
|
+
slhdsaOk = slhdsaInst.verifyHashPrehashed(pkSlhdsa, digest, sigSlhdsa, slhdsaHashAlgo, effectiveCtx);
|
|
218
|
+
}
|
|
219
|
+
finally {
|
|
220
|
+
slhdsaInst.dispose();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
finally {
|
|
224
|
+
wipe(effectiveCtx);
|
|
225
|
+
}
|
|
226
|
+
// Do NOT wipe sub-sig subarrays; they alias caller-owned `sig`.
|
|
227
|
+
return mldsaOk && slhdsaOk;
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
// ── Exported suite consts ───────────────────────────────────────────────────
|
|
232
|
+
export const MlDsa44SlhDsa128fSuite = MldsaSlhdsaHybridSuite(MlDsa44, MLDSA44, SlhDsa128f, SLHDSA128F, 0x30, 'mldsa44-slhdsa128f', 'mldsa44-slhdsa128f-envelope-v3', 'shake-128', 32);
|
|
233
|
+
export const MlDsa65SlhDsa192fSuite = MldsaSlhdsaHybridSuite(MlDsa65, MLDSA65, SlhDsa192f, SLHDSA192F, 0x31, 'mldsa65-slhdsa192f', 'mldsa65-slhdsa192f-envelope-v3', 'shake-256', 64);
|
|
234
|
+
export const MlDsa87SlhDsa256fSuite = MldsaSlhdsaHybridSuite(MlDsa87, MLDSA87, SlhDsa256f, SLHDSA256F, 0x32, 'mldsa87-slhdsa256f', 'mldsa87-slhdsa256f-envelope-v3', 'shake-256', 64);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SignatureSuite, StreamableSignatureSuite } from '../types.js';
|
|
2
|
+
export declare const MlDsa44Suite: SignatureSuite;
|
|
3
|
+
export declare const MlDsa65Suite: SignatureSuite;
|
|
4
|
+
export declare const MlDsa87Suite: SignatureSuite;
|
|
5
|
+
export declare const MlDsa44PreHashSuite: StreamableSignatureSuite;
|
|
6
|
+
export declare const MlDsa65PreHashSuite: StreamableSignatureSuite;
|
|
7
|
+
export declare const MlDsa87PreHashSuite: StreamableSignatureSuite;
|
|
@@ -0,0 +1,161 @@
|
|
|
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/sign/suites/mldsa.ts
|
|
23
|
+
//
|
|
24
|
+
// Pure (0x03/0x04/0x05) and prehash (0x13/0x14/0x15) ML-DSA suites,
|
|
25
|
+
// FIPS 204.
|
|
26
|
+
//
|
|
27
|
+
// Catalog + prehash mapping: docs/signaturesuite.md, docs/mldsa.md.
|
|
28
|
+
import { utf8ToBytes, wipe } from '../../utils.js';
|
|
29
|
+
import { SigningError } from '../../errors.js';
|
|
30
|
+
import { MlDsa44, MlDsa65, MlDsa87, MLDSA44, MLDSA65, MLDSA87, } from '../../mldsa/index.js';
|
|
31
|
+
import { buildEffectiveCtx, prehashAlgoToMldsa, CTX_DOMAIN_MAX, } from '../ctx.js';
|
|
32
|
+
// ── Pure-mode factory ───────────────────────────────────────────────────────
|
|
33
|
+
function MldsaPureSuite(MlDsaClass, params, formatEnum, formatName, ctxDomain) {
|
|
34
|
+
if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
|
|
35
|
+
throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
|
|
36
|
+
const wasmModules = Object.freeze(['mldsa', 'sha3']);
|
|
37
|
+
return {
|
|
38
|
+
formatEnum,
|
|
39
|
+
formatName,
|
|
40
|
+
ctxDomain,
|
|
41
|
+
pkSize: params.pkBytes,
|
|
42
|
+
skSize: params.skBytes,
|
|
43
|
+
sigMaxSize: params.sigBytes,
|
|
44
|
+
wasmModules,
|
|
45
|
+
sign(sk, msg, ctx) {
|
|
46
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
47
|
+
const inst = new MlDsaClass();
|
|
48
|
+
try {
|
|
49
|
+
return inst.sign(sk, msg, effectiveCtx);
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
inst.dispose();
|
|
53
|
+
wipe(effectiveCtx);
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
verify(pk, msg, sig, ctx) {
|
|
57
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
58
|
+
const inst = new MlDsaClass();
|
|
59
|
+
try {
|
|
60
|
+
return inst.verify(pk, msg, sig, effectiveCtx);
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
inst.dispose();
|
|
64
|
+
wipe(effectiveCtx);
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
keygen() {
|
|
68
|
+
const inst = new MlDsaClass();
|
|
69
|
+
try {
|
|
70
|
+
const kp = inst.keygen();
|
|
71
|
+
return { pk: kp.verificationKey, sk: kp.signingKey };
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
inst.dispose();
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// ── Prehash-mode factory ────────────────────────────────────────────────────
|
|
80
|
+
function MldsaPrehashSuite(MlDsaClass, params, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
|
|
81
|
+
if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
|
|
82
|
+
throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
|
|
83
|
+
const wasmModules = Object.freeze(['mldsa', 'sha3']);
|
|
84
|
+
const mldsaHashAlgo = prehashAlgoToMldsa(prehashAlgorithm);
|
|
85
|
+
return {
|
|
86
|
+
formatEnum,
|
|
87
|
+
formatName,
|
|
88
|
+
ctxDomain,
|
|
89
|
+
pkSize: params.pkBytes,
|
|
90
|
+
skSize: params.skBytes,
|
|
91
|
+
sigMaxSize: params.sigBytes,
|
|
92
|
+
wasmModules,
|
|
93
|
+
prehashAlgorithm,
|
|
94
|
+
prehashSize,
|
|
95
|
+
sign(sk, msg, ctx) {
|
|
96
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
97
|
+
const inst = new MlDsaClass();
|
|
98
|
+
try {
|
|
99
|
+
return inst.signHash(sk, msg, mldsaHashAlgo, effectiveCtx);
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
inst.dispose();
|
|
103
|
+
wipe(effectiveCtx);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
verify(pk, msg, sig, ctx) {
|
|
107
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
108
|
+
const inst = new MlDsaClass();
|
|
109
|
+
try {
|
|
110
|
+
return inst.verifyHash(pk, msg, sig, mldsaHashAlgo, effectiveCtx);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
inst.dispose();
|
|
114
|
+
wipe(effectiveCtx);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
keygen() {
|
|
118
|
+
const inst = new MlDsaClass();
|
|
119
|
+
try {
|
|
120
|
+
const kp = inst.keygen();
|
|
121
|
+
return { pk: kp.verificationKey, sk: kp.signingKey };
|
|
122
|
+
}
|
|
123
|
+
finally {
|
|
124
|
+
inst.dispose();
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
signPrehashed(sk, digest, ctx) {
|
|
128
|
+
if (digest.length !== prehashSize)
|
|
129
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
|
|
130
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
131
|
+
const inst = new MlDsaClass();
|
|
132
|
+
try {
|
|
133
|
+
return inst.signHashPrehashed(sk, digest, mldsaHashAlgo, effectiveCtx);
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
inst.dispose();
|
|
137
|
+
wipe(effectiveCtx);
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
verifyPrehashed(pk, digest, sig, ctx) {
|
|
141
|
+
if (digest.length !== prehashSize)
|
|
142
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
|
|
143
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
144
|
+
const inst = new MlDsaClass();
|
|
145
|
+
try {
|
|
146
|
+
return inst.verifyHashPrehashed(pk, digest, sig, mldsaHashAlgo, effectiveCtx);
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
inst.dispose();
|
|
150
|
+
wipe(effectiveCtx);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// ── Exported suite consts ───────────────────────────────────────────────────
|
|
156
|
+
export const MlDsa44Suite = MldsaPureSuite(MlDsa44, MLDSA44, 0x03, 'mldsa44', 'mldsa44-envelope-v3');
|
|
157
|
+
export const MlDsa65Suite = MldsaPureSuite(MlDsa65, MLDSA65, 0x04, 'mldsa65', 'mldsa65-envelope-v3');
|
|
158
|
+
export const MlDsa87Suite = MldsaPureSuite(MlDsa87, MLDSA87, 0x05, 'mldsa87', 'mldsa87-envelope-v3');
|
|
159
|
+
export const MlDsa44PreHashSuite = MldsaPrehashSuite(MlDsa44, MLDSA44, 0x13, 'mldsa44-prehash', 'mldsa44-prehash-envelope-v3', 'sha3-256', 32);
|
|
160
|
+
export const MlDsa65PreHashSuite = MldsaPrehashSuite(MlDsa65, MLDSA65, 0x14, 'mldsa65-prehash', 'mldsa65-prehash-envelope-v3', 'sha3-256', 32);
|
|
161
|
+
export const MlDsa87PreHashSuite = MldsaPrehashSuite(MlDsa87, MLDSA87, 0x15, 'mldsa87-prehash', 'mldsa87-prehash-envelope-v3', 'sha3-512', 64);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SignatureSuite, StreamableSignatureSuite } from '../types.js';
|
|
2
|
+
export declare const SlhDsa128fSuite: SignatureSuite;
|
|
3
|
+
export declare const SlhDsa192fSuite: SignatureSuite;
|
|
4
|
+
export declare const SlhDsa256fSuite: SignatureSuite;
|
|
5
|
+
export declare const SlhDsa128fPreHashSuite: StreamableSignatureSuite;
|
|
6
|
+
export declare const SlhDsa192fPreHashSuite: StreamableSignatureSuite;
|
|
7
|
+
export declare const SlhDsa256fPreHashSuite: StreamableSignatureSuite;
|
|
@@ -0,0 +1,176 @@
|
|
|
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/sign/suites/slhdsa.ts
|
|
23
|
+
//
|
|
24
|
+
// Pure (0x06/0x07/0x08) and prehash (0x16/0x17/0x18) SLH-DSA SHAKE-family
|
|
25
|
+
// fast suites, FIPS 205. Hash pinning per §10.2.2: 128f→SHAKE128 cat 1,
|
|
26
|
+
// 192f→SHAKE256 cat 3, 256f→SHAKE256 cat 5.
|
|
27
|
+
//
|
|
28
|
+
// Catalog + prehash mapping: docs/signaturesuite.md, docs/slhdsa.md.
|
|
29
|
+
import { utf8ToBytes, wipe } from '../../utils.js';
|
|
30
|
+
import { SigningError } from '../../errors.js';
|
|
31
|
+
import { SlhDsa128f, SlhDsa192f, SlhDsa256f, SLHDSA128F, SLHDSA192F, SLHDSA256F, } from '../../slhdsa/index.js';
|
|
32
|
+
import { buildEffectiveCtx, CTX_DOMAIN_MAX } from '../ctx.js';
|
|
33
|
+
function prehashAlgoToSlhdsa(algo) {
|
|
34
|
+
switch (algo) {
|
|
35
|
+
case 'shake-128': return 'SHAKE128';
|
|
36
|
+
case 'shake-256': return 'SHAKE256';
|
|
37
|
+
case 'sha-256': return 'SHA2-256';
|
|
38
|
+
case 'sha-512': return 'SHA2-512';
|
|
39
|
+
case 'sha3-256': return 'SHA3-256';
|
|
40
|
+
case 'sha3-512': return 'SHA3-512';
|
|
41
|
+
default: {
|
|
42
|
+
const _exhaustive = algo;
|
|
43
|
+
throw new Error(`leviathan-crypto: unknown prehash algorithm ${_exhaustive}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// ── Pure-mode factory ───────────────────────────────────────────────────────
|
|
48
|
+
function SlhdsaPureSuite(SlhDsaClass, params, formatEnum, formatName, ctxDomain) {
|
|
49
|
+
if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
|
|
50
|
+
throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
|
|
51
|
+
const wasmModules = Object.freeze(['slhdsa']);
|
|
52
|
+
return {
|
|
53
|
+
formatEnum,
|
|
54
|
+
formatName,
|
|
55
|
+
ctxDomain,
|
|
56
|
+
pkSize: params.pkBytes,
|
|
57
|
+
skSize: params.skBytes,
|
|
58
|
+
sigMaxSize: params.sigBytes,
|
|
59
|
+
wasmModules,
|
|
60
|
+
sign(sk, msg, ctx) {
|
|
61
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
62
|
+
const inst = new SlhDsaClass();
|
|
63
|
+
try {
|
|
64
|
+
return inst.sign(sk, msg, effectiveCtx);
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
inst.dispose();
|
|
68
|
+
wipe(effectiveCtx);
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
verify(pk, msg, sig, ctx) {
|
|
72
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
73
|
+
const inst = new SlhDsaClass();
|
|
74
|
+
try {
|
|
75
|
+
return inst.verify(pk, msg, sig, effectiveCtx);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
inst.dispose();
|
|
79
|
+
wipe(effectiveCtx);
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
keygen() {
|
|
83
|
+
const inst = new SlhDsaClass();
|
|
84
|
+
try {
|
|
85
|
+
const kp = inst.keygen();
|
|
86
|
+
return { pk: kp.verificationKey, sk: kp.signingKey };
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
inst.dispose();
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ── Prehash-mode factory ────────────────────────────────────────────────────
|
|
95
|
+
function SlhdsaPrehashSuite(SlhDsaClass, params, formatEnum, formatName, ctxDomain, prehashAlgorithm, prehashSize) {
|
|
96
|
+
if (utf8ToBytes(ctxDomain).length > CTX_DOMAIN_MAX)
|
|
97
|
+
throw new Error(`leviathan-crypto: ctxDomain '${ctxDomain}' too long for ${formatName}`);
|
|
98
|
+
const wasmModules = Object.freeze(['slhdsa', 'sha3']);
|
|
99
|
+
const slhHashAlgo = prehashAlgoToSlhdsa(prehashAlgorithm);
|
|
100
|
+
return {
|
|
101
|
+
formatEnum,
|
|
102
|
+
formatName,
|
|
103
|
+
ctxDomain,
|
|
104
|
+
pkSize: params.pkBytes,
|
|
105
|
+
skSize: params.skBytes,
|
|
106
|
+
sigMaxSize: params.sigBytes,
|
|
107
|
+
wasmModules,
|
|
108
|
+
prehashAlgorithm,
|
|
109
|
+
prehashSize,
|
|
110
|
+
sign(sk, msg, ctx) {
|
|
111
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
112
|
+
const inst = new SlhDsaClass();
|
|
113
|
+
try {
|
|
114
|
+
return inst.signHash(sk, msg, slhHashAlgo, effectiveCtx);
|
|
115
|
+
}
|
|
116
|
+
finally {
|
|
117
|
+
inst.dispose();
|
|
118
|
+
wipe(effectiveCtx);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
verify(pk, msg, sig, ctx) {
|
|
122
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
123
|
+
const inst = new SlhDsaClass();
|
|
124
|
+
try {
|
|
125
|
+
return inst.verifyHash(pk, msg, sig, slhHashAlgo, effectiveCtx);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
inst.dispose();
|
|
129
|
+
wipe(effectiveCtx);
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
keygen() {
|
|
133
|
+
const inst = new SlhDsaClass();
|
|
134
|
+
try {
|
|
135
|
+
const kp = inst.keygen();
|
|
136
|
+
return { pk: kp.verificationKey, sk: kp.signingKey };
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
inst.dispose();
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
signPrehashed(sk, digest, ctx) {
|
|
143
|
+
if (digest.length !== prehashSize)
|
|
144
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
|
|
145
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
146
|
+
const inst = new SlhDsaClass();
|
|
147
|
+
try {
|
|
148
|
+
return inst.signHashPrehashed(sk, digest, slhHashAlgo, effectiveCtx);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
inst.dispose();
|
|
152
|
+
wipe(effectiveCtx);
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
verifyPrehashed(pk, digest, sig, ctx) {
|
|
156
|
+
if (digest.length !== prehashSize)
|
|
157
|
+
throw new SigningError('sig-malformed-input', `digest length ${digest.length} != expected ${prehashSize} for ${formatName}`);
|
|
158
|
+
const effectiveCtx = buildEffectiveCtx(ctxDomain, ctx);
|
|
159
|
+
const inst = new SlhDsaClass();
|
|
160
|
+
try {
|
|
161
|
+
return inst.verifyHashPrehashed(pk, digest, sig, slhHashAlgo, effectiveCtx);
|
|
162
|
+
}
|
|
163
|
+
finally {
|
|
164
|
+
inst.dispose();
|
|
165
|
+
wipe(effectiveCtx);
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// ── Exported suite consts ───────────────────────────────────────────────────
|
|
171
|
+
export const SlhDsa128fSuite = SlhdsaPureSuite(SlhDsa128f, SLHDSA128F, 0x06, 'slhdsa128f', 'slhdsa128f-envelope-v3');
|
|
172
|
+
export const SlhDsa192fSuite = SlhdsaPureSuite(SlhDsa192f, SLHDSA192F, 0x07, 'slhdsa192f', 'slhdsa192f-envelope-v3');
|
|
173
|
+
export const SlhDsa256fSuite = SlhdsaPureSuite(SlhDsa256f, SLHDSA256F, 0x08, 'slhdsa256f', 'slhdsa256f-envelope-v3');
|
|
174
|
+
export const SlhDsa128fPreHashSuite = SlhdsaPrehashSuite(SlhDsa128f, SLHDSA128F, 0x16, 'slhdsa128f-prehash', 'slhdsa128f-prehash-envelope-v3', 'shake-128', 32);
|
|
175
|
+
export const SlhDsa192fPreHashSuite = SlhdsaPrehashSuite(SlhDsa192f, SLHDSA192F, 0x17, 'slhdsa192f-prehash', 'slhdsa192f-prehash-envelope-v3', 'shake-256', 64);
|
|
176
|
+
export const SlhDsa256fPreHashSuite = SlhdsaPrehashSuite(SlhDsa256f, SLHDSA256F, 0x18, 'slhdsa256f-prehash', 'slhdsa256f-prehash-envelope-v3', 'shake-256', 64);
|