https://github.com/valpackett/argon2ian
Very compact Argon2 in WASM - mirror of https://codeberg.org/valpackett/argon2ian
https://github.com/valpackett/argon2ian
argon2 deno deno-module password-hash typescript typescript-library wasm webassembly
Last synced: 5 months ago
JSON representation
Very compact Argon2 in WASM - mirror of https://codeberg.org/valpackett/argon2ian
- Host: GitHub
- URL: https://github.com/valpackett/argon2ian
- Owner: valpackett
- License: other
- Created: 2023-06-24T04:00:10.000Z (almost 3 years ago)
- Default Branch: trunk
- Last Pushed: 2024-07-26T08:24:20.000Z (almost 2 years ago)
- Last Synced: 2025-09-28T04:15:29.558Z (9 months ago)
- Topics: argon2, deno, deno-module, password-hash, typescript, typescript-library, wasm, webassembly
- Language: TypeScript
- Homepage: https://jsr.io/@valpackett/argon2ian
- Size: 58.6 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Funding: .github/FUNDING.yml
- License: LICENSE
Awesome Lists containing this project
README
# argon2ian [](https://www.patreon.com/valpackett)
A *seriously size-optimized* WebAssembly build + conveniently async-ified TypeScript wrapper
for [Monocypher's implementation](https://monocypher.org/manual/argon2)
of the Argon2 password hash / KDF, the winner of the Password Hashing Competition.
| File | Size in bytes |
| ------------------- | ------------- |
| Raw WASM | 7145 |
| WASM gzipped | 3129 |
| WASM gzipped base64 | 4172 |
| With sync wrapper | 5839 |
| With async wrapper | 6393 |
- No emscripten in the build! Built with raw clang using [wasi-libc](https://github.com/WebAssembly/wasi-libc) for basic headers / compiler-rt
- Using a simple arena allocator
- Both `key` (called `secret`) and `ad` options are exposed for advanced usage
- No `$argon2…` encoded strings support as of right now, as my primary use case is key derivation
- TODO: implement in typescript using [this constant-time base64 impl](https://github.com/StableLib/stablelib/blob/master/packages/base64/base64.ts) I guess
- The `WebAssembly.Instance` is thrown away on every invocation to avoid occupying RAM when not working
- Before that, secrets are wiped from that memory (not that they won't remain all over everywhere on the JS side lol)
- Native `DecompressionStream` used for decompressing the module ([caniuse](https://caniuse.com/mdn-api_compressionstream); WARN: arrived *very* recently in Firefox and Safari as of mid 2023)
- Async wrapper based on Web Workers but completely bundle-able / deno-cache-able, no separate worker files because everything is inlined!
- The sync version exposes the non-keyed blake2b hash function as well, because it's basically free (only added 20 bytes to encoded wasm)
Note: the 1.x version were based on the reference implementation and therefore support version 0x10 and perform a tiny bit better
(e.g. 393 → 372 ms/iter for argon2id with 256MiB) at the cost of extra ~2.2KiB size, not exposing blake2b, and not supporting the `p` (lanes) parameter
(that one was just my fault, not the reference implementation's).
## Usage
### Async (powered by Web Workers)
It's typically not a great idea to block the main thread, whether in a client-side app in a browser or in a server app.
Argon2ian provides an async API that hides all the messiness of Web Workers.
```typescript
import { ArgonWorker, variant } from 'https://deno.land/x/argon2ian/dist/argon2ian.async.min.js'; // bundled
// import { ArgonWorker, variant } from 'jsr:@valpackett/argon2ian/async'; // ← JSR/Deno
import { decode } from 'https://deno.land/std@0.192.0/encoding/hex.ts'; // just for the demo here
const wrk = new ArgonWorker();
const enco = new TextEncoder();
await wrk.ready;
const hash = await wrk.hash(enco.encode('password'), enco.encode('somesalt'),
{ t: 2, variant: variant.Argon2i }); // -> Uint8Array
const isCorrect = await wrk.verify(enco.encode('password'), enco.encode('somesalt'),
decode(enco.encode('c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0')),
{ t: 2, variant: variant.Argon2i }); // -> boolean
console.log(hash, isCorrect);
wrk.terminate(); // e.g. once you're done with it in a browser,
// in a server just keep the worker running forever of course
```
### Blocking
In some scenarios like with many CLI apps there wouldn't be any benefit from the asynchornicity,
or if you're already doing your own Web Worker with your own logic, etc…
```typescript
import { hash, variant, verify } from 'https://deno.land/x/argon2ian/dist/argon2ian.sync.min.js'; // bundled
// import { hash, variant, verify } from 'jsr:@valpackett/argon2ian/sync'; // ← JSR/Deno
import { decode } from 'https://deno.land/std@0.192.0/encoding/hex.ts'; // just for the demo here
const enco = new TextEncoder();
const hsh = hash(enco.encode('password'), enco.encode('somesalt'),
{ t: 2, variant: variant.Argon2i }); // -> Uint8Array
const isCorrect = verify(enco.encode('password'), enco.encode('somesalt'),
decode(enco.encode('c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0')),
{ t: 2, variant: variant.Argon2i }); // -> boolean
console.log(hsh, isCorrect);
```
## License
Like Monocypher, argon2ian is available under CC0 or 2-clause BSD.