"""Argon2id password hashing (SPEC §6.1, §10.1). Params are fixed: ``time_cost=3``, ``memory_cost=64 MiB``, ``parallelism=4``. No other password hashing is permitted anywhere (SPEC §10.1). """ from __future__ import annotations from argon2 import PasswordHasher from argon2.exceptions import VerificationError, VerifyMismatchError _hasher = PasswordHasher( time_cost=3, memory_cost=64 * 1024, # KiB -> 64 MiB parallelism=4, ) def hash_password(password: str) -> str: """Return an argon2id hash for ``password``.""" return _hasher.hash(password) def verify_password(password_hash: str, password: str) -> bool: """Constant-time verify ``password`` against ``password_hash``.""" try: return _hasher.verify(password_hash, password) except (VerifyMismatchError, VerificationError): return False def needs_rehash(password_hash: str) -> bool: """Return True if ``password_hash`` was made with outdated parameters.""" return _hasher.check_needs_rehash(password_hash)