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
//! A pure-Rust port of the reference Argon2 implementation
//! ([phc-winner-argon2](https://github.com/P-H-C/phc-winner-argon2)), with
//! runtime-dispatched SIMD backends.
//!
//! Argon2 is the winner of the 2015 Password Hashing Competition and is
//! specified in [RFC 9106](https://www.rfc-editor.org/rfc/rfc9106). Three
//! variants exist, see [`Algorithm`]:
//!
//! * `Argon2d` — data-dependent addressing: fastest, but leaks a memory access
//! pattern that depends on the password.
//! * `Argon2i` — data-independent addressing: side-channel resistant.
//! * `Argon2id` — independent for the first half-pass, dependent afterwards.
//! The default, and what RFC 9106 recommends.
//!
//! # Example
//!
//! ```
//! use argon2_rust::{Algorithm, Argon2, Error, Params, Version};
//!
//! // Default: 19 MiB, t=2, 1 lane, 32-byte tag (raw hash output). ~8 ms per
//! // hash in release on M-series — cheap enough for a real doctest. Raise
//! // `m_cost` until it fits your budget.
//! let params = Params::default();
//! let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
//!
//! let mut tag = [0u8; 32];
//! argon2.hash_into(b"password", b"somesalt", &mut tag)?;
//! assert_eq!(argon2.verify(b"password", b"somesalt", &tag), Ok(()));
//! assert_eq!(
//! argon2.verify(b"wrong", b"somesalt", &tag),
//! Err(Error::VerifyMismatch),
//! );
//! # Ok::<(), argon2_rust::Error>(())
//! ```
//!
//! # SIMD backends
//!
//! The compression function is selected by **runtime** CPU feature detection,
//! never by `cfg(target_feature)` alone, so one binary runs at full speed on
//! every machine. Detection happens at most once per process and the result is
//! cached; a hash call resolves one function pointer before entering its loops.
//! Ask [`detected_backend`] what this CPU picked. The cost model is documented
//! on the private `fill_block` module.
//!
//! | [`Backend`] | Requires | Source it was ported from |
//! |---|---|---|
//! | `Scalar` | — | `src/ref.c` |
//! | `Neon` | `aarch64` | `src/opt.c` (128-bit path) |
//! | `Sse2` | `x86`/`x86_64` + SSE2 | `src/opt.c` (128-bit path) |
//! | `Avx2` | `x86_64` + AVX2 | `src/opt.c` (`__AVX2__`) |
//! | `Avx512` | `x86_64` + AVX-512F | `src/opt.c` (`__AVX512F__`) |
//!
//! The unpadded standard-Base64 codec used by PHC strings has a separate,
//! cached dispatch: AVX2, SSSE3, AArch64 NEON, wasm SIMD128, then scalar. Its
//! vector kernels follow `base64-simd`/`aklomp/base64`, while inputs shorter
//! than one vector stay on the original scalar loop. As in `base64-simd`,
//! AVX-512-capable CPUs use this codec's AVX2 path; the wider backend remains
//! specific to the Argon2 compression function above.
//!
//! # Features
//!
//! * `std` *(default)* — runtime CPU feature detection.
//! * `parallel` *(default, implies `std`)* — multi-threaded fill. One
//! [`std::thread::scope`] for the **whole** fill, whose workers meet at a
//! barrier at each of the `4 * t_cost` algorithmic sync points, rather than a
//! fresh scope per sync point. Note that the thread count does **not** change
//! the tag; only [`Params::lanes`] does.
//! * `zeroize-memory` *(default)* — securely wipe internal buffers, the
//! equivalent of `FLAG_clear_internal_memory` in the C.
//! * `bump-alloc` — internal test/bench control. Together with `internal-api`,
//! gives `memory::Workspace` a reusable bump allocator for measuring small
//! scratch buffers. It does **not** change the stable hash/encode/verify paths,
//! which deliberately keep their `Vec`s. Measured upper bound: 17 ns per hash,
//! or 0.00013% of an RFC 9106 hash.
//! * `internal-api` — exposes `__internal` for tests and benches. Not stable.
//!
//! The crate is `#![no_std]` and needs only `alloc`; that stays true with every
//! feature turned on. Without `std`, backend selection falls back to
//! compile-time `target_feature` cfgs.
//!
//! # Not a `password-hash` provider
//!
//! This is a port of the C reference, not an implementation of the RustCrypto
//! `password-hash` traits: there is no `PasswordHasher` or `PasswordVerifier`
//! here, and no dependency that would supply one. [`Params`] carries no `serde`
//! impls either, though its full state round-trips through the accessors and
//! [`Params::to_builder`]. Interoperation is at the string level — the PHC
//! strings this crate reads and writes are the ones the `argon2` crate reads and
//! writes. A future optional feature for those traits would be additive and
//! would not change this default surface.
//!
//! # SemVer
//!
//! From `1.0.0`, the default-feature public API is covered by Semantic
//! Versioning. The `internal-api` feature and its `__internal` module are not.
//! MSRV may rise on a minor release. See the README "SemVer policy" section for
//! the full list.
//!
//! # Reusing memory across hashes
//!
//! Each [`Argon2`] hash acquires its block arena once and releases it on the
//! way out. A process that hashes repeatedly can instead keep a [`Hasher`],
//! from [`Argon2::hasher`], which parks the arena between calls and wipes it on
//! release, so the next call gets a zeroed arena that is **already mapped and
//! already resident**.
//!
//! Skipping the `mmap`, the first-touch faults and the `munmap` is worth around
//! -25% at `m_cost = 64 MiB`, and next to nothing below 1 MiB, where a hash is
//! mostly BLAKE2b; [`Hasher`](Hasher#what-it-is-worth-measured) has the
//! per-cost measurements.
//!
//! ```
//! use argon2_rust::{Algorithm, Argon2, Hasher, Params, Version, params::Memory};
//!
//! // Nameable, so it can be a field, a `thread_local!` or a worker slot —
//! // which is the only shape in which reuse is worth anything.
//! struct Worker {
//! hasher: Hasher,
//! }
//!
//! let params = Params::builder().memory(Memory::kib(1 << 8)).passes(1).build()?;
//! let mut worker = Worker {
//! hasher: Argon2::new(Algorithm::Argon2id, Version::V0x13, params).hasher(),
//! };
//! let mut tag = [0u8; 32];
//! worker.hasher.hash_into(b"password", b"somesalt", &mut tag)?;
//! # Ok::<(), argon2_rust::Error>(())
//! ```
//!
//! # Salts
//!
//! [`Argon2::hash_password_with_random_salt`] (and the pooled
//! [`Hasher::hash_password_with_random_salt`]) draw a [`RANDOM_SALT_LEN`]-byte
//! salt from the OS and put it in the returned PHC string, so nothing has to be
//! stored alongside. The entropy comes from whichever entry point is correct
//! for the target — `getrandom(2)`, `getentropy`, `CCRandomGenerateBytes`,
//! `ProcessPrng`, WASI `random_get`, or `/dev/urandom` — each declared by hand,
//! so this costs no dependency. Callers who already run a CSPRNG should keep
//! passing their own salt.
//!
//! # Verifying strings you did not write
//!
//! `m_cost` in a PHC string is up to ten digits of decimal, and
//! [`Argon2::verify_encoded`] will honour all of them — up to
//! [`params::MAX_MEMORY`] KiB, which is 4 TiB — because `argon2_verify` does
//! too. That is fine for a config file and a denial of service for a login
//! endpoint. [`Argon2::verify_encoded_bounded`] takes a ceiling and rejects an
//! over-large cost while it is still a number, before anything is allocated:
//!
//! ```
//! use argon2_rust::{Algorithm, Argon2, Error, Params, params::Memory};
//!
//! let hostile = "$argon2id$v=19$m=4294967295,t=1,p=1$c29tZXNhbHQ$\
//! CTFhFdXPJO1aFaMaO6Mm5c8y7cJHAph8ArZWb2GRPPc";
//! let ceiling = Params::builder().memory(Memory::mib(64)).passes(8).lanes(4).build()?;
//! assert_eq!(
//! Argon2::verify_encoded_bounded(hostile, b"pw", Algorithm::Argon2id, &ceiling),
//! Err(Error::MemoryTooMuch),
//! );
//! # Ok::<(), argon2_rust::Error>(())
//! ```
//!
//! Memory is not the only resource the string spends. Decoding sets
//! `threads = lanes` (C parity), so `p` also picks how many OS threads the
//! verify spawns; the ceiling's own `threads` bounds that, and a ceiling that
//! leaves [`ParamsBuilder::threads`](params::ParamsBuilder::threads) unset bounds
//! it together with `lanes`. Set that one setter to accept wide strings without
//! spawning wide. The clamp cannot change a verdict — only `lanes` feeds the tag.
//!
//! # Panics
//!
//! No fallible path in this crate panics: hashing, verifying, encoding,
//! decoding and parameter validation all report failure as an [`Error`], whose
//! numeric [`Error::as_c_code`] matches the C reference — except for the
//! crate-specific codes below [`Error::MIN_C_CODE`], which the C has no
//! equivalent for.
//!
//! There is exactly one intentional exception, and it is not on a fallible
//! path: [`ParamsBuilder::build_or_panic`](params::ParamsBuilder::build_or_panic)
//! panics on invalid parameters. It exists so a `const` item can turn bad
//! parameters into a *compile* error, which is what a panic in a `const`
//! evaluation is. Anywhere a runtime error is the right answer, use
//! [`ParamsBuilder::build`](params::ParamsBuilder::build) — it is the normal way
//! in.
// A `pub` item that a downstream crate cannot *name* is only half-public: it
// works in `let` bindings and nowhere else — not in a struct field, a function
// signature, a `Vec`, or a `thread_local!`. `Hasher` shipped that way once
// (`Argon2::hasher()` returned it, `lib.rs` never re-exported it), which broke
// the one shape the reuse layer exists to serve: one hasher per worker, owned
// by that worker's struct. This lint is the regression guard.
// NOTE FOR EVERY CONTRIBUTOR: this crate has a module named `core`, which
// shadows the `core` crate *in this root module only*. Inside `src/lib.rs`
// always write `::core::...`. Submodules are unaffected — bare `core::` there
// still means the `core` crate.
extern crate alloc;
extern crate std;
// These modules are private, and a good deal of what they expose escapes the
// crate only through `__internal` (below), which tests and benches enable. In a
// plain build those items are legitimately unreachable, so `dead_code` would
// fire on all of them.
//
// Rather than blanket-allowing `dead_code` — which would also hide code that is
// dead by mistake — the allow is tied to `internal-api` being OFF. With the
// feature ON, `__internal` re-exports the intended surface, so anything the
// compiler still calls dead really is dead and gets reported.
private_modules!;
// OS entropy for the convenience salt API; needs std for the syscall and the
// /dev/urandom fallback. Declared per-platform inside the module.
//
// Deliberately not in `private_modules!`: everything here is reachable from
// `Argon2::hash_password_with_random_salt` on every `std` build, so it needs no
// `dead_code` allow, and should not have one hiding a future mistake.
pub use crate;
// `RANDOM_SALT_LEN` is std-only because the API it describes is;
// `BOUNDED_MAX_SALT_LEN` is not, because `verify_encoded_bounded` works without
// `std` and a caller has to be able to name the bound it is being held to.
pub use crateRANDOM_SALT_LEN;
pub use crateencoded_len;
pub use crateError;
pub use crateBackend;
pub use crate;
/// The [`Backend`] this CPU resolved to, cached after the first call.
///
/// Diagnostic only — the hashing entry points call this for you.
///
/// ```
/// println!("argon2 backend: {}", argon2_rust::detected_backend());
/// ```
/// Unstable internals, exposed for this crate's own tests and benches.
///
/// Gated behind the non-default `internal-api` feature. **No stability
/// guarantees**: anything here can change in a patch release.
///
/// # Soundness
///
/// Unstable is not the same as unsound. Every entry point here that takes an
/// explicit [`Backend`] or `Blake2bBackend` — including
/// `fill_memory_blocks_traced`, `hash_traced`, `hash_with_backend`,
/// `blake2b_with_backend`, and `blake2b_long_with_backend` — is an `unsafe fn`,
/// and so is each backend's low-level entry point. They dispatch to a
/// `#[target_feature(enable = ...)]` function, so running one whose feature
/// this CPU lacks is undefined behaviour (`SIGILL` in practice), and only the
/// caller can rule that out. Each backend type's `is_available` method is the
/// portable way.
///
/// The safe entry points — [`Argon2`], [`detected_backend`], `blake2b`,
/// `blake2b_long`, and `fill_memory_blocks` — never let a caller name the
/// backend. They take it from the corresponding cached runtime cascade, which
/// by construction only ever names a backend this CPU advertises. That is the
/// whole reason they can be safe, and it is why turning on `internal-api`
/// cannot make a `#![forbid(unsafe_code)]` program reachable by UB.