oxios-web 0.2.0

Web dashboard channel for Oxios
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
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
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# noble-ciphers

Audited & minimal JS implementation of Salsa20, ChaCha and AES.

- 🔒 [**Audited**]#security by an independent security firm
- 🔻 Tree-shakeable: unused code is excluded from your builds
- 🏎 Fast: hand-optimized for caveats of JS engines
- 🔍 Reliable: property-based / cross-library / wycheproof tests ensure correctness
- 💼 AES: ECB, CBC, CTR, CFB, GCM, SIV (nonce misuse-resistant), AESKW, AESKWP
- 💃 Salsa20, ChaCha, XSalsa20, XChaCha, ChaCha8, ChaCha12, Poly1305
- 🥈 Two AES implementations: pure JS or friendly wrapper around webcrypto
- 🪶 29KB (11KB gzipped) for everything, 7KB (3KB gzipped) for ChaCha build

Take a glance at [GitHub Discussions](https://github.com/paulmillr/noble-ciphers/discussions) for questions and support.

### This library belongs to _noble_ cryptography

> **noble cryptography** — high-security, easily auditable set of contained cryptographic libraries and tools.

- Zero or minimal dependencies
- Highly readable TypeScript / JS code
- PGP-signed releases and transparent NPM builds
- All libraries:
  [ciphers]https://github.com/paulmillr/noble-ciphers,
  [curves]https://github.com/paulmillr/noble-curves,
  [hashes]https://github.com/paulmillr/noble-hashes,
  [post-quantum]https://github.com/paulmillr/noble-post-quantum,
  4kb [secp256k1]https://github.com/paulmillr/noble-secp256k1 /
  [ed25519]https://github.com/paulmillr/noble-ed25519
- [Check out homepage]https://paulmillr.com/noble/
  for reading resources, documentation and apps built with noble

## Usage

> `npm install @noble/ciphers`

> `deno add jsr:@noble/ciphers`

> `deno doc jsr:@noble/ciphers` # command-line documentation

We support all major platforms and runtimes.
For React Native, you may need a
[polyfill for getRandomValues](https://github.com/LinusU/react-native-get-random-values).
A standalone file
[noble-ciphers.js](https://github.com/paulmillr/noble-ciphers/releases) is also available.

```ts
// import * from '@noble/ciphers'; // Error: use sub-imports, to ensure small app size
import { gcm, siv } from '@noble/ciphers/aes';
import { chacha20poly1305, xchacha20poly1305 } from '@noble/ciphers/chacha';
import { xsalsa20poly1305, secretbox } from '@noble/ciphers/salsa';

// Unauthenticated encryption: make sure to use HMAC or similar
import { ctr, cfb, cbc, ecb } from '@noble/ciphers/aes';
import { salsa20, xsalsa20 } from '@noble/ciphers/salsa';
import { chacha20, xchacha20, chacha8, chacha12 } from '@noble/ciphers/chacha';
import { aeskw, aeskwp } from '@noble/ciphers/aes'; // KW
import { bytesToHex, hexToBytes, bytesToUtf8, utf8ToBytes } from '@noble/ciphers/utils';
import { managedNonce, randomBytes } from '@noble/ciphers/webcrypto';
```

- [Examples]#examples
  - [XChaCha20-Poly1305 encryption]#xchacha20-poly1305-encryption
  - [AES-256-GCM encryption]#aes-256-gcm-encryption
  - [AES: gcm, siv, ctr, cfb, cbc, ecb]#aes-gcm-siv-ctr-cfb-cbc-ecb
  - [Friendly WebCrypto AES]#friendly-webcrypto-aes
  - [AESKW and AESKWP]#aeskw-and-aeskwp
  - [Auto-handle nonces]#auto-handle-nonces
  - [Reuse array for input and output]#reuse-array-for-input-and-output
- [Internals]#internals
  - [Implemented primitives]#implemented-primitives
  - [Which cipher should I pick?]#which-cipher-should-i-pick
  - [How to encrypt properly]#how-to-encrypt-properly
  - [Nonces]#nonces
  - [Encryption limits]#encryption-limits
  - [AES internals and block modes]#aes-internals-and-block-modes
- [Security]#security
- [Speed]#speed
- [Upgrading]#upgrading
- [Contributing & testing]#contributing--testing
- [License]#license

## Examples

> [!NOTE]
> Use different nonce every time `encrypt()` is done.

#### XChaCha20-Poly1305 encryption

```js
import { xchacha20poly1305 } from '@noble/ciphers/chacha';
import { utf8ToBytes } from '@noble/ciphers/utils';
import { randomBytes } from '@noble/ciphers/webcrypto';
const key = randomBytes(32); // random key
// const key = new Uint8Array([ // existing key
//   169, 88, 160, 139, 168, 29, 147, 196, 14, 88, 237, 76, 243, 177, 109, 140,
//   195, 140, 80, 10, 216, 134, 215, 71, 191, 48, 20, 104, 189, 37, 38, 55,
// ]);
// import { hexToBytes } from '@noble/ciphers/utils'; // hex key
// const key = hexToBytes('4b7f89bac90a1086fef73f5da2cbe93b2fae9dfbf7678ae1f3e75fd118ddf999');
const nonce = randomBytes(24);
const chacha = xchacha20poly1305(key, nonce);
const data = utf8ToBytes('hello, noble');
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext); // utils.bytesToUtf8(data_) === data
```

#### AES-256-GCM encryption

```js
import { gcm } from '@noble/ciphers/aes';
import { utf8ToBytes } from '@noble/ciphers/utils';
import { randomBytes } from '@noble/ciphers/webcrypto';
const key = randomBytes(32);
const nonce = randomBytes(24);
const data = utf8ToBytes('hello, noble');
const aes = gcm(key, nonce);
const ciphertext = aes.encrypt(data);
const data_ = aes.decrypt(ciphertext); // utils.bytesToUtf8(data_) === data
```

#### AES: gcm, siv, ctr, cfb, cbc, ecb

```js
import { gcm, siv, ctr, cfb, cbc, ecb } from '@noble/ciphers/aes';
import { randomBytes } from '@noble/ciphers/webcrypto';
const plaintext = new Uint8Array(32).fill(16);
for (let cipher of [gcm, siv]) {
  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
  const nonce = randomBytes(12);
  const ciphertext_ = cipher(key, nonce).encrypt(plaintext);
  const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ctr, cbc, cfb]) {
  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
  const nonce = randomBytes(16);
  const ciphertext_ = cipher(key, nonce).encrypt(plaintext);
  const plaintext_ = cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ecb]) {
  const key = randomBytes(32); // 24 for AES-192, 16 for AES-128
  const ciphertext_ = cipher(key).encrypt(plaintext);
  const plaintext_ = cipher(key).decrypt(ciphertext_);
}
```

#### Friendly WebCrypto AES

Noble implements AES. Sometimes people want to use built-in `crypto.subtle` instead. However, it has terrible API. We simplify access to built-ins.

> [!NOTE]
> Webcrypto methods are always async.

```js
import { gcm, ctr, cbc, randomBytes } from '@noble/ciphers/webcrypto';
const plaintext = new Uint8Array(32).fill(16);
const key = randomBytes(32);
for (const cipher of [gcm]) {
  const nonce = randomBytes(12);
  const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);
  const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);
}
for (const cipher of [ctr, cbc]) {
  const nonce = randomBytes(16);
  const ciphertext_ = await cipher(key, nonce).encrypt(plaintext);
  const plaintext_ = await cipher(key, nonce).decrypt(ciphertext_);
}
```

#### AESKW and AESKWP

```ts
import { aeskw, aeskwp } from '@noble/ciphers/aes';
import { hexToBytes } from '@noble/ciphers/utils';

const kek = hexToBytes('000102030405060708090A0B0C0D0E0F');
const keyData = hexToBytes('00112233445566778899AABBCCDDEEFF');
const ciphertext = aeskw(kek).encrypt(keyData);
```

#### Auto-handle nonces

We provide API that manages nonce internally instead of exposing them to library's user.

For `encrypt`, a `nonceBytes`-length buffer is fetched from CSPRNG and prenended to encrypted ciphertext.

For `decrypt`, first `nonceBytes` of ciphertext are treated as nonce.

```js
import { xchacha20poly1305 } from '@noble/ciphers/chacha';
import { managedNonce } from '@noble/ciphers/webcrypto';
import { hexToBytes, utf8ToBytes } from '@noble/ciphers/utils';
const key = hexToBytes('fa686bfdffd3758f6377abbc23bf3d9bdc1a0dda4a6e7f8dbdd579fa1ff6d7e1');
const chacha = managedNonce(xchacha20poly1305)(key); // manages nonces for you
const data = utf8ToBytes('hello, noble');
const ciphertext = chacha.encrypt(data);
const data_ = chacha.decrypt(ciphertext);
```

#### Reuse array for input and output

To avoid additional allocations, Uint8Array can be reused
between encryption and decryption calls.

> [!NOTE]
> Some ciphers don't support unaligned (`byteOffset % 4 !== 0`) Uint8Array as
> destination. It can decrease performance, making the optimization pointless.

```js
import { chacha20poly1305 } from '@noble/ciphers/chacha';
import { utf8ToBytes } from '@noble/ciphers/utils';
import { randomBytes } from '@noble/ciphers/webcrypto';

const key = randomBytes(32);
const nonce = randomBytes(12);
const chacha = chacha20poly1305(key, nonce);

const input = utf8ToBytes('hello, noble'); // length == 12
const inputLength = input.length;
const tagLength = 16;

const buf = new Uint8Array(inputLength + tagLength);
const start = buf.subarray(0, inputLength);
start.set(input); // copy input to buf

chacha.encrypt(start, buf); // encrypt into `buf`
chacha.decrypt(buf, start); // decrypt into `start`
```

xsalsa20poly1305 also supports this, but requires 32 additional bytes for encryption / decryption,
due to its inner workings.

## Internals

### Implemented primitives

- [Salsa20]https://cr.yp.to/snuffle.html stream cipher, released in 2005.
  Salsa's goal was to implement AES replacement that does not rely on S-Boxes,
  which are hard to implement in a constant-time manner.
  Salsa20 is usually faster than AES, a big deal on slow, budget mobile phones.
  - [XSalsa20]https://cr.yp.to/snuffle/xsalsa-20110204.pdf, extended-nonce
    variant was released in 2008. It switched nonces from 96-bit to 192-bit,
    and became safe to be picked at random. - Nacl / Libsodium popularized term "secretbox", a simple black-box
    authenticated encryption. Secretbox is just xsalsa20-poly1305. We provide the
    alias and corresponding seal / open methods. We don't provide "box" or "sealedbox".
  - Check out [PDF]https://cr.yp.to/snuffle/salsafamily-20071225.pdf and
    [wiki]https://en.wikipedia.org/wiki/Salsa20.
- [ChaCha20]https://cr.yp.to/chacha.html stream cipher, released
  in 2008. Developed after Salsa20, ChaCha aims to increase diffusion per round.
  It was standardized in [RFC 8439]https://datatracker.ietf.org/doc/html/rfc8439
  and is now used in TLS 1.3.
  - [XChaCha20]https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha
    extended-nonce variant is also provided. Similar to XSalsa, it's safe to use with
    randomly-generated nonces.
  - Check out [PDF]http://cr.yp.to/chacha/chacha-20080128.pdf and [wiki]https://en.wikipedia.org/wiki/Salsa20.
- [AES]https://en.wikipedia.org/wiki/Advanced_Encryption_Standard
  is a variant of Rijndael block cipher, standardized by NIST in 2001.
  We provide the fastest available pure JS implementation.
  - We support AES-128, AES-192 and AES-256: the mode is selected dynamically,
    based on key length (16, 24, 32).
  - [AES-GCM-SIV]https://en.wikipedia.org/wiki/AES-GCM-SIV
    nonce-misuse-resistant mode is also provided. It's recommended to use it,
    to prevent catastrophic consequences of nonce reuse. Our implementation of SIV
    has the same speed as GCM: there is no performance hit.
  - We also have AESKW and AESKWP from
    [RFC 3394]https://datatracker.ietf.org/doc/html/rfc3394 / [RFC 5649]https://datatracker.ietf.org/doc/html/rfc5649
  - Check out [AES internals and block modes]#aes-internals-and-block-modes.
- We expose polynomial-evaluation MACs: [Poly1305]https://cr.yp.to/mac.html, AES-GCM's [GHash]https://en.wikipedia.org/wiki/Galois/Counter_Mode and
  AES-SIV's [Polyval]https://en.wikipedia.org/wiki/AES-GCM-SIV.
  - Poly1305 ([PDF]https://cr.yp.to/mac/poly1305-20050329.pdf,
    [wiki]https://en.wikipedia.org/wiki/Poly1305)
    is a fast and parallel secret-key message-authentication code suitable for
    a wide variety of applications. It was standardized in
    [RFC 8439]https://datatracker.ietf.org/doc/html/rfc8439 and is now used in TLS 1.3.
  - Polynomial MACs are not perfect for every situation:
    they lack Random Key Robustness: the MAC can be forged, and can't
    be used in PAKE schemes. See
    [invisible salamanders attack]https://keymaterial.net/2020/09/07/invisible-salamanders-in-aes-gcm-siv/.
    To combat invisible salamanders, `hash(key)` can be included in ciphertext,
    however, this would violate ciphertext indistinguishability:
    an attacker would know which key was used - so `HKDF(key, i)`
    could be used instead.
- Format-preserving encryption algorithm (FPE-FF1) specified in NIST Special Publication 800-38G.
  [See more info]https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-38G.pdf.

### Which cipher should I pick?

We suggest to use XChaCha20-Poly1305.
If you can't use it, prefer AES-GCM-SIV, or AES-GCM.

### How to encrypt properly

- Use unpredictable key with enough entropy
  - Random key must be using cryptographically secure random number generator (CSPRNG), not `Math.random` etc.
  - Non-random key generated from KDF is fine
  - Re-using key is fine, but be aware of rules for cryptographic key wear-out and [encryption limits]#encryption-limits
- Use new nonce every time and [don't repeat it]#nonces
  - chacha and salsa20 are fine for sequential counters that _never_ repeat: `01, 02...`
  - xchacha and xsalsa20 should use random nonces instead
  - AES-GCM should use 12-byte nonces: smaller nonces are security risk
- Prefer authenticated encryption (AEAD)
  - chacha20poly1305 / aes-gcm / ChaCha + HMAC / AES + HMAC is good
  - chacha20 / aes-ctr / aes-cbc without poly1305 or hmac is bad
  - Flipping bits or ciphertext substitution won't be detected in unauthenticated ciphers
- Don't re-use keys between different protocols
  - For example, using secp256k1 key in AES can be bad
  - Use hkdf or, at least, a hash function to create sub-key instead
- If you need AES, only use AES-256 for new protocols
  - For post-quantum security

### Nonces

Most ciphers need a key and a nonce (aka initialization vector / IV) to encrypt a data:

    ciphertext = encrypt(plaintext, key, nonce)

Repeating (key, nonce) pair with different plaintexts would allow an attacker to decrypt it:

    ciphertext_a = encrypt(plaintext_a, key, nonce)
    ciphertext_b = encrypt(plaintext_b, key, nonce)
    stream_diff = xor(ciphertext_a, ciphertext_b)   # Break encryption

So, you can't repeat nonces. One way of doing so is using counters:

    for i in 0..:
        ciphertext[i] = encrypt(plaintexts[i], key, i)

Another is generating random nonce every time:

    for i in 0..:
        rand_nonces[i] = random()
        ciphertext[i] = encrypt(plaintexts[i], key, rand_nonces[i])

Counters are OK, but it's not always possible to store current counter value:
e.g. in decentralized, unsyncable systems.

Randomness is OK, but there's a catch:
ChaCha20 and AES-GCM use 96-bit / 12-byte nonces, which implies higher chance of collision.
In the example above, `random()` can collide and produce repeating nonce.
Chance is even higher for 64-bit nonces, which GCM allows - don't use them.

To safely use random nonces, utilize XSalsa20 or XChaCha:
they increased nonce length to 192-bit, minimizing a chance of collision.
AES-SIV is also fine. In situations where you can't use eXtended-nonce
algorithms, key rotation is advised. hkdf would work great for this case.

### Encryption limits

A "protected message" would mean a probability of `2**-50` that a passive attacker
successfully distinguishes the ciphertext outputs of the AEAD scheme from the outputs
of a random function. See [draft-irtf-cfrg-aead-limits](https://datatracker.ietf.org/doc/draft-irtf-cfrg-aead-limits/) for details.

- Max message size:
  - AES-GCM: ~68GB, `2**36-256`
  - Salsa, ChaCha, XSalsa, XChaCha: ~256GB, `2**38-64`
- Max amount of protected messages, under same key:
  - AES-GCM: `2**32.5`
  - Salsa, ChaCha: `2**46`, but only integrity is affected, not confidentiality
  - XSalsa, XChaCha: `2**72`
- Max amount of protected messages, across all keys:
  - AES-GCM: `2**69/B` where B is max blocks encrypted by a key. Meaning
    `2**59` for 1KB, `2**49` for 1MB, `2**39` for 1GB
  - Salsa, ChaCha, XSalsa, XChaCha: `2**100`

##### AES internals and block modes

`cipher = encrypt(block, key)`. Data is split into 128-bit blocks. Encrypted in 10/12/14 rounds (128/192/256bit). Every round does:

1. **S-box**, table substitution
2. **Shift rows**, cyclic shift left of all rows of data array
3. **Mix columns**, multiplying every column by fixed polynomial
4. **Add round key**, round_key xor i-th column of array

For non-deterministic (not ECB) schemes, initialization vector (IV) is mixed to block/key;
and each new round either depends on previous block's key, or on some counter.

- ECB (Electronic Codebook): Deterministic encryption; identical plaintext blocks yield identical ciphertexts. Insecure due to pattern leakage.
  See [AES Penguin]https://words.filippo.io/the-ecb-penguin/
- CBC (Cipher Block Chaining): Each plaintext block is XORed with the previous ciphertext block before encryption.
  Hard to use: requires proper padding and an IV. Needs a separate MAC.
- CTR (Counter Mode): Turns a block cipher into a stream cipher using a counter and IV (nonce).
  Efficient and parallelizable. Requires a unique nonce per encryption. Better, but still needs a separate MAC.
- GCM (Galois/Counter Mode): Combines CTR mode with polynomial MAC. Efficient and widely used.
- SIV (Synthetic IV): Nonce-misuse-resistant mode; repeating nonces reveal only if plaintexts are identical.
  Maintains security even if nonces are reused.
- XTS: Designed for disk encryption.
  Similar to ECB (deterministic), but has `[i][j]` tweak arguments corresponding to sector i and 16-byte block (part of sector) j.
  Lacks MAC.

GCM / SIV are not ideal:

- Conservative key wear-out is `2**32` (4B) msgs
- MAC can be forged: see Poly1305 section above. Same for SIV

## Security

The library has been independently audited:

- at version 1.0.0, in Sep 2024, by [cure53]https://cure53.de
  - PDFs: [website]https://cure53.de/audit-report_noble-crypto-libs.pdf, [in-repo]./audit/2024-09-cure53-audit-nbl4.pdf
  - [Changes since audit]https://github.com/paulmillr/noble-ciphers/compare/1.0.0..main
  - Scope: everything
  - The audit has been funded by [OpenSats]https://opensats.org

It is tested against property-based, cross-library and Wycheproof vectors,
and is being fuzzed in [the separate repo](https://github.com/paulmillr/fuzzing).

If you see anything unusual: investigate and report.

### Constant-timeness

We're targetting algorithmic constant time. _JIT-compiler_ and _Garbage Collector_ make "constant time"
extremely hard to achieve [timing attack](https://en.wikipedia.org/wiki/Timing_attack) resistance
in a scripting language. Which means _any other JS library can't have
constant-timeness_. Even statically typed Rust, a language without GC,
[makes it harder to achieve constant-time](https://www.chosenplaintext.ca/open-source/rust-timing-shield/security)
for some cases. If your goal is absolute security, don't use any JS lib — including bindings to native ones.
Use low-level libraries & languages.

The library uses T-tables for AES, which
[leak access timings](https://cr.yp.to/antiforgery/cachetiming-20050414.pdf).
This is also done in [OpenSSL](https://github.com/openssl/openssl/blob/2f33265039cdbd0e4589c80970e02e208f3f94d2/crypto/aes/aes_core.c#L706) and
[Go stdlib](https://cs.opensource.google/go/go/+/refs/tags/go1.22.6:src/crypto/aes/const.go;l=90) for performance reasons.
The analysis was mentioned in [hal-04652991](https://hal.science/hal-04652991/document).

### Supply chain security

- **Commits** are signed with PGP keys, to prevent forgery. Make sure to verify commit signatures
- **Releases** are transparent and built on GitHub CI. Make sure to verify [provenance]https://docs.npmjs.com/generating-provenance-statements logs
  - Use GitHub CLI to verify single-file builds:
    `gh attestation verify --owner paulmillr noble-ciphers.js`
- **Rare releasing** is followed to ensure less re-audit need for end-users
- **Dependencies** are minimized and locked-down: any dependency could get hacked and users will be downloading malware with every install.
  - We make sure to use as few dependencies as possible
  - Automatic dep updates are prevented by locking-down version ranges; diffs are checked with `npm-diff`
- **Dev Dependencies** are disabled for end-users; they are only used to develop / build the source code

For this package, there are 0 dependencies; and a few dev dependencies:

- micro-bmark, micro-should and jsbt are used for benchmarking / testing / build tooling and developed by the same author
- prettier, fast-check and typescript are used for code quality / test generation / ts compilation. It's hard to audit their source code thoroughly and fully because of their size

### Randomness

We're deferring to built-in
[crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues)
which is considered cryptographically secure (CSPRNG).

In the past, browsers had bugs that made it weak: it may happen again.
Implementing a userspace CSPRNG to get resilient to the weakness
is even worse: there is no reliable userspace source of quality entropy.

## Speed

To summarize, noble is the fastest JS implementation of Salsa, ChaCha and AES.

You can gain additional speed-up and
avoid memory allocations by passing `output`
uint8array into encrypt / decrypt methods.

Benchmark results on Apple M4:

```
64B
xsalsa20poly1305 x 675,675 ops/sec @ 1μs/op
chacha20poly1305 x 568,181 ops/sec @ 1μs/op
xchacha20poly1305 x 460,617 ops/sec @ 2μs/op
aes-256-gcm x 201,126 ops/sec @ 4μs/op
aes-256-gcm-siv x 162,284 ops/sec @ 6μs/op
# Unauthenticated encryption
salsa20 x 1,655,629 ops/sec @ 604ns/op
xsalsa20 x 1,400,560 ops/sec @ 714ns/op
chacha20 x 1,996,007 ops/sec @ 501ns/op
xchacha20 x 1,404,494 ops/sec @ 712ns/op
chacha8 x 2,145,922 ops/sec @ 466ns/op
chacha12 x 2,036,659 ops/sec @ 491ns/op
aes-ecb-256 x 1,019,367 ops/sec @ 981ns/op
aes-cbc-256 x 931,966 ops/sec @ 1μs/op
aes-ctr-256 x 954,198 ops/sec @ 1μs/op

1MB
xsalsa20poly1305 x 322 ops/sec @ 3ms/op
chacha20poly1305 x 327 ops/sec @ 3ms/op
xchacha20poly1305 x 331 ops/sec @ 3ms/op
aes-256-gcm x 94 ops/sec @ 10ms/op
aes-256-gcm-siv x 90 ops/sec @ 11ms/op
# Unauthenticated encryption
salsa20 x 791 ops/sec @ 1ms/op
xsalsa20 x 801 ops/sec @ 1ms/op
chacha20 x 787 ops/sec @ 1ms/op
xchacha20 x 781 ops/sec @ 1ms/op
chacha8 x 1,457 ops/sec @ 686μs/op
chacha12 x 1,130 ops/sec @ 884μs/op
aes-ecb-256 x 289 ops/sec @ 3ms/op
aes-cbc-256 x 114 ops/sec @ 8ms/op
aes-ctr-256 x 127 ops/sec @ 7ms/op
# Wrapper over built-in webcrypto
webcrypto ctr-256 x 6,508 ops/sec @ 153μs/op
webcrypto cbc-256 x 1,820 ops/sec @ 549μs/op
webcrypto gcm-256 x 5,106 ops/sec @ 195μs/op
```

Compare to other implementations:

```
xsalsa20poly1305 (encrypt, 1MB)
├─tweetnacl x 196 ops/sec
└─noble x 305 ops/sec

chacha20poly1305 (encrypt, 1MB)
├─node x 1,668 ops/sec
├─stablelib x 202 ops/sec
└─noble x 319 ops/sec

aes-ctr-256 (encrypt, 1MB)
├─stablelib x 123 ops/sec
├─aesjs x 42 ops/sec
├─noble-webcrypto x 5,965 ops/sec
└─noble x 124 ops/sec
```

## Contributing & testing

- `npm install && npm run build && npm test` will build the code and run tests.
- `npm run lint` / `npm run format` will run linter / fix linter issues.
- `npm run bench` will run benchmarks, which may need their deps first (`npm run bench:install`)
- `npm run build:release` will build single file

Check out [github.com/paulmillr/guidelines](https://github.com/paulmillr/guidelines)
for general coding practices and rules.

See [paulmillr.com/noble](https://paulmillr.com/noble/)
for useful resources, articles, documentation and demos
related to the library.

## License

The MIT License (MIT)

Copyright (c) 2023 Paul Miller [(https://paulmillr.com)](https://paulmillr.com)
Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>

See LICENSE file.