---
title: "scrypt"
description: "A memory-hard password KDF. Needs a salt and prints the one it drew and the cost it ran with"
canonical_url: "https://hashes.agntn.dev/algorithms/scrypt"
---
# scrypt

> A memory-hard password KDF. Needs a salt and prints the one it drew and the cost it ran with

<algorithm-facts name="scrypt">



</algorithm-facts>

scrypt fills a big block of memory and reads it back in an order that depends on the data. That makes it expensive on GPUs and ASICs, which is the whole reason it exists. Litecoin mines with it, and wallets from Ethereum's keystore to BIP38 derive keys with it.

```ts
create("scrypt").hash("password", { salt: "4e61436c", N: 1024, r: 8, p: 16 }).digest;
// "fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640"
```

That's the second test vector of RFC 7914: `NaCl` as salt, in hex here, because the salt is hex by default. Without a salt, 32 random bytes are drawn and reported in `result.options`. Keep them, [Salted KDFs](https://hashes.agntn.dev/guide/kdf) has the full story.

Memory is 128·r·N bytes, 16 MiB at the defaults. The page above computes its sample at N 1024, so the tab doesn't freeze while it renders.

Opening a wallet or a keystore yourself? Skip the result object. `scrypt` takes bytes and gives back bytes:

```ts
import { scrypt } from "@agntn/hashes/scrypt";

const text = new TextEncoder();
scrypt(text.encode("password"), text.encode("NaCl"), 1024, 8, 16, 64);
// the same 64 bytes as above
```

Order goes N, r, p, then the key length. No defaults, no random salt, you pass all six. The checks stay, though. Break RFC 7914 and you get an `InvalidOptionError` before any memory is taken. Asking for 1 GiB with N 2^20 and r 8? It'll try. Only the tools cap memory.


## Sitemap

See the full [sitemap](https://hashes.agntn.dev/sitemap.md) for all pages.
