3 unstable releases
Uses new Rust 2024
| new 0.2.0 | Feb 27, 2026 |
|---|---|
| 0.1.1 | Feb 23, 2026 |
| 0.1.0 | Feb 23, 2026 |
#989 in Cryptography
24KB
425 lines
compact_argon2
The ergonomics of the argon2 crate sucks.
This crate provides a thin wrapper around argon2's methods and an alternate,
much smaller binary serialization format. It uses whatever the default
parameters of argon2 current are, but uses deserialized parameters during
verification, just like the argon2 crate. It's hardcoded to use the
argon2id algorithm with the default salt and output lengths because get real.
Usage
let password = b"hunter2";
// hash a password
let hash = compact_argon2::hash(password).unwrap();
// verify a password against a hash
assert!(hash.verify(password).unwrap());
// can also be written as
assert!(compact_argon2::verify(password, &hash).unwrap());
// serialize a hash into a byte array
let bytes: [u8; compact_argon2::OUTPUT_LEN] = hash.to_bytes();
// deserialize a hash from a byte array
let reconstructed = compact_argon2.from_bytes(&bytes).unwrap();
assert_eq!(hash, reconstructed);
Stability
The format may change with only a minor version bump until the 1.0.0 release, by which it should hopefully be stable.
serde compatibility
Enable the serde feature for Serialize and Deserialize impls on Hash.
#[derive(Serialize, Deserialize)]
struct User {
pub name: String,
pub password: compact_argon2::Hash,
}
Binary format
The Hash struct is fully stack allocated and serializes to a compact binary
representation. This is the recommended format, and the default for serde.
The format looks like this (made up types, all integers are big-endian):
#[repr(C, packed)]
struct Hash {
iterations: u24be, // non-zero
parallelism: u24be, // non-zero
memory: u32be, // non-zero
version: u8,
salt: [u8; 16],
out: [u8; 32]
}
base64 format
This crate also offers helpers to serialize/deserialize hashes in base64, if
you need to store hashes as strings for whatever reason. The output is still
constant size and always smaller than the PHC equivalent. This is just a
wrapper around the base64 crate with
the URL-safe alphabet and no padding (because it's constant size).
let hash = compact_argon2::hash(b"hunter2").unwrap();
let hash_string = hash.to_string();
let parsed_hash = hash_string.parse().unwrap();
assert_eq!(hash, parsed_hash);
// Can also be used with serde
#[derive(Serialize, Deserialize)]
struct User {
pub name: String,
#[serde(with = "compact_argon2::serde::base64")]
pub password: compact_argon2::Hash,
}
sqlx::Postgres compatibility
Enable the postgres feature to use Hash with sqlx's PostgeSQL driver.
#[derive(FromRow)]
struct User {
pub name: String,
pub password: compact_argon2::Hash,
}
let mut user: User = sqlx::query_as("SELECT * FROM users WHERE name=?")
.bind("AzureDiamond")
.fetch_one(&pool)
.await?;
let new_password = compact_argon2::hash(b"hunter2").unwrap();
sqlx::query("UPDATE users SET password=? WHERE name=?")
.bind(&new_password)
.bind(&user.name)
.execute(&pool)
.await?;
Dependencies
~1–14MB
~115K SLoC