Bounded Authority Protocol v3 Wire Profile

Copy Markdown View Source

Document revision: rev 2 (2026-11-09: erratum 6; rev 1, 2026-09-21; errata 3 and 5 amend revision 1 in place; see the errata registry). Status: normative. Contract-major 3, suite BAP3-ES256-SHA256. This profile was activated under the successor-major charter; the signature-suite bridge it realizes is specified by the AP2 interop profile §3.

The v3 profile is a complete closed wire profile parallel to the frozen v1 (bap-v1.md) and v2 (bap-v2.md) profiles. Conformance language, the abstract data model, JSON decoding and canonical serialization, base64url, protected-header and claim closed sets, URI normalization, signing and digest inputs, the consumption chain and anchored export, the public verification contract, the untrusted key locator, typ values, and security/privacy considerations are INCORPORATED FROM v1 BY REFERENCE with the substitutions of §2; the selector algebra is INCORPORATED FROM v2 BY REFERENCE (§4). No section of either incorporated profile is optional, open, or best-effort in v3. Sections 3–7 state the v3-specific normative rules in full, including the ES256 signature suite.

1. Suite identity and major detection

The v3 profile's suite is BAP3-ES256-SHA256: ECDSA over the NIST P-256 curve with SHA-256 (ES256, RFC 7518 §3.4), SHA-256 digests, RFC 8785 JCS canonical bytes, and the BAP3-* domain separators — under the major-bound naming scheme BAP<contract-major>-<signature>-<digest> (see the registries) with the signature family changed from EdDSA/Ed25519 to ECDSA/P-256.

Every v3 artifact declares its contract-major mechanically: the payload v claim is exactly integer 3, the protected typ header carries the same closed values as v1, the protected alg header is exactly ES256, and the domain separators are version-bound. A conforming v3 verifier detects the profile of any artifact from its bytes alone.

Cross-major rules (REQ3-CORE-cross-major-reject): a v3 verifier rejects every artifact whose payload v is not exactly 3 — including all v1 and v2 artifacts — with the single closed error; the v1 and v2 profiles reject v3 bytes symmetrically through their closed v checks. There is no cross-major fallback, downgrade, or best-effort parsing in any direction. A holder presents artifacts of one major end-to-end: a v3 proof MUST pair with a v3 grant (REQ3-EVO-proof-major-equals-grant); mixed-major credentials are invalid by construction (REQ3-EVO-mixed-major-invalid). Cross-suite evidence rules for prior-major artifacts remain the reserved ba+suite-attestation mechanism of the suite-succession design; this profile activates none of it.

2. Substitutions incorporated from v1

For every v1 section not restated below, the normative v3 text is the v1 text with exactly these substitutions (REQ3-CORE-v1-incorporation):

v1 constantv3 constant
v claim value 1 (grant, proof, boundary anchor, key transition, chain row, export header) — grants and proofs MUST carry exactly integer 3 (REQ3-CLAIM-v, REQ3-CLAIM-proof-v); anchors, transitions, rows, and the export header inherit the same substitution3
request-digest prefix BAP1-REQUEST\0BAP3-REQUEST\0 (REQ3-SIGNING-digest-prefix)
chain-row domain BAP1-CHAIN\0BAP3-CHAIN\0
archive prefix BAP1-ARCHIVE\0EXPORT\0BAP3-ARCHIVE\0EXPORT\0
suite name BAP1-Ed25519-SHA256BAP3-ES256-SHA256
protected alg "EdDSA" (grant, proof, boundary anchor, key transition)"ES256" (REQ3-HEADER-alg)
proof JWK {crv: "Ed25519", kty: "OKP", x} and its thumbprint preimagethe EC JWK and preimage of §3
selector kind set{all, equals, one_of, lte, gte} — incorporated from v2 (§4)
facts and decoded-struct version field 13
normative references RFC 8032/8037 (EdDSA)RFC 7518 §3.4/§6.2.1 (ES256, EC JWK parameters); SEC 1 v2 (uncompressed EC point form, as profiled by RFC 5480 §2.2)

All bounds, claim member sets, header member sets, typ values (ba+cap, dpop+jwt, ba+chain-anchor, ba+key-transition), and requirement cross-references to the shared verification semantics are unchanged except where §3 restates the suite's fixed widths. The local-loopback application proof profile (bap-application-proof/local-loopback-http/v1) is bound to contract-major 1; it pairs with no v3 grant, and the v3 façade exposes no loopback functions.

