// Wire types: claim payload, signature block, full envelope. // Field names and ordering match Rust exactly so JCS bytes are identical. import type { Identity } from "./identity.js"; export const CLAIM_TYPE = "kez.claim"; export const SIGCHAIN_EVENT_TYPE = "kez.sigchain.event"; export const FORMAT_VERSION = 1; export const NOSTR_SCHNORR_ALG = "nostr-secp256k1-schnorr-sha256-jcs"; export const ED25519_SHA512_ALG = "ed25519-sha512-jcs"; export const COMPACT_PROOF_PREFIX = "kez:z1:"; export const COMPACT_CHAIN_PREFIX = "kez:zc1:"; export interface ClaimPayload { type: typeof CLAIM_TYPE; version: number; subject: string; // serialized Identity primary: string; // serialized Identity created_at: string; // RFC 3339 expires_at?: string; } export interface SignatureBlock { alg: string; key: string; // serialized Identity (matches `primary`) sig: string; // hex } export interface SignedClaimEnvelope { kez: "claim"; payload: ClaimPayload; signature: SignatureBlock; } /** * Spec ยง6 sigchain event payload. Field order/names match Rust exactly so * JCS-canonicalized bytes are byte-identical across implementations. */ export interface SigchainEventPayload { type: typeof SIGCHAIN_EVENT_TYPE; version: number; primary: string; // serialized Identity, e.g. "nostr:npub1..." seq: number; prev?: string; // "sha256:" of prior envelope; omitted iff seq === 0 created_at: string; op: SigchainOp; payload: Record; } export type SigchainOp = "add" | "revoke" | "rotate" | "add_device"; export interface SignedSigchainEvent { kez: "sigchain_event"; payload: SigchainEventPayload; signature: SignatureBlock; } /** Build a fresh ClaimPayload with the right `type` and `version` fields. */ export function newClaimPayload( subject: Identity, primary: Identity, createdAt: Date, ): ClaimPayload { return { type: CLAIM_TYPE, version: FORMAT_VERSION, subject: subject.toString(), primary: primary.toString(), created_at: rfc3339Utc(createdAt), }; } /** RFC 3339 / ISO 8601 in UTC, matching the format Rust's chrono emits. */ export function rfc3339Utc(date: Date): string { return date.toISOString().replace(/Z$/, "Z"); }