defmodule Attesto.SecureCompare do @moduledoc """ Constant-time comparison of two binaries. Used wherever an attacker-controlled value is checked against a secret or a derived digest (a DPoP `ath`, a PKCE challenge) and a short-circuiting `==` would leak information through timing. """ @doc """ Returns `true` iff `a` and `b` are byte-identical, comparing in constant time. `:crypto.hash_equals/2` requires equal-length inputs, and at least one operand here is attacker-controlled, so the length is gated first. The length check is not itself timing-sensitive in the cases this is used for: the operands are fixed-length base64url digests, so a length mismatch only ever means a malformed input, not a near-miss secret. """ @spec equal?(binary(), binary()) :: boolean() def equal?(a, b) when is_binary(a) and is_binary(b) do byte_size(a) == byte_size(b) and :crypto.hash_equals(a, b) end def equal?(_, _), do: false end