import hashlib
import hmac
import os

_N = 2 ** 14
_R = 8
_P = 1
_DKLEN = 32


class InvalidPin(ValueError):
    pass


def _validate(pin: str) -> None:
    if not isinstance(pin, str) or len(pin) < 6 or not pin.isdigit():
        raise InvalidPin("PIN must be at least 6 digits")


def hash_pin(pin: str) -> str:
    _validate(pin)
    salt = os.urandom(16)
    dk = hashlib.scrypt(pin.encode("utf-8"), salt=salt, n=_N, r=_R, p=_P, dklen=_DKLEN)
    return f"scrypt${_N}${_R}${_P}${salt.hex()}${dk.hex()}"


def verify_pin(pin: str, stored: str) -> bool:
    try:
        scheme, n, r, p, salt_hex, hash_hex = stored.split("$")
        if scheme != "scrypt":
            return False
        dk = hashlib.scrypt(
            pin.encode("utf-8"), salt=bytes.fromhex(salt_hex),
            n=int(n), r=int(r), p=int(p), dklen=len(bytes.fromhex(hash_hex)),
        )
        return hmac.compare_digest(dk, bytes.fromhex(hash_hex))
    except (ValueError, AttributeError):
        return False
