> ## Documentation Index
> Fetch the complete documentation index at: https://docs.algovoi.co.uk/llms.txt
> Use this file to discover all available pages before exploring further.

# RFC 9421 HTTP Signatures Verifier

> AlgoVoi authored reference verifier for RFC 9421 HTTP Message Signatures and RFC 9530 Digest Fields. Python and TypeScript at byte parity, Ed25519.

The AlgoVoi RFC 9421 verifier is a standalone reference implementation of
[RFC 9421 (HTTP Message Signatures)](https://www.rfc-editor.org/rfc/rfc9421)
and
[RFC 9530 (Digest Fields for HTTP)](https://www.rfc-editor.org/rfc/rfc9530).

It is **standalone** — a verifier can re-validate any RFC 9421-signed request
against a known public key without trusting AlgoVoi's gateway, signing service,
or control plane.

The signing base it validates is the **RFC 9421 §2.5 signing-base substrate**
(`rfc9421_proxy_chain_v1`) — one half of AlgoVoi's authored L1 (the other is the
[JCS canonicalisation substrate](/canonicalisation-substrate)), dated in
`draft-hopley-x402-rfc9421-binding`. Build L2 on it freely; the one ask is to **attribute the L1**
(keep the NOTICE, import the signing base by hash).

<CardGroup cols={2}>
  <Card title="Hosted endpoint" icon="cloud" href="https://verify.algovoi.co.uk/rfc9421">
    `verify.algovoi.co.uk/rfc9421` — POST any captured request, get back a full `VerifyResult`. No installation required.
  </Card>

  <Card title="Signer" icon="signature" href="/rfc9421-signer">
    Companion signer package — see the [RFC 9421 Signer](/rfc9421-signer) page.
  </Card>
</CardGroup>

<CardGroup cols={2}>
  <Card title="Python verifier (PyPI)" icon="python" href="https://pypi.org/project/algovoi-rfc9421-verifier/">
    `pip install algovoi-rfc9421-verifier`
  </Card>

  <Card title="TypeScript verifier (npm)" icon="js" href="https://www.npmjs.com/package/@algovoi/rfc9421-verifier">
    `npm install @algovoi/rfc9421-verifier`
  </Card>
</CardGroup>

Both packages are byte-deterministic on identical inputs: the Python and TypeScript
implementations produce byte-identical output, and the underlying JCS (RFC 8785)
canonicalisation is cross-validated byte-for-byte against four independent reference
implementations from the [canonicalisation substrate](/canonicalisation-substrate). Apache 2.0.

## Use cases

* **Inbound request verification** — verify an RFC 9421-signed HTTP request against a known public key before processing it.
* **Proxy-chain re-validation** — re-validate a captured request after it traverses a TLS-re-terminating proxy chain (the property pinned in the [`rfc9421_proxy_chain_v1`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/tree/main/vectors/rfc9421_proxy_chain_v1) RFC 9421 §2.5-conformant fixture, with the legacy [`rfc9421_proxy_chain_v0`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/tree/main/vectors/rfc9421_proxy_chain_v0) companion for the `algovoi-v0` base).
* **Conformance test harnesses** — build test suites anchored to the RFC 8032 Section 7.1 deterministic Ed25519 reference keypair, byte-reproducible across both implementations.
* **A2A and x402 receipt validation** — verify that incoming compliance receipts and settlement attestations carry valid HTTP signatures before inserting them into the audit chain.

## Hosted endpoint

AlgoVoi runs a public hosted instance at
[`verify.algovoi.co.uk/rfc9421`](https://verify.algovoi.co.uk/rfc9421).
No installation or authentication required. Rate limit: 60 req/min per IP.

```bash theme={null}
# Schema and input reference
curl https://verify.algovoi.co.uk/rfc9421

# Verify a signed request
curl -X POST https://verify.algovoi.co.uk/rfc9421 \
  -H "Content-Type: application/json" \
  -d '{
    "method": "POST",
    "authority": "api.algovoi.co.uk",
    "path": "/checkout",
    "headers": {
      "signature-input": "sig=(\"@method\" \"@authority\" \"@path\" \"content-digest\" \"created\");created=1748534400;keyid=\"did:web:api.algovoi.co.uk\";alg=\"ed25519\"",
      "signature": "sig=:<base64-signature>:",
      "content-digest": "sha-256=:<base64-sha256>:"
    },
    "body_b64": "<base64-encoded-body>",
    "public_key_hex": "<64-char-hex-ed25519-pubkey>",
    "require_content_digest": true
  }'
```

The response includes `valid`, `signature_valid`, `content_digest_valid`, the
reconstructed `signing_base`, and the full `covered_components` list — useful for
debugging signing-base mismatches without running anything locally.

## What the verifier checks

| # | Check                         | What it proves                                                                                                                                                            |
| - | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 1 | `Signature-Input` parse       | Header parses to a valid covered-component list with `keyid`, `alg`, and `created` parameters                                                                             |
| 2 | `Content-Digest` match        | `SHA-256` or `SHA-512` digest of the request body matches the `Content-Digest` field (RFC 9530)                                                                           |
| 3 | Signature base reconstruction | Canonical signature base rebuilt from covered components per RFC 9421 §2.5                                                                                                |
| 4 | Key verification              | Ed25519 signature over the reconstructed base verifies against the supplied public key (ECDSA-P256 is roadmap — see Algorithm support below)                              |
| 5 | `created` resolution          | the `created` parameter is resolved into the signature base per RFC 9421 (the verifier does not enforce a freshness/staleness window — the caller applies its own policy) |

## Quick start

The fixture below uses the AlgoVoi test Ed25519 keypair
(seed `9d61b19d…`, public key `700e2ce7…`) — the same keypair used across
the [signer](/rfc9421-signer) and [conformance vector](/conformance-vectors) test suites.

### Python

```python theme={null}
from algovoi_rfc9421_verifier import verify_request

result = verify_request(
    method="GET",
    authority="api.algovoi.co.uk",
    path="/compliance/attestation",
    headers={
        "content-digest": "sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:",
        "signature-input": (
            'sig=("@method" "@authority" "@path" "content-digest" "created");'
            'created=1778955520;keyid="did:web:api.algovoi.co.uk";alg="ed25519"'
        ),
        "signature": (
            "sig=:JZ3cN4Gl8h5s2635bQ6/bczGo+e9acNWxVbR4XhqQiBrFteh71trVrGbBJUkw7v1"
            "NVv1GlpVEZMvvKXYGPuLBQ==:"
        ),
    },
    body=b"",
    public_key="700e2ce7c4b674427eab27ba820bcf6f0faebe68e09fe8564292114e41dc6a41",
)
assert result.valid
```

### TypeScript

```typescript theme={null}
import { verifyRequest } from "@algovoi/rfc9421-verifier";

const result = await verifyRequest({
  method: "GET",
  authority: "api.algovoi.co.uk",
  path: "/compliance/attestation",
  headers: {
    "content-digest": "sha-256=:47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=:",
    "signature-input":
      'sig=("@method" "@authority" "@path" "content-digest" "created");created=1778955520;keyid="did:web:api.algovoi.co.uk";alg="ed25519"',
    signature:
      "sig=:JZ3cN4Gl8h5s2635bQ6/bczGo+e9acNWxVbR4XhqQiBrFteh71trVrGbBJUkw7v1NVv1GlpVEZMvvKXYGPuLBQ==:",
  },
  body: Buffer.from(""),
  publicKey: "700e2ce7c4b674427eab27ba820bcf6f0faebe68e09fe8564292114e41dc6a41",
});
console.assert(result.valid);
```

### Sign then verify (round-trip)

Use the companion [signer package](/rfc9421-signer) to produce a signed request, then verify it locally:

```python theme={null}
import json, time
import nacl.signing
from algovoi_rfc9421_signer import sign_request
from algovoi_rfc9421_verifier import verify_request

SEED = bytes.fromhex("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae3d55")
pubkey_hex = nacl.signing.SigningKey(SEED).verify_key.encode().hex()

body = json.dumps({"recipient_address": "ALGO...", "network": "algorand"}, separators=(",", ":")).encode()

sig = sign_request(
    method="POST",
    authority="api.algovoi.co.uk",
    path="/compliance/screen",
    body=body,
    private_key=SEED,
    keyid="did:web:api.algovoi.co.uk",
    created=int(time.time()),
)

result = verify_request(
    method="POST",
    authority="api.algovoi.co.uk",
    path="/compliance/screen",
    headers={
        "signature-input": sig.signature_input,
        "signature": sig.signature,
        "content-digest": sig.content_digest,
    },
    body=body,
    public_key=pubkey_hex,
)
assert result.valid       # True
assert result.signature_valid
assert result.content_digest_valid
```

## Cross-implementation parity

The Python and TypeScript verifiers produce byte-identical output on the same inputs.
Parity is exercised against the AlgoVoi test Ed25519 keypair
(seed `9d61b19d…`, derived public key `700e2ce7…` — consistent across both PyNaCl and `@noble/ed25519`):

* Same `Signature-Input` parse output
* Same signature base reconstruction bytes (RFC 9421 §2.5 — uppercase method, `@signature-params` appended)
* Same `Content-Digest` computation (SHA-256 and SHA-512)
* Same pass/fail verdict across all conformance fixtures

The [`rfc9421_proxy_chain_v1`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/tree/main/vectors/rfc9421_proxy_chain_v1) vector set (RFC 9421 §2.5-conformant) at the [conformance vectors repository](/conformance-vectors) pins these properties byte-reproducibly; the legacy [`rfc9421_proxy_chain_v0`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors/tree/main/vectors/rfc9421_proxy_chain_v0) set pins the earlier `algovoi-v0` signing base.

## v0.3.0 — default mode

From v0.3.0, `verify_request()` defaults to `mode="rfc9421"` (RFC 9421 §2.5 compliant —
`@method` case-preserved, `@signature-params` line appended). The legacy `mode="algovoi-v0"`
(lowercase method, no `@signature-params`) is retained for backward compatibility with
pre-v0.2.0 conformance fixtures.

```python theme={null}
# Default (v0.3.0+): rfc9421 — verifies the rfc9421_proxy_chain_v1 fixture; matches algovoi-rfc9421-signer output
result = verify_request(..., mode="rfc9421")   # explicit — same as default

# Legacy: for the rfc9421_proxy_chain_v0 corpus fixture (algovoi-v0 base, pre-v0.2.0)
result = verify_request(..., mode="algovoi-v0")
```

## Algorithm support

| Algorithm  | Identifier          | Key format                      | Status    |
| ---------- | ------------------- | ------------------------------- | --------- |
| Ed25519    | `ed25519`           | 32-byte hex or raw bytes        | Supported |
| ECDSA-P256 | `ecdsa-p256-sha256` | SEC1 compressed or uncompressed | Roadmap   |

Ed25519 signatures are deterministic (RFC 8032 deterministic nonce), enabling byte-reproducible test fixtures.

## Gateway integration — `/compliance/screen`

AlgoVoi's payment gateway uses `algovoi-rfc9421-verifier` to optionally verify
inbound request signatures on the `/compliance/screen` endpoint.

When a caller supplies `Signature-Input`, `Signature`, and `X-Signer-Pubkey` headers,
the gateway verifies the signature and returns the result in the response:

```json theme={null}
{
  "verdict": "allow",
  "request_signature_verified": true,
  "request_signature_keyid": "did:web:api.algovoi.co.uk"
}
```

If the headers are absent the endpoint still processes the request normally —
`request_signature_verified` is `null`. If headers are present but verification fails,
`request_signature_verified` is `false` and the request proceeds (verification is
advisory, not a gate).

## Composition with the compliance stack

The verifier composes with the [JCS canonicalisation substrate](/canonicalisation-substrate). A compliance receipt or settlement attestation emitted by AlgoVoi's gateway carries an RFC 9421 signature over its HTTP delivery. A downstream verifier can:

1. Verify the HTTP signature to confirm the receipt was issued by the declared `keyid` DID.
2. Verify the `content_hash` of the receipt body using the [audit verifier](/audit-verifier).

This two-layer verification confirms both origin (HTTP signature) and tamper-evidence (JCS hash chain) without trusting any single AlgoVoi endpoint.

## Conformance vectors

The `rfc9421_proxy_chain_v1` (RFC 9421 §2.5-conformant) and legacy `rfc9421_proxy_chain_v0` (`algovoi-v0` base) fixture sets at [`algovoi-jcs-conformance-vectors`](https://github.com/chopmob-cloud/algovoi-jcs-conformance-vectors) cover:

* Baseline signing and verification round-trip (Ed25519 + ECDSA-P256)
* Proxy chain re-validation after TLS re-termination
* `Content-Digest` computation for empty and non-empty bodies
* `created` freshness window enforcement
* Covered-component ordering invariants

## See also

* [Key-credential binding](/key-credential-binding) — vectors binding an RFC 9421 signature to an issued agent credential
* [Canonicalisation substrate](/canonicalisation-substrate) — the JCS RFC 8785 discipline that underpins the receipt formats
* [Audit verifier](/audit-verifier) — selective-disclosure audit-bundle verifier
* [Conformance vectors](/conformance-vectors) — full cross-implementation vector corpus
* [Package suite](/package-suite) — all 16 AlgoVoi packages at a glance
* [Substrate authorship and provenance](/substrate-authorship-provenance) — citable AlgoVoi authorship record
