# `Ankusa.Verifier.Asymmetric`
[🔗](https://github.com/jamescarr/ankusa/blob/ankusa-v0.7.0/packages/ankusa/lib/ankusa/verifier/asymmetric.ex#L1)

Public-key signature verifier: the provider signs with a private key only it
holds, and Ankusa holds nothing secret, only the provider's *public* key. A
leak of the node's config cannot be used to forge a hook, which is the point
over `Ankusa.Verifier.Hmac`.

`opts`:

  * `:scheme` — a preset atom (`:standard_webhooks_asym`, resolved through
    `Ankusa.Verifier.Schemes.fetch_asymmetric/1`) or an inline
    `%Ankusa.Verifier.Asymmetric.Scheme{}`. The wire half (which header, how it
    parses, what is signed, which timestamp) is `Ankusa.Verifier.Template`,
    the same engine `Hmac` runs on.
  * `:public_key` — the provider's key, or a list of them (current first;
    every key is tried, so a rotation is `public_key: [new, old]`). A key is
    one of
      * `whpk_<base64>`: the Standard Webhooks form, the 32 raw bytes of an
        Ed25519 public key;
      * the bare base64 of those 32 bytes;
      * a PEM `PUBLIC KEY` (SubjectPublicKeyInfo) or, for RSA, `RSA PUBLIC KEY`
        (PKCS#1) block;
      * for RSA, the bare base64 of the DER of either.
    A missing key, an empty list, more than 8 keys, or any element that
    does not decode to a key of the scheme's algorithm fails every hook with
    `:bad_key`, and a source declared in config refuses to boot.
  * `:tolerance` — the replay window in seconds, as `Ankusa.Verifier.Hmac`.

Algorithms (`Scheme.algorithm`): `:ed25519` (RFC 8032, the signature is 64
bytes) and `:rsa_sha256` (RSASSA-PKCS1-v1_5 over SHA-256; a modulus under 2048
bits or an exponent under 65537 is `:bad_key`). Signatures are base64 or hex
(`Scheme.encoding`).

The request path stays cheap for a forged flood: a candidate whose decoded
length is not the key's signature length is dropped before any public-key
operation, and at most 8 candidates are tried.

# `scheme_name`

```elixir
@spec scheme_name(keyword()) :: String.t()
```

Human name of the scheme for telemetry: the preset name, or `"custom"`.

# `validate_opts`

```elixir
@spec validate_opts(keyword()) ::
  :ok | {:error, :bad_scheme | :bad_tolerance | :bad_key}
```

Check `opts` the way `verify/2` would use them, without a request: the scheme
resolves, `:tolerance` is in range and every public key decodes. `:ok`, or
the error `verify/2` would return for every hook.

---

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