Skip to main content

validate_inputs

Function validate_inputs 

Source
pub const fn validate_inputs(
    out_len: usize,
    pwd_len: usize,
    salt_len: usize,
    secret_len: usize,
    ad_len: usize,
    m_cost: u32,
    t_cost: u32,
    lanes: u32,
    threads: u32,
) -> Result<(), Error>
Expand description

validate_inputs() from src/core.c, in the exact same order.

The order is load-bearing: when several inputs are invalid, the C reference returns the error for whichever check runs first, and the differential tests compare error codes.

Checks the C performs that are omitted here, with the reason:

  • context == NULLARGON2_INCORRECT_PARAMETER: no null contexts in Rust.
  • out == NULLARGON2_OUTPUT_PTR_NULL: no null slices in Rust.
  • the four *_PTR_MISMATCH checks: a Rust slice always has a valid pointer.
  • ARGON2_MIN_PWD_LENGTH > pwdlen, ARGON2_MIN_AD_LENGTH > adlen, ARGON2_MIN_SECRET > secretlen: those minima are all 0, so the checks can never fire (and would be tautological comparisons in Rust).
  • the two allocator-callback checks: this crate has no allocator callbacks.

Note the C computes 8 * context->lanes in uint32_t, before lanes has been range-checked, so it can wrap. u32::wrapping_mul reproduces that: lanes = 0xFFFF_FFFF yields MemoryTooLittle, not LanesTooMany.

§Prefer Params::validate_for

This free function is the escape hatch, not the main path. Params::validate_for calls it with five of the nine arguments filled in from the receiver: the tag length (out_len, from Params::tag_len_bytes) and the four cost values (m_cost, t_cost, lanes, threads). It leaves the caller exactly the four buffer lengths, pwd_len, salt_len, secret_len and ad_len. Those five values come from a Params that ParamsBuilder::build already ran through this function, so they cannot drift from the costs the hash will actually run with, and core takes that route on every hash.

Reach for this function directly only when the C’s exact check ordering is what is wanted, which is the one thing the Params route cannot give you: ParamsBuilder::build validates the cost parameters at construction time, so a caller who supplies both a bad m_cost and a short salt sees the m_cost error where the C reports ARGON2_SALT_TOO_SHORT (the divergence note on Params spells this out). decode_string is the in-crate example: it calls this function directly on the decoded fields and only builds its Params afterwards, so that a malformed PHC string yields the same error code validate_inputs() (core.c:388-513) yields in the C.

use argon2_rust::Error;
use argon2_rust::params::{Memory, Params, validate_inputs};

let params = Params::builder().memory(Memory::kib(19_456)).passes(2).build()?;

// Four arguments. The tag length and the four costs come from `params`.
assert_eq!(params.validate_for(8, 16, 0, 0), Ok(()));

// The same check spelled out. The five values `params` would have supplied
// have to be repeated by hand and kept in step with it.
assert_eq!(validate_inputs(32, 8, 16, 0, 0, 19_456, 2, 1, 1), Ok(()));

// `out_len` and `pwd_len` transposed, which is the pair `validate_for`
// takes off the call site entirely. Both are `usize` and adjacent, so this
// compiles, and there is no error to notice: the password length 8 is now
// the tag length, 8 clears `MIN_OUTLEN` (4), and the call says `Ok(())`
// while agreeing to a 64-bit tag.
assert_eq!(validate_inputs(8, 32, 16, 0, 0, 19_456, 2, 1, 1), Ok(()));

// The method form cannot be told that. `out_len` is not one of its four
// arguments; it comes from the `Params`, which holds it at 32.
assert_eq!(params.tag_len_bytes(), 32);
assert_eq!(params.validate_for(32, 16, 0, 0), Ok(()));