# `Attesto.Thumbprint`
[🔗](https://github.com/XukuLLC/attesto/blob/v0.13.0/lib/attesto/thumbprint.ex#L1)

Canonical SHA-256 thumbprint shape, shared across the sender-constraint
schemes.

Three different specs converge on the same 32-byte-digest-as-base64url
shape:

  * RFC 7638 JWK thumbprints (DPoP `cnf.jkt`),
  * RFC 8705 §3.1 X.509 certificate thumbprints (`cnf.x5t#S256`), and
  * the RFC 7515 §4.1.8 `x5t#S256` JOSE header parameter.

In every case the value is

    Base.url_encode64(<32-byte SHA-256 digest>, padding: false)

which is exactly 43 characters drawn from the RFC 4648 §5 alphabet
`[A-Za-z0-9_-]`.

## Why 43 base64url characters is necessary but not sufficient

The last character of a 43-character base64url-no-pad string encodes
only the final 4 bits of the 256-bit digest, so its low 2 bits are
structurally zero. A 43-character string whose last character carries
non-zero trailing bits is therefore **not** something
`Base.url_encode64/2` could ever have produced. Accepting such a value
as a thumbprint would let a caller embed a `cnf` binding that no real
key or certificate could ever match - silently turning a
sender-constraint into a no-op. `valid?/1` rejects these by decoding
and re-encoding: a value is canonical iff it round-trips to itself and
decodes to exactly 32 bytes.

# `length`

```elixir
@spec length() :: pos_integer()
```

The fixed character length of a well-formed SHA-256 base64url-no-pad
thumbprint. Exposed so documentation / API specs can advertise the
same shape this module enforces.

# `of`

```elixir
@spec of(binary()) :: String.t()
```

Compute the SHA-256 thumbprint of `bytes` in the canonical
base64url-no-pad shape this module validates.

# `valid?`

```elixir
@spec valid?(term()) :: boolean()
```

Returns `true` iff `value` is the canonical base64url-no-pad encoding
of a 32-byte SHA-256 digest: 43 characters from the base64url
alphabet that decode to exactly 32 bytes and re-encode unchanged.
Anything else - wrong length, illegal characters, non-canonical
trailing bits, or a non-binary - returns `false`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
