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,307 @@
|
|
|
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/prehash.ts
|
|
23
|
+
//
|
|
24
|
+
// HashSLH-DSA pre-hash dispatcher and OID DER table.
|
|
25
|
+
// FIPS 205 §10.2.2 Algorithm 23 (HashSLH-DSA-Sign) and Algorithm 25
|
|
26
|
+
// (HashSLH-DSA-Verify) build M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID ‖ PH_M, where
|
|
27
|
+
// • PH_M = H_PH(M) for the caller-selected approved pre-hash function PH
|
|
28
|
+
// • OID = the DER encoding of PH's NIST CSOR object identifier
|
|
29
|
+
//
|
|
30
|
+
// The M' construction is BYTE-IDENTICAL to FIPS 204 §5.4 HashML-DSA's M'.
|
|
31
|
+
// `src/ts/mldsa/hashvariant.ts:constructMPrimeHash` already implements
|
|
32
|
+
// this byte layout; the duplication is intentional and extraction is
|
|
33
|
+
// deferred until a third consumer materialises.
|
|
34
|
+
//
|
|
35
|
+
// All OIDs share the 10-byte DER prefix `06 09 60 86 48 01 65 03 04 02`
|
|
36
|
+
// (joint-iso-itu-t.country(2).us(16).organization(840).gov(1).csor(101)
|
|
37
|
+
// .nistalgorithm(3).hashalgs(4).hashalg(2)) and are distinguished by the
|
|
38
|
+
// trailing arc byte. Spec authority: FIPS 205 §10.2.2 Algorithm 23 lines
|
|
39
|
+
// 10, 13, 16, 19 enumerate SHA-256 (.01), SHA-512 (.03), SHAKE128 (.0B),
|
|
40
|
+
// SHAKE256 (.0C) by example; the remaining eight arcs are the NIST CSOR
|
|
41
|
+
// registrations on the same 2.16.840.1.101.3.4.2.x branch and must match
|
|
42
|
+
// the verifying-party expectation byte-for-byte.
|
|
43
|
+
import { sha3Absorb } from '../mldsa/sha3-helpers.js';
|
|
44
|
+
// ── OID DER table, FIPS 205 §10.2.2 ────────────────────────────────────────
|
|
45
|
+
// Shared 10-byte DER prefix: tag 0x06 (OBJECT IDENTIFIER), length 0x09,
|
|
46
|
+
// then the encoded ancestor arcs 2.16.840.1.101.3.4.2. The trailing byte
|
|
47
|
+
// is the per-algorithm arc.
|
|
48
|
+
const DER_PREFIX = Object.freeze([0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02]);
|
|
49
|
+
function oid(arc) {
|
|
50
|
+
const out = new Uint8Array(11);
|
|
51
|
+
for (let i = 0; i < 10; i++)
|
|
52
|
+
out[i] = DER_PREFIX[i];
|
|
53
|
+
out[10] = arc & 0xFF;
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
// id-sha224, 2.16.840.1.101.3.4.2.4
|
|
57
|
+
const OID_SHA2_224 = oid(0x04);
|
|
58
|
+
// id-sha256, 2.16.840.1.101.3.4.2.1 (FIPS 205 §10.2.2 Algorithm 23 line 10)
|
|
59
|
+
const OID_SHA2_256 = oid(0x01);
|
|
60
|
+
// id-sha384, 2.16.840.1.101.3.4.2.2
|
|
61
|
+
const OID_SHA2_384 = oid(0x02);
|
|
62
|
+
// id-sha512, 2.16.840.1.101.3.4.2.3 (FIPS 205 §10.2.2 Algorithm 23 line 13)
|
|
63
|
+
const OID_SHA2_512 = oid(0x03);
|
|
64
|
+
// id-sha512-224, 2.16.840.1.101.3.4.2.5
|
|
65
|
+
const OID_SHA2_512_224 = oid(0x05);
|
|
66
|
+
// id-sha512-256, 2.16.840.1.101.3.4.2.6
|
|
67
|
+
const OID_SHA2_512_256 = oid(0x06);
|
|
68
|
+
// id-sha3-224, 2.16.840.1.101.3.4.2.7
|
|
69
|
+
const OID_SHA3_224 = oid(0x07);
|
|
70
|
+
// id-sha3-256, 2.16.840.1.101.3.4.2.8
|
|
71
|
+
const OID_SHA3_256 = oid(0x08);
|
|
72
|
+
// id-sha3-384, 2.16.840.1.101.3.4.2.9
|
|
73
|
+
const OID_SHA3_384 = oid(0x09);
|
|
74
|
+
// id-sha3-512, 2.16.840.1.101.3.4.2.10
|
|
75
|
+
const OID_SHA3_512 = oid(0x0A);
|
|
76
|
+
// id-shake128, 2.16.840.1.101.3.4.2.11 (FIPS 205 §10.2.2 Algorithm 23 line 16)
|
|
77
|
+
const OID_SHAKE128 = oid(0x0B);
|
|
78
|
+
// id-shake256, 2.16.840.1.101.3.4.2.12 (FIPS 205 §10.2.2 Algorithm 23 line 19)
|
|
79
|
+
const OID_SHAKE256 = oid(0x0C);
|
|
80
|
+
const OID_TABLE = Object.freeze({
|
|
81
|
+
'SHA2-224': OID_SHA2_224,
|
|
82
|
+
'SHA2-256': OID_SHA2_256,
|
|
83
|
+
'SHA2-384': OID_SHA2_384,
|
|
84
|
+
'SHA2-512': OID_SHA2_512,
|
|
85
|
+
'SHA2-512/224': OID_SHA2_512_224,
|
|
86
|
+
'SHA2-512/256': OID_SHA2_512_256,
|
|
87
|
+
'SHA3-224': OID_SHA3_224,
|
|
88
|
+
'SHA3-256': OID_SHA3_256,
|
|
89
|
+
'SHA3-384': OID_SHA3_384,
|
|
90
|
+
'SHA3-512': OID_SHA3_512,
|
|
91
|
+
'SHAKE128': OID_SHAKE128,
|
|
92
|
+
'SHAKE256': OID_SHAKE256,
|
|
93
|
+
});
|
|
94
|
+
/** Look up the FIPS 205 §10.2.2 OID DER bytes for `algo`. Returns a fresh
|
|
95
|
+
* Uint8Array each call so callers can wipe / mutate without aliasing the
|
|
96
|
+
* module-private constant. */
|
|
97
|
+
export function getOid(algo) {
|
|
98
|
+
const tab = OID_TABLE[algo];
|
|
99
|
+
if (!tab)
|
|
100
|
+
throw new RangeError(`leviathan-crypto: unsupported HashSLH-DSA pre-hash algorithm '${algo}'`);
|
|
101
|
+
return tab.slice();
|
|
102
|
+
}
|
|
103
|
+
/** FIPS 205 §10.2.2 PH_M byte length for `algo`. SHAKE128 / SHAKE256 are
|
|
104
|
+
* XOFs but the spec fixes their HashSLH-DSA output to 32 / 64 bytes
|
|
105
|
+
* respectively; the SHA-3 and SHA-2 entries return their natural digest
|
|
106
|
+
* size. Used by `validateDigest` to bound the caller-supplied prehash.
|
|
107
|
+
*
|
|
108
|
+
* Duplicated from `src/ts/mldsa/hashvariant.ts:digestSize`; extraction
|
|
109
|
+
* is deferred until a third consumer materialises. */
|
|
110
|
+
export function digestSize(algo) {
|
|
111
|
+
switch (algo) {
|
|
112
|
+
case 'SHA2-224': return 28;
|
|
113
|
+
case 'SHA2-256': return 32;
|
|
114
|
+
case 'SHA2-384': return 48;
|
|
115
|
+
case 'SHA2-512': return 64;
|
|
116
|
+
case 'SHA2-512/224': return 28;
|
|
117
|
+
case 'SHA2-512/256': return 32;
|
|
118
|
+
case 'SHA3-224': return 28;
|
|
119
|
+
case 'SHA3-256': return 32;
|
|
120
|
+
case 'SHA3-384': return 48;
|
|
121
|
+
case 'SHA3-512': return 64;
|
|
122
|
+
case 'SHAKE128': return 32;
|
|
123
|
+
case 'SHAKE256': return 64;
|
|
124
|
+
default: {
|
|
125
|
+
const exhaustive = algo;
|
|
126
|
+
throw new RangeError(`leviathan-crypto: unsupported HashSLH-DSA pre-hash algorithm '${exhaustive}'`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/** True iff `algo` is one of the SHA-2 family pre-hashes (and therefore
|
|
131
|
+
* requires `init({ sha2: ... })`). The SHA-3 family and SHAKE variants
|
|
132
|
+
* use the `sha3` module. */
|
|
133
|
+
export function algoNeedsSha2(algo) {
|
|
134
|
+
switch (algo) {
|
|
135
|
+
case 'SHA2-224':
|
|
136
|
+
case 'SHA2-256':
|
|
137
|
+
case 'SHA2-384':
|
|
138
|
+
case 'SHA2-512':
|
|
139
|
+
case 'SHA2-512/224':
|
|
140
|
+
case 'SHA2-512/256':
|
|
141
|
+
return true;
|
|
142
|
+
default:
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
/** True iff `algo` is a SHA-3 or SHAKE pre-hash (and therefore requires
|
|
147
|
+
* `init({ sha3: ... })`). slhdsa's own embedded Keccak permutation is
|
|
148
|
+
* used internally by `slh_sign_internal` / `slh_verify_internal`, but the
|
|
149
|
+
* HashSLH-DSA prehash dispatcher routes through the `sha3` module to keep
|
|
150
|
+
* the public surface byte-identical with `src/ts/mldsa/hashvariant.ts`
|
|
151
|
+
* (which also uses the sha3 module). */
|
|
152
|
+
export function algoNeedsSha3(algo) {
|
|
153
|
+
switch (algo) {
|
|
154
|
+
case 'SHA3-224':
|
|
155
|
+
case 'SHA3-256':
|
|
156
|
+
case 'SHA3-384':
|
|
157
|
+
case 'SHA3-512':
|
|
158
|
+
case 'SHAKE128':
|
|
159
|
+
case 'SHAKE256':
|
|
160
|
+
return true;
|
|
161
|
+
default:
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// ── M' construction (FIPS 205 §10.2.2) ─────────────────────────────────────
|
|
166
|
+
/**
|
|
167
|
+
* Build the HashSLH-DSA M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID ‖ PH_M.
|
|
168
|
+
*
|
|
169
|
+
* FIPS 205 §10.2.2 Algorithm 23 lines 18-19 (sign) and §10.3 Algorithm 25
|
|
170
|
+
* lines 16-17 (verify). The leading byte is 0x01 (vs 0x00 for pure
|
|
171
|
+
* SLH-DSA), domain separation across pure / pre-hash modes per FIPS 205
|
|
172
|
+
* §10.2 narrative. Caller has already validated ctx.length ≤ 255.
|
|
173
|
+
*
|
|
174
|
+
* Byte-identical to FIPS 204 §5.4 Algorithm 4 M' construction; see
|
|
175
|
+
* src/ts/mldsa/hashvariant.ts and src/ts/mldsa/format.ts:constructMPrimeHash
|
|
176
|
+
* for the ML-DSA mirror. Q7 resolution: duplicate, do not extract.
|
|
177
|
+
*/
|
|
178
|
+
export function constructMPrimeHash(digest, ph, ctx) {
|
|
179
|
+
const o = OID_TABLE[ph];
|
|
180
|
+
if (!o)
|
|
181
|
+
throw new RangeError(`leviathan-crypto: unsupported HashSLH-DSA pre-hash algorithm '${ph}'`);
|
|
182
|
+
const out = new Uint8Array(2 + ctx.length + o.length + digest.length);
|
|
183
|
+
out[0] = 0x01;
|
|
184
|
+
out[1] = ctx.length & 0xFF;
|
|
185
|
+
out.set(ctx, 2);
|
|
186
|
+
out.set(o, 2 + ctx.length);
|
|
187
|
+
out.set(digest, 2 + ctx.length + o.length);
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Build the pure-mode M' = 0x00 ‖ |ctx| ‖ ctx ‖ M for FIPS 205 §10.2.1
|
|
192
|
+
* Algorithm 22 line 8 (sign) and §10.3 Algorithm 24 line 8 (verify).
|
|
193
|
+
*
|
|
194
|
+
* Caller has already validated ctx.length ≤ 255. The leading byte is 0x00,
|
|
195
|
+
* which separates pure SLH-DSA signatures from HashSLH-DSA signatures (the
|
|
196
|
+
* latter prepends 0x01 via constructMPrimeHash) on the same key per the
|
|
197
|
+
* §10.2 narrative.
|
|
198
|
+
*/
|
|
199
|
+
export function constructMPrimePure(M, ctx) {
|
|
200
|
+
const out = new Uint8Array(2 + ctx.length + M.length);
|
|
201
|
+
out[0] = 0x00;
|
|
202
|
+
out[1] = ctx.length & 0xFF;
|
|
203
|
+
out.set(ctx, 2);
|
|
204
|
+
out.set(M, 2 + ctx.length);
|
|
205
|
+
return out;
|
|
206
|
+
}
|
|
207
|
+
// ── SHA-2 driver (matches src/ts/mldsa/hashvariant.ts:sha2Hash) ────────────
|
|
208
|
+
function feedSha2(x, msg, inputOff, chunkSize, updateFn) {
|
|
209
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
210
|
+
let pos = 0;
|
|
211
|
+
while (pos < msg.length) {
|
|
212
|
+
const n = Math.min(msg.length - pos, chunkSize);
|
|
213
|
+
mem.set(msg.subarray(pos, pos + n), inputOff);
|
|
214
|
+
updateFn(n);
|
|
215
|
+
pos += n;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function sha2Hash(x, msg, initFn, finalFn, inputOff, outOff, blockSize, updateFn, outLen) {
|
|
219
|
+
initFn();
|
|
220
|
+
feedSha2(x, msg, inputOff, blockSize, updateFn);
|
|
221
|
+
finalFn();
|
|
222
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
223
|
+
return mem.slice(outOff, outOff + outLen);
|
|
224
|
+
}
|
|
225
|
+
// ── SHA-3 fixed-length driver ──────────────────────────────────────────────
|
|
226
|
+
function sha3HashFixed(sx, msg, initFn, finalFn, outLen) {
|
|
227
|
+
initFn();
|
|
228
|
+
sha3Absorb(sx, msg);
|
|
229
|
+
finalFn();
|
|
230
|
+
const mem = new Uint8Array(sx.memory.buffer);
|
|
231
|
+
const off = sx.getOutOffset();
|
|
232
|
+
return mem.slice(off, off + outLen);
|
|
233
|
+
}
|
|
234
|
+
// ── SHAKE driver, fixed output length per FIPS 205 §10.2.2 ─────────────────
|
|
235
|
+
function shakeHashFixed(sx, msg, initFn, rate, outLen) {
|
|
236
|
+
initFn();
|
|
237
|
+
sha3Absorb(sx, msg);
|
|
238
|
+
sx.shakePad();
|
|
239
|
+
const mem = new Uint8Array(sx.memory.buffer);
|
|
240
|
+
const off = sx.getOutOffset();
|
|
241
|
+
const out = new Uint8Array(outLen);
|
|
242
|
+
let pos = 0;
|
|
243
|
+
while (pos < outLen) {
|
|
244
|
+
sx.shakeSqueezeBlock();
|
|
245
|
+
const take = Math.min(outLen - pos, rate);
|
|
246
|
+
out.set(mem.subarray(off, off + take), pos);
|
|
247
|
+
pos += take;
|
|
248
|
+
}
|
|
249
|
+
return out;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Pre-hash dispatcher, applies the FIPS 205 §10.2.2 hash function `algo`
|
|
253
|
+
* to message `M` and returns PH_M (the bytes that go into M' alongside
|
|
254
|
+
* the OID).
|
|
255
|
+
*
|
|
256
|
+
* `sx` is the sha3-wasm Sha3Exports, required for SHA-3 / SHAKE prehashes.
|
|
257
|
+
* `sha2x` is the sha2-wasm Sha2Exports, required for SHA-2 prehashes.
|
|
258
|
+
* Either argument may be `undefined` when the chosen `algo` does not need
|
|
259
|
+
* that module; the dispatcher throws a clear error if a required module
|
|
260
|
+
* is missing rather than NPE'ing on a member access. Pure-SLH-DSA users
|
|
261
|
+
* call neither (slhdsa-wasm has its own embedded Keccak permutation), so
|
|
262
|
+
* both modules are strictly optional.
|
|
263
|
+
*/
|
|
264
|
+
export function preHashMessage(sx, sha2x, algo, M) {
|
|
265
|
+
if (algoNeedsSha3(algo)) {
|
|
266
|
+
if (sx === undefined)
|
|
267
|
+
throw new Error('leviathan-crypto: HashSLH-DSA SHA-3 / SHAKE pre-hash requires the sha3 module to be initialized');
|
|
268
|
+
switch (algo) {
|
|
269
|
+
case 'SHA3-224':
|
|
270
|
+
return sha3HashFixed(sx, M, sx.sha3_224Init, sx.sha3_224Final, 28);
|
|
271
|
+
case 'SHA3-256':
|
|
272
|
+
return sha3HashFixed(sx, M, sx.sha3_256Init, sx.sha3_256Final, 32);
|
|
273
|
+
case 'SHA3-384':
|
|
274
|
+
return sha3HashFixed(sx, M, sx.sha3_384Init, sx.sha3_384Final, 48);
|
|
275
|
+
case 'SHA3-512':
|
|
276
|
+
return sha3HashFixed(sx, M, sx.sha3_512Init, sx.sha3_512Final, 64);
|
|
277
|
+
case 'SHAKE128':
|
|
278
|
+
// FIPS 205 §10.2.2 Algorithm 23 line 17: PH_M = SHAKE128(M, 256).
|
|
279
|
+
return shakeHashFixed(sx, M, sx.shake128Init, 168, 32);
|
|
280
|
+
case 'SHAKE256':
|
|
281
|
+
// FIPS 205 §10.2.2 Algorithm 23 line 20: PH_M = SHAKE256(M, 512).
|
|
282
|
+
return shakeHashFixed(sx, M, sx.shake256Init, 136, 64);
|
|
283
|
+
default: break;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (algoNeedsSha2(algo)) {
|
|
287
|
+
if (sha2x === undefined)
|
|
288
|
+
throw new Error('leviathan-crypto: HashSLH-DSA SHA-2 pre-hash requires the sha2 module to be initialized');
|
|
289
|
+
const x = sha2x;
|
|
290
|
+
switch (algo) {
|
|
291
|
+
case 'SHA2-224':
|
|
292
|
+
return sha2Hash(x, M, x.sha224Init, x.sha224Final, x.getSha256InputOffset(), x.getSha256OutOffset(), 64, x.sha256Update, 28);
|
|
293
|
+
case 'SHA2-256':
|
|
294
|
+
return sha2Hash(x, M, x.sha256Init, x.sha256Final, x.getSha256InputOffset(), x.getSha256OutOffset(), 64, x.sha256Update, 32);
|
|
295
|
+
case 'SHA2-384':
|
|
296
|
+
return sha2Hash(x, M, x.sha384Init, x.sha384Final, x.getSha512InputOffset(), x.getSha512OutOffset(), 128, x.sha512Update, 48);
|
|
297
|
+
case 'SHA2-512':
|
|
298
|
+
return sha2Hash(x, M, x.sha512Init, x.sha512Final, x.getSha512InputOffset(), x.getSha512OutOffset(), 128, x.sha512Update, 64);
|
|
299
|
+
case 'SHA2-512/224':
|
|
300
|
+
return sha2Hash(x, M, x.sha512_224Init, x.sha512_224Final, x.getSha512InputOffset(), x.getSha512OutOffset(), 128, x.sha512Update, 28);
|
|
301
|
+
case 'SHA2-512/256':
|
|
302
|
+
return sha2Hash(x, M, x.sha512_256Init, x.sha512_256Final, x.getSha512InputOffset(), x.getSha512OutOffset(), 128, x.sha512Update, 32);
|
|
303
|
+
default: break;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
throw new RangeError(`leviathan-crypto: unsupported HashSLH-DSA pre-hash algorithm '${algo}'`);
|
|
307
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { SlhDsaExports } from './types.js';
|
|
2
|
+
import type { SlhDsaParams } from './params.js';
|
|
3
|
+
import { type PreHashAlgorithm } from './prehash.js';
|
|
4
|
+
/**
|
|
5
|
+
* Drive slhSignInternal with caller-built M' bytes plus opt_rand.
|
|
6
|
+
*
|
|
7
|
+
* Layout written into INPUT (per src/asm/slhdsa/slh.ts §slhSignInternal):
|
|
8
|
+
* INPUT = sk (4n) ‖ M' (msgLen) ‖ opt_rand (n)
|
|
9
|
+
*
|
|
10
|
+
* `sk` must be exactly `params.skBytes` bytes; `optRand` must be exactly
|
|
11
|
+
* `params.n` bytes. The caller is responsible for those length contracts
|
|
12
|
+
* (the public surface validates before this driver runs).
|
|
13
|
+
*
|
|
14
|
+
* Returns a fresh `sigBytes`-long Uint8Array sliced out of OUT. The
|
|
15
|
+
* finally block wipes the INPUT region (which held the secret sk and
|
|
16
|
+
* potentially-secret opt_rand) and calls `wipeBuffers()` on the WASM
|
|
17
|
+
* module to zero OUT, STATE, SCRATCH.
|
|
18
|
+
*/
|
|
19
|
+
export declare function slhSignInternalTs(x: SlhDsaExports, params: SlhDsaParams, sk: Uint8Array, MPrime: Uint8Array, optRand: Uint8Array): Uint8Array;
|
|
20
|
+
/**
|
|
21
|
+
* HashSLH-DSA sign, post-prehash. FIPS 205 §10.2.2 Algorithm 23 lines
|
|
22
|
+
* 18-25. Builds M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID(algo) ‖ prehash and drives
|
|
23
|
+
* Sign_internal with the caller-supplied opt_rand.
|
|
24
|
+
*
|
|
25
|
+
* The caller owns `prehash` (it may be a slice of WASM memory, a
|
|
26
|
+
* caller-controlled digest, or an internally-computed PH_M); this helper
|
|
27
|
+
* never wipes it. The caller also owns `optRand` (hedged: caller wipes a
|
|
28
|
+
* freshly-generated value; deterministic: optRand = PK.seed slice, no
|
|
29
|
+
* separate wipe; derand: caller-supplied per FIPS 205 §3.4 contract).
|
|
30
|
+
*
|
|
31
|
+
* The 12 approved pre-hash functions (`algo`) and their OIDs are FIPS 205
|
|
32
|
+
* §10.2.2's catalog (matches FIPS 204 §5.4.1 byte-for-byte). Domain-sep
|
|
33
|
+
* byte 0x01 inside the M' construction separates HashSLH-DSA signatures
|
|
34
|
+
* from pure-SLH-DSA signatures on the same key per the §10.2 narrative.
|
|
35
|
+
*
|
|
36
|
+
* signWithPrehash is duplicated from `src/ts/mldsa/sign.ts:signWithPrehash`;
|
|
37
|
+
* extraction is deferred until a third consumer materialises.
|
|
38
|
+
*/
|
|
39
|
+
export declare function signWithPrehash(x: SlhDsaExports, params: SlhDsaParams, sk: Uint8Array, prehash: Uint8Array, algo: PreHashAlgorithm, ctx: Uint8Array, optRand: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,116 @@
|
|
|
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/sign.ts
|
|
23
|
+
//
|
|
24
|
+
// SLH-DSA sign drivers, FIPS 205 §10.2 wrappers around the WASM
|
|
25
|
+
// slhSignInternal entry point (FIPS 205 §9.2 Algorithm 19).
|
|
26
|
+
//
|
|
27
|
+
// Two drivers:
|
|
28
|
+
// • slhSignInternalTs, writes (sk ‖ M' ‖ opt_rand) into INPUT, runs
|
|
29
|
+
// slhSignInternal, copies sig out of OUT, wipes INPUT scratch and
|
|
30
|
+
// WASM buffers in finally. M' here is the already-domain-separated
|
|
31
|
+
// bytes (constructMPrimePure for pure mode, constructMPrimeHash for
|
|
32
|
+
// HashSLH-DSA mode), produced by the caller.
|
|
33
|
+
// • signWithPrehash, builds the HashSLH-DSA M' from (digest, oid(ph),
|
|
34
|
+
// ctx) and forwards to slhSignInternalTs. Mirrors
|
|
35
|
+
// src/ts/mldsa/sign.ts:signWithPrehash.
|
|
36
|
+
//
|
|
37
|
+
// Buffer hygiene:
|
|
38
|
+
// - INPUT region zeroed before return (lib wipe; sk + M' + opt_rand all
|
|
39
|
+
// land there). slhdsa's WASM-side wipeBuffers() handles OUT / STATE /
|
|
40
|
+
// SCRATCH but NOT INPUT (see src/asm/slhdsa/buffers.ts comment).
|
|
41
|
+
// - PH_M and M' are lib-allocated TS-side buffers; wiped in finally.
|
|
42
|
+
// - Lib does NOT wipe caller's sk / msg / ctx / digest / opt_rand.
|
|
43
|
+
import { wipe } from '../utils.js';
|
|
44
|
+
import { constructMPrimeHash } from './prehash.js';
|
|
45
|
+
/**
|
|
46
|
+
* Drive slhSignInternal with caller-built M' bytes plus opt_rand.
|
|
47
|
+
*
|
|
48
|
+
* Layout written into INPUT (per src/asm/slhdsa/slh.ts §slhSignInternal):
|
|
49
|
+
* INPUT = sk (4n) ‖ M' (msgLen) ‖ opt_rand (n)
|
|
50
|
+
*
|
|
51
|
+
* `sk` must be exactly `params.skBytes` bytes; `optRand` must be exactly
|
|
52
|
+
* `params.n` bytes. The caller is responsible for those length contracts
|
|
53
|
+
* (the public surface validates before this driver runs).
|
|
54
|
+
*
|
|
55
|
+
* Returns a fresh `sigBytes`-long Uint8Array sliced out of OUT. The
|
|
56
|
+
* finally block wipes the INPUT region (which held the secret sk and
|
|
57
|
+
* potentially-secret opt_rand) and calls `wipeBuffers()` on the WASM
|
|
58
|
+
* module to zero OUT, STATE, SCRATCH.
|
|
59
|
+
*/
|
|
60
|
+
export function slhSignInternalTs(x, params, sk, MPrime, optRand) {
|
|
61
|
+
const inOff = x.getInputOffset();
|
|
62
|
+
const outOff = x.getOutOffset();
|
|
63
|
+
const skLen = params.skBytes;
|
|
64
|
+
const nLen = params.n;
|
|
65
|
+
const msgLen = MPrime.length;
|
|
66
|
+
const inputTotal = skLen + msgLen + nLen;
|
|
67
|
+
const mem = new Uint8Array(x.memory.buffer);
|
|
68
|
+
try {
|
|
69
|
+
// Bind active parameter set into the WASM PARAMS slot. WASM dimension
|
|
70
|
+
// lookups (slhK, slhA, slhD, slhHPrime) all read from PARAMS, so this
|
|
71
|
+
// must precede slhSignInternal.
|
|
72
|
+
params.wasmSelector();
|
|
73
|
+
mem.set(sk, inOff);
|
|
74
|
+
mem.set(MPrime, inOff + skLen);
|
|
75
|
+
mem.set(optRand, inOff + skLen + msgLen);
|
|
76
|
+
x.slhSignInternal(msgLen);
|
|
77
|
+
return mem.slice(outOff, outOff + params.sigBytes);
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
// INPUT held sk (secret) + M' (caller input, includes ctx + message)
|
|
81
|
+
// + opt_rand (sensitive: PK.seed in det mode, fresh randomness in
|
|
82
|
+
// hedged mode, caller-owned in derand mode). The lib wipes its own
|
|
83
|
+
// staging copy unconditionally so a later op cannot read these bytes.
|
|
84
|
+
mem.fill(0, inOff, inOff + inputTotal);
|
|
85
|
+
// OUT / STATE / SCRATCH all held secret-derived intermediates.
|
|
86
|
+
x.wipeBuffers();
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* HashSLH-DSA sign, post-prehash. FIPS 205 §10.2.2 Algorithm 23 lines
|
|
91
|
+
* 18-25. Builds M' = 0x01 ‖ |ctx| ‖ ctx ‖ OID(algo) ‖ prehash and drives
|
|
92
|
+
* Sign_internal with the caller-supplied opt_rand.
|
|
93
|
+
*
|
|
94
|
+
* The caller owns `prehash` (it may be a slice of WASM memory, a
|
|
95
|
+
* caller-controlled digest, or an internally-computed PH_M); this helper
|
|
96
|
+
* never wipes it. The caller also owns `optRand` (hedged: caller wipes a
|
|
97
|
+
* freshly-generated value; deterministic: optRand = PK.seed slice, no
|
|
98
|
+
* separate wipe; derand: caller-supplied per FIPS 205 §3.4 contract).
|
|
99
|
+
*
|
|
100
|
+
* The 12 approved pre-hash functions (`algo`) and their OIDs are FIPS 205
|
|
101
|
+
* §10.2.2's catalog (matches FIPS 204 §5.4.1 byte-for-byte). Domain-sep
|
|
102
|
+
* byte 0x01 inside the M' construction separates HashSLH-DSA signatures
|
|
103
|
+
* from pure-SLH-DSA signatures on the same key per the §10.2 narrative.
|
|
104
|
+
*
|
|
105
|
+
* signWithPrehash is duplicated from `src/ts/mldsa/sign.ts:signWithPrehash`;
|
|
106
|
+
* extraction is deferred until a third consumer materialises.
|
|
107
|
+
*/
|
|
108
|
+
export function signWithPrehash(x, params, sk, prehash, algo, ctx, optRand) {
|
|
109
|
+
const MPrime = constructMPrimeHash(prehash, algo, ctx);
|
|
110
|
+
try {
|
|
111
|
+
return slhSignInternalTs(x, params, sk, MPrime, optRand);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
wipe(MPrime);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/** SLH-DSA WASM exports. Mirrors the AssemblyScript surface in
|
|
2
|
+
* `src/asm/slhdsa/index.ts`. The consumer-facing TS surface (SlhDsaBase and
|
|
3
|
+
* its subclasses) calls slhKeygenInternal / slhSignInternal /
|
|
4
|
+
* slhVerifyInternal directly; the lower-level hash family + ADRS helpers
|
|
5
|
+
* are exported so the unit suite can drive each primitive layer in
|
|
6
|
+
* isolation. */
|
|
7
|
+
export interface SlhDsaExports {
|
|
8
|
+
memory: WebAssembly.Memory;
|
|
9
|
+
getModuleId: () => number;
|
|
10
|
+
getMemoryPages: () => number;
|
|
11
|
+
getInputOffset: () => number;
|
|
12
|
+
getOutOffset: () => number;
|
|
13
|
+
getStateOffset: () => number;
|
|
14
|
+
getScratchOffset: () => number;
|
|
15
|
+
getAdrsOffset: () => number;
|
|
16
|
+
getParamsOffset: () => number;
|
|
17
|
+
getParamN: () => number;
|
|
18
|
+
getParamM: () => number;
|
|
19
|
+
getParamSet: () => number;
|
|
20
|
+
slhSetParams128f: () => void;
|
|
21
|
+
slhSetParams192f: () => void;
|
|
22
|
+
slhSetParams256f: () => void;
|
|
23
|
+
wipeBuffers: () => void;
|
|
24
|
+
adrsClear: (adrs: number) => void;
|
|
25
|
+
adrsCopy: (dst: number, src: number) => void;
|
|
26
|
+
adrsSetLayerAddress: (adrs: number, layer: number) => void;
|
|
27
|
+
adrsGetLayerAddress: (adrs: number) => number;
|
|
28
|
+
adrsSetTreeAddr: (adrs: number, hi: number, mid: number, lo: number) => void;
|
|
29
|
+
adrsGetTreeHi: (adrs: number) => number;
|
|
30
|
+
adrsGetTreeMid: (adrs: number) => number;
|
|
31
|
+
adrsGetTreeLo: (adrs: number) => number;
|
|
32
|
+
adrsSetType: (adrs: number, typ: number) => void;
|
|
33
|
+
adrsGetType: (adrs: number) => number;
|
|
34
|
+
adrsSetKeyPairAddress: (adrs: number, kp: number) => void;
|
|
35
|
+
adrsGetKeyPairAddress: (adrs: number) => number;
|
|
36
|
+
adrsSetChainAddress: (adrs: number, chain: number) => void;
|
|
37
|
+
adrsGetChainAddress: (adrs: number) => number;
|
|
38
|
+
adrsSetHashAddress: (adrs: number, h: number) => void;
|
|
39
|
+
adrsGetHashAddress: (adrs: number) => number;
|
|
40
|
+
adrsSetTreeHeight: (adrs: number, height: number) => void;
|
|
41
|
+
adrsGetTreeHeight: (adrs: number) => number;
|
|
42
|
+
adrsSetTreeIndex: (adrs: number, index: number) => void;
|
|
43
|
+
adrsGetTreeIndex: (adrs: number) => number;
|
|
44
|
+
ADRS_WOTS_HASH: {
|
|
45
|
+
value: number;
|
|
46
|
+
};
|
|
47
|
+
ADRS_WOTS_PK: {
|
|
48
|
+
value: number;
|
|
49
|
+
};
|
|
50
|
+
ADRS_TREE: {
|
|
51
|
+
value: number;
|
|
52
|
+
};
|
|
53
|
+
ADRS_FORS_TREE: {
|
|
54
|
+
value: number;
|
|
55
|
+
};
|
|
56
|
+
ADRS_FORS_ROOTS: {
|
|
57
|
+
value: number;
|
|
58
|
+
};
|
|
59
|
+
ADRS_WOTS_PRF: {
|
|
60
|
+
value: number;
|
|
61
|
+
};
|
|
62
|
+
ADRS_FORS_PRF: {
|
|
63
|
+
value: number;
|
|
64
|
+
};
|
|
65
|
+
ADRS_BYTES: {
|
|
66
|
+
value: number;
|
|
67
|
+
};
|
|
68
|
+
slhHashF: (out: number, pkSeed: number, adrs: number, m1: number) => void;
|
|
69
|
+
slhHashH: (out: number, pkSeed: number, adrs: number, m2: number) => void;
|
|
70
|
+
slhHashTl: (out: number, pkSeed: number, adrs: number, m: number, mLen: number) => void;
|
|
71
|
+
slhPRF: (out: number, pkSeed: number, skSeed: number, adrs: number) => void;
|
|
72
|
+
slhPRFmsg: (out: number, prf: number, optRand: number, m: number, mLen: number) => void;
|
|
73
|
+
slhHmsg: (out: number, r: number, pkSeed: number, pkRoot: number, m: number, mLen: number) => void;
|
|
74
|
+
slhShake256: (out: number, outLen: number, in_: number, inLen: number) => void;
|
|
75
|
+
shake128Init: () => void;
|
|
76
|
+
shake256Init: () => void;
|
|
77
|
+
keccakAbsorb: (len: number) => void;
|
|
78
|
+
keccakAbsorbAt: (src: number, len: number) => void;
|
|
79
|
+
keccakSqueezeTo: (dst: number, outLen: number) => void;
|
|
80
|
+
shakeFinal: (outLen: number) => void;
|
|
81
|
+
slhKeygenInternal: () => void;
|
|
82
|
+
slhSignInternal: (msgLen: number) => void;
|
|
83
|
+
slhVerifyInternal: (msgLen: number) => number;
|
|
84
|
+
}
|
|
85
|
+
/** SLH-DSA key pair returned by keygen / keygenDerand. */
|
|
86
|
+
export interface SlhDsaKeyPair {
|
|
87
|
+
verificationKey: Uint8Array;
|
|
88
|
+
signingKey: Uint8Array;
|
|
89
|
+
}
|
|
90
|
+
/** SLH-DSA WASM internal test exports. NOT part of the consumer surface,
|
|
91
|
+
* NOT re-exported from src/ts/slhdsa/index.ts. Wired exclusively for the
|
|
92
|
+
* unit suite (slhdsa-wots / slhdsa-fors / slhdsa-xmss / slhdsa-hypertree
|
|
93
|
+
* tests) to drive each primitive layer in isolation.
|
|
94
|
+
*
|
|
95
|
+
* Tests obtain these via test/unit/slhdsa/helpers.ts which casts the
|
|
96
|
+
* public SlhDsaExports to (SlhDsaExports & SlhDsaTestExports). The cast
|
|
97
|
+
* is contained inside the test helpers, so consumer code never sees
|
|
98
|
+
* the _test* surface. */
|
|
99
|
+
export interface SlhDsaTestExports {
|
|
100
|
+
_testBase2b: (out: number, x: number, b: number, outLen: number) => void;
|
|
101
|
+
_testWotsLen: () => number;
|
|
102
|
+
_testWotsLen1: () => number;
|
|
103
|
+
_testWotsTmpOffset: () => number;
|
|
104
|
+
_testWotsSkOffset: () => number;
|
|
105
|
+
_testWotsMsgOffset: () => number;
|
|
106
|
+
_testWotsChain: (out: number, x: number, i: number, s: number, pkSeed: number, adrs: number) => void;
|
|
107
|
+
_testWotsPkGen: (outPk: number, skSeed: number, pkSeed: number, adrs: number) => void;
|
|
108
|
+
_testWotsSign: (outSig: number, m: number, skSeed: number, pkSeed: number, adrs: number) => void;
|
|
109
|
+
_testWotsPkFromSig: (outPk: number, sig: number, m: number, pkSeed: number, adrs: number) => void;
|
|
110
|
+
_testForsK: () => number;
|
|
111
|
+
_testForsA: () => number;
|
|
112
|
+
_testForsRootsOffset: () => number;
|
|
113
|
+
_testForsLeafOffset: () => number;
|
|
114
|
+
_testForsPairBase: () => number;
|
|
115
|
+
_testForsSkGen: (out: number, skSeed: number, idx: number, pkSeed: number, adrs: number) => void;
|
|
116
|
+
_testForsNode: (out: number, skSeed: number, i: number, z: number, pkSeed: number, adrs: number) => void;
|
|
117
|
+
_testForsSign: (outSig: number, md: number, skSeed: number, pkSeed: number, adrs: number) => void;
|
|
118
|
+
_testForsPkFromSig: (outPk: number, sig: number, md: number, pkSeed: number, adrs: number) => void;
|
|
119
|
+
_testXmssHPrime: () => number;
|
|
120
|
+
_testXmssPairBase: () => number;
|
|
121
|
+
_testXmssNode: (out: number, skSeed: number, i: number, z: number, pkSeed: number, adrs: number) => void;
|
|
122
|
+
_testXmssSign: (outSig: number, m: number, skSeed: number, idx: number, pkSeed: number, adrs: number) => void;
|
|
123
|
+
_testXmssPkFromSig: (outRoot: number, idx: number, sig: number, m: number, pkSeed: number, adrs: number) => void;
|
|
124
|
+
_testHtD: () => number;
|
|
125
|
+
_testHtHPrime: () => number;
|
|
126
|
+
_testHtRootOffset: () => number;
|
|
127
|
+
_testHtSign: (outSig: number, m: number, skSeed: number, pkSeed: number, idxTreeHi: number, idxTreeLo: number, idxLeaf: number, adrs: number) => void;
|
|
128
|
+
_testHtVerify: (m: number, sig: number, pkSeed: number, idxTreeHi: number, idxTreeLo: number, idxLeaf: number, pkRoot: number, adrs: number) => number;
|
|
129
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
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/types.ts
|
|
23
|
+
//
|
|
24
|
+
// SLH-DSA type definitions: WASM export interface (substrate surface), the
|
|
25
|
+
// top-level keygen/sign/verify entry points, and the public TS types
|
|
26
|
+
// (SlhDsaKeyPair, SlhDsaTestExports).
|
|
27
|
+
export {};
|