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.
- package/CLAUDE.md +129 -94
- package/README.md +166 -223
- package/SECURITY.md +85 -45
- package/dist/chacha20/cipher-suite.d.ts +4 -0
- package/dist/chacha20/cipher-suite.js +78 -0
- package/dist/chacha20/embedded.d.ts +1 -0
- package/dist/chacha20/embedded.js +27 -0
- package/dist/chacha20/index.d.ts +20 -27
- package/dist/chacha20/index.js +40 -59
- package/dist/chacha20/ops.d.ts +1 -1
- package/dist/chacha20/ops.js +19 -18
- package/dist/chacha20/pool-worker.js +77 -0
- package/dist/ct-wasm.d.ts +1 -0
- package/dist/ct-wasm.js +3 -0
- package/dist/ct.wasm +0 -0
- package/dist/docs/aead.md +320 -0
- package/dist/docs/architecture.md +419 -285
- package/dist/docs/argon2id.md +42 -30
- package/dist/docs/chacha20.md +192 -266
- package/dist/docs/exports.md +241 -0
- package/dist/docs/fortuna.md +60 -69
- package/dist/docs/init.md +172 -178
- package/dist/docs/loader.md +87 -142
- package/dist/docs/serpent.md +134 -583
- package/dist/docs/sha2.md +91 -103
- package/dist/docs/sha3.md +70 -36
- package/dist/docs/types.md +93 -16
- package/dist/docs/utils.md +109 -32
- package/dist/embedded/kyber.d.ts +1 -0
- package/dist/embedded/kyber.js +3 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +38 -0
- package/dist/fortuna.d.ts +0 -6
- package/dist/fortuna.js +5 -5
- package/dist/index.d.ts +25 -9
- package/dist/index.js +36 -7
- package/dist/init.d.ts +3 -7
- package/dist/init.js +18 -35
- package/dist/keccak/embedded.d.ts +1 -0
- package/dist/keccak/embedded.js +27 -0
- package/dist/keccak/index.d.ts +4 -0
- package/dist/keccak/index.js +31 -0
- package/dist/kyber/embedded.d.ts +1 -0
- package/dist/kyber/embedded.js +27 -0
- package/dist/kyber/indcpa.d.ts +49 -0
- package/dist/kyber/indcpa.js +352 -0
- package/dist/kyber/index.d.ts +38 -0
- package/dist/kyber/index.js +150 -0
- package/dist/kyber/kem.d.ts +21 -0
- package/dist/kyber/kem.js +160 -0
- package/dist/kyber/params.d.ts +14 -0
- package/dist/kyber/params.js +37 -0
- package/dist/kyber/suite.d.ts +13 -0
- package/dist/kyber/suite.js +93 -0
- package/dist/kyber/types.d.ts +98 -0
- package/dist/kyber/types.js +25 -0
- package/dist/kyber/validate.d.ts +19 -0
- package/dist/kyber/validate.js +68 -0
- package/dist/kyber.wasm +0 -0
- package/dist/loader.d.ts +15 -6
- package/dist/loader.js +65 -21
- package/dist/serpent/cipher-suite.d.ts +4 -0
- package/dist/serpent/cipher-suite.js +121 -0
- package/dist/serpent/embedded.d.ts +1 -0
- package/dist/serpent/embedded.js +27 -0
- package/dist/serpent/index.d.ts +6 -37
- package/dist/serpent/index.js +9 -118
- package/dist/serpent/pool-worker.d.ts +1 -0
- package/dist/serpent/pool-worker.js +202 -0
- package/dist/serpent/serpent-cbc.d.ts +30 -0
- package/dist/serpent/serpent-cbc.js +136 -0
- package/dist/sha2/embedded.d.ts +1 -0
- package/dist/sha2/embedded.js +27 -0
- package/dist/sha2/hkdf.js +6 -2
- package/dist/sha2/index.d.ts +3 -2
- package/dist/sha2/index.js +3 -4
- package/dist/sha3/embedded.d.ts +1 -0
- package/dist/sha3/embedded.js +27 -0
- package/dist/sha3/index.d.ts +3 -2
- package/dist/sha3/index.js +3 -4
- package/dist/stream/constants.d.ts +6 -0
- package/dist/stream/constants.js +30 -0
- package/dist/stream/header.d.ts +9 -0
- package/dist/stream/header.js +77 -0
- package/dist/stream/index.d.ts +7 -0
- package/dist/stream/index.js +27 -0
- package/dist/stream/open-stream.d.ts +21 -0
- package/dist/stream/open-stream.js +146 -0
- package/dist/stream/seal-stream-pool.d.ts +38 -0
- package/dist/stream/seal-stream-pool.js +391 -0
- package/dist/stream/seal-stream.d.ts +20 -0
- package/dist/stream/seal-stream.js +142 -0
- package/dist/stream/seal.d.ts +9 -0
- package/dist/stream/seal.js +75 -0
- package/dist/stream/types.d.ts +24 -0
- package/dist/stream/types.js +26 -0
- package/dist/utils.d.ts +7 -2
- package/dist/utils.js +49 -3
- package/dist/wasm-source.d.ts +12 -0
- package/dist/wasm-source.js +26 -0
- package/package.json +13 -5
- package/dist/chacha20/pool.d.ts +0 -52
- package/dist/chacha20/pool.js +0 -178
- package/dist/chacha20/pool.worker.js +0 -37
- package/dist/chacha20/stream-sealer.d.ts +0 -49
- package/dist/chacha20/stream-sealer.js +0 -327
- package/dist/docs/chacha20_pool.md +0 -309
- package/dist/docs/wasm.md +0 -194
- package/dist/serpent/seal.d.ts +0 -8
- package/dist/serpent/seal.js +0 -72
- package/dist/serpent/stream-pool.d.ts +0 -48
- package/dist/serpent/stream-pool.js +0 -275
- package/dist/serpent/stream-sealer.d.ts +0 -55
- package/dist/serpent/stream-sealer.js +0 -342
- package/dist/serpent/stream.d.ts +0 -28
- package/dist/serpent/stream.js +0 -205
- package/dist/serpent/stream.worker.d.ts +0 -32
- package/dist/serpent/stream.worker.js +0 -117
- /package/dist/chacha20/{pool.worker.d.ts → pool-worker.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
[](https://github.com/xero/leviathan-crypto/releases/latest) [](https://www.npmjs.com/package/leviathan-crypto) [](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml) [](https://github.com/xero/leviathan-crypto/wiki)
|
|
1
|
+
[](https://github.com/xero/leviathan-crypto/releases/latest) [](https://www.npmjs.com/package/leviathan-crypto) [](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml) [](https://github.com/xero/leviathan-crypto/wiki)
|
|
2
2
|
|
|
3
3
|
    [](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
61
|
-
exclude everything else.
|
|
23
|
+
**Zero dependencies.** No npm graph to audit. No supply chain attack surface.
|
|
62
24
|
|
|
63
|
-
|
|
25
|
+
**Tree-shakeable.** Import only what you use. Subpath exports let bundlers exclude everything else.
|
|
64
26
|
|
|
65
|
-
Nothing runs
|
|
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
|
-
>
|
|
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
|
-
|
|
47
|
+
Three loading strategies are available. Choose based on your runtime and bundler setup.
|
|
87
48
|
|
|
88
|
-
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
-
|
|
100
|
-
|
|
101
|
-
|
|
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
|
-
|
|
64
|
+
### Tree-shaking with subpath imports
|
|
107
65
|
|
|
108
|
-
|
|
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
|
-
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
125
|
-
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
|
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
|
|
|
136
|
-
|
|
137
|
-
|
|
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
|
-
|
|
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,
|
|
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(
|
|
116
|
+
await init({ chacha20: chacha20Wasm, sha2: sha2Wasm })
|
|
166
117
|
|
|
167
|
-
const key
|
|
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
|
-
|
|
123
|
+
_Prefer Serpent-256?_ Swap the cipher object and everything else stays the same.
|
|
170
124
|
|
|
171
|
-
|
|
172
|
-
|
|
125
|
+
```typescript
|
|
126
|
+
import { SerpentCipher } from 'leviathan-crypto'
|
|
127
|
+
import { serpentWasm } from 'leviathan-crypto/serpent/embedded'
|
|
173
128
|
|
|
174
|
-
|
|
175
|
-
const decrypted = seal.decrypt(key, ciphertext)
|
|
129
|
+
await init({ serpent: serpentWasm, sha2: sha2Wasm })
|
|
176
130
|
|
|
177
|
-
|
|
131
|
+
const key = SerpentCipher.keygen()
|
|
132
|
+
const blob = Seal.encrypt(SerpentCipher, key, plaintext)
|
|
178
133
|
```
|
|
179
134
|
|
|
180
|
-
|
|
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 {
|
|
138
|
+
import { SealStream, OpenStream } from 'leviathan-crypto/stream'
|
|
184
139
|
|
|
185
|
-
|
|
140
|
+
const sealer = new SealStream(XChaCha20Cipher, key, { chunkSize: 65536 })
|
|
141
|
+
const preamble = sealer.preamble // send first
|
|
186
142
|
|
|
187
|
-
const
|
|
143
|
+
const ct0 = sealer.push(chunk0)
|
|
144
|
+
const ct1 = sealer.push(chunk1)
|
|
145
|
+
const ctLast = sealer.finalize(lastChunk)
|
|
188
146
|
|
|
189
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
195
|
-
|
|
155
|
+
```typescript
|
|
156
|
+
import { SealStreamPool } from 'leviathan-crypto/stream'
|
|
196
157
|
|
|
197
|
-
|
|
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
|
-
|
|
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
|
-
|
|
171
|
+
await init({ kyber: kyberWasm, sha3: sha3Wasm, chacha20: chacha20Wasm, sha2: sha2Wasm })
|
|
206
172
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
await init(['serpent', 'sha3'])
|
|
173
|
+
const suite = KyberSuite(new MlKem768(), XChaCha20Cipher)
|
|
174
|
+
const { encapsulationKey: ek, decapsulationKey: dk } = suite.keygen()
|
|
210
175
|
|
|
211
|
-
//
|
|
212
|
-
|
|
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
|
-
//
|
|
215
|
-
|
|
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
|
-
|
|
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
|
-
|
|
221
|
-
support and `"sideEffects": false` will exclude every module you don't import:
|
|
190
|
+
---
|
|
222
191
|
|
|
223
|
-
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
|
238
|
-
|
|
239
|
-
| `leviathan-crypto/
|
|
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
|
-
##
|
|
244
|
-
|
|
245
|
-
|
|
|
246
|
-
|
|
247
|
-
|
|
|
248
|
-
|
|
|
249
|
-
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
|
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
|
-
|