3. The ES256 signature suite

3.1 Keys and the proof JWK

The suite's keys are NIST P-256 (secp256r1, prime256v1) key pairs. The wire form of a public key is the JWK; the raw-byte form used where v1 uses "the raw 32-byte Ed25519 public key" (caller-supplied issuer and historical keys, and the decoded holder key) is the uncompressed SEC1 point — exactly 65 bytes, 0x04 || x || y (REQ3-KEY-uncompressed-sec1). Compressed points are invalid in this form.

The proof JWK is exactly {crv: "P-256", kty: "EC", x: X, y: Y} in any member order (REQ3-HEADER-proof-jwk), where X and Y are canonical unpadded base64url of exactly 32 bytes each — the fixed-width unsigned big-endian coordinate spelling of RFC 7518 §6.2.1.2 (x) and §6.2.1.3 (y). Every additional member, including private d, is invalid (REQ3-HEADER-no-private-jwk). The decoded coordinates MUST each be less than the field prime p and MUST form a point on the curve (REQ3-KEY-point-on-curve); this check is pure arithmetic in the profile (it precedes the crypto backend, whose off-curve behavior is backend-specific and never load-bearing).

Issuer-key and holder-key fingerprinting (cnf.jkt and the facts fingerprint) use the RFC 7638 thumbprint over exactly:

{"crv":"P-256","kty":"EC","x":"<canonical-X>","y":"<canonical-Y>"}

(REQ3-HEADER-thumbprint) — the required EC members in lexicographic order; the thumbprint is unpadded base64url SHA-256 of those UTF-8 bytes, and verified facts carry the raw 32-byte digest (REQ3-HEADER-digest-width, incorporated). BAP cnf.jkt and AP2 cnf.jwk are two spellings of one key identity (the AP2 interop profile §3 bridge).

3.2 Signatures

The wire signature is the RFC 7518 §3.4 raw form: exactly 64 bytes, r || s, two fixed-width 32-byte unsigned big-endian integers (REQ3-SIGNING-raw-rs). DER is never a v3 wire spelling.

The verifier rejects, as invalid encodings before any backend call (REQ3-SIGNING-range):

  • r = 0 or s = 0;
  • r ≥ n or s ≥ n, where n is the P-256 group order;
  • s > n/2 — the HIGH-S half (low-S required, REQ3-SIGNING-low-s).

Low-S makes each signature non-malleable: for a valid ECDSA signature (r, s), the counterpart (r, n − s) also satisfies the verification equation, so a third party observing a valid signature could otherwise re-spell it into a second, differently-hashing, still-valid encoding; only the low-S rule admits one of the two. ECDSA signs with a per-signature nonce, so the same key and message admit many independently generated valid low-S signatures — the rule selects one encoding per signature, not one signature per message. Producers MUST normalize (s ← n − s when high), one conditional subtraction, before the signature leaves the signer. Normalization is the signer's duty: the party that receives the signature from the external signer (HSM or KMS) applies it. The profile's producer surfaces do not normalize; they refuse. Compact assembly (assemble_compact) and anchored-export encoding (encode_anchored_export) MUST return exactly the profile's closed error value when any signature they frame fails the range or low-S rule above, and MUST emit every accepted signature's bytes unchanged (REQ3-SIGNING-producer-canonical; erratum 3). These surfaces hold no key and verify no signature, so a signature they accept can still fail verification. Decode does not apply the range or low-S rule: a decoded compact is not a verified one. A backend rejection OR exception (an off-curve point, a backend that raises) returns exactly the profile's closed error value (REQ3-SIGNING-backend-reject, incorporated from REQ1-SIGNING-backend-reject).

Verification order follows the v1 bounds-ordering discipline (REQ3-BOUNDS-ordering, incorporated): segment and canonical-base64url checks; JWK member-set, width, < p, and on-curve checks; signature width and integer-range checks; then the backend verification over the exact RFC 7515 signing input.

3.3 Protected headers

The protected headers bind the suite via alg: "ES256"; the member sets are v1's exactly:

