leviathan-crypto 1.0.0 → 1.1.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/README.md +187 -253
- package/dist/docs/architecture.md +15 -15
- package/dist/docs/argon2id.md +8 -8
- package/dist/docs/chacha20.md +8 -8
- package/dist/docs/chacha20_pool.md +8 -8
- package/dist/docs/fortuna.md +9 -9
- package/dist/docs/init.md +6 -6
- package/dist/docs/loader.md +6 -6
- package/dist/docs/serpent.md +11 -11
- package/dist/docs/sha2.md +10 -10
- package/dist/docs/sha3.md +7 -7
- package/dist/docs/types.md +10 -10
- package/dist/docs/utils.md +10 -10
- package/dist/docs/wasm.md +8 -8
- package/dist/sha2/hkdf.js +14 -2
- package/package.json +1 -33
package/README.md
CHANGED
|
@@ -1,256 +1,142 @@
|
|
|
1
|
-
[](https://github.com/xero/leviathan-crypto/releases/latest)
|
|
3
|
-
[](https://github.com/xero/leviathan-crypto/)
|
|
4
|
-
[](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml)
|
|
5
|
-
[](https://github.com/xero/leviathan-crypto/wiki)
|
|
6
|
-
|
|
7
|
-
<img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="Leviathan logo" width="400">
|
|
8
|
-
|
|
9
|
-
# Leviathan-Crypto: Serpent-256 & XChaCha20-Poly1305 Cryptography for the Web
|
|
10
|
-
|
|
11
|
-
Serpent-256, the most conservative AES finalist, employs 32 rounds and a
|
|
12
|
-
maximum security margin, built to withstand future cryptanalytic advancements.
|
|
13
|
-
Paired with the streamlined brilliance of ChaCha20-Poly1305, and complemented
|
|
14
|
-
by SHA-2 and SHA-3. Two design philosophies, four cryptographic primitives,
|
|
15
|
-
integrated into one coherent API.
|
|
16
|
-
|
|
17
|
-
**WebAssembly (WASM) serves as the correctness layer.** It features spec-driven and
|
|
18
|
-
vector-verified AssemblyScript implementations of Serpent-256, ChaCha20/Poly1305,
|
|
19
|
-
SHA-2, and SHA-3. Each cryptographic primitive is compiled into its own isolated
|
|
20
|
-
binary, executing outside the JavaScript JIT. This ensures no speculative
|
|
21
|
-
optimization affects key material and eliminates data-dependent timing
|
|
22
|
-
vulnerabilities from table lookups.
|
|
23
|
-
|
|
24
|
-
**TypeScript acts as the ergonomics layer.** Fully typed classes, explicit
|
|
25
|
-
`init()` gates, input validation, and authenticated compositions
|
|
26
|
-
([`SerpentSeal`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentseal),
|
|
27
|
-
[`SerpentStream`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentstream),
|
|
28
|
-
[`SerpentStreamSealer`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentstreamsealer--serpentstreamopener))
|
|
29
|
-
ensure primitives are connected correctly, simplifying development and ensuring
|
|
30
|
-
correctness. Advanced users retain the ability to directly access the raw block
|
|
31
|
-
cipher classes.
|
|
32
|
-
|
|
33
|
-
## Why Serpent-256
|
|
34
|
-
|
|
35
|
-
Serpent-256, an AES finalist, received more first-place security votes than
|
|
36
|
-
Rijndael from the NIST evaluation committee. It was designed with a larger
|
|
37
|
-
security margin: 32 rounds compared to AES's 10, 12, or 14.
|
|
38
|
-
|
|
39
|
-
While Serpent won on security margin, AES (Rijndael) ultimately won the
|
|
40
|
-
competition due to its performance. Rijndael was selected because speed
|
|
41
|
-
was paramount for the hardware and embedded targets NIST was optimizing for
|
|
42
|
-
in 2001. However, for software running on modern hardware where milliseconds
|
|
43
|
-
of encryption latency are acceptable, this tradeoff is no longer as relevant.
|
|
44
|
-
|
|
45
|
-
**Security Margin.** Serpent has been a target of cryptanalytic research
|
|
46
|
-
since the AES competition. The current state-of-the-art is as follows:
|
|
47
|
-
|
|
48
|
-
- **Best known reduced-round attack:**
|
|
49
|
-
- multidimensional linear cryptanalysis reaching 12 of 32 rounds (Nguyen,
|
|
50
|
-
Wu & Wang, ACISP 2011), less than half the full cipher, requiring 2¹¹⁸
|
|
51
|
-
known plaintexts and 2²²⁸·⁸ time.
|
|
52
|
-
- Multidimensional linear cryptanalysis reaches 12 of 32 rounds (Nguyen,
|
|
53
|
-
Wu & Wang, ACISP 2011), less than half the full cipher. This requires
|
|
54
|
-
2¹¹⁸ known plaintexts and 2²²⁸·⁸ time. [source](https://personal.ntu.edu.sg/wuhj/research/publications/2011_ACISP_MLC.pdf) & [mirror](https://archive.is/6pwMM)
|
|
55
|
-
- **Best known full-round attack:**
|
|
56
|
-
- biclique cryptanalysis of full 32-round Serpent-256 (de Carvalho & Kowada,
|
|
57
|
-
SBSeg 2020), time complexity 2²⁵⁵·²¹, only 0.79 bits below the 256-bit
|
|
58
|
-
brute-force ceiling of 2²⁵⁶, and requires 2⁸⁸ chosen ciphertexts, making
|
|
59
|
-
it strictly less practical than brute force. For comparison, the analogous
|
|
60
|
-
biclique attack on full-round AES-256 (Bogdanov et al., 2011) reaches
|
|
61
|
-
2²⁵⁴·⁴. Serpent-256 is marginally harder to attack by this method than AES-256.
|
|
62
|
-
- Biclique cryptanalysis of full 32-round Serpent-256 (de Carvalho & Kowada,
|
|
63
|
-
SBSeg 2020) has a time complexity of 2²⁵⁵·²¹, only 0.79 bits below the 256-bit
|
|
64
|
-
brute-force ceiling of 2²⁵⁶. It requires 2⁸⁸ chosen ciphertexts, making it
|
|
65
|
-
strictly less practical than brute force. For comparison, the analogous biclique
|
|
66
|
-
attack on full-round AES-256 (Bogdanov et al., 2011) reaches 2²⁵⁴·⁴.
|
|
67
|
-
Serpent-256 is marginally harder to attack by this method than AES-256. [source](https://sol.sbc.org.br/index.php/sbseg/article/view/19225/19054) & [mirror](https://archive.is/ZZjrT)
|
|
68
|
-
- Our independent research improved the published result by
|
|
69
|
-
−0.20 bits through systematic search over v position, biclique nibble
|
|
70
|
-
selection, and nabla pair. the best configuration (K31/K17, delta nibble 0,
|
|
71
|
-
nabla nibble 10, v = state 66 nibbles 8+9) achieves 2²⁵⁵·¹⁹ with only 2⁴
|
|
72
|
-
chosen ciphertexts. The K17 nabla result is a new finding not present in
|
|
73
|
-
the published papers.
|
|
74
|
-
- Our independent research improved the published result by −0.20 bits through
|
|
75
|
-
systematic search over v position, biclique nibble selection, and nabla pair.
|
|
76
|
-
The best configuration (K31/K17, delta nibble 0, nabla nibble 10, v = state
|
|
77
|
-
66 nibbles 8+9) achieves 2²⁵⁵·¹⁹ with only 2⁴ chosen ciphertexts. The K17 nabla
|
|
78
|
-
result is a new finding not present in the published papers. [`biclique_research`](https://github.com/xero/BicliqueFinder/blob/main/biclique-research.md)
|
|
79
|
-
|
|
80
|
-
See: [`serpent_audit.md`](https://github.com/xero/leviathan-crypto/wiki/serpent_audit)
|
|
81
|
-
for the full analysis.
|
|
82
|
-
|
|
83
|
-
**Implementation.** Implementation: Serpent's S-boxes are implemented as Boolean gate
|
|
84
|
-
circuits, meaning there are no table lookups, data-dependent memory access, or
|
|
85
|
-
data-dependent branches. Every bit is processed unconditionally on every block.
|
|
86
|
-
This approach provides the most timing-safe cipher implementation available in a
|
|
87
|
-
JavaScript runtime, where JIT optimization can otherwise introduce observable
|
|
88
|
-
timing variations.
|
|
89
|
-
|
|
90
|
-
**Key Size:** The default API only supports 256-bit keys. The absence of 128 or
|
|
91
|
-
192-bit variants mitigates the risk of key-size downgrade attacks.
|
|
1
|
+
[](https://github.com/xero/leviathan-crypto/releases/latest) [](https://github.com/xero/leviathan-crypto/) [](https://github.com/xero/leviathan-crypto/actions/workflows/test-suite.yml) [](https://github.com/xero/leviathan-crypto/wiki)
|
|
92
2
|
|
|
93
|
-
|
|
3
|
+
   [](https://github.com/xero/text0wnz/blob/main/LICENSE)
|
|
94
4
|
|
|
95
|
-
|
|
96
|
-
|---------|--------|------|-------|
|
|
97
|
-
| `SerpentSeal` | `serpent`, `sha2` | **Yes** | Authenticated encryption: Serpent-CBC + HMAC-SHA256. Recommended for most use cases. |
|
|
98
|
-
| `SerpentStream`, `SerpentStreamPool` | `serpent`, `sha2` | **Yes** | Chunked one-shot AEAD for large payloads. Pool variant parallelises across workers. |
|
|
99
|
-
| `SerpentStreamSealer`, `SerpentStreamOpener` | `serpent`, `sha2` | **Yes** | Incremental streaming AEAD: seal and open one chunk at a time without buffering the full message. |
|
|
100
|
-
| `SerpentStreamEncoder`, `SerpentStreamDecoder` | `serpent`, `sha2` | **Yes** | Length-prefixed framing over SerpentStreamSealer/Opener for flat byte streams (files, buffered TCP). |
|
|
101
|
-
| `Serpent`, `SerpentCtr`, `SerpentCbc` | `serpent` | **No** | Raw ECB, CTR, CBC modes. Pair with HMAC-SHA256 for authentication. |
|
|
102
|
-
| `ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305` | `chacha20` | Yes (AEAD) | RFC 8439 |
|
|
103
|
-
| `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512` | `sha2` | -- | FIPS 180-4, RFC 2104 |
|
|
104
|
-
| `HKDF_SHA256`, `HKDF_SHA512` | `sha2` | -- | Key derivation: RFC 5869. Extract-and-expand over HMAC. |
|
|
105
|
-
| `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` | `sha3` | -- | FIPS 202 |
|
|
106
|
-
| `Fortuna` | `fortuna` | -- | Fortuna CSPRNG (Ferguson & Schneier). Requires `Fortuna.create()`. |
|
|
107
|
-
|
|
108
|
-
>[!IMPORTANT]
|
|
109
|
-
> All cryptographic computation runs in WASM (AssemblyScript), isolated outside the JavaScript JIT.
|
|
110
|
-
> The TypeScript layer provides the public API with input validation, type safety, and developer ergonomics.
|
|
5
|
+
<img src="https://github.com/xero/leviathan-crypto/raw/main/docs/logo.svg" alt="Leviathan logo" width="400" >
|
|
111
6
|
|
|
112
|
-
|
|
7
|
+
# Leviathan-Crypto
|
|
113
8
|
|
|
114
|
-
|
|
9
|
+
> Web cryptography built on Serpent-256 paranoia and XChaCha20-Poly1305 elegance.
|
|
115
10
|
|
|
116
|
-
|
|
117
|
-
import { init, SerpentSeal, randomBytes } from 'leviathan-crypto'
|
|
11
|
+
**Serpent-256 is the cipher for those who distrust consensus.** In 2001, when NIST selected AES, Serpent actually received more first-place security votes from the evaluation committee. However, it lost because the competition also considered performance on hardware embedded systems, which are no longer representative of the environments for which we develop software. Serpent's designers made no compromises: thirty-two rounds, S-boxes implemented using pure Boolean logic gates without table lookups, and every bit processed for each block. You use Serpent not because a committee recommended it, but because you trust the cryptanalysis. The current best attack on the full thirty-two-round Serpent-256 achieves 2²⁵⁵·¹⁹ — less than one bit below the brute-force ceiling, and strictly impractical. This includes our own independent research, which improved upon the published result. See [`serpent_audit.md`](https://github.com/xero/leviathan-crypto/wiki/serpent_audit).
|
|
118
12
|
|
|
119
|
-
|
|
13
|
+
**XChaCha20-Poly1305 is the cipher for those who appreciate design that has nothing to hide.** Daniel Bernstein built ChaCha20 as a twenty-round ARX construction: add, rotate, and XOR, in a precise choreography that simply doesn't have the attack surface that table-based ciphers do. It has no S-boxes, no cache-timing leakage, and requires no hardware acceleration to be fast. Poly1305 adds a final layer of security: a one-time authenticator with an unconditional forgery bound, mathematically guaranteed regardless of attacker compute power. XChaCha20-Poly1305 is the construction you reach for when you want an AEAD whose security proof you can actually read without a PhD. See [`chacha_audit.md`](https://github.com/xero/leviathan-crypto/wiki/chacha_audit).
|
|
120
14
|
|
|
121
|
-
|
|
15
|
+
The tension between these two approaches constitutes the library's core identity. Serpent embodies defiance, ChaCha embodies elegance, yet both arrive at the same place: constant-time, side-channel resistant implementations, independently audited against their specifications. They represent two design philosophies that do not agree on anything, except the answer.
|
|
122
16
|
|
|
123
|
-
|
|
17
|
+
**WebAssembly provides a correctness layer.** Each primitive compiles into its own isolated binary, executing outside the JavaScript JIT. This prevents speculative optimization from affecting key material and ensures that data-dependent timing vulnerabilities do not cross the boundary.
|
|
124
18
|
|
|
125
|
-
|
|
126
|
-
const ciphertext = seal.encrypt(key, plaintext)
|
|
19
|
+
**TypeScript acts as the ergonomics layer.** Fully typed classes, explicit `init()` gates, input validation, and authenticated compositions ensure primitives are connected correctly.
|
|
127
20
|
|
|
128
|
-
|
|
129
|
-
const decrypted = seal.decrypt(key, ciphertext)
|
|
21
|
+
---
|
|
130
22
|
|
|
131
|
-
|
|
132
|
-
|
|
23
|
+
#### **Zero Dependencies.**
|
|
24
|
+
With no npm dependency graph to audit, the supply chain attack surface is eliminated.
|
|
133
25
|
|
|
134
|
-
|
|
26
|
+
#### **Tree-shakeable.**
|
|
27
|
+
Import only the cipher(s) you intend to use. Subpath exports allow bundlers to exclude everything else.
|
|
135
28
|
|
|
136
|
-
|
|
137
|
-
|
|
29
|
+
#### **Side-effect Free.**
|
|
30
|
+
Nothing runs upon import. Initialization via `init()` is explicit and asynchronous.
|
|
138
31
|
|
|
139
|
-
|
|
140
|
-
import { init, SerpentStreamSealer, SerpentStreamOpener, randomBytes } from 'leviathan-crypto'
|
|
32
|
+
---
|
|
141
33
|
|
|
142
|
-
|
|
34
|
+
## Installation
|
|
143
35
|
|
|
144
|
-
|
|
36
|
+
```bash
|
|
37
|
+
# use bun
|
|
38
|
+
bun i leviathan-crypto
|
|
39
|
+
# or npm
|
|
40
|
+
npm install leviathan-crypto
|
|
41
|
+
```
|
|
145
42
|
|
|
146
|
-
|
|
147
|
-
const sealer = new SerpentStreamSealer(key, 65536)
|
|
148
|
-
const header = sealer.header() // transmit to opener before any chunks
|
|
43
|
+
---
|
|
149
44
|
|
|
150
|
-
|
|
151
|
-
const chunk1 = sealer.seal(data1)
|
|
152
|
-
const last = sealer.final(tail) // any size up to chunkSize; wipes key on return
|
|
45
|
+
## Demos
|
|
153
46
|
|
|
154
|
-
|
|
155
|
-
const opener = new SerpentStreamOpener(key, header)
|
|
47
|
+
**`lvthn-web`** [ [demo](https://leviathan.3xi.club/web) · [source](https://github.com/xero/leviathan-demos/tree/main/lvthn-web) · [readme](https://github.com/xero/leviathan-demos/blob/main/lvthn-web/README.md) ]
|
|
156
48
|
|
|
157
|
-
|
|
158
|
-
const pt1 = opener.open(chunk1)
|
|
159
|
-
const ptN = opener.open(last) // detects final chunk; wipes key on return
|
|
49
|
+
A browser encryption tool in a single, self-contained HTML file. Encrypt text or files using Serpent-256-CBC and Argon2id key derivation, then share the armored output. No server, installation, or network connection required after initial load. The code in is written to be read. The Encrypt-then-MAC construction, HMAC input (header with HMAC field zeroed + ciphertext), and Argon2id parameters are all intentional examples worth reading.
|
|
160
50
|
|
|
161
|
-
|
|
162
|
-
```
|
|
51
|
+
**`lvthn-chat`** [ [demo](https://leviathan.3xi.club/chat) · [source](https://github.com/xero/leviathan-demos/tree/main/lvthn-chat) · [readme](https://github.com/xero/leviathan-demos/blob/main/lvthn-chat/README.md) ]
|
|
163
52
|
|
|
164
|
-
|
|
53
|
+
End-to-end encrypted chat featuring two-party messaging over X25519 key exchange and XChaCha20-Poly1305 message encryption. The relay server functions as a dumb WebSocket pipe that never sees plaintext. Each message incorporates sequence numbers, which allows the system to detect and reject replayed messages from an attacker. The demo deconstructs the protocol step by step, with visual feedback for both injection and replays.
|
|
165
54
|
|
|
166
|
-
|
|
167
|
-
import { init, SerpentStream, randomBytes } from 'leviathan-crypto'
|
|
55
|
+
**`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) ]
|
|
168
56
|
|
|
169
|
-
|
|
57
|
+
File encryption CLI. Supports both Serpent-256 and XChaCha20-Poly1305, selectable via the `--cipher` flag. A single keyfile is compatible with both ciphers; the header byte determines decryption automatically. Encryption and decryption distribute 64KB chunks across a worker pool sized to hardwareConcurrency. Each worker owns an isolated WASM instance with no shared memory between workers.
|
|
170
58
|
|
|
171
|
-
|
|
59
|
+
```sh
|
|
60
|
+
bun i -g lvthn # or npm slow mode
|
|
61
|
+
lvthn keygen --armor -o my.key
|
|
62
|
+
cat secret.txt | lvthn encrypt -k my.key --armor > secret.enc
|
|
63
|
+
```
|
|
64
|
+
*[`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`.*
|
|
172
65
|
|
|
173
|
-
|
|
174
|
-
const ciphertext = stream.seal(key, largePlaintext) // default 64KB chunks
|
|
175
|
-
const decrypted = stream.open(key, ciphertext)
|
|
66
|
+
---
|
|
176
67
|
|
|
177
|
-
|
|
178
|
-
|
|
68
|
+
## Primitives
|
|
69
|
+
|
|
70
|
+
| Classes | Module | Auth | Notes |
|
|
71
|
+
| ------------------------------------------------------------------------- | ----------------- | ------- | ---------------------------------------------------------------------------------------------------- |
|
|
72
|
+
| `SerpentSeal` | `serpent`, `sha2` | **Yes** | Authenticated encryption: Serpent-CBC + HMAC-SHA256. Recommended for most use cases. |
|
|
73
|
+
| `SerpentStream`, `SerpentStreamPool` | `serpent`, `sha2` | **Yes** | Chunked one-shot AEAD for large payloads. Pool variant parallelises across workers. |
|
|
74
|
+
| `SerpentStreamSealer`, `SerpentStreamOpener` | `serpent`, `sha2` | **Yes** | Incremental streaming AEAD: seal and open one chunk at a time without buffering the full message. |
|
|
75
|
+
| `SerpentStreamEncoder`, `SerpentStreamDecoder` | `serpent`, `sha2` | **Yes** | Length-prefixed framing over SerpentStreamSealer/Opener for flat byte streams (files, buffered TCP). |
|
|
76
|
+
| `Serpent`, `SerpentCtr`, `SerpentCbc` | `serpent` | **No** | Raw ECB, CTR, CBC modes. Unauthenticated — pair with HMAC-SHA256 for authentication. |
|
|
77
|
+
| `XChaCha20Poly1305`, `ChaCha20Poly1305` | `chacha20` | **Yes** | AEAD — RFC 8439. XChaCha20 recommended (192-bit nonce). |
|
|
78
|
+
| `ChaCha20` | `chacha20` | **No** | Raw stream cipher. Unauthenticated — use with `Poly1305` for authentication. |
|
|
79
|
+
| `Poly1305` | `chacha20` | **No** | One-time MAC — RFC 8439. Use via the AEAD classes unless you have a specific reason not to. |
|
|
80
|
+
| `SHA256`, `SHA384`, `SHA512`, `HMAC_SHA256`, `HMAC_SHA384`, `HMAC_SHA512` | `sha2` | - | FIPS 180-4, RFC 2104 |
|
|
81
|
+
| `HKDF_SHA256`, `HKDF_SHA512` | `sha2` | - | Key derivation — RFC 5869. Extract-and-expand over HMAC. |
|
|
82
|
+
| `SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256` | `sha3` | - | FIPS 202 |
|
|
83
|
+
| `Fortuna` | `fortuna` | - | Fortuna CSPRNG (Ferguson & Schneier). Requires `Fortuna.create()`. |
|
|
84
|
+
|
|
85
|
+
> [!IMPORTANT]
|
|
86
|
+
> 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.
|
|
87
|
+
|
|
88
|
+
> [!WARNING]
|
|
89
|
+
> `SerpentCtr` and `SerpentCbc` are **unauthenticated** cipher modes. They provide confidentiality but not integrity or authenticity. An attacker can modify ciphertext without detection. For authenticated Serpent encryption use `SerpentSeal` or `SerpentStreamSealer`. When using CBC/CTR directly, pair with `HMAC_SHA256` using the Encrypt-then-MAC pattern.
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
## Quick Start
|
|
179
94
|
|
|
180
|
-
###
|
|
95
|
+
### Authenticated encryption with Serpent
|
|
181
96
|
|
|
182
97
|
```typescript
|
|
183
|
-
import { init,
|
|
98
|
+
import { init, SerpentSeal, randomBytes } from 'leviathan-crypto'
|
|
184
99
|
|
|
185
100
|
await init(['serpent', 'sha2'])
|
|
186
101
|
|
|
187
|
-
const
|
|
188
|
-
|
|
102
|
+
const key = randomBytes(64) // 64-byte key (encKey + macKey)
|
|
103
|
+
|
|
104
|
+
const seal = new SerpentSeal()
|
|
189
105
|
|
|
190
|
-
|
|
106
|
+
// Encrypt and authenticate
|
|
107
|
+
const ciphertext = seal.encrypt(key, plaintext)
|
|
108
|
+
|
|
109
|
+
// Decrypt and verify (throws on tamper)
|
|
110
|
+
const decrypted = seal.decrypt(key, ciphertext)
|
|
111
|
+
|
|
112
|
+
seal.dispose()
|
|
191
113
|
```
|
|
192
114
|
|
|
193
|
-
###
|
|
115
|
+
### Authenticated encryption with XChaCha20-Poly1305
|
|
194
116
|
|
|
195
117
|
```typescript
|
|
196
|
-
import { init,
|
|
118
|
+
import { init, XChaCha20Poly1305, randomBytes } from 'leviathan-crypto'
|
|
197
119
|
|
|
198
|
-
await init(['
|
|
120
|
+
await init(['chacha20'])
|
|
199
121
|
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
// digest is a 32-byte Uint8Array
|
|
122
|
+
const key = randomBytes(32) // 32-byte key
|
|
123
|
+
const nonce = randomBytes(24) // 24-byte nonce (XChaCha20 extended nonce)
|
|
203
124
|
|
|
204
|
-
|
|
205
|
-
```
|
|
125
|
+
const chacha = new XChaCha20Poly1305()
|
|
206
126
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
These helpers are available immediately on import: no `init()` required.
|
|
210
|
-
|
|
211
|
-
| Function | Description |
|
|
212
|
-
|----------|-------------|
|
|
213
|
-
| `hexToBytes(hex)` | Hex string to `Uint8Array` (accepts uppercase, `0x` prefix) |
|
|
214
|
-
| `bytesToHex(bytes)` | `Uint8Array` to lowercase hex string |
|
|
215
|
-
| `utf8ToBytes(str)` | UTF-8 string to `Uint8Array` |
|
|
216
|
-
| `bytesToUtf8(bytes)` | `Uint8Array` to UTF-8 string |
|
|
217
|
-
| `base64ToBytes(b64)` | Base64/base64url string to `Uint8Array` (undefined on invalid) |
|
|
218
|
-
| `bytesToBase64(bytes, url?)` | `Uint8Array` to base64 string (url=true for base64url) |
|
|
219
|
-
| `constantTimeEqual(a, b)` | Constant-time byte comparison (XOR-accumulate) |
|
|
220
|
-
| `wipe(data)` | Zero a typed array in place |
|
|
221
|
-
| `xor(a, b)` | XOR two equal-length `Uint8Array`s |
|
|
222
|
-
| `concat(a, b)` | Concatenate two `Uint8Array`s |
|
|
223
|
-
| `randomBytes(n)` | Cryptographically secure random bytes via Web Crypto |
|
|
224
|
-
|
|
225
|
-
## Authentication Warning
|
|
226
|
-
|
|
227
|
-
`SerpentCtr` and `SerpentCbc` are **unauthenticated** cipher modes. They provide
|
|
228
|
-
confidentiality but not integrity or authenticity. An attacker can modify
|
|
229
|
-
ciphertext without detection.
|
|
230
|
-
|
|
231
|
-
>[!TIP]
|
|
232
|
-
> **For authenticated Serpent encryption:** use [`SerpentSeal`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentseal) or [`SerpentStreamSealer`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentstreamsealer--serpentstreamopener)
|
|
233
|
-
>
|
|
234
|
-
> **Using Serpent CBC/CTR directly:** pair with `HMAC_SHA256` using the Encrypt-then-MAC pattern
|
|
235
|
-
|
|
236
|
-
>[!NOTE]
|
|
237
|
-
> **[`SerpentStream`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentstream) and [`SerpentStreamSealer`](https://github.com/xero/leviathan-crypto/wiki/serpent#serpentstreamsealer--serpentstreamopener)
|
|
238
|
-
> inherently satisfy the Cryptographic Doom Principle.** Message Authentication Code (MAC)
|
|
239
|
-
> verification is the mandatory check on every `open()` call; decryption is impossible until
|
|
240
|
-
> this verification succeeds. Per-chunk HKDF key derivation, using position-bound info,
|
|
241
|
-
> extends this protection to stream integrity. Reordering, truncation, and cross-stream
|
|
242
|
-
> substitution are all detected at the MAC layer, preventing any plaintext from being
|
|
243
|
-
> produced in such cases. [Full analysis.](https://github.com/xero/leviathan-crypto/wiki/serpent_audit#24-serpentstream-encrypt-then-mac-and-the-cryptographic-doom-principle)
|
|
127
|
+
// Encrypt and authenticate
|
|
128
|
+
const ciphertext = chacha.encrypt(key, nonce, plaintext)
|
|
244
129
|
|
|
245
|
-
|
|
130
|
+
// Decrypt and verify (throws on tamper)
|
|
131
|
+
const decrypted = chacha.decrypt(key, nonce, ciphertext)
|
|
246
132
|
|
|
247
|
-
|
|
248
|
-
# use bun
|
|
249
|
-
bun i leviathan-crypto
|
|
250
|
-
# or npm
|
|
251
|
-
npm install leviathan-crypto
|
|
133
|
+
chacha.dispose()
|
|
252
134
|
```
|
|
253
135
|
|
|
136
|
+
For more examples — streaming, chunking, hashing, key derivation: see the [examples page](https://github.com/xero/leviathan-crypto/wiki/examples).
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
254
140
|
## Loading Modes
|
|
255
141
|
|
|
256
142
|
```typescript
|
|
@@ -264,59 +150,107 @@ await init(['serpent'], 'streaming', { wasmUrl: '/assets/wasm/' })
|
|
|
264
150
|
await init(['serpent'], 'manual', { wasmBinary: { serpent: myBuffer } })
|
|
265
151
|
```
|
|
266
152
|
|
|
153
|
+
### Tree-shaking with subpath imports
|
|
154
|
+
|
|
155
|
+
Each cipher ships as its own subpath export. A bundler with tree-shaking support and `"sideEffects": false` will exclude every module you don't import:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
// Only serpent.wasm ends up in your bundle
|
|
159
|
+
import { serpentInit, SerpentSeal } from 'leviathan-crypto/serpent'
|
|
160
|
+
await serpentInit()
|
|
161
|
+
|
|
162
|
+
// Only chacha20.wasm ends up in your bundle
|
|
163
|
+
import { chacha20Init, XChaCha20Poly1305 } from 'leviathan-crypto/chacha20'
|
|
164
|
+
await chacha20Init()
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
| Subpath | Entry point |
|
|
168
|
+
| --------------------------- | -------------------------- |
|
|
169
|
+
| `leviathan-crypto` | `./dist/index.js` |
|
|
170
|
+
| `leviathan-crypto/serpent` | `./dist/serpent/index.js` |
|
|
171
|
+
| `leviathan-crypto/chacha20` | `./dist/chacha20/index.js` |
|
|
172
|
+
| `leviathan-crypto/sha2` | `./dist/sha2/index.js` |
|
|
173
|
+
| `leviathan-crypto/sha3` | `./dist/sha3/index.js` |
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Utilities
|
|
178
|
+
|
|
179
|
+
These helpers are available immediately on import with no `init()` required.
|
|
180
|
+
|
|
181
|
+
| Function | Description |
|
|
182
|
+
| -------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
183
|
+
| [`hexToBytes(hex)`](./docs/utils.md#hextobytes) | Hex string to `Uint8Array` (accepts uppercase, `0x` prefix) |
|
|
184
|
+
| [`bytesToHex(bytes)`](./docs/utils.md#bytestohex) | `Uint8Array` to lowercase hex string |
|
|
185
|
+
| [`utf8ToBytes(str)`](./docs/utils.md#utf8tobytes) | UTF-8 string to `Uint8Array` |
|
|
186
|
+
| [`bytesToUtf8(bytes)`](./docs/utils.md#bytestoutf8) | `Uint8Array` to UTF-8 string |
|
|
187
|
+
| [`base64ToBytes(b64)`](./docs/utils.md#base64tobytes) | Base64/base64url string to `Uint8Array` (undefined on invalid) |
|
|
188
|
+
| [`bytesToBase64(bytes, url?)`](./docs/utils.md#bytestobase64) | `Uint8Array` to base64 string (url=true for base64url) |
|
|
189
|
+
| [`constantTimeEqual(a, b)`](./docs/utils.md#constanttimeequal) | Constant-time byte comparison (XOR-accumulate) |
|
|
190
|
+
| [`wipe(data)`](./docs/utils.md#wipe) | Zero a typed array in place |
|
|
191
|
+
| [`xor(a, b)`](./docs/utils.md#xor) | XOR two equal-length `Uint8Array`s |
|
|
192
|
+
| [`concat(a, b)`](./docs/utils.md#concat) | Concatenate two `Uint8Array`s |
|
|
193
|
+
| [`randomBytes(n)`](./docs/utils.md#randombytes) | Cryptographically secure random bytes via Web Crypto |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
267
197
|
## Documentation
|
|
268
198
|
|
|
269
199
|
**Full API documentation:** [./docs](./docs/README.md)
|
|
270
200
|
|
|
271
|
-
| Module
|
|
272
|
-
|
|
273
|
-
| [serpent.md](./docs/serpent.md)
|
|
274
|
-
| [asm_serpent.md](./docs/asm_serpent.md)
|
|
275
|
-
| [chacha20.md](./docs/chacha20.md)
|
|
276
|
-
| [asm_chacha.md](./docs/asm_chacha.md)
|
|
277
|
-
| [sha2.md](./docs/sha2.md)
|
|
278
|
-
| [asm_sha2.md](./docs/asm_sha2.md)
|
|
279
|
-
| [sha3.md](./docs/sha3.md)
|
|
280
|
-
| [asm_sha3.md](./docs/asm_sha3.md)
|
|
281
|
-
| [fortuna.md](./docs/fortuna.md)
|
|
282
|
-
| [init.md](./docs/init.md)
|
|
283
|
-
| [utils.md](./docs/utils.md)
|
|
284
|
-
| [types.md](./docs/types.md)
|
|
285
|
-
| [architecture.md](./docs/architecture.md
|
|
286
|
-
| [test-suite.md](./test-suite.md)
|
|
201
|
+
| Module | Description |
|
|
202
|
+
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
203
|
+
| [serpent.md](./docs/serpent.md) | Serpent-256 TypeScript API (`SerpentSeal`, `SerpentStream`, `SerpentStreamPool`, `SerpentStreamSealer`, `SerpentStreamOpener`, `Serpent`, `SerpentCtr`, `SerpentCbc`) |
|
|
204
|
+
| [asm_serpent.md](./docs/asm_serpent.md) | Serpent-256 WASM implementation (bitslice S-boxes, key schedule, CTR/CBC) |
|
|
205
|
+
| [chacha20.md](./docs/chacha20.md) | ChaCha20/Poly1305 TypeScript API (`ChaCha20`, `Poly1305`, `ChaCha20Poly1305`, `XChaCha20Poly1305`) |
|
|
206
|
+
| [asm_chacha.md](./docs/asm_chacha.md) | ChaCha20/Poly1305 WASM implementation (quarter-round, HChaCha20) |
|
|
207
|
+
| [sha2.md](./docs/sha2.md) | SHA-2 TypeScript API (`SHA256`, `SHA512`, `SHA384`, `HMAC_SHA256`, `HMAC_SHA512`, `HMAC_SHA384`) |
|
|
208
|
+
| [asm_sha2.md](./docs/asm_sha2.md) | SHA-2 WASM implementation (compression functions, HMAC) |
|
|
209
|
+
| [sha3.md](./docs/sha3.md) | SHA-3 TypeScript API (`SHA3_224`, `SHA3_256`, `SHA3_384`, `SHA3_512`, `SHAKE128`, `SHAKE256`) |
|
|
210
|
+
| [asm_sha3.md](./docs/asm_sha3.md) | SHA-3 WASM implementation (Keccak-f[1600], sponge construction) |
|
|
211
|
+
| [fortuna.md](./docs/fortuna.md) | Fortuna CSPRNG (forward secrecy, 32 entropy pools) |
|
|
212
|
+
| [init.md](./docs/init.md) | `init()` API and WASM loading modes |
|
|
213
|
+
| [utils.md](./docs/utils.md) | Encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes` |
|
|
214
|
+
| [types.md](./docs/types.md) | TypeScript interfaces (`Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD`) |
|
|
215
|
+
| [architecture.md](./docs/architecture.md) | Architecture overview, build pipeline, module relationships |
|
|
216
|
+
| [test-suite.md](./docs/test-suite.md) | Test suite structure, vector corpus, gate discipline |
|
|
217
|
+
|
|
218
|
+
### Algorithm correctness and verifications
|
|
219
|
+
|
|
220
|
+
| Primitive | Audit Description |
|
|
221
|
+
| ------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
222
|
+
| [serpent_audit.md](./docs/serpent_audit.md) | Correctness verification, side-channel analysis, cryptanalytic paper review |
|
|
223
|
+
| [chacha_audit.md](./docs/chacha_audit.md) | XChaCha20-Poly1305 correctness, Poly1305 field arithmetic, HChaCha20 nonce extension |
|
|
224
|
+
| [sha2_audit.md](./docs/sha2_audit.md) | SHA-256/512/384 correctness, HMAC and HKDF composition, constant verification |
|
|
225
|
+
| [sha3_audit.md](./docs/sha3_audit.md) | Keccak permutation correctness, θ/ρ/π/χ/ι step verification, round constant derivation |
|
|
226
|
+
| [hmac_audit.md](./docs/hmac_audit.md) | HMAC-SHA256/512/384 construction, key processing, RFC 4231 vector coverage |
|
|
227
|
+
| [hkdf_audit.md](./docs/hkdf_audit.md) | HKDF extract-then-expand, info field domain separation, SerpentStream key derivation |
|
|
228
|
+
|
|
229
|
+
---
|
|
287
230
|
|
|
288
231
|
## License
|
|
232
|
+
|
|
289
233
|
leviathan is written under the [MIT license](http://www.opensource.org/licenses/MIT).
|
|
290
234
|
|
|
291
235
|
```
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
▄▄██████████ ▐███ ▄▄
|
|
313
|
-
▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
314
|
-
▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███
|
|
315
|
-
▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀
|
|
316
|
-
████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄
|
|
317
|
-
█████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄███▀
|
|
318
|
-
▀██████▀ ▀████▄▄▄████▀
|
|
319
|
-
▀█████▀
|
|
320
|
-
|
|
321
|
-
Serpent256 & Xchacha20-Poly1305 Cryptography for the Web
|
|
236
|
+
▄▄▄▄▄▄▄▄▄▄
|
|
237
|
+
▄████████████████████▄▄
|
|
238
|
+
▄██████████████████████ ▀████▄
|
|
239
|
+
▄█████████▀▀▀ ▀███████▄▄███████▌
|
|
240
|
+
▐████████▀ ▄▄▄▄ ▀████████▀██▀█▌
|
|
241
|
+
████████ ███▀▀ ████▀ █▀ █▀
|
|
242
|
+
███████▌ ▀██▀ ██
|
|
243
|
+
███████ ▀███ ▀██ ▀█▄
|
|
244
|
+
▀██████ ▄▄██ ▀▀ ██▄
|
|
245
|
+
▀█████▄ ▄██▄ ▄▀▄▀
|
|
246
|
+
▀████▄ ▄██▄
|
|
247
|
+
▐████ ▐███
|
|
248
|
+
▄▄██████████ ▐███ ▄▄
|
|
249
|
+
▄██▀▀▀▀▀▀▀▀▀▀ ▄████ ▄██▀
|
|
250
|
+
▄▀ ▄▄█████████▄▄ ▀▀▀▀▀ ▄███
|
|
251
|
+
▄██████▀▀▀▀▀▀██████▄ ▀▄▄▄▄████▀
|
|
252
|
+
████▀ ▄▄▄▄▄▄▄ ▀████▄ ▀█████▀ ▄▄▄▄
|
|
253
|
+
█████▄▄█████▀▀▀▀▀▀▄ ▀███▄ ▄███▀
|
|
254
|
+
▀██████▀ ▀████▄▄▄████▀
|
|
255
|
+
▀█████▀
|
|
322
256
|
```
|
|
@@ -778,18 +778,18 @@ They are the immutable truth, and must never be modified to make tests pass.
|
|
|
778
778
|
|
|
779
779
|
---
|
|
780
780
|
|
|
781
|
-
## Cross-References
|
|
782
|
-
|
|
783
|
-
- [README.md](./README.md) —
|
|
784
|
-
- [test-suite.md](./test-suite.md) — testing methodology, vector corpus, and gate discipline
|
|
785
|
-
- [init.md](./init.md) — `init()` API, three loading modes, and idempotent behavior
|
|
786
|
-
- [loader.md](./loader.md) — internal WASM binary loading strategies (embedded, streaming, manual)
|
|
787
|
-
- [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
|
|
788
|
-
- [types.md](./types.md) — public TypeScript interfaces (`Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD`)
|
|
789
|
-
- [utils.md](./utils.md) — encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes`
|
|
790
|
-
- [serpent.md](./serpent.md) — Serpent-256 TypeScript API (SerpentSeal, SerpentStream, raw modes)
|
|
791
|
-
- [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 TypeScript API and XChaCha20-Poly1305 AEAD
|
|
792
|
-
- [sha2.md](./sha2.md) — SHA-2 hashes, HMAC, and HKDF TypeScript API
|
|
793
|
-
- [sha3.md](./sha3.md) — SHA-3 hashes and SHAKE XOFs TypeScript API
|
|
794
|
-
- [fortuna.md](./fortuna.md) — Fortuna CSPRNG with forward secrecy and entropy pooling
|
|
795
|
-
- [argon2id.md](./argon2id.md) — Argon2id password hashing and key derivation
|
|
781
|
+
> ## Cross-References
|
|
782
|
+
>
|
|
783
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
784
|
+
> - [test-suite.md](./test-suite.md) — testing methodology, vector corpus, and gate discipline
|
|
785
|
+
> - [init.md](./init.md) — `init()` API, three loading modes, and idempotent behavior
|
|
786
|
+
> - [loader.md](./loader.md) — internal WASM binary loading strategies (embedded, streaming, manual)
|
|
787
|
+
> - [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
|
|
788
|
+
> - [types.md](./types.md) — public TypeScript interfaces (`Hash`, `KeyedHash`, `Blockcipher`, `Streamcipher`, `AEAD`)
|
|
789
|
+
> - [utils.md](./utils.md) — encoding helpers, `constantTimeEqual`, `wipe`, `randomBytes`
|
|
790
|
+
> - [serpent.md](./serpent.md) — Serpent-256 TypeScript API (SerpentSeal, SerpentStream, raw modes)
|
|
791
|
+
> - [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 TypeScript API and XChaCha20-Poly1305 AEAD
|
|
792
|
+
> - [sha2.md](./sha2.md) — SHA-2 hashes, HMAC, and HKDF TypeScript API
|
|
793
|
+
> - [sha3.md](./sha3.md) — SHA-3 hashes and SHAKE XOFs TypeScript API
|
|
794
|
+
> - [fortuna.md](./fortuna.md) — Fortuna CSPRNG with forward secrecy and entropy pooling
|
|
795
|
+
> - [argon2id.md](./argon2id.md) — Argon2id password hashing and key derivation
|
package/dist/docs/argon2id.md
CHANGED
|
@@ -280,11 +280,11 @@ xc2.dispose();
|
|
|
280
280
|
|
|
281
281
|
---
|
|
282
282
|
|
|
283
|
-
## Cross-References
|
|
284
|
-
|
|
285
|
-
- [README.md](./README.md) — project overview and quick-start guide
|
|
286
|
-
- [sha2.md](./sha2.md) — HKDF-SHA256 for key expansion from Argon2id root keys
|
|
287
|
-
- [serpent.md](./serpent.md) — SerpentSeal: Serpent-256 authenticated encryption (pairs with Argon2id-derived keys)
|
|
288
|
-
- [chacha20.md](./chacha20.md) — XChaCha20Poly1305: ChaCha20 authenticated encryption (pairs with Argon2id-derived keys)
|
|
289
|
-
- [utils.md](./utils.md) — `randomBytes` for generating salts, `constantTimeEqual` for hash verification
|
|
290
|
-
- [architecture.md](./architecture.md) —
|
|
283
|
+
> ## Cross-References
|
|
284
|
+
>
|
|
285
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
286
|
+
> - [sha2.md](./sha2.md) — HKDF-SHA256 for key expansion from Argon2id root keys
|
|
287
|
+
> - [serpent.md](./serpent.md) — SerpentSeal: Serpent-256 authenticated encryption (pairs with Argon2id-derived keys)
|
|
288
|
+
> - [chacha20.md](./chacha20.md) — XChaCha20Poly1305: ChaCha20 authenticated encryption (pairs with Argon2id-derived keys)
|
|
289
|
+
> - [utils.md](./utils.md) — `randomBytes` for generating salts, `constantTimeEqual` for hash verification
|
|
290
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
package/dist/docs/chacha20.md
CHANGED
|
@@ -592,11 +592,11 @@ cipher.dispose()
|
|
|
592
592
|
| Authentication tag does not match on decrypt | `Error` | `ChaCha20Poly1305: authentication failed` |
|
|
593
593
|
| Empty plaintext | — | Allowed. Encrypting zero bytes produces just a 16-byte tag (AEAD) or zero bytes (raw ChaCha20). |
|
|
594
594
|
|
|
595
|
-
## Cross-References
|
|
596
|
-
|
|
597
|
-
- [README.md](./README.md) —
|
|
598
|
-
- [asm_chacha.md](./asm_chacha.md) — WASM (AssemblyScript) implementation details for the chacha20 module
|
|
599
|
-
- [chacha20_pool.md](./chacha20_pool.md) — `XChaCha20Poly1305Pool` worker-pool wrapper for parallel encryption
|
|
600
|
-
- [serpent.md](./serpent.md) — alternative: Serpent block cipher modes (CBC, CTR — unauthenticated, needs HMAC pairing)
|
|
601
|
-
- [sha2.md](./sha2.md) — SHA-2 hashes and HMAC — needed for Encrypt-then-MAC if using Serpent or raw ChaCha20
|
|
602
|
-
- [types.md](./types.md) — `AEAD` and `Streamcipher` interfaces implemented by ChaCha20 classes
|
|
595
|
+
> ## Cross-References
|
|
596
|
+
>
|
|
597
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
598
|
+
> - [asm_chacha.md](./asm_chacha.md) — WASM (AssemblyScript) implementation details for the chacha20 module
|
|
599
|
+
> - [chacha20_pool.md](./chacha20_pool.md) — `XChaCha20Poly1305Pool` worker-pool wrapper for parallel encryption
|
|
600
|
+
> - [serpent.md](./serpent.md) — alternative: Serpent block cipher modes (CBC, CTR — unauthenticated, needs HMAC pairing)
|
|
601
|
+
> - [sha2.md](./sha2.md) — SHA-2 hashes and HMAC — needed for Encrypt-then-MAC if using Serpent or raw ChaCha20
|
|
602
|
+
> - [types.md](./types.md) — `AEAD` and `Streamcipher` interfaces implemented by ChaCha20 classes
|
|
@@ -296,11 +296,11 @@ const result = concat(chunk1, chunk2)
|
|
|
296
296
|
|
|
297
297
|
---
|
|
298
298
|
|
|
299
|
-
## Cross-References
|
|
300
|
-
|
|
301
|
-
- [
|
|
302
|
-
- [
|
|
303
|
-
- [
|
|
304
|
-
- [
|
|
305
|
-
- [
|
|
306
|
-
- [
|
|
299
|
+
> ## Cross-References
|
|
300
|
+
>
|
|
301
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
302
|
+
> - [chacha20.md](./chacha20.md) — single-instance XChaCha20-Poly1305 API
|
|
303
|
+
> - [asm_chacha.md](./asm_chacha.md) — WASM implementation details (quarter-round, Poly1305 accumulator, HChaCha20)
|
|
304
|
+
> - [wasm.md](./wasm.md) — WebAssembly primer: how one compiled module spawns many worker instances
|
|
305
|
+
> - [fortuna.md](./fortuna.md) — another class using the `static async create()` factory pattern
|
|
306
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
package/dist/docs/fortuna.md
CHANGED
|
@@ -311,12 +311,12 @@ to read the spec:
|
|
|
311
311
|
|
|
312
312
|
---
|
|
313
313
|
|
|
314
|
-
## Cross-References
|
|
315
|
-
|
|
316
|
-
- [README.md](./README.md)
|
|
317
|
-
- [architecture.md](./architecture.md)
|
|
318
|
-
- [serpent.md](./serpent.md): Serpent-256 TypeScript API (Fortuna uses Serpent ECB internally)
|
|
319
|
-
- [sha2.md](./sha2.md): SHA-256 TypeScript API (Fortuna uses SHA-256 for entropy accumulation)
|
|
320
|
-
- [asm_serpent.md](./asm_serpent.md): Serpent-256 WASM implementation details
|
|
321
|
-
- [asm_sha2.md](./asm_sha2.md): SHA-256 WASM implementation details
|
|
322
|
-
- [utils.md](./utils.md): `randomBytes()` for simpler random generation needs
|
|
314
|
+
> ## Cross-References
|
|
315
|
+
>
|
|
316
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
317
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
318
|
+
> - [serpent.md](./serpent.md): Serpent-256 TypeScript API (Fortuna uses Serpent ECB internally)
|
|
319
|
+
> - [sha2.md](./sha2.md): SHA-256 TypeScript API (Fortuna uses SHA-256 for entropy accumulation)
|
|
320
|
+
> - [asm_serpent.md](./asm_serpent.md): Serpent-256 WASM implementation details
|
|
321
|
+
> - [asm_sha2.md](./asm_sha2.md): SHA-256 WASM implementation details
|
|
322
|
+
> - [utils.md](./utils.md): `randomBytes()` for simpler random generation needs
|
package/dist/docs/init.md
CHANGED
|
@@ -300,9 +300,9 @@ if (!isInitialized('sha2')) {
|
|
|
300
300
|
|
|
301
301
|
---
|
|
302
302
|
|
|
303
|
-
## Cross-References
|
|
304
|
-
|
|
305
|
-
- [README.md](./README.md) —
|
|
306
|
-
- [loader.md](./loader.md) — WASM binary loading strategies (internal details)
|
|
307
|
-
- [architecture.md](./architecture.md) — architecture overview, module
|
|
308
|
-
- [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
|
|
303
|
+
> ## Cross-References
|
|
304
|
+
>
|
|
305
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
306
|
+
> - [loader.md](./loader.md) — WASM binary loading strategies (internal details)
|
|
307
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
308
|
+
> - [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, memory, and the init gate
|
package/dist/docs/loader.md
CHANGED
|
@@ -198,9 +198,9 @@ unexpected allocations and makes the memory layout predictable and auditable.
|
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
201
|
-
## Cross-References
|
|
202
|
-
|
|
203
|
-
- [README.md](./README.md) —
|
|
204
|
-
- [architecture.md](./architecture.md) — architecture overview and build pipeline
|
|
205
|
-
- [init.md](./init.md) — the public `init()` API that uses this loader
|
|
206
|
-
- [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, and memory model
|
|
201
|
+
> ## Cross-References
|
|
202
|
+
>
|
|
203
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
204
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
205
|
+
> - [init.md](./init.md) — the public `init()` API that uses this loader
|
|
206
|
+
> - [wasm.md](./wasm.md) — WebAssembly primer: modules, instances, and memory model
|
package/dist/docs/serpent.md
CHANGED
|
@@ -900,15 +900,15 @@ cipher.dispose();
|
|
|
900
900
|
|
|
901
901
|
---
|
|
902
902
|
|
|
903
|
-
## Cross-References
|
|
904
|
-
|
|
905
|
-
- [README.md](./README.md) —
|
|
906
|
-
- [architecture.md](./architecture.md) — module
|
|
907
|
-
- [asm_serpent.md](./asm_serpent.md) — WASM implementation details and buffer layout
|
|
908
|
-
- [serpent_reference.md](./serpent_reference.md) — algorithm specification, S-boxes, linear transform, and known attacks
|
|
909
|
-
- [serpent_audit.md](./serpent_audit.md) — security audit findings (correctness, side-channel analysis)
|
|
910
|
-
- [chacha20.md](./chacha20.md) — XChaCha20Poly1305 authenticated encryption (alternative AEAD)
|
|
911
|
-
- [sha2.md](./sha2.md) — HMAC-SHA256 and HKDF used internally by SerpentSeal and SerpentStream
|
|
912
|
-
- [types.md](./types.md) — `Blockcipher`, `Streamcipher`, and `AEAD` interfaces implemented by Serpent classes
|
|
913
|
-
- [utils.md](./utils.md) — `constantTimeEqual`, `wipe`, `randomBytes` used by Serpent wrappers
|
|
903
|
+
> ## Cross-References
|
|
904
|
+
>
|
|
905
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
906
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
907
|
+
> - [asm_serpent.md](./asm_serpent.md) — WASM implementation details and buffer layout
|
|
908
|
+
> - [serpent_reference.md](./serpent_reference.md) — algorithm specification, S-boxes, linear transform, and known attacks
|
|
909
|
+
> - [serpent_audit.md](./serpent_audit.md) — security audit findings (correctness, side-channel analysis)
|
|
910
|
+
> - [chacha20.md](./chacha20.md) — XChaCha20Poly1305 authenticated encryption (alternative AEAD)
|
|
911
|
+
> - [sha2.md](./sha2.md) — HMAC-SHA256 and HKDF used internally by SerpentSeal and SerpentStream
|
|
912
|
+
> - [types.md](./types.md) — `Blockcipher`, `Streamcipher`, and `AEAD` interfaces implemented by Serpent classes
|
|
913
|
+
> - [utils.md](./utils.md) — `constantTimeEqual`, `wipe`, `randomBytes` used by Serpent wrappers
|
|
914
914
|
|
package/dist/docs/sha2.md
CHANGED
|
@@ -608,13 +608,13 @@ SHA-2 is well-defined for zero-length messages and will return the correct diges
|
|
|
608
608
|
|
|
609
609
|
---
|
|
610
610
|
|
|
611
|
-
## Cross-References
|
|
612
|
-
|
|
613
|
-
- [README.md](./README.md) — project overview and quick-start guide
|
|
614
|
-
- [architecture.md](./architecture.md) —
|
|
615
|
-
- [asm_sha2.md](./asm_sha2.md) — WASM implementation details (AssemblyScript buffer layout, compression functions)
|
|
616
|
-
- [sha3.md](./sha3.md) — alternative: SHA-3 family (immune to length extension attacks)
|
|
617
|
-
- [serpent.md](./serpent.md) — SerpentSeal and SerpentStream use HMAC-SHA256 and HKDF internally
|
|
618
|
-
- [argon2id.md](./argon2id.md) — Argon2id password hashing; HKDF expands Argon2id root keys
|
|
619
|
-
- [fortuna.md](./fortuna.md) — Fortuna CSPRNG uses SHA-256 for entropy accumulation
|
|
620
|
-
- [utils.md](./utils.md) — `constantTimeEqual`, `bytesToHex`, `utf8ToBytes`, `randomBytes`
|
|
611
|
+
> ## Cross-References
|
|
612
|
+
>
|
|
613
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
614
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
615
|
+
> - [asm_sha2.md](./asm_sha2.md) — WASM implementation details (AssemblyScript buffer layout, compression functions)
|
|
616
|
+
> - [sha3.md](./sha3.md) — alternative: SHA-3 family (immune to length extension attacks)
|
|
617
|
+
> - [serpent.md](./serpent.md) — SerpentSeal and SerpentStream use HMAC-SHA256 and HKDF internally
|
|
618
|
+
> - [argon2id.md](./argon2id.md) — Argon2id password hashing; HKDF expands Argon2id root keys
|
|
619
|
+
> - [fortuna.md](./fortuna.md) — Fortuna CSPRNG uses SHA-256 for entropy accumulation
|
|
620
|
+
> - [utils.md](./utils.md) — `constantTimeEqual`, `bytesToHex`, `utf8ToBytes`, `randomBytes`
|
package/dist/docs/sha3.md
CHANGED
|
@@ -500,10 +500,10 @@ absorbs zero bytes and then squeezes.
|
|
|
500
500
|
|
|
501
501
|
---
|
|
502
502
|
|
|
503
|
-
## Cross-References
|
|
504
|
-
|
|
505
|
-
- [README.md](./README.md)
|
|
506
|
-
- [asm_sha3.md](./asm_sha3.md): WASM implementation details (buffer layout, Keccak internals, variant parameters)
|
|
507
|
-
- [sha2.md](./sha2.md): Alternative: SHA-2 family (SHA-256, SHA-384, SHA-512) and HMAC
|
|
508
|
-
- [utils.md](./utils.md): Encoding utilities: `bytesToHex`, `hexToBytes`, `utf8ToBytes`
|
|
509
|
-
- [architecture.md](./architecture.md)
|
|
503
|
+
> ## Cross-References
|
|
504
|
+
>
|
|
505
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
506
|
+
> - [asm_sha3.md](./asm_sha3.md): WASM implementation details (buffer layout, Keccak internals, variant parameters)
|
|
507
|
+
> - [sha2.md](./sha2.md): Alternative: SHA-2 family (SHA-256, SHA-384, SHA-512) and HMAC
|
|
508
|
+
> - [utils.md](./utils.md): Encoding utilities: `bytesToHex`, `hexToBytes`, `utf8ToBytes`
|
|
509
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
package/dist/docs/types.md
CHANGED
|
@@ -186,13 +186,13 @@ function cleanup(ctx: EncryptionContext): void {
|
|
|
186
186
|
|
|
187
187
|
---
|
|
188
188
|
|
|
189
|
-
## Cross-References
|
|
190
|
-
|
|
191
|
-
- [README.md](./README.md) —
|
|
192
|
-
- [architecture.md](./architecture.md) — module
|
|
193
|
-
- [utils.md](./utils.md) — encoding utilities and `constantTimeEqual` for verifying MACs from `KeyedHash`
|
|
194
|
-
- [serpent.md](./serpent.md) — Serpent classes implement `Blockcipher`, `Streamcipher`, and `AEAD`
|
|
195
|
-
- [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 classes implement `Streamcipher` and `AEAD`
|
|
196
|
-
- [sha2.md](./sha2.md) — SHA-2 classes implement `Hash`; HMAC classes implement `KeyedHash`
|
|
197
|
-
- [sha3.md](./sha3.md) — SHA-3 classes implement `Hash`; SHAKE classes extend with XOF API
|
|
198
|
-
- [test-suite.md](./test-suite.md) — test suite structure and vector corpus
|
|
189
|
+
> ## Cross-References
|
|
190
|
+
>
|
|
191
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
192
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
193
|
+
> - [utils.md](./utils.md) — encoding utilities and `constantTimeEqual` for verifying MACs from `KeyedHash`
|
|
194
|
+
> - [serpent.md](./serpent.md) — Serpent classes implement `Blockcipher`, `Streamcipher`, and `AEAD`
|
|
195
|
+
> - [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 classes implement `Streamcipher` and `AEAD`
|
|
196
|
+
> - [sha2.md](./sha2.md) — SHA-2 classes implement `Hash`; HMAC classes implement `KeyedHash`
|
|
197
|
+
> - [sha3.md](./sha3.md) — SHA-3 classes implement `Hash`; SHAKE classes extend with XOF API
|
|
198
|
+
> - [test-suite.md](./test-suite.md) — test suite structure and vector corpus
|
package/dist/docs/utils.md
CHANGED
|
@@ -261,13 +261,13 @@ console.log(combined.length) // 32
|
|
|
261
261
|
|
|
262
262
|
---
|
|
263
263
|
|
|
264
|
-
## Cross-References
|
|
265
|
-
|
|
266
|
-
- [README.md](./README.md) —
|
|
267
|
-
- [architecture.md](./architecture.md) — module
|
|
268
|
-
- [serpent.md](./serpent.md) — Serpent modes consume keys from `randomBytes`; wrappers use `wipe` and `constantTimeEqual`
|
|
269
|
-
- [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 classes use `randomBytes` for nonce generation
|
|
270
|
-
- [sha2.md](./sha2.md) — SHA-2 and HMAC classes; output often converted with `bytesToHex`
|
|
271
|
-
- [sha3.md](./sha3.md) — SHA-3 and SHAKE classes; output often converted with `bytesToHex`
|
|
272
|
-
- [types.md](./types.md) — public interfaces whose implementations rely on these utilities
|
|
273
|
-
- [test-suite.md](./test-suite.md) — test suite structure and vector corpus
|
|
264
|
+
> ## Cross-References
|
|
265
|
+
>
|
|
266
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
267
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
268
|
+
> - [serpent.md](./serpent.md) — Serpent modes consume keys from `randomBytes`; wrappers use `wipe` and `constantTimeEqual`
|
|
269
|
+
> - [chacha20.md](./chacha20.md) — ChaCha20/Poly1305 classes use `randomBytes` for nonce generation
|
|
270
|
+
> - [sha2.md](./sha2.md) — SHA-2 and HMAC classes; output often converted with `bytesToHex`
|
|
271
|
+
> - [sha3.md](./sha3.md) — SHA-3 and SHAKE classes; output often converted with `bytesToHex`
|
|
272
|
+
> - [types.md](./types.md) — public interfaces whose implementations rely on these utilities
|
|
273
|
+
> - [test-suite.md](./test-suite.md) — test suite structure and vector corpus
|
package/dist/docs/wasm.md
CHANGED
|
@@ -183,11 +183,11 @@ See [init.md](./init.md) for the full API.
|
|
|
183
183
|
|
|
184
184
|
---
|
|
185
185
|
|
|
186
|
-
## Cross-References
|
|
187
|
-
|
|
188
|
-
- [
|
|
189
|
-
|
|
190
|
-
- [init.md](./init.md) — `init()` API and the three loading modes
|
|
191
|
-
- [loader.md](./loader.md) — how WASM binaries are loaded and instantiated
|
|
192
|
-
- [chacha20_pool.md](./chacha20_pool.md) — example of one compiled module
|
|
193
|
-
|
|
186
|
+
> ## Cross-References
|
|
187
|
+
>
|
|
188
|
+
> - [README.md](./README.md) — project overview and quick-start guide
|
|
189
|
+
> - [architecture.md](./architecture.md) — architecture overview, module relationships, buffer layouts, and build pipeline
|
|
190
|
+
> - [init.md](./init.md) — `init()` API and the three loading modes
|
|
191
|
+
> - [loader.md](./loader.md) — how WASM binaries are loaded and instantiated
|
|
192
|
+
> - [chacha20_pool.md](./chacha20_pool.md) — example of one compiled module
|
|
193
|
+
> spawning many instances across workers
|
package/dist/sha2/hkdf.js
CHANGED
|
@@ -51,15 +51,21 @@ export class HKDF_SHA256 {
|
|
|
51
51
|
buf.set(prev, 0);
|
|
52
52
|
buf.set(info, prev.length);
|
|
53
53
|
buf[prev.length + info.length] = i;
|
|
54
|
+
const oldPrev = prev;
|
|
54
55
|
prev = this.hmac.hash(prk, buf);
|
|
55
56
|
okm.set(prev, (i - 1) * 32);
|
|
57
|
+
buf.fill(0);
|
|
58
|
+
oldPrev.fill(0);
|
|
56
59
|
}
|
|
60
|
+
prev.fill(0);
|
|
57
61
|
return okm.slice(0, length);
|
|
58
62
|
}
|
|
59
63
|
// One-shot: extract then expand
|
|
60
64
|
derive(ikm, salt, info, length) {
|
|
61
65
|
const prk = this.extract(salt, ikm);
|
|
62
|
-
|
|
66
|
+
const okm = this.expand(prk, info, length);
|
|
67
|
+
prk.fill(0);
|
|
68
|
+
return okm;
|
|
63
69
|
}
|
|
64
70
|
dispose() {
|
|
65
71
|
this.hmac.dispose();
|
|
@@ -92,15 +98,21 @@ export class HKDF_SHA512 {
|
|
|
92
98
|
buf.set(prev, 0);
|
|
93
99
|
buf.set(info, prev.length);
|
|
94
100
|
buf[prev.length + info.length] = i;
|
|
101
|
+
const oldPrev = prev;
|
|
95
102
|
prev = this.hmac.hash(prk, buf);
|
|
96
103
|
okm.set(prev, (i - 1) * 64);
|
|
104
|
+
buf.fill(0);
|
|
105
|
+
oldPrev.fill(0);
|
|
97
106
|
}
|
|
107
|
+
prev.fill(0);
|
|
98
108
|
return okm.slice(0, length);
|
|
99
109
|
}
|
|
100
110
|
// One-shot: extract then expand
|
|
101
111
|
derive(ikm, salt, info, length) {
|
|
102
112
|
const prk = this.extract(salt, ikm);
|
|
103
|
-
|
|
113
|
+
const okm = this.expand(prk, info, length);
|
|
114
|
+
prk.fill(0);
|
|
115
|
+
return okm;
|
|
104
116
|
}
|
|
105
117
|
dispose() {
|
|
106
118
|
this.hmac.dispose();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "leviathan-crypto",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"author": "xero (https://x-e.ro)",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"description": "Zero-dependency WebAssembly cryptography library for TypeScript: Serpent-256, XChaCha20-Poly1305, SHA-2/3, HMAC, HKDF, and Fortuna CSPRNG, with a strictly typed API built on vector-verified primitives.",
|
|
@@ -20,38 +20,6 @@
|
|
|
20
20
|
"SECURITY.md",
|
|
21
21
|
"CLAUDE.md"
|
|
22
22
|
],
|
|
23
|
-
"scripts": {
|
|
24
|
-
"build:asm": "node scripts/build-asm.js",
|
|
25
|
-
"build:embed": "npx tsx scripts/embed-wasm.ts",
|
|
26
|
-
"build:ts": "tsc",
|
|
27
|
-
"build:docs": "bunx tsx scripts/copy-docs.ts",
|
|
28
|
-
"build": "rm -rf src/ts/embedded/* dist && bun run build:asm && bun run build:embed && bun run build:ts && cp build/*.wasm dist/ 2>/dev/null || true && cp docs/CLAUDE_consumer.md CLAUDE.md && bun run build:docs",
|
|
29
|
-
"test": "bun run build:asm && bun run build:embed && vitest run",
|
|
30
|
-
"test:browser": "bun run build && playwright test",
|
|
31
|
-
"test:all": "bun run test && bun run test:browser",
|
|
32
|
-
"lint": "eslint .",
|
|
33
|
-
"lint:fix": "eslint . --fix",
|
|
34
|
-
"pin-actions": "bun run scripts/pin-actions.ts",
|
|
35
|
-
"_shorthand": "# aliases: 'bun bake' = build, 'bun fix' = lint:fix, 'bun check' = test:all, 'bun pin' = pin-actions",
|
|
36
|
-
"bake": "bun run build",
|
|
37
|
-
"fix": "bun run lint:fix",
|
|
38
|
-
"check": "bun run test:all",
|
|
39
|
-
"pin": "bun run pin-actions"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@eslint/js": "^10.0.1",
|
|
43
|
-
"@playwright/test": "^1.58.2",
|
|
44
|
-
"@types/node": "^25.5.0",
|
|
45
|
-
"@vitest/web-worker": "^3.2.4",
|
|
46
|
-
"assemblyscript": "^0.27.37",
|
|
47
|
-
"eslint": "^10.0.3",
|
|
48
|
-
"jiti": "^2.6.1",
|
|
49
|
-
"pin-github-action": "^3.4.0",
|
|
50
|
-
"tsx": "^4.21.0",
|
|
51
|
-
"typescript": "^5.9.3",
|
|
52
|
-
"typescript-eslint": "^8.57.1",
|
|
53
|
-
"vitest": "^3.2.4"
|
|
54
|
-
},
|
|
55
23
|
"repository": {
|
|
56
24
|
"type": "git",
|
|
57
25
|
"url": "git+https://github.com/xero/leviathan-crypto.git"
|