scrypt: a memory-hard key derivation function and its deliberately cautious CLI
The scrypt key derivation function was originally developed for use in the Tarsnap online backup system and is designed to be far more secure against hardware brute-force attacks than alternative functions such as PBKDF2 or bcrypt.
At a glance
- What is it?
- scrypt is a key derivation function built to make hardware brute-force attacks expensive by requiring large amounts of memory, and it ships with a demonstration encryption utility whose own documentation warns that decryption can emit output before it knows the data was corrupt. It is the KDF behind Tarsnap and the subject of RFC 7914.
- Who is it for?
- scrypt fits a developer deriving a key from a password for a file or a service, who wants a memory-hard function with a published specification and a reference implementation in C they can read.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 32 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Memory hardness is the whole point
scrypt is a key derivation function, a KDF, which is the primitive that turns a low entropy password into a key suitable for encrypting something. The README states why this one exists: it was originally developed for use in the Tarsnap online backup system and is designed to be far more secure against hardware brute-force attacks than alternative functions such as PBKDF2 or bcrypt.
The mechanism that distinguishes it is memory hardness, which the README links to the original conference paper, Colin Percival's Stronger Key Derivation via Sequential Memory-Hard Functions, presented at BSDCan in May 2009, and to the IETF specification RFC 7914. Later cryptanalysis is also cited, the paper Scrypt is Maximally Memory-Hard from the 2016 IACR eprint archive, which is the reference to read if you want the current state of the argument rather than the original claim.
The practical difference from the alternatives the README names is that an attacker who builds a dedicated machine to try passwords pays in memory as well as in time. A function that can be attacked with cheap parallel hardware without a large memory footprint is attractive to an attacker with a budget. A memory-hard function removes that shortcut, so the attacker has to buy memory as well as silicon.
The audience is developers who need a password-derived key and want a function with a written specification, a reference implementation they can read in C, and a track record of having been deployed in a real backup service rather than only benchmarked.
The cost claims are the project's own, and they are dated
The README makes quantitative claims, and they are worth quoting with their caveats attached rather than repeating as fact.
The first estimate: on modern (2009) hardware, if 5 seconds are spent computing a derived key, the cost of a hardware brute-force attack against scrypt is roughly 4000 times greater than the cost of a similar attack against bcrypt to find the same password, and 20000 times greater than a similar attack against PBKDF2.
The second: if the scrypt encryption utility is used with default parameters, the cost of cracking the password on a file encrypted by scrypt enc is approximately 100 billion times more than the cost of cracking the same password on a file encrypted by openssl enc. The README draws the conclusion that a five-character password using scrypt is stronger than a ten-character password using openssl.
Three observations for anyone deciding on this. First, these are the maintainer's estimates, published by the project, not an independent measurement, and they are anchored to 2009 hardware, which is a decade and a half old. Second, the comparison in the second claim is between two password-based encryption utilities, not between scrypt and a modern memory-hard alternative, and it inherits whatever weaknesses the older tool has. Third, the underlying security argument has moved on since 2009, which is why the README cites the 2016 memory-hardness result and why it links to Filippo Valsorda's explanation of how the scrypt parameters affect memory usage and CPU time.
For a decision, the useful part is not the ratio. It is that scrypt is memory-hard, standardised, and has been analysed since publication.
The scrypt utility is a demonstration, not a product
The command line tool exists to show the KDF in use, and the README says so: it is a simple password-based encryption utility available as a demonstration of the scrypt key derivation function.
Its shape is three subcommands:
* `scrypt enc [options] infile [outfile]` to encrypt data, * `scrypt dec [options] infile [outfile]` to decrypt data, or * `scrypt info infile` to see the encryption parameters used, and the memory required to decrypt the encrypted file.
If the output file is not specified, the output is written to standard output, which makes the tool composable in a pipeline.
The options are the interesting part, because they encode the time-memory cost trade-off. `-t maxtime` instructs scrypt to spend at most maxtime seconds computing the derived encryption key. For encryption that value determines how secure the encrypted data is; for decryption it is used as an upper limit, and if scrypt detects that it would take too long to decrypt the data it exits with an error message. `-m maxmemfrac` sets the maximum fraction of available RAM, with the same asymmetry: raising it might increase security of new data, and for decryption it is an upper limit that may cause scrypt to exit with an error. `-M maxmem` is the same idea in absolute bytes.
For explicit control, `--logN value1`, `-r value2` and `-p value3` set the encryption parameters outright, and `--passphrase method:arg` chooses where the passphrase comes from: stdin, /dev/tty, an environment variable, or a file.
The `scrypt info` subcommand is the one an operator should remember. When someone asks you to decrypt a file on a machine with less memory than the file needs, info tells you the parameters and the memory requirement before you try.
Decryption can emit output before it knows the data was corrupt
This is the paragraph in the README that any engineer integrating the tool should read twice.
If the encrypted data is corrupt, scrypt dec exits with a non-zero status. But, and this is the point, scrypt dec may produce output before it determines that the encrypted data was corrupt. The README's guidance is direct: for applications which require data to be authenticated, you must store the output of scrypt dec in a temporary location and check scrypt's exit code before using the decrypted data.
The reason is structural rather than a bug in the tool. Encryption here is a stream of data followed by a check that detects corruption at the end, so the tool has to decrypt and stream as it goes, and by the time it learns the tail is wrong it has already emitted bytes that looked fine. The exit status carries the verdict, but the bytes on stdout do not.
That makes the correct integration pattern clear. Write the decrypted output to a temporary file, run the command, check the exit status, and only then move the file into place. Any pipeline that pipes scrypt dec straight into another program is consuming unauthenticated data and should not be used where integrity matters.
It also defines where this utility stops being the right tool. If your requirement is authenticated encryption in one step, a tool that provides a MAC or an AEAD construction is the correct dependency, and this CLI is a demonstration of a KDF rather than a serious file encryption product.
Using the KDF from C, with constraints the API states outright
If you are writing an application rather than encrypting a file by hand, the library is the point of the project. The README describes using scrypt as a key derivation function with libscrypt-kdf: include scrypt-kdf.h and call one function.
/**
* scrypt_kdf(passwd, passwdlen, salt, saltlen, N, r, p, buf, buflen):
* Compute scrypt(passwd[0 .. passwdlen - 1], salt[0 .. saltlen - 1], N, r,
* p, buflen) and write the result into buf. The parameters r, p, and buflen
* must satisfy 0 < r * p < 2^30 and buflen <= (2^32 - 1) * 32. The parameter
* N must be a power of 2 greater than 1.
*
* Return 0 on success; or -1 on error.
*/
int scrypt_kdf(const uint8_t *, size_t, const uint8_t *, size_t, uint64_t,
uint32_t, uint32_t, uint8_t *, size_t);The header comment states the parameter constraints rather than leaving them to the reader. r times p must be strictly between 0 and 2^30, the output length cannot exceed (2^32 - 1) times 32, and N has to be a power of two greater than one. Get any of those wrong and the call returns -1 rather than producing a key.
A working example ships with the source. The README points to the sample of using this function in tests/libscrypt-kdf, and if you have installed the library you can compile that file and run the binary:
$ cd tests/libscrypt-kdf/
$ c99 sample-libscrypt-kdf.c -lscrypt-kdf
$ ./a.out
crypto_scrypt(): successThere is a second integration route for projects that would rather vendor the source than link a library. The README says that if you prefer to copy the source files directly into your project, take a look at the lib/crypto/crypto_scrypt.h header, which provides crypto_scrypt(). That is a real choice for embedded targets with no package manager, at the cost of carrying the code yourself.
Building and testing, with memory-aware test modes
The build is a standard autotools one, and the README strongly recommends using the latest official release tarball rather than a checkout. To build scrypt, extract the tarball and run ./configure and make. The BUILDING file has more detail, including dealing with OpenSSL on OSX.
The test suite has options that reflect the fact that this function is memory hungry. A small test suite can be run with make test. On platforms with less than 1 GB of RAM, use make test SMALLMEM=1. Memory-testing normal operations with valgrind, which takes approximately 4 times as long as no valgrind tests, is enabled with make test USE_VALGRIND=1, and memory-testing all tests with valgrind, which requires over 1 GB of memory and takes approximately 4 times as long as USE_VALGRIND=1, is enabled with make test USE_VALGRIND=2.
The platform coverage is documented as well. The scrypt utility has been tested on FreeBSD, NetBSD, OpenBSD, Linux (Slackware, CentOS, Gentoo, Ubuntu), Solaris, OS X, Cygwin and GNU Hurd. The repository layout supports that breadth: lib-platform/ holds the platform specific pieces, libcperciva/ and lib/ carry the reusable code, libscrypt-kdf/ is the KDF library, and main.c, scrypt.1, configure.ac, Makefile.am and m4/ make up the utility and its build system. There is also an AGENTS.md file at the root, which is worth reading before you make changes, and separate STYLE and FORMAT documents.
The mailing list is announced at the end of the README for both the KDF and the encryption utility, which is the right place to take a question that the documentation does not answer.
Releases come from tarsnap.com with a signature, not from GitHub
The repository has no GitHub releases. Instead, the official releases are hosted by Tarsnap, and the README links a scrypt version 1.3.3 source tarball along with a GPG-signed SHA256 file for that same version, whose signature was generated using the Tarsnap code signing key.
The verification procedure is written out. The cleartext signature of the SHA256 output can be verified with gpg --decrypt scrypt-sigs-1.3.3.asc, and you may then compare the displayed hash to the SHA256 hash of the tarball. That is a complete supply chain check for a two-file download, and it is worth doing for a component that ends up guarding password material.
Packaging is handled elsewhere too. The README notes that scrypt is available in the OpenBSD and FreeBSD ports trees and in NetBSD pkgsrc as security/scrypt, so on those systems you install a packaged version rather than building it yourself.
One governance point deserves a close look. The licence is recorded as a custom one that GitHub cannot classify, and the repository root contains a COPYRIGHT file alongside the source. For a library that many projects vendor by copying crypto_scrypt() into their own tree, the licence text is the thing to read before you do that, because it governs how the code may be redistributed. That is a pointer to a document rather than a legal opinion, and the place to check is the COPYRIGHT file in the repository root.
On activity, the last push was on 2026-09-21, so the tree is being maintained even though the released artefact and the repository are separate things.
Editorial conclusion
scrypt fits a developer deriving a key from a password for a file or a service, who wants a memory-hard function with a published specification and a reference implementation in C they can read. It does not fit a pipeline that needs authenticated encryption in one step, since the utility warns that scrypt dec may produce output before it detects corruption, and it does not fit a team unwilling to read the COPYRIGHT file, because the licence is a custom one GitHub cannot classify. Verify first that you check the exit status of scrypt dec before using its output, that the parameters you pass satisfy 0 < r * p < 2^30 with N a power of two, and that the release tarball you download matches the GPG-signed SHA256 file.
Frequently asked questions
Why would I use scrypt instead of PBKDF2 or bcrypt?
The README says scrypt was developed for Tarsnap and is designed to be far more secure against hardware brute-force attacks than alternatives such as PBKDF2 or bcrypt. Its distinguishing property is memory hardness, described in Percival's 2009 paper and standardised in RFC 7914.
How do I encrypt and decrypt a file with the scrypt utility?
Use scrypt enc [options] infile [outfile] to encrypt, scrypt dec [options] infile [outfile] to decrypt, and scrypt info infile to see the encryption parameters and the memory needed to decrypt. If the output file is not given, output goes to standard output.
What do the -t, -m and -M options do in scrypt?
They set limits on the work done to derive the key: -t maxtime caps the seconds spent, -m maxmemfrac caps the fraction of available RAM and -M maxmem caps the bytes of RAM. For encryption they influence how secure the new data is; for decryption they act as upper limits that can make the command exit with an error.
Is the output of scrypt dec safe to use directly?
Not without checking the exit status. The README warns that scrypt dec may produce output before it determines that the encrypted data was corrupt, so applications that need authenticated data must write the output to a temporary location and check scrypt's exit code before using it.
How do I call scrypt from C?
Include scrypt-kdf.h and call scrypt_kdf, which returns 0 on success or -1 on error. The parameters must satisfy 0 < r * p < 2^30, buflen <= (2^32 - 1) * 32, and N must be a power of 2 greater than 1. A sample lives in tests/libscrypt-kdf, and crypto_scrypt() is available in lib/crypto/crypto_scrypt.h if you prefer to copy the source into your project.
How do I verify the scrypt release tarball?
Download the tarball and the GPG-signed SHA256 file from tarsnap.com, run gpg --decrypt scrypt-sigs-1.3.3.asc and compare the displayed hash with the SHA256 of the tarball. On BSD systems, scrypt is also packaged in the OpenBSD and FreeBSD ports trees and in NetBSD pkgsrc as security/scrypt.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/tarsnap-scrypt)Was this useful?