# HAP-1/WA-1 interoperability kit

Reference release 0.6.1 adds a separately coded Python WebAuthn verifier, a shared
public adversarial corpus, and a read-only inspection contract. Other networks
can implement [PRESENCE.md](PRESENCE.md), run the corpus locally, and retain their
own keys and evidence. No Money Musk account, token, endpoint, registry, or
permission service is required. The files in `hap1/` use [0BSD](LICENSE).

This is a second verification implementation by the same project. It is not an
independently operated authority, a third-party audit, or evidence of outside
adoption. The Python implementation does not issue permits or implement the
authority's transactional storage. Existing HAP-1/1 signed bytes and the WA-1
challenge grammar remain unchanged.

The [external adapter protocol and runner](PRESENCE-ADAPTER.md) can drive a
verifier written in another language through stdin/stdout, without importing
either reference implementation. It checks the pinned complete corpus and
produces an unsigned local report with no captured logs or credential data.
An [optional detached attestation](PRESENCE-ATTESTATION.md) can separately bind
that exact report to a caller-pinned signer key. Reports remain unsigned and
byte-for-byte deterministic; signing never upgrades the truth of their metadata,
independence, review or execution claims.
The [independent review guide](PRESENCE-REVIEW.md) covers reproduction, threat
boundaries, physical authenticator checks and evidence for adoption claims.

## What another implementation can reproduce

| Component | JavaScript | Python | Scope |
| --- | --- | --- | --- |
| HAP-1 signatures and canonical bytes | `runtime.mjs` | `verify.py` | Ticket, challenge and request evidence |
| WebAuthn verification | `webauthn.mjs` | `presence-verify.py` | ES256, none attestation, raw client bytes, RP/origin, UP/UV, counters |
| Presence inspection | `presence-inspect.mjs` | `presence-verify.py` | Registered key and exact ticket/request/context binding |
| Stateful authority | `presence.mjs` | Not implemented | Atomic counter, nonce, budget, revocation and journal commit |

`presence-vectors.json` is `HAP-1/WA-conformance/1`: each case has a unique `name`,
an `operation` (`registration`, `assertion`, or `inspect`), explicit `input`, and
expected boolean `valid`. Successful registration/assertion cases also specify
the exact `result`. An inspection case supplies an explicit synthetic `now` in
Unix milliseconds. A conformance runner must run every case, refuse unknown
operations, compare results, and fail on any disagreement. There is no skip mode.
The golden section publishes the exact context preimage, challenge, and raw
client-data hash. The corpus's keys are **public synthetic test keys**; never
enroll them or authorize an external effect with them.

Install verification dependencies once in an environment you control:

```sh
python3 -m venv /tmp/hap1-verify
/tmp/hap1-verify/bin/python -m pip install -r hap1/requirements-verify.txt
HAP1_PYTHON=/tmp/hap1-verify/bin/python node --test scripts/hap1-presence-conformance.mjs
/tmp/hap1-verify/bin/python scripts/hap1-presence-vectors.py --check
```

The conformance command compares both languages against the same corpus,
disables their network entry points, and exercises Python-produced registration
and assertion bytes through the actual JavaScript wrapper and executor. It
checks one simulated dispatch, replay refusal, and absent-assertion refusal.
Separate existing suites cover durable storage, races and virtual-authenticator
browser behavior. Dependency installation may use a package index; verification
itself is local. No private keys are needed to verify.

## Read-only inspection contract, version 1

The caller supplies five separate objects. `pin` and `context` are trusted owner
inputs retained independently of the candidate response. A delegate must not
choose them. File separation alone does not authenticate their provenance.

| Input | Required content |
| --- | --- |
| `pin` | Exact fields `schema`, `rpId`, `origin`, `issuerPublicKey`, `delegatePublicKey`, `executorPublicKey`, `credential`; schema `HAP-1/WA-pin/1` |
| `pin.credential` | Retained registration record: exact `id`, `publicKey`, `userHandle`, `signCount`, `backupEligible`, `backupState` |
| `pin.credential.publicKey` | Exact `kty`, `crv`, `x`, `y`; EC P-256 with 32-byte base64url coordinates |
| `context` | Exact WA-1 context returned by the owner's `begin()`, retained before the assertion |
| `ticket`, `request` | Original canonical HAP-1 ticket and signed delegate request |
| `assertion` | Exact wrapper fields `schema`, `ceremony`, `credential`; schema `HAP-1/WA-assertion/1` |

Credential ID is canonical unpadded base64url, 1–1023 bytes. User handle is
1–64 bytes. The retained counter is an integer from 0 through 2^32−1; both backup
fields are booleans, and backup state requires backup eligibility. The context
nonce is exactly 32 bytes. All role keys are authenticated 32-byte Ed25519 public
keys encoded as lowercase hex. Unknown pin/context/proof fields or versions
refuse. Browser credential metadata is ignored, including supplied replacement
public keys; it cannot change the retained key.

