# PRF extension support _(no submodules)_ ## Purpose Implements the W3C WebAuthn L3 §10.1.4 PRF (Pseudo-Random Function) extension passthrough plus result parsing. PRF is the cornerstone of passkey-as-master-key-unlock flows: the authenticator's secure element materialises a ~32-byte symmetric secret deterministic in the (credential id, caller-supplied salt) pair. Consumers (notably `@suaveplan/vault`) use the secret to wrap an Account Unlock Key so a vault unlocks without the user typing a master password. ## Features - Typed input shapes for both ceremonies: `PrfRegisterInput` (`{ eval: { first, second? } }`) and `PrfAuthenticateInput` (`{ eval | evalByCredential }`). - `readPrfResult(extensions)` extracts the `prf` field from the raw `ClientExtensionResults` object, narrowing types so callers consume `Uint8Array`s rather than `unknown`. - `buildPrfExtension(input)` produces the wire-shape forwarded to `navigator.credentials.create/get` so callers do not duplicate the structural construction. - Three-state result: `enabled === false` (not supported), `enabled === true` with no `results` (supported but caller did not request an eval), `enabled === true` with `results.first: Uint8Array` (the materialised secret). ## Usage: Basic Example ```ts import { readPrfResult } from "@suaveplan/webauthn/extensions/prf"; const prf = readPrfResult(authenticationResult.extensions); if (prf?.enabled && prf.results?.first) { const wrapKey = prf.results.first; } ``` ## Usage: Advanced Example ```ts import { buildPrfExtension, readPrfResult, } from "@suaveplan/webauthn/extensions/prf"; const ext = buildPrfExtension({ eval: { first: new Uint8Array(32) } }); const cred = await navigator.credentials.get({ publicKey: { challenge, allowCredentials, extensions: ext }, }); const prf = readPrfResult( (cred as PublicKeyCredential).getClientExtensionResults() ); if (!prf?.enabled) { throw new Error("authenticator does not support PRF"); } ``` ## API Reference - `PrfRegisterInput` — `{ eval?: { first: Uint8Array, second?: Uint8Array } }`. - `PrfAuthenticateInput` — `{ eval?, evalByCredential? }`. - `PrfRegisterResult` / `PrfAuthenticateResult` — `{ enabled: boolean, results?: { first: Uint8Array, second?: Uint8Array } }`. - `readPrfResult(extensions): PrfRegisterResult | undefined` — narrow + extract. - `buildPrfExtension(input): { prf?: ... }` — wire-shape builder. ## Implementation Notes - The package does NOT request or surface a `prf` second-input by default. Consumers that need two-input PRF (key rotation flows) opt in by setting `eval.second`. - The `enabled` field is set to `true` by some Chromium platform authenticators even when the caller did not request an eval; consumers SHOULD treat `enabled === true` without `results` as "PRF is available, request it next time" rather than "secret is materialised". - `readPrfResult` is intentionally tolerant of missing fields — it returns `undefined` when no PRF extension is present at all, distinguishing that from `{ enabled: false }` (PRF requested but not supported by the authenticator).