# `BoundedAuthorityProtocol.V3`
[🔗](https://github.com/baselabs/bounded_authority_protocol/blob/v1.0.0/lib/bounded_authority_protocol/v3.ex#L1)

Explicit entry point for the v3 wire profile (contract-major 3, the
[`BAP3-ES256-SHA256`](../docs/design/registries.md) suite).

The v3 profile is byte-distinct from v1 and v2: grant and proof payloads carry
`v: 3`, protected headers carry `alg: "ES256"`, the proof key is the EC P-256
JWK, domain separators are `BAP3-*`, and signatures are the RFC 7518 §3.4 raw
`r || s` form with the low-S canonicality rule
(`spec/bap-v3.md` § 3.2). Each major
verifies under its own complete closed profile; the v1 and v2 façades reject
v3 bytes and this façade rejects v1 and v2 bytes.

Every function here has the contract documented on its `BoundedAuthorityProtocol.V1`
namespace counterpart (same arguments, same `{:ok, value}` or exactly `{:error, :invalid}`
results, same redacted facts), applied to this profile, with 65-byte uncompressed SEC1 public
keys and 64-byte raw signatures. `BoundedAuthorityProtocol.V3.EcJwk` handles the EC JWK, and
`BoundedAuthorityProtocol.Es256` owns the signature and key rules. The struct types are
shared, except `Grant`, `Operation`, `Proof`, `Selector`, `DecodedGrant`, `DecodedProof`, and
the facts, which have their own modules under this namespace.

# `assemble_compact`

```elixir
@spec assemble_compact(BoundedAuthorityProtocol.V1.SigningInput.t(), binary()) ::
  {:ok, binary()} | {:error, :invalid}
```

Assembles a validated signing input and raw ES256 signature at profile maxima.

# `assemble_compact`

```elixir
@spec assemble_compact(
  BoundedAuthorityProtocol.V1.SigningInput.t(),
  binary(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, binary()} | {:error, :invalid}
```

Assembles a validated signing input and raw ES256 signature under caller bounds.

Since 0.9.0, assembly also refuses, with `{:error, :invalid}`, a
signature that no conforming signer emits: an ES256 signature with `r` or `s` outside
`0 < r < n`, `0 < s <= floor(n / 2)` (high-S included); convert a DER signature with
`BoundedAuthorityProtocol.Es256.der_to_raw/1` and normalize it with
`BoundedAuthorityProtocol.Es256.normalize_low_s/1` before assembly (erratum 3). It never
rewrites the signature bytes it accepts.

# `boundary_anchor_signing_input`

```elixir
@spec boundary_anchor_signing_input(
  BoundedAuthorityProtocol.V1.BoundaryAnchor.t(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, BoundedAuthorityProtocol.V1.SigningInput.t()} | {:error, :invalid}
```

Builds the deterministic standard-JWS boundary-anchor signing input.

# `encode_anchored_export`

```elixir
@spec encode_anchored_export(
  BoundedAuthorityProtocol.V1.AnchoredExportInput.t(),
  BoundedAuthorityProtocol.V1.ExpectedExport.t()
) ::
  {:ok, BoundedAuthorityProtocol.V1.EncodedAnchoredExport.t()}
  | {:error, :invalid}
```

Frames an exact deterministic anchored export after semantic validation.

Since 0.9.0, encoding also refuses, with `{:error, :invalid}`, a
signature that no conforming signer emits: an ES256 signature with `r` or `s` outside
`0 < r < n`, `0 < s <= floor(n / 2)` (high-S included); convert a DER signature with
`BoundedAuthorityProtocol.Es256.der_to_raw/1` and normalize it with
`BoundedAuthorityProtocol.Es256.normalize_low_s/1` before assembly (erratum 3). It never
rewrites the signature bytes it accepts.

# `encode_consumption_entry`

```elixir
@spec encode_consumption_entry(
  BoundedAuthorityProtocol.V1.ConsumptionEntry.t(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) ::
  {:ok, BoundedAuthorityProtocol.V1.EncodedConsumptionEntry.t()}
  | {:error, :invalid}
```

Encodes one exact canonical consumption-chain row.

# `grant_signing_input`

```elixir
@spec grant_signing_input(
  BoundedAuthorityProtocol.V3.Grant.t(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, BoundedAuthorityProtocol.V1.SigningInput.t()} | {:error, :invalid}
```

Builds the deterministic standard-JWS grant signing input.

# `key_transition_signing_input`

```elixir
@spec key_transition_signing_input(
  BoundedAuthorityProtocol.V1.KeyTransition.t(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, BoundedAuthorityProtocol.V1.SigningInput.t()} | {:error, :invalid}
```

Builds the deterministic standard-JWS historical-key-transition signing input.

# `proof_signing_input`

```elixir
@spec proof_signing_input(
  BoundedAuthorityProtocol.V3.Proof.t(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, BoundedAuthorityProtocol.V1.SigningInput.t()} | {:error, :invalid}
```

Builds the deterministic standard-JWS holder-proof signing input.

# `request_digest`

```elixir
@spec request_digest(
  binary(),
  BoundedAuthorityProtocol.V1.Json.value(),
  BoundedAuthorityProtocol.V1.Bounds.t() | map()
) :: {:ok, binary()} | {:error, :invalid}
```

Returns the canonical type-preserving request digest.

# `decode_grant`

```elixir
@spec decode_grant(binary(), BoundedAuthorityProtocol.V1.Bounds.t() | map()) ::
  {:ok, BoundedAuthorityProtocol.V3.DecodedGrant.t()} | {:error, :invalid}
```

Boundedly decodes a raw compact grant without evaluating trust.

# `decode_proof`

```elixir
@spec decode_proof(binary(), BoundedAuthorityProtocol.V1.Bounds.t() | map()) ::
  {:ok, BoundedAuthorityProtocol.V3.DecodedProof.t()} | {:error, :invalid}
```

Boundedly decodes a raw compact proof without evaluating trust.

# `untrusted_key_locator`

```elixir
@spec untrusted_key_locator(binary(), BoundedAuthorityProtocol.V1.Bounds.t() | map()) ::
  {:ok, BoundedAuthorityProtocol.V1.KeyLocator.t()} | {:error, :invalid}
```

Parses only the protected grant header and returns its untrusted `kid` hint.

The complete compact input is bounded. Payload and signature segments are not decoded,
interpreted, or independently size-checked. The header walk pins this suite's `alg`.

# `check_chain`

```elixir
@spec check_chain(
  BoundedAuthorityProtocol.V1.ChainInput.t(),
  BoundedAuthorityProtocol.V1.ExpectedChain.t()
) :: {:ok, BoundedAuthorityProtocol.V3.ChainFacts.t()} | {:error, :invalid}
```

Checks a raw nonempty consumption-chain range against mandatory caller boundaries.

# `check_envelope`

```elixir
@spec check_envelope(
  BoundedAuthorityProtocol.V1.Credentials.t(),
  BoundedAuthorityProtocol.V1.ExpectedRequest.t()
) :: {:ok, BoundedAuthorityProtocol.V3.EnvelopeFacts.t()} | {:error, :invalid}
```

Verifies a raw grant-and-proof envelope against server-derived expected context.

# `verify_anchored_export`

```elixir
@spec verify_anchored_export(
  BoundedAuthorityProtocol.V1.ArchivedObject.t(),
  BoundedAuthorityProtocol.V1.HistoricalKeyChain.t(),
  BoundedAuthorityProtocol.V1.ExpectedAnchoredExport.t()
) ::
  {:ok, BoundedAuthorityProtocol.V3.AnchoredExportFacts.t()}
  | {:error, :invalid}
```

Atomically verifies one raw anchored export against caller boundaries and key history.

# `verify_grant`

```elixir
@spec verify_grant(
  binary(),
  BoundedAuthorityProtocol.V1.TrustedIssuer.t(),
  BoundedAuthorityProtocol.V1.ExpectedGrant.t()
) :: {:ok, BoundedAuthorityProtocol.V3.GrantFacts.t()} | {:error, :invalid}
```

Verifies one raw compact grant against caller-supplied trust and expected context.

# `verify_historical_anchor`

```elixir
@spec verify_historical_anchor(
  binary(),
  BoundedAuthorityProtocol.V1.HistoricalPublicKey.t(),
  BoundedAuthorityProtocol.V1.ExpectedAnchor.t()
) :: {:ok, BoundedAuthorityProtocol.V3.AnchorFacts.t()} | {:error, :invalid}
```

Verifies one raw compact boundary anchor against one exact historical public key.

# `verify_key_transition`

```elixir
@spec verify_key_transition(
  binary(),
  BoundedAuthorityProtocol.V1.HistoricalPublicKey.t(),
  BoundedAuthorityProtocol.V1.HistoricalPublicKey.t(),
  BoundedAuthorityProtocol.V1.ExpectedKeyTransition.t()
) ::
  {:ok, BoundedAuthorityProtocol.V3.KeyTransitionFacts.t()} | {:error, :invalid}
```

Verifies one raw compact authenticated historical-key transition.

---

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