Referencia Zigspire-zig (SDK consumido)

zig/src/cap/sct.zig

Declaraciones públicas de zig/src/cap/sct.zig (spire-zig (SDK consumido)).

ImplementadoSin versión del tren todavía· generada desde apps/docs/generated/zig/spire.json

Página generada desde spire@spire-0.2.0-XvnrRek1BgCX4Bh8miuITCQgkn0FqeQrYYE3goFfDcQd (zig/src/root.zig). No se edita a mano: bun run docs:gen la regenera y bun run docs:check falla si difiere.

styx:parser

Styx Capability Token (SCT) v1: codec, signature check and resource digests (dec-0117 §4.1, spec protocols/capability-token/SCT_SPEC.md).

The daemon only VERIFIES. The private key lives in playback-svc (A4); the only signing code is testing.sign (sct_testing.zig), reachable from tests.

Wire layout (big endian, fixed length, no optional fields):

off len field 0 1 version = 1 1 1 scope 1 read · 2 publish · 3 ingest · 4 control 2 1 range_kind 0 none · 1 bytes [start, end) · 2 groups [start, end) 3 1 flags = 0 (reserved; non-zero is malformed) 4 8 kid SHA-256(raw Ed25519 public key)[0..8] 12 16 aud SHA-256("styx.sct.aud\x00" ++ node id)[0..16] 28 16 sid the 16 random bytes of the daemon session id 44 16 actor SHA-256("styx.sct.actor\x00" ++ actor id)[0..16] 60 32 resource resource digest (see Resource) 92 8 range_start 100 8 range_end 108 8 nbf unix seconds 116 8 exp unix seconds 124 16 jti random, unique per token 140 64 signature Ed25519 over SIGNING_DOMAIN ++ bytes[0..140]

Everything in this file is a pure function of its input: no allocation, no global state, no clock. Stateful checks (keys, sessions, replay, time) live in authority.zig.

cap.sct.VERSION

const · línea 37

pub const VERSION: u8 = 1

Sin ///.

cap.sct.BODY_LEN

const · línea 38

pub const BODY_LEN: usize = 140

Sin ///.

cap.sct.SIGNATURE_LEN

const · línea 39

pub const SIGNATURE_LEN: usize = Ed25519.Signature.encoded_length

Sin ///.

cap.sct.TOKEN_LEN

const · línea 40

pub const TOKEN_LEN: usize = BODY_LEN + SIGNATURE_LEN

Sin ///.

cap.sct.TOKEN_B64_LEN

const · línea 43

pub const TOKEN_B64_LEN: usize = TOKEN_LEN / 3 * 4

base64url without padding. 204 is a multiple of 3, so there are no trailing bits that a non-canonical encoding could hide data in.

cap.sct.SIGNING_DOMAIN

const · línea 44

pub const SIGNING_DOMAIN = "styx-sct/v1\x00"

Sin ///.

cap.sct.Kid

const · línea 52

pub const Kid = [8]u8

Sin ///.

cap.sct.Digest16

const · línea 53

pub const Digest16 = [16]u8

Sin ///.

cap.sct.Digest32

const · línea 54

pub const Digest32 = [32]u8

Sin ///.

cap.sct.SessionKey

const · línea 55

pub const SessionKey = [16]u8

Sin ///.

cap.sct.Jti

const · línea 56

pub const Jti = [16]u8

Sin ///.

cap.sct.Scope

type · línea 58

pub const Scope = enum

Sin ///.

cap.sct.Scope.fromByte

fn · línea 64

pub fn fromByte(b: u8) ?Scope

Sin ///.

cap.sct.Scope.isWrite

fn · línea 69

pub fn isWrite(self: Scope) bool

Write scopes are single-use per jti (dec-0117 §4.1).

cap.sct.RangeKind

type · línea 74

pub const RangeKind = enum

Sin ///.

cap.sct.RangeKind.fromByte

fn · línea 82

pub fn fromByte(b: u8) ?RangeKind

Sin ///.

cap.sct.Claims

type · línea 87

pub const Claims = struct

Sin ///.

cap.sct.Token

type · línea 102

pub const Token = struct

Sin ///.

cap.sct.DecodeError

const · línea 110