Compact valueMembers
grantalg: "ES256", typ: "ba+cap", kid: key_identifier
proofalg: "ES256", typ: "dpop+jwt", jwk: public_EC_JWK

crit, b64, embedded grant keys, unknown algorithms, and every unlisted member are invalid (REQ3-HEADER-closed-set, incorporated). Grant kid keeps the v1 byte discipline (REQ1-HEADER-kid-bytes incorporated) and remains an untrusted hint. The boundary-anchor and key-transition headers substitute alg: "ES256" into the v1 forms verbatim.

4. Selector algebra

The v3 selector algebra is the v2 algebra unchanged: the closed member-set discipline with the FIVE kinds — the three v1 kinds all, equals, one_of plus the two range kinds lte, gte that contract-major 2 activated — the same-tag/inclusive range rules, the interval conjunction, and the v2 path/count/verdict-internal rules (REQ2-SELECTOR-* semantics incorporated; v3 carries them as REQ3-SELECTOR-*). See bap-v2.md §4. Attenuation posture and the no-strict-kinds exclusion carry over unchanged.

Erratum 6 carries the selector float-zero rule over with the algebra: grant decode rejects an equals value or one_of member that contains a float-tagged zero at any depth (REQ3-SELECTOR-float-zero), range bounds compare numerically with −0.0 = 0.0 (REQ3-SELECTOR-range-signed-zero), and the grant producer refuses a float-tagged integral number in any selector value, range bounds included (REQ3-SIGNING-integral-float-selector).

5. Hard maxima

Every v1 bound carries over (REQ3-BOUNDS-inherited) except the suite fixed widths, restated for this suite as immutable cryptographic constants (REQ3-BOUNDS-fixed-widths):

Suite constantBytes
P-256 coordinate (x, y)32 each
raw public key (uncompressed SEC1)65
signature (r || s)64
SHA-256 digest32

No new magnitude arises: ECDSA verification consumes two range-checked 32-byte integers, a 65-byte point, and the bounded signing input (the contract-major 3 bounds review). Callers tighten ceilings exactly as in v1; the fixed widths cannot be tightened or widened.

6. Requirement identifiers

The v3 profile carries its own REQ3-* range under the stable requirement-identifier scheme of bap-v1.md; REQ1-* and REQ2-* ids remain bound to the v1 and v2 profiles and never apply to v3 behavior. The v3 MUST-to-cell traceability lives in the requirement map § v3.

7. Conformance corpus

The v3 conformance corpus is a certified artifact with its own identity (priv/conformance/v3/corpus, revision 1). Its certified index SHA-256 is pinned in the verifier CLI and every SDK runner exactly as the v1 and v2 corpora are; a runner fails closed unless the loaded corpus is that exact certified snapshot. Version-neutral primitive surfaces execute the same shared implementations the v1 corpus certifies, and their cases are carried into the v3 corpus byte-for-byte; the profile-bound surfaces carry v3-minted fixtures — every applicability cell v1 populates is populated in v3, and the full range-selector class matrix of bap-v2.md §4's activation corpus carries over (v1 populates no lte/gte cell, and the SDKs' only normative evidence for the range kinds is this corpus) — plus the suite matrices (signature canonicality: tampered r, tampered s, high-s, zero r/s, r ≥ n, s ≥ n; key encodings: wrong crv/kty, non-canonical or wrong-width coordinates, extra JWK member, off-curve point; thumbprint over the wrong member set) and the cross-major rejections (v1 and v2 artifact bytes under v3 verification). Signed fixtures were minted with ephemeral in-memory P-256 keys; no private material is tracked (REQ3-CORPUS-certified-identity).

Producer-surface signature canonicality is certified by the additive bap-producer-canonicality/1 corpus (priv/conformance/producer-canonicality, revision 1, erratum 3), whose index SHA-256 99ee6fbbf32758b03d4630647f721d8d4e349f0628d860493d667fe6e762c601 is pinned beside this corpus's. No verdict of this corpus changes.

The selector float-zero rule (erratum 6) is certified by the additive bap-selector-float-zero/1 corpus (priv/conformance/selector-float-zero, revision 1), whose index SHA-256 97fd7a99cdbf3acc0a78f5ba1c6556e23a63e0ad66f533e31fd69f82dc5f3003 is pinned beside this corpus's. No verdict of this corpus changes.