Files
zap-spec/capabilities_kinds.md
zeekay 9198e3b89b capabilities: bump sig field 96 → 3408 for ML-DSA-65 (v1.1)
Widen the Sig footer from sig96 (96 B) to sig3408 (3408 B) so a full
FIPS 204 ML-DSA-65 signature (3309 B) fits inline. Capability struct
grows from 260 B to 3572 B; Revocation from 136 B to 3448 B. The field
offset of Sig itself (164) is unchanged — only the field width.

3408 is the smallest 16-byte-aligned size that fits ML-DSA-65 with
99 B headroom. Schemes shorter than 3408 (secp256k1 65 B, Ed25519
64 B) are zero-padded on the right; the algorithm tag at Sig[3407]
tells the verifier which primitive to dispatch on.

Wire-incompatible with v1.0. Per the project's "no backwards
compatibility, only forwards perfection" rule, every encoder/decoder
updates in lockstep at the v1.1 tag — no compat layer, no union, no
version negotiation.

Cross-references:
  - capabilities_kinds.md gains the "Wire schemes" tag table.
  - SPEC.md §6 documents the v1.0 → v1.1 wire transition.
2026-06-07 11:45:13 -07:00

6.7 KiB

ZAP Capability Enums

The .zap DSL has no native enum primitive — its single-pass codegen is deliberately minimal. Enum constants are normative here; codegen tools emit them as named integer constants in the target language alongside the struct accessors. This file is part of the wire contract. Changes require a new struct family + bump.

Wire schemes (Capability.Sig algorithm tag, u8)

The final byte of the 3408-byte Sig footer is the algorithm tag. The verifier dispatches on this byte to pick the right primitive; the tag byte is inside the signed payload, so tag-substitution attacks are detected by verifier mismatch. Encoded signature occupies bytes [0..L) where L is the per-algorithm signature length; the bytes [L..3407) are zero pad and byte 3407 is the tag.

Constant Value Algorithm Sig length
SchemeReserved 0x00 (do not use; verifiers MUST refuse) n/a
SchemeSecp256k1 0x01 secp256k1 ECDSA (32B R || 32B S || 1B v) 65
SchemeEd25519 0x02 Ed25519 (RFC 8032) 64
SchemeMLDSA65 0x03 ML-DSA-65 (FIPS 204 Level 3) 3309
SchemeHybrid 0x04 Ed25519 || ML-DSA-65 concatenated 64+3309

CapKind (Capability.Kind, u32)

Identifies the authority profile — which Target type, which Permission semantics, which Caveat kinds make sense. Reserved range 0x0000_0000 through 0x0000_00FF for stack-level kinds; 0x0001_0000+ reserved for application-defined kinds (registered in this file when stable).

Constant Value Replaces
CapKindReserved 0x00 (do not use)
CapKindIAMSession 0x01 bearer JWT session tokens
CapKindIAMAPIKey 0x02 client-credentials API keys
CapKindKMSAccess 0x10 KMS access tokens for read/list
CapKindKMSSign 0x11 KMS signing authority
CapKindMPCSign 0x20 MPC threshold-signing intent
CapKindATSOrder 0x30 ATS order placement authority
CapKindBridgeXfer 0x40 cross-chain transfer authority
CapKindStake 0x50 validator stake-backed authority
CapKindDelegate 0xFF meta: ability to attenuate-and-reissue

CapKindDelegate is special: a cap whose Kind is CapKindDelegate permits its Holder to mint child caps of any Kind whose Permissions are a subset of the delegate's Permissions and whose Target matches. This is how an org admin grants a service the right to issue session caps to its users.

CaveatKind (Caveat.Kind, u32)

Identifies what the Caveat.Value bytes mean. All values are encoded little-endian where applicable.

Constant Value Value encoding
CaveatKindExpiresAt 0x00 u64 unix seconds
CaveatKindMaxAmount 0x01 u64 amount in smallest denomination of asset
CaveatKindDestChain 0x02 id32 chain identifier
CaveatKindRateLimit 0x03 u32 ops-per-minute LE || u32 burst LE
CaveatKindIPCIDR 0x04 1 byte AF (4 or 6) || 1 byte prefix-len || addr bytes
CaveatKindAssetID 0x05 id32 allowed asset (repeat caveat for multi)
CaveatKindOpAllow 0x06 u64 bitmask LE, intersected with parent
CaveatKindMaxDepth 0x07 u8 remaining hops the cap chain may extend
CaveatKindAudience 0x08 id32 hash of target service principal pubkey
CaveatKindNonceHash 0x09 id32 of single-use binding (see SPEC.md)

The verifier MUST refuse any unknown CaveatKind. Unknown caveats are fail-closed by definition: an issuer that doesn't understand a caveat cannot enforce it, so it cannot honor a cap that carries it.

Permission bits (Capability.Permissions, u64)

Permission bits are per-CapKind. Each CapKind owns the bottom 32 bits of this field; the top 32 are reserved for cross-cutting bits (audit, delegation lifecycle). The same bit value MAY mean different things in different CapKinds — verifiers MUST dispatch on CapKind first.

Cross-cutting bits (top 32, all CapKinds)

Bit Constant Meaning
1 << 32 PermAttenuate may mint child caps with subset perms
1 << 33 PermAudit may read audit trail for Target
1 << 63 PermRoot root-of-trust marker (set on root caps only)

CapKindIAMSession (0x01) low bits

Bit Constant Meaning
1 << 0 PermSessionRead read operations on user resources
1 << 1 PermSessionWrite write operations
1 << 2 PermSessionDelete delete operations
1 << 3 PermSessionAssumeOrg switch active organization

CapKindKMSSign (0x11) low bits

Bit Constant Meaning
1 << 0 PermSignTx sign a transaction
1 << 1 PermSignBlob sign an arbitrary blob
1 << 2 PermSignAttest sign an attestation

CapKindATSOrder (0x30) low bits

Bit Constant Meaning
1 << 0 PermOrderPlace submit new orders
1 << 1 PermOrderCancel cancel orders
1 << 2 PermOrderModify modify resting orders
1 << 3 PermOrderShort enter short positions
1 << 4 PermOrderMargin use margin

CapKindBridgeXfer (0x40) low bits

Bit Constant Meaning
1 << 0 PermXferOut initiate outbound transfer
1 << 1 PermXferIn accept inbound transfer

Remaining CapKinds reserve their permission bit layout for definition at implementation time; record the assignment here when stabilized.