pub const DecodeError = error{ /// Wrong length, bad base64, unknown scope/range kind, reserved flags /// set, or an empty/inverted range. Malformed, UnsupportedVersion, }

Sin ///.

cap.sct.decode

fn · línea 119

pub fn decode(bytes: []const u8) DecodeError!Token

Decode a raw SCT. Checks structure only; the signature, the key and the time window are the authority's job.

cap.sct.decodeBase64

fn · línea 154

pub fn decodeBase64(text: []const u8) DecodeError!Token

Decode the base64url (no padding) form used in cap= and Authorization.

cap.sct.encodeBody

fn · línea 163

pub fn encodeBody(c: Claims) [BODY_LEN]u8

Serialize claims into the signed body (used by testing.sign and by the codec round-trip tests; the daemon never re-encodes a received token).

cap.sct.SignatureError

const · línea 182

pub const SignatureError = error{BadSignature}

Sin ///.

cap.sct.verifySignature

fn · línea 185

pub fn verifySignature(token: *const Token, public_key: Ed25519.PublicKey) SignatureError!void

Strict (cofactorless) Ed25519 verification over the domain-separated body.

cap.sct.kidOf

fn · línea 195

pub fn kidOf(public_key: [32]u8) Kid

kid of a public key: the first 8 bytes of SHA-256 of its raw encoding. Derived, never configured, so a key and its id cannot disagree.

cap.sct.audienceOf

fn · línea 208

pub fn audienceOf(node_id: []const u8) Digest16

Sin ///.

cap.sct.actorOf

fn · línea 212

pub fn actorOf(actor_id: []const u8) Digest16

Sin ///.

cap.sct.Resource

type · línea 219

pub const Resource = struct

Resource digests. Each kind has its own domain, and tuple elements are length-prefixed, so no two distinct resources share a digest by concatenation (["a/b"] vs ["a","b"], namespace vs track).

cap.sct.Resource.asset

fn · línea 221

pub fn asset(id: []const u8) Digest32

A media asset served over WT/H3 (the string playback-svc bound on IPC).

cap.sct.Resource.moqtNamespace

fn · línea 226

pub fn moqtNamespace(ns: []const []const u8) Digest32

A whole MoQT namespace (every track under it).

cap.sct.Resource.ingestRoot

fn · línea 235

pub fn ingestRoot(root_id: []const u8) Digest32

An ingest destination (conduit, dec-0121): the id of the daemon's ingest root (STYX_INGEST_ROOT_ID) the upload lands in.

cap.sct.Resource.moqtTrack

fn · línea 240

pub fn moqtTrack(ns: []const []const u8, name: []const u8) Digest32

One MoQT track.

cap.sct.sessionKeyFromId

fn · línea 268

pub fn sessionKeyFromId(session_id: []const u8) ?SessionKey

Parse the 32 lowercase hex chars after sess_ of a daemon session id into the 16 bytes an SCT carries. Anything else is not a session id.

cap.sct.packagingKeyFromId

fn · línea 276

pub fn packagingKeyFromId(packaging_id: []const u8) ?SessionKey

Same for a packaging session id (pkg_<32 hex>, dec-0110 §3): an SCT for /styx/pkg/<id>/... binds these 16 bytes. Session and packaging keys share the authority's map, whose bindSession refuses a key already bound, so one key names at most one live thing.

cap.sct.ingestKeyFromId

fn · línea 282

pub fn ingestKeyFromId(ingest_id: []const u8) ?SessionKey

Same for an ingest session id (ing_<32 hex>, dec-0121): one upload under one capability, bound in the same authority map.

cap.sct.parseHexFixed

fn · línea 299

pub fn parseHexFixed(comptime N: usize, text: []const u8) ?[N]u8

Parse exactly 2 * N lowercase hex chars into [N]u8.

cap.sct.testing

namespace · línea 320

pub const testing = @import("sct_testing.zig")

Signing support for tests only (sct_testing.zig: not a parser, no input). A daemon build has no caller of it, and no key material.

cap.authority.SessionKey

const · línea 55

pub const SessionKey = [16]u8

Sin ///.

cap.authority.Digest16

const · línea 53

pub const Digest16 = [16]u8

Sin ///.

cap.authority.Digest32

const · línea 54

pub const Digest32 = [32]u8

Sin ///.

cap.authority.Scope

type · línea 58

pub const Scope = enum

Sin ///.

cap.authority.Scope.fromByte

fn · línea 64

pub fn fromByte(b: u8) ?Scope

Sin ///.

cap.authority.Scope.isWrite

fn · línea 69

pub fn isWrite(self: Scope) bool

Write scopes are single-use per jti (dec-0117 §4.1).