Version 1 inspection supports serialized HTTPS origins with exact ASCII DNS
hosts (including punycode) or canonical IP literals. HTTP is limited to
`localhost`, `127.0.0.1`, and `[::1]`. DNS hosts use lowercase letters, digits,
dots, underscores and hyphens; a numeric or hex-numeric final label is not
accepted as a DNS name. Paths, credentials, query strings, fragments,
noncanonical IPs, and explicit default ports refuse. This deliberately bounded
inspection interface does not broaden the authority's RP policy.

The inspector verifies the ticket and both request-role signatures, scope,
challenge shape, and deadline. It reconstructs the exact binding and WebAuthn
challenge using the retained nonce. It then verifies the registered credential,
origin, RP hash, UP/UV, backup flags, signature and counter semantics. The action
payload itself is not an input: inspection verifies its signed digest binding;
the executor must hash and match the actual payload before dispatch.

Python operator command:

```sh
/tmp/hap1-verify/bin/python hap1/presence-verify.py \
  --pin retained-pin.json --context retained-context.json \
  --ticket ticket.json --request request.json --assertion assertion.json
```

Each file must contain canonical HAP-1 JSON, optionally followed by one LF, and
be a bounded regular file of at most 32,768 bytes including that LF. Duplicate
members, invalid UTF-8, BOMs, symlinks in the final path component, special files,
unknown flags, repeated flags, and missing inputs refuse. Protect parent
directories and retained state against replacement. On platforms without
`O_NOFOLLOW` and `O_NONBLOCK`, this CLI refuses rather than weakening its file
handling. Use a supported local environment.

The CLI checks the local wall clock before and after verification, refuses at
the exact deadline, and exposes no clock-override flag. Keep the clock correct;
this is not a trusted time service or hardware rollback protection. For test or
historical inspection, the JS `inspectPresence({pin,context,ticket,request,
assertion,now})` and Python `inspect_presence(pin,context,ticket,request,proof,
now)` APIs take explicit time. Their result only applies at that supplied time.

Both return this metadata-only report on success:

```json
{"schema":"HAP-1/WA-inspection/1","profile":"HAP-1/WA-1","verified":true,"code":"PRESENCE_VERIFIED","executionAuthorized":false,"consumed":false,"counterPersisted":false}
```

Refusal changes `verified` to `false` and `code` to
`INVALID_PRESENCE_EVIDENCE`. The CLI exits 0 on verified evidence and 1 on
refusal; it prints no paths, credential IDs, origins, payloads or input excerpts.

**A verified report is never a permit.** Inspection can repeat the same evidence.
It cannot discover a newer revoke, spent allowance, consumed nonce, newer
counter, hidden fork, or restored old owner state. Its output must never replace
`createPresenceAuthority().check()` or be used to update a counter separately
from the authority transaction. The stateful wrapper must still atomically
consume the ceremony, advance the counter, commit the budget and journal, and
release a permit only before the deadline. The executor must enforce its own
durable one-use consumption. No inspection outcome enables a fallback route.

## Local ownership and adoption evidence

Self-host the browser assets on your trusted HTTPS origin and retain authority
state locally with access control and backups. An RP/origin change is a new
deployment decision, not an automatic migration. Keep private device keys,
credential records, pending contexts, and operation details out of public test
reports. Publish only synthetic fixtures and aggregate compatibility results.
Even public keys, digests and credential identifiers may enable correlation;
local processing is not selective disclosure or a zero-knowledge system. A
synced passkey may involve its authenticator provider's sync service; this kit
does not prevent or attest to that provider behavior.

For an external implementation, publish its authors, repository, exact commit,
supported profile, dependency versions, and results for every shared case. Run
its own hostile and stateful tests as well. Document which components it actually
implements and who operates them. A second verifier is useful evidence of
interoperability; an independently operated permit issuer additionally needs
durable replay, counter, revocation, crash, rollback and executor-boundary tests.
No central Money Musk approval is required to implement the open profile.

The practical goal is interoperable human control, not an exclusive global
authority or a universal identity registry. WebAuthn user verification supplies
stronger evidence of local interaction than a device signature alone. It is not
legal identity, guaranteed biological liveness, or proof that an owner understood
every consequence. Physical authenticator testing and independent security
review remain separate evidence.

References: [WA-1 contract](PRESENCE.md), [HAP-1 signed grammar](SPEC.md),
[W3C assertion verification](https://www.w3.org/TR/webauthn-3/#sctn-verifying-assertion),
[W3C signature counters](https://www.w3.org/TR/webauthn-3/#sctn-sign-counter).
