leviathan-crypto 1.4.0 → 2.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.
Files changed (119) hide show
  1. package/CLAUDE.md +129 -94
  2. package/README.md +166 -223
  3. package/SECURITY.md +85 -45
  4. package/dist/chacha20/cipher-suite.d.ts +4 -0
  5. package/dist/chacha20/cipher-suite.js +78 -0
  6. package/dist/chacha20/embedded.d.ts +1 -0
  7. package/dist/chacha20/embedded.js +27 -0
  8. package/dist/chacha20/index.d.ts +20 -27
  9. package/dist/chacha20/index.js +40 -59
  10. package/dist/chacha20/ops.d.ts +1 -1
  11. package/dist/chacha20/ops.js +19 -18
  12. package/dist/chacha20/pool-worker.js +77 -0
  13. package/dist/ct-wasm.d.ts +1 -0
  14. package/dist/ct-wasm.js +3 -0
  15. package/dist/ct.wasm +0 -0
  16. package/dist/docs/aead.md +320 -0
  17. package/dist/docs/architecture.md +419 -285
  18. package/dist/docs/argon2id.md +42 -30
  19. package/dist/docs/chacha20.md +192 -266
  20. package/dist/docs/exports.md +241 -0
  21. package/dist/docs/fortuna.md +60 -69
  22. package/dist/docs/init.md +172 -178
  23. package/dist/docs/loader.md +87 -142
  24. package/dist/docs/serpent.md +134 -583
  25. package/dist/docs/sha2.md +91 -103
  26. package/dist/docs/sha3.md +70 -36
  27. package/dist/docs/types.md +93 -16
  28. package/dist/docs/utils.md +109 -32
  29. package/dist/embedded/kyber.d.ts +1 -0
  30. package/dist/embedded/kyber.js +3 -0
  31. package/dist/errors.d.ts +10 -0
  32. package/dist/errors.js +38 -0
  33. package/dist/fortuna.d.ts +0 -6
  34. package/dist/fortuna.js +5 -5
  35. package/dist/index.d.ts +25 -9
  36. package/dist/index.js +36 -7
  37. package/dist/init.d.ts +3 -7
  38. package/dist/init.js +18 -35
  39. package/dist/keccak/embedded.d.ts +1 -0
  40. package/dist/keccak/embedded.js +27 -0
  41. package/dist/keccak/index.d.ts +4 -0
  42. package/dist/keccak/index.js +31 -0
  43. package/dist/kyber/embedded.d.ts +1 -0
  44. package/dist/kyber/embedded.js +27 -0
  45. package/dist/kyber/indcpa.d.ts +49 -0
  46. package/dist/kyber/indcpa.js +352 -0
  47. package/dist/kyber/index.d.ts +38 -0
  48. package/dist/kyber/index.js +150 -0
  49. package/dist/kyber/kem.d.ts +21 -0
  50. package/dist/kyber/kem.js +160 -0
  51. package/dist/kyber/params.d.ts +14 -0
  52. package/dist/kyber/params.js +37 -0
  53. package/dist/kyber/suite.d.ts +13 -0
  54. package/dist/kyber/suite.js +93 -0
  55. package/dist/kyber/types.d.ts +98 -0
  56. package/dist/kyber/types.js +25 -0
  57. package/dist/kyber/validate.d.ts +19 -0
  58. package/dist/kyber/validate.js +68 -0
  59. package/dist/kyber.wasm +0 -0
  60. package/dist/loader.d.ts +15 -6
  61. package/dist/loader.js +65 -21
  62. package/dist/serpent/cipher-suite.d.ts +4 -0
  63. package/dist/serpent/cipher-suite.js +121 -0
  64. package/dist/serpent/embedded.d.ts +1 -0
  65. package/dist/serpent/embedded.js +27 -0
  66. package/dist/serpent/index.d.ts +6 -37
  67. package/dist/serpent/index.js +9 -118
  68. package/dist/serpent/pool-worker.d.ts +1 -0
  69. package/dist/serpent/pool-worker.js +202 -0
  70. package/dist/serpent/serpent-cbc.d.ts +30 -0
  71. package/dist/serpent/serpent-cbc.js +136 -0
  72. package/dist/sha2/embedded.d.ts +1 -0
  73. package/dist/sha2/embedded.js +27 -0
  74. package/dist/sha2/hkdf.js +6 -2
  75. package/dist/sha2/index.d.ts +3 -2
  76. package/dist/sha2/index.js +3 -4
  77. package/dist/sha3/embedded.d.ts +1 -0
  78. package/dist/sha3/embedded.js +27 -0
  79. package/dist/sha3/index.d.ts +3 -2
  80. package/dist/sha3/index.js +3 -4
  81. package/dist/stream/constants.d.ts +6 -0
  82. package/dist/stream/constants.js +30 -0
  83. package/dist/stream/header.d.ts +9 -0
  84. package/dist/stream/header.js +77 -0
  85. package/dist/stream/index.d.ts +7 -0
  86. package/dist/stream/index.js +27 -0
  87. package/dist/stream/open-stream.d.ts +21 -0
  88. package/dist/stream/open-stream.js +146 -0
  89. package/dist/stream/seal-stream-pool.d.ts +38 -0
  90. package/dist/stream/seal-stream-pool.js +391 -0
  91. package/dist/stream/seal-stream.d.ts +20 -0
  92. package/dist/stream/seal-stream.js +142 -0
  93. package/dist/stream/seal.d.ts +9 -0
  94. package/dist/stream/seal.js +75 -0
  95. package/dist/stream/types.d.ts +24 -0
  96. package/dist/stream/types.js +26 -0
  97. package/dist/utils.d.ts +7 -2
  98. package/dist/utils.js +49 -3
  99. package/dist/wasm-source.d.ts +12 -0
  100. package/dist/wasm-source.js +26 -0
  101. package/package.json +13 -5
  102. package/dist/chacha20/pool.d.ts +0 -52
  103. package/dist/chacha20/pool.js +0 -178
  104. package/dist/chacha20/pool.worker.js +0 -37
  105. package/dist/chacha20/stream-sealer.d.ts +0 -49
  106. package/dist/chacha20/stream-sealer.js +0 -327
  107. package/dist/docs/chacha20_pool.md +0 -309
  108. package/dist/docs/wasm.md +0 -194
  109. package/dist/serpent/seal.d.ts +0 -8
  110. package/dist/serpent/seal.js +0 -72
  111. package/dist/serpent/stream-pool.d.ts +0 -48
  112. package/dist/serpent/stream-pool.js +0 -275
  113. package/dist/serpent/stream-sealer.d.ts +0 -55
  114. package/dist/serpent/stream-sealer.js +0 -342
  115. package/dist/serpent/stream.d.ts +0 -28
  116. package/dist/serpent/stream.js +0 -205
  117. package/dist/serpent/stream.worker.d.ts +0 -32
  118. package/dist/serpent/stream.worker.js +0 -117
  119. /package/dist/chacha20/{pool.worker.d.ts → pool-worker.d.ts} +0 -0
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![GitHub Release](https://img.shields.io/github/v/release/xero/leviathan-crypto?sort=semver&display_name=tag&style=flat&logo=github&logoColor=989da4&label=latest%20release&labelColor=161925&color=1c7293)](https://github.com/xero/leviathan-crypto/releases/latest) [![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/leviathan-crypto?format=both&style=flat&logo=googlecontaineroptimizedos&logoColor=989da4&label=package%20size&labelColor=161925&color=1c7293)](https://www.npmjs.com/package/leviathan-crypto) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/xero/leviathan-crypto/test-suite.yml?branch=main&style=flat&logo=github&logoColor=989da4&label=test%20suite&labelColor=161925&color=1a936f)](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/xero/leviathan-crypto/wiki.yml?branch=main&style=flat&logo=gitbook&logoColor=989da4&label=wiki%20publish&labelColor=161925&color=1a936f)](https://github.com/xero/leviathan-crypto/wiki)
1
+ [![GitHub Release](https://img.shields.io/github/v/release/xero/leviathan-crypto?sort=semver&display_name=tag&style=flat&logo=github&logoColor=989da4&label=latest%20release&labelColor=161925&color=1c7293)](https://github.com/xero/leviathan-crypto/releases/latest) [![npm package minimized gzipped size](https://img.shields.io/bundlejs/size/leviathan-crypto?format=both&style=flat&logo=googlecontaineroptimizedos&logoColor=989da4&label=package%20size&labelColor=161925&color=1c7293&cacheSeconds=36000)](https://www.npmjs.com/package/leviathan-crypto) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/xero/leviathan-crypto/test-suite.yml?branch=main&style=flat&logo=github&logoColor=989da4&label=test%20suite&labelColor=161925&color=1a936f)](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml) [![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/xero/leviathan-crypto/wiki.yml?branch=main&style=flat&logo=gitbook&logoColor=989da4&label=wiki%20publish&labelColor=161925&color=1a936f)](https://github.com/xero/leviathan-crypto/wiki)
2
2
 
3
3
  ![simd webassembly](https://img.shields.io/badge/SIMD%20-%20WASM?style=flat&logo=wasmer&logoColor=1a936f&label=WASM&labelColor=33383e&color=161925) ![side-effect free](https://github.com/xero/leviathan-crypto/raw/main/docs/badge-side-effect-free.svg) ![tree-shakeable](https://github.com/xero/leviathan-crypto/raw/main/docs/badge-tree-shakable.svg) ![zero dependencies](https://github.com/xero/leviathan-crypto/raw/main/docs/badge-zero-dependancies.svg) [![MIT Licensed](https://github.com/xero/leviathan-crypto/raw/main/docs/badge-mit-license.svg)](https://github.com/xero/leviathan-crypto/blob/main/LICENSE)
4
4
 
@@ -6,65 +6,29 @@
6
6
 
7
7
  # Leviathan-Crypto
8
8
 
9
- > Web cryptography built on Serpent-256 paranoia and XChaCha20-Poly1305 elegance.
10
-
11
- **Serpent-256 is the cipher for those who distrust consensus.** In 2001, when
12
- NIST selected AES, Serpent actually received more first-place security votes
13
- from the evaluation committee. However, it lost because the competition also
14
- considered performance on hardware embedded systems, which are no longer
15
- representative of the environments for which we develop software. Serpent's
16
- designers made no compromises: thirty-two rounds, S-boxes implemented using
17
- pure Boolean logic gates without table lookups, and every bit processed for
18
- each block. You use Serpent not because a committee recommended it, but because
19
- you trust the cryptanalysis. The current best attack on the full
20
- thirty-two-round Serpent-256 achieves 2²⁵⁵·¹⁹ — less than one bit below the
21
- brute-force ceiling, and strictly impractical. This includes our own
22
- independent research, which improved upon the published result. See
23
- [`serpent_audit.md`](https://github.com/xero/leviathan-crypto/wiki/serpent_audit).
24
-
25
- **XChaCha20-Poly1305 is the cipher for those who appreciate design that has
26
- nothing to hide.** Daniel Bernstein built ChaCha20 as a twenty-round ARX
27
- construction: add, rotate, and XOR, in a precise choreography that simply
28
- doesn't have the attack surface that table-based ciphers do. It has no S-boxes,
29
- no cache-timing leakage, and requires no hardware acceleration to be fast.
30
- Poly1305 adds a final layer of security: a one-time authenticator with an
31
- unconditional forgery bound, mathematically guaranteed regardless of attacker
32
- compute power. XChaCha20-Poly1305 is the construction you reach for when you
33
- want an AEAD whose security proof you can actually read without a PhD. See
34
- [`chacha_audit.md`](https://github.com/xero/leviathan-crypto/wiki/chacha_audit).
35
-
36
- The tension between these two approaches constitutes the library's core
37
- identity. Serpent embodies defiance, ChaCha embodies elegance, yet both arrive
38
- at the same place: constant-time, side-channel resistant implementations,
39
- independently audited against their specifications. They represent two design
40
- philosophies that do not agree on anything, except the answer.
41
-
42
- **WebAssembly provides a correctness layer.** Each primitive compiles into its
43
- own isolated binary, executing outside the JavaScript JIT. This prevents
44
- speculative optimization from affecting key material and ensures that
45
- data-dependent timing vulnerabilities do not cross the boundary.
46
-
47
- **TypeScript acts as the ergonomics layer.** Fully typed classes, explicit
48
- `init()` gates, input validation, and authenticated compositions ensure
49
- primitives are connected correctly.
50
-
51
9
  ---
52
10
 
53
- #### **Zero Dependencies.**
11
+ > WebAssembly cryptography library built on the paranoia of Serpent-256 and the elegance of XChaCha20-Poly1305.
12
+
13
+ **Serpent-256** won the AES security vote but lost the competition. The deciding factor was performance on embedded hardware, a constraint that doesn't apply to modern software. 32 rounds. S-boxes in pure Boolean logic with no table lookups. It processes every bit in every block. You use it because you trust the cryptanalysis, not because a committee endorsed it.
14
+
15
+ **XChaCha20-Poly1305** has nothing to hide. An ARX construction with 20 rounds. Add, rotate, XOR with no S-boxes or cache-timing leakage. It needs no hardware acceleration to be fast. Poly1305 adds an unconditional forgery bound. The security proof is readable.
16
+
17
+ **_Two ciphers from opposite design philosophies, only agreeing on security properties._**
54
18
 
55
- With no npm dependency graph to audit, the supply chain attack surface is
56
- eliminated.
19
+ **WebAssembly is the correctness layer.** Every primitive runs in its own isolated binary with its own linear memory. Execution is deterministic with no JIT speculation. Key material in one module can't interact with another, even in principle. See the [security policy](./SECURITY.md).
57
20
 
58
- #### **Tree-shakeable.**
21
+ **TypeScript is the ergonomics layer.** The `Seal` and `SealStream` family are cipher-agnostic. Drop in `SerpentCipher` or `XChaCha20Cipher` and they handle nonces, key derivation, and authentication for you. Explicit [`init()`](https://github.com/xero/leviathan-crypto/wiki/init) gates give you full control over how and when WASM loads. Strict typing catches misuse before it reaches production.
59
22
 
60
- Import only the cipher(s) you intend to use. Subpath exports allow bundlers to
61
- exclude everything else.
23
+ **Zero dependencies.** No npm graph to audit. No supply chain attack surface.
62
24
 
63
- #### **Side-effect Free.**
25
+ **Tree-shakeable.** Import only what you use. Subpath exports let bundlers exclude everything else.
64
26
 
65
- Nothing runs upon import. Initialization via `init()` is explicit and
66
- asynchronous.
27
+ **Side-effect free.** Nothing runs on import. [`init()`](https://github.com/xero/leviathan-crypto/wiki/init) is explicit and asynchronous.
67
28
 
29
+ **Audited primitives.** Every implementation is verified against its specification. See the [audit index](https://github.com/xero/leviathan-crypto/wiki/audits.md).
30
+
31
+ ---
68
32
 
69
33
  ## Installation
70
34
 
@@ -76,227 +40,207 @@ npm install leviathan-crypto
76
40
  ```
77
41
 
78
42
  > [!NOTE]
79
- > The Serpent and ChaCha20 modules require a runtime with WebAssembly SIMD
80
- > support. [This has been a feature of all major browsers and runtimes since
81
- > 2021](https://caniuse.com/wasm-simd). All other primitives (SHA-2, SHA-3,
82
- > Poly1305) run on any WASM-capable runtime.
43
+ > [Serpent](https://github.com/xero/leviathan-crypto/wiki/serpent.md), [ChaCha20](https://github.com/xero/leviathan-crypto/wiki/chacha20.md), [ML-KEM](https://github.com/xero/leviathan-crypto/wiki/kyber.md), and [constantTimeEqual](https://github.com/xero/leviathan-crypto/wiki/utils.md#constanttimeequal) require WebAssembly SIMD support. This has been a baseline feature of all major browsers and runtimes [since 2021](https://caniuse.com/wasm-simd). SHA-2 and SHA-3 run on any WASM-capable runtime.
83
44
 
84
- ---
45
+ ### Loading
85
46
 
86
- ## Demos
47
+ Three loading strategies are available. Choose based on your runtime and bundler setup.
87
48
 
88
- **`lvthn-web`** [ [demo](https://leviathan.3xi.club/web) · [source](https://github.com/xero/leviathan-demos/tree/main/web) · [readme](https://github.com/xero/leviathan-demos/blob/main/web/README.md) ]
49
+ ```typescript
50
+ import { init } from 'leviathan-crypto'
51
+ import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
52
+ import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
89
53
 
90
- A browser encryption tool in a single, self-contained HTML file. Encrypt text
91
- or files using Serpent-256-CBC and Argon2id key derivation, then share the
92
- armored output. No server, installation, or network connection required after
93
- initial load. The code is written to be read. The Encrypt-then-MAC
94
- construction, HMAC input (header with HMAC field zeroed + ciphertext), and
95
- Argon2id parameters are all intentional examples worth reading.
54
+ // Embedded: gzip+base64 blobs bundled in the package
55
+ await init({ serpent: serpentWasm, sha2: sha2Wasm })
96
56
 
97
- **`lvthn-chat`** [ [demo](https://leviathan.3xi.club/chat) · [source](https://github.com/xero/leviathan-demos/tree/main/chat) · [readme](https://github.com/xero/leviathan-demos/blob/main/chat/README.md) ]
57
+ // URL: streaming compilation from a served .wasm file
58
+ await init({ serpent: new URL('/assets/wasm/serpent.wasm', import.meta.url) })
98
59
 
99
- End-to-end encrypted chat featuring two-party messaging over X25519 key
100
- exchange and XChaCha20-Poly1305 message encryption. The relay server functions
101
- as a dumb WebSocket pipe that never sees plaintext. Each message incorporates
102
- sequence numbers, which allows the system to detect and reject replayed
103
- messages from an attacker. The demo deconstructs the protocol step by step,
104
- with visual feedback for both injection and replays.
60
+ // Pre-compiled: pass a WebAssembly.Module directly (edge runtimes, KV cache)
61
+ await init({ serpent: compiledModule })
62
+ ```
105
63
 
106
- **`lvthn-cli`** [ [npm](https://www.npmjs.com/package/lvthn) · [source](https://github.com/xero/leviathan-demos/tree/main/lvthn-cli) · [readme](https://github.com/xero/leviathan-demos/blob/main/lvthn-cli/README.md) ]
64
+ ### Tree-shaking with subpath imports
107
65
 
108
- File encryption CLI. Supports both Serpent-256 and XChaCha20-Poly1305,
109
- selectable via the `--cipher` flag. A single keyfile is compatible with both
110
- ciphers; the header byte determines decryption automatically. Encryption and
111
- decryption distribute 64KB chunks across a worker pool sized to
112
- hardwareConcurrency. Each worker owns an isolated WASM instance with no shared
113
- memory between workers.
66
+ Each module ships as its own subpath export. Bundlers with tree-shaking support and `"sideEffects": false` drop every module you don't import.
114
67
 
115
- ```sh
116
- bun i -g lvthn # or npm slow mode
117
- lvthn keygen --armor -o my.key
118
- cat secret.txt | lvthn encrypt -k my.key --armor > secret.enc
68
+ ```typescript
69
+ // Only serpent.wasm + sha2.wasm end up in your bundle
70
+ import { serpentInit } from 'leviathan-crypto/serpent'
71
+ import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
72
+ import { sha2Init } from 'leviathan-crypto/sha2'
73
+ import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
74
+
75
+ await serpentInit(serpentWasm)
76
+ await sha2Init(sha2Wasm)
77
+
78
+ // ML-KEM requires kyber + sha3
79
+ import { kyberInit } from 'leviathan-crypto/kyber'
80
+ import { kyberWasm } from 'leviathan-crypto/kyber/embedded'
81
+ import { sha3Init } from 'leviathan-crypto/sha3'
82
+ import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
83
+
84
+ await kyberInit(kyberWasm)
85
+ await sha3Init(sha3Wasm)
119
86
  ```
120
- *[`lvthncli-serpent`](https://github.com/xero/leviathan-demos/tree/main/lvthncli-serpent) and [`lvthncli-chacha`](https://github.com/xero/leviathan-demos/tree/main/lvthncli-chacha) are additional educational tools: structurally identical to the main CLI tool, each implementing only a single cipher. By comparing the two, you can pinpoint the exact changes that occur when primitives are swapped; these are limited to `src/pool.ts` and `src/worker.ts`.*
121
87
 
122
- ---
123
-
124
- ## Primitives
125
-
126
- | Class | Module | Auth | Notes |
127
- | ----------------------------------------------------------- | ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
128
- | **Authenticated encryption** | | | |
129
- | `SerpentSeal` | `serpent`, `sha2` | **Yes** | Serpent-CBC + HMAC-SHA256. Recommended Serpent default. 64-byte key. |
130
- | `XChaCha20Seal` | `chacha20` | **Yes** | XChaCha20-Poly1305 with internal nonce management. Recommended ChaCha20 default. 32-byte key. |
131
- | `SerpentStream`, `SerpentStreamPool` | `serpent`, `sha2` | **Yes** | Chunked one-shot AEAD for large payloads. Pool variant parallelises across workers. 32-byte key. |
132
- | `SerpentStreamSealer`, `SerpentStreamOpener` | `serpent`, `sha2` | **Yes** | Incremental streaming AEAD: seal/open one chunk at a time. Pass `{ framed: true }` for self-delimiting `u32be` length-prefix framing. 64-byte key. |
133
- | `XChaCha20StreamSealer`, `XChaCha20StreamOpener` | `chacha20` | **Yes** | Incremental streaming AEAD using XChaCha20-Poly1305. Per-chunk random nonces, position-bound AAD. `{ framed: true }` for length-prefixed framing. 32-byte key. |
134
- | `XChaCha20Poly1305Pool` | `chacha20` | **Yes** | Worker-pool wrapper for `XChaCha20Poly1305`. Parallelises encryption across isolated WASM instances. |
135
- | **Stateless primitives** _caller manages nonces_ | | | |
136
- | `XChaCha20Poly1305` | `chacha20` | **Yes** | RFC-faithful stateless AEAD. 24-byte nonce, caller-managed. Use `XChaCha20Seal` unless you need explicit nonce control. |
137
- | `ChaCha20Poly1305` | `chacha20` | **Yes** | RFC 8439 stateless AEAD. 12-byte nonce, caller-managed. Prefer `XChaCha20Seal` unless you need RFC 8439 exact compliance. |
138
- | **Unauthenticated primitives** _pair with HMAC or use AEAD_ | | | |
139
- | `Serpent` | `serpent` | **No** | Serpent-256 ECB block cipher. Single-block encrypt/decrypt. |
140
- | `SerpentCtr` | `serpent` | **No** | Serpent-256 CTR mode stream cipher. Requires `{ dangerUnauthenticated: true }`. |
141
- | `SerpentCbc` | `serpent` | **No** | Serpent-256 CBC mode with PKCS7 padding. Requires `{ dangerUnauthenticated: true }`. |
142
- | `ChaCha20` | `chacha20` | **No** | ChaCha20 stream cipher — RFC 8439. Unauthenticated; use `XChaCha20Seal` unless you need raw keystream. |
143
- | `Poly1305` | `chacha20` | **No** | Poly1305 one-time MAC — RFC 8439. Use via the AEAD classes unless you have a specific reason not to. |
144
- | **Hashing and key derivation** | | | |
145
- | `SHA256`, `SHA384`, `SHA512` | `sha2` | — | SHA-2 family — FIPS 180-4. |
146
- | `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512` | `sha2` | — | HMAC construction over SHA-2 — RFC 2104. |
147
- | `HKDF_SHA256`, `HKDF_SHA512` | `sha2` | — | Extract-and-expand key derivation over HMAC — RFC 5869. |
148
- | `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512` | `sha3` | — | SHA-3 family — FIPS 202. Keccak-based, structurally independent of SHA-2. |
149
- | `SHAKE128`, `SHAKE256` | `sha3` | — | Extendable output functions (XOF) — FIPS 202. Variable-length output; useful for key derivation and stream generation. |
150
- | **CSPRNG** | | | |
151
- | `Fortuna` | `serpent`, `sha2` | — | Fortuna CSPRNG (Ferguson & Schneier). 32 entropy pools, forward secrecy. Use `Fortuna.create()`. |
152
-
153
- > [!IMPORTANT]
154
- > All cryptographic computation runs in WASM (AssemblyScript), isolated outside the JavaScript JIT. The TypeScript layer provides the public API with input validation, type safety, and developer ergonomics.
88
+ | Subpath | Entry point |
89
+ | ------------------------------------ | ------------------------------ |
90
+ | `leviathan-crypto` | `./dist/index.js` |
91
+ | `leviathan-crypto/stream` | `./dist/stream/index.js` |
92
+ | `leviathan-crypto/serpent` | `./dist/serpent/index.js` |
93
+ | `leviathan-crypto/serpent/embedded` | `./dist/serpent/embedded.js` |
94
+ | `leviathan-crypto/chacha20` | `./dist/chacha20/index.js` |
95
+ | `leviathan-crypto/chacha20/embedded` | `./dist/chacha20/embedded.js` |
96
+ | `leviathan-crypto/sha2` | `./dist/sha2/index.js` |
97
+ | `leviathan-crypto/sha2/embedded` | `./dist/sha2/embedded.js` |
98
+ | `leviathan-crypto/sha3` | `./dist/sha3/index.js` |
99
+ | `leviathan-crypto/sha3/embedded` | `./dist/sha3/embedded.js` |
100
+ | `leviathan-crypto/kyber` | `./dist/kyber/index.js` |
101
+ | `leviathan-crypto/kyber/embedded` | `./dist/kyber/embedded.js` |
102
+
103
+ See [loader.md](https://github.com/xero/leviathan-crypto/wiki/loader) for the full WASM loading reference.
155
104
 
156
105
  ---
157
106
 
158
107
  ## Quick Start
159
108
 
160
- ### Authenticated encryption with Serpent
109
+ *One-shot authenticated encryption.* [`Seal`](https://github.com/xero/leviathan-crypto/wiki/aead.md#seal) handles nonces, key derivation, and authentication. Zero config beyond [`init()`](https://github.com/xero/leviathan-crypto/wiki/init.md#init).
161
110
 
162
111
  ```typescript
163
- import { init, SerpentSeal, randomBytes } from 'leviathan-crypto'
112
+ import { init, Seal, XChaCha20Cipher } from 'leviathan-crypto'
113
+ import { chacha20Wasm } from 'leviathan-crypto/chacha20/embedded'
114
+ import { sha2Wasm } from 'leviathan-crypto/sha2/embedded'
164
115
 
165
- await init(['serpent', 'sha2'])
116
+ await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
166
117
 
167
- const key = randomBytes(64) // 64-byte key (encKey + macKey)
118
+ const key = XChaCha20Cipher.keygen()
119
+ const blob = Seal.encrypt(XChaCha20Cipher, key, plaintext)
120
+ const pt = Seal.decrypt(XChaCha20Cipher, key, blob) // throws AuthenticationError on tamper
121
+ ```
168
122
 
169
- const seal = new SerpentSeal()
123
+ _Prefer Serpent-256?_ Swap the cipher object and everything else stays the same.
170
124
 
171
- // Encrypt and authenticate
172
- const ciphertext = seal.encrypt(key, plaintext)
125
+ ```typescript
126
+ import { SerpentCipher } from 'leviathan-crypto'
127
+ import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
173
128
 
174
- // Decrypt and verify (throws on tamper)
175
- const decrypted = seal.decrypt(key, ciphertext)
129
+ await init({ serpent: serpentWasm, sha2: sha2Wasm })
176
130
 
177
- seal.dispose()
131
+ const key = SerpentCipher.keygen()
132
+ const blob = Seal.encrypt(SerpentCipher, key, plaintext)
178
133
  ```
179
134
 
180
- ### Authenticated encryption with XChaCha20
135
+ _Data too large to buffer in memory?_ [`SealStream`](https://github.com/xero/leviathan-crypto/wiki/aead.md#sealstream) and [`OpenStream`](https://github.com/xero/leviathan-crypto/wiki/aead.md#openstream) encrypt and decrypt in chunks without loading the full message.
181
136
 
182
137
  ```typescript
183
- import { init, XChaCha20Seal, randomBytes } from 'leviathan-crypto'
138
+ import { SealStream, OpenStream } from 'leviathan-crypto/stream'
184
139
 
185
- await init(['chacha20'])
140
+ const sealer = new SealStream(XChaCha20Cipher, key, { chunkSize: 65536 })
141
+ const preamble = sealer.preamble // send first
186
142
 
187
- const key = randomBytes(32) // 32-byte key
143
+ const ct0 = sealer.push(chunk0)
144
+ const ct1 = sealer.push(chunk1)
145
+ const ctLast = sealer.finalize(lastChunk)
188
146
 
189
- const seal = new XChaCha20Seal(key)
147
+ const opener = new OpenStream(XChaCha20Cipher, key, preamble)
148
+ const pt0 = opener.pull(ct0)
149
+ const pt1 = opener.pull(ct1)
150
+ const ptLast = opener.finalize(ctLast)
151
+ ```
190
152
 
191
- // Encrypt and authenticate (nonce generated internally)
192
- const ciphertext = seal.encrypt(plaintext)
153
+ _Need parallel throughput?_ [`SealStreamPool`](https://github.com/xero/leviathan-crypto/wiki/aead.md#sealstreampool) distributes chunks across Web Workers with the same wire format.
193
154
 
194
- // Decrypt and verify (throws on tamper)
195
- const decrypted = seal.decrypt(ciphertext)
155
+ ```typescript
156
+ import { SealStreamPool } from 'leviathan-crypto/stream'
196
157
 
197
- seal.dispose()
158
+ const pool = await SealStreamPool.create(XChaCha20Cipher, key, { wasm: chacha20Wasm })
159
+ const encrypted = await pool.seal(plaintext)
160
+ const decrypted = await pool.open(encrypted)
161
+ pool.destroy()
198
162
  ```
199
163
 
200
- For more examples, including streaming, chunking, hashing, and key derivation,
201
- see the [examples page](https://github.com/xero/leviathan-crypto/wiki/examples).
164
+ _Want post-quantum security?_ [`KyberSuite`](https://github.com/xero/leviathan-crypto/wiki/kyber.md#kybersuite) wraps ML-KEM and a cipher suite into a hybrid construction. It plugs directly into [`SealStream`](https://github.com/xero/leviathan-crypto/wiki/aead.md#sealstream). The sender encrypts with the public encapsulation key and only the recipient's private decapsulation key can open it.
202
165
 
203
- ---
166
+ ```typescript
167
+ import { KyberSuite, MlKem768 } from 'leviathan-crypto/kyber'
168
+ import { kyberWasm } from 'leviathan-crypto/kyber/embedded'
169
+ import { sha3Wasm } from 'leviathan-crypto/sha3/embedded'
204
170
 
205
- ## Loading Modes
171
+ await init({ kyber: kyberWasm, sha3: sha3Wasm, chacha20: chacha20Wasm, sha2: sha2Wasm })
206
172
 
207
- ```typescript
208
- // Embedded (default): zero-config, base64-encoded WASM inline
209
- await init(['serpent', 'sha3'])
173
+ const suite = KyberSuite(new MlKem768(), XChaCha20Cipher)
174
+ const { encapsulationKey: ek, decapsulationKey: dk } = suite.keygen()
210
175
 
211
- // Streaming: uses instantiateStreaming for performance
212
- await init(['serpent'], 'streaming', { wasmUrl: '/assets/wasm/' })
176
+ // sender encrypts with the public key
177
+ const sealer = new SealStream(suite, ek)
178
+ const preamble = sealer.preamble // 1108 bytes: 20B header + 1088B KEM ciphertext
179
+ const ct0 = sealer.push(chunk0)
180
+ const ctLast = sealer.finalize(lastChunk)
213
181
 
214
- // Manual: provide your own binary
215
- await init(['serpent'], 'manual', { wasmBinary: { serpent: myBuffer } })
182
+ // recipient decrypts with the private key
183
+ const opener = new OpenStream(suite, dk, preamble)
184
+ const pt0 = opener.pull(ct0)
185
+ const ptLast = opener.finalize(ctLast)
216
186
  ```
217
187
 
218
- ### Tree-shaking with subpath imports
188
+ _More examples including hashing, key derivation, Fortuna, and raw primitives?_ See the [examples page](https://github.com/xero/leviathan-crypto/wiki/examples).
219
189
 
220
- Each cipher ships as its own subpath export. A bundler with tree-shaking
221
- support and `"sideEffects": false` will exclude every module you don't import:
190
+ ---
222
191
 
223
- ```typescript
224
- // Only serpent.wasm ends up in your bundle
225
- import { serpentInit, SerpentSeal } from 'leviathan-crypto/serpent'
226
- await serpentInit()
192
+ ## Demos
227
193
 
228
- // Only chacha20.wasm ends up in your bundle
229
- import { chacha20Init, XChaCha20Seal } from 'leviathan-crypto/chacha20'
230
- await chacha20Init()
194
+ **`lvthn-web`** [ [demo](https://leviathan.3xi.club/web) · [source](https://github.com/xero/leviathan-demos/tree/main/web) · [readme](https://github.com/xero/leviathan-demos/blob/main/web/README.md) ]
195
+
196
+ A self-contained browser encryption tool in a single HTML file. Encrypt text or files with Serpent-256-CBC and Argon2id key derivation, then share the armored output. No server, no install, no network connection after initial load. The code is written to be read. The Encrypt-then-MAC construction, HMAC input, and Argon2id parameters are all intentional examples worth studying.
197
+
198
+ **`lvthn-chat`** [ [demo](https://leviathan.3xi.club/chat) · [source](https://github.com/xero/leviathan-demos/tree/main/chat) · [readme](https://github.com/xero/leviathan-demos/blob/main/chat/README.md) ]
199
+
200
+ End-to-end encrypted chat over X25519 key exchange and XChaCha20-Poly1305 message encryption. The relay server is a dumb WebSocket pipe that never sees plaintext. Messages carry sequence numbers so the protocol detects and rejects replayed messages. The demo deconstructs the protocol step by step with visual feedback for injection and replay attacks.
201
+
202
+ **`lvthn-cli`** [ [npm](https://www.npmjs.com/package/lvthn) · [source](https://github.com/xero/leviathan-demos/tree/main/lvthn-cli) · [readme](https://github.com/xero/leviathan-demos/blob/main/lvthn-cli/README.md) ]
203
+
204
+ File encryption CLI supporting both Serpent-256 and XChaCha20-Poly1305 via `--cipher`. A single keyfile works with both ciphers. The header byte determines decryption automatically. Chunks distribute across a worker pool sized to `hardwareConcurrency`. Each worker owns an isolated WASM instance with no shared memory.
205
+
206
+ ```sh
207
+ bun i -g lvthn # or npm slow mode
208
+ lvthn keygen --armor -o my.key
209
+ cat secret.txt | lvthn encrypt -k my.key --armor > secret.enc
231
210
  ```
232
211
 
233
- | Subpath | Entry point |
234
- | --------------------------- | -------------------------- |
235
- | `leviathan-crypto` | `./dist/index.js` |
236
- | `leviathan-crypto/serpent` | `./dist/serpent/index.js` |
237
- | `leviathan-crypto/chacha20` | `./dist/chacha20/index.js` |
238
- | `leviathan-crypto/sha2` | `./dist/sha2/index.js` |
239
- | `leviathan-crypto/sha3` | `./dist/sha3/index.js` |
212
+ ---
213
+
214
+ ## Highlights
215
+
216
+ | **_I want to..._** | |
217
+ |---|---|
218
+ | Encrypt data | [`Seal`](https://github.com/xero/leviathan-crypto/wiki/aead.md#seal) with [`SerpentCipher`](https://github.com/xero/leviathan-crypto/wiki/serpent.md#serpentcipher) or [`XChaCha20Cipher`](https://github.com/xero/leviathan-crypto/wiki/chacha20.md#xchacha20cipher) |
219
+ | Encrypt a stream or large file | [`SealStream`](https://github.com/xero/leviathan-crypto/wiki/aead.md#sealstream) to encrypt, [`OpenStream`](https://github.com/xero/leviathan-crypto/wiki/aead.md#openstream) to decrypt |
220
+ | Encrypt in parallel | [`SealStreamPool`](https://github.com/xero/leviathan-crypto/wiki/aead.md#sealstreampool) distributes chunks across Web Workers |
221
+ | Add post-quantum security | [`KyberSuite`](https://github.com/xero/leviathan-crypto/wiki/kyber.md#kybersuite) wraps [`MlKem512`](https://github.com/xero/leviathan-crypto/wiki/kyber.md#parameter-sets), [`MlKem768`](https://github.com/xero/leviathan-crypto/wiki/kyber.md#parameter-sets), or [`MlKem1024`](https://github.com/xero/leviathan-crypto/wiki/kyber.md#parameter-sets) with any cipher suite |
222
+ | Hash data | [`SHA256`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#sha256), [`SHA384`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#sha384), [`SHA512`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#sha512), [`SHA3_256`](https://github.com/xero/leviathan-crypto/wiki/sha3.md#sha3_256), [`SHA3_512`](https://github.com/xero/leviathan-crypto/wiki/sha3.md#sha3_512), [`SHAKE256`](https://github.com/xero/leviathan-crypto/wiki/sha3.md#shake256) ... |
223
+ | Authenticate a message | [`HMAC_SHA256`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#hmac_sha256), [`HMAC_SHA384`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#hmac_sha384), or [`HMAC_SHA512`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#hmac_sha512) |
224
+ | Derive keys | [`HKDF_SHA256`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#hkdf_sha256) or [`HKDF_SHA512`](https://github.com/xero/leviathan-crypto/wiki/sha2.md#hkdf_sha512) |
225
+ | Generate random bytes | [`Fortuna`](https://github.com/xero/leviathan-crypto/wiki/fortuna.md#api-reference) for forward-secret generation, [`randomBytes`](https://github.com/xero/leviathan-crypto/wiki/utils.md#randombytes) for one-off use |
226
+ | Compare secrets safely | [`constantTimeEqual`](https://github.com/xero/leviathan-crypto/wiki/utils.md#constanttimeequal) uses a WASM SIMD path to prevent timing attacks |
227
+ | Work with bytes | [`hexToBytes`](https://github.com/xero/leviathan-crypto/wiki/utils.md#hextobytes), [`bytesToHex`](https://github.com/xero/leviathan-crypto/wiki/utils.md#bytestohex), [`wipe`](https://github.com/xero/leviathan-crypto/wiki/utils.md#wipe), [`xor`](https://github.com/xero/leviathan-crypto/wiki/utils.md#xor), [`concat`](https://github.com/xero/leviathan-crypto/wiki/utils.md#concat) ... |
228
+
229
+ *For raw primitives, low-level cipher access, and ASM internals see the [full API reference](https://github.com/xero/leviathan-crypto/wiki/index).*
240
230
 
241
231
  ---
242
232
 
243
- ## Documentation
244
-
245
- | Document | MD/Wiki | Description |
246
- | ------------ | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
247
- | architecture | [](./docs/architecture.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/architecture) | Architecture overview, build pipeline, module relationships |
248
- | test-suite | [▼](./docs/test-suite.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/test-suite) | Test suite structure, vector corpus, gate discipline |
249
- | security | [▼](./SECURITY.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/security_policy) | Project security policy covering posture, disclosure, and scopes |
250
-
251
- ### API Surface
252
-
253
- | Module | MD/Wiki | Description |
254
- | ----------- | ------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
255
- | serpent | [▼](./docs/serpent.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/serpent) | Serpent-256 TypeScript API (`SerpentSeal`, `SerpentStream`, `SerpentStreamPool`, `SerpentStreamSealer`, `SerpentStreamOpener`, `Serpent`, `SerpentCtr`, `SerpentCbc`) |
256
- | asm_serpent | [▼](./docs/asm_serpent.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/asm_serpent) | Serpent-256 WASM implementation (bitslice S-boxes, key schedule, CTR/CBC) |
257
- | chacha20 | [▼](./docs/chacha20.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/chacha20) | ChaCha20/Poly1305 TypeScript API (`XChaCha20Seal`, `XChaCha20StreamSealer`, `XChaCha20StreamOpener`, `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`, `XChaCha20Poly1305Pool`) |
258
- | asm_chacha | [▼](./docs/asm_chacha.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/asm_chacha) | ChaCha20/Poly1305 WASM implementation (quarter-round, HChaCha20) |
259
- | sha2 | [▼](./docs/sha2.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/sha2) | SHA-2 TypeScript API (`SHA256`, `SHA512`, `SHA384`, `HMAC_SHA256`, `HMAC_SHA512`, `HMAC_SHA384`) |
260
- | asm_sha2 | [▼](./docs/asm_sha2.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/asm_sha2) | SHA-2 WASM implementation (compression functions, HMAC) |
261
- | sha3 | [▼](./docs/sha3.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/sha3) | SHA-3 TypeScript API (`SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256`) |
262
- | asm_sha3 | [▼](./docs/asm_sha3.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/asm_sha3) | SHA-3 WASM implementation (Keccak-f[1600], sponge construction) |
263
- | fortuna | [▼](./docs/fortuna.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/fortuna) | Fortuna CSPRNG (forward secrecy, 32 entropy pools) |
264
- | init | [▼](./docs/init.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/init) | `init()` API and WASM loading modes |
265
- | utils | [▼](./docs/utils.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils) | Encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes` |
266
- | types | [▼](./docs/types.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/types) | TypeScript interfaces (`Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD`) |
267
-
268
- ### Utilities
269
-
270
- These helpers are available immediately on import with no `init()` required.
271
-
272
- | Function | MD/Wiki | Description |
273
- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
274
- | `hexToBytes(hex)` | [▼](./docs/utils.md#hextobytes) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#hextobytes) | Hex string to `Uint8Array` (accepts uppercase, `0x` prefix) |
275
- | `bytesToHex(bytes)` | [▼](./docs/utils.md#bytestohex) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#bytestohex) | `Uint8Array` to lowercase hex string |
276
- | `utf8ToBytes(str)` | [▼](./docs/utils.md#utf8tobytes) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#utf8tobytes) | UTF-8 string to `Uint8Array` |
277
- | `bytesToUtf8(bytes)` | [▼](./docs/utils.md#bytestoutf8) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#bytestoutf8) | `Uint8Array` to UTF-8 string |
278
- | `base64ToBytes(b64)` | [▼](./docs/utils.md#base64tobytes) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#base64tobytes) | Base64/base64url string to `Uint8Array` (undefined on invalid) |
279
- | `bytesToBase64(bytes, url?)` | [▼](./docs/utils.md#bytestobase64) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#bytestobase64) | `Uint8Array` to base64 string (url=true for base64url) |
280
- | `constantTimeEqual(a, b)` | [▼](./docs/utils.md#constanttimeequal) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#constanttimeequal) | Constant-time byte comparison (XOR-accumulate) |
281
- | `wipe(data)` | [▼](./docs/utils.md#wipe) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#wipe) | Zero a typed array in place |
282
- | `xor(a, b)` | [▼](./docs/utils.md#xor) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#xor) | XOR two equal-length `Uint8Array`s |
283
- | `concat(...arrays)` | [▼](./docs/utils.md#concat) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#concat) | Concatenate `Uint8Array`s (variadic) |
284
- | `hasSIMD()` | [▼](./docs/utils.md#hassimd) · [¶](https://github.com/xero/leviathan-crypto/wiki/utils#hassimd) | Detects WebAssembly SIMD support. Cached after first call. Used internally for CTR/CBC/ChaCha20 dispatch. |
285
-
286
- ### Algorithm correctness and verifications
287
-
288
- | Primitive | MD/Wiki | Description |
289
- | ------------- | ----------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
290
- | serpent_audit | [▼](./docs/serpent_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/serpent_audit) | Correctness verification, side-channel analysis, cryptanalytic paper review |
291
- | chacha_audit | [▼](./docs/chacha_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/chacha_audit) | XChaCha20-Poly1305 correctness, Poly1305 field arithmetic, HChaCha20 nonce extension |
292
- | sha2_audit | [▼](./docs/sha2_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/sha2_audit) | SHA-256/512/384 correctness, HMAC and HKDF composition, constant verification |
293
- | sha3_audit | [▼](./docs/sha3_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/sha3_audit) | Keccak permutation correctness, θ/ρ/π/χ/ι step verification, round constant derivation |
294
- | hmac_audit | [▼](./docs/hmac_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/hmac_audit) | HMAC-SHA256/512/384 construction, key processing, RFC 4231 vector coverage |
295
- | hkdf_audit | [▼](./docs/hkdf_audit.md) · [¶](https://github.com/xero/leviathan-crypto/wiki/hkdf_audit) | HKDF extract-then-expand, info field domain separation, SerpentStream key derivation |
296
-
297
- >[!NOTE]
298
- > Additional documentation available in [./docs](./docs/README.md) and on the
299
- > [project wiki](https://github.com/xero/leviathan-crypto/wiki/).
233
+ ## Going deeper
234
+
235
+ | | |
236
+ |---|---|
237
+ | [Architecture](https://github.com/xero/leviathan-crypto/wiki/architecture.md) | Repository structure, module relationships, build pipeline, and buffer layouts |
238
+ | [Test Suite](https://github.com/xero/leviathan-crypto/wiki/test-suite.md) | How the test suite works, vector corpus, and gate discipline |
239
+ | [Security Policy](./SECURITY.md) | Security posture and vulnerability disclosure details |
240
+ | [Lexicon](https://github.com/xero/leviathan-crypto/wiki/lexicon.md) | Glossary of cryptographic terms |
241
+ | [WASM Primer](https://github.com/xero/leviathan-crypto/wiki/wasm.md) | WebAssembly primer in the context of this library |
242
+ | [CDN](https://github.com/xero/leviathan-crypto/wiki/cdn.md) | Use leviathan-crypto directly from a CDN with no bundler |
243
+ | [argon2id](https://github.com/xero/leviathan-crypto/wiki/argon2id.md) | Passphrase-based encryption using Argon2id alongside leviathan primitives |
300
244
 
301
245
  ---
302
246
 
@@ -326,4 +270,3 @@ leviathan-crypto is released under the [MIT license](./LICENSE).
326
270
  ▀██████▀ ▀████▄▄▄████▀
327
271
  ▀█████▀
328
272
  ```
329
-