import type { DidDocument } from "./identity.js"; import { type Mandate, type Revocation } from "./mandate.js"; /** * Envelope format version currently understood. * * Spec §11 revision note (v0.2.0): the envelope shape is stable; what evolves * is the `params` payload sitting beside it, which the envelope only covers * through `params_hash`. */ export declare const ENVELOPE_VERSION: "0.1.0"; export interface EnvelopeProof { readonly type: "Ed25519Signature2020"; /** * Either a DID URL into the issuer's verification method set * (e.g. `did:aithos:z6Mk…#public`) when the subject signs directly, OR a * bare multibase Ed25519 public key when a delegate signs — in the latter * case `SignedEnvelope.mandate` is REQUIRED (§11.6). */ readonly verificationMethod: string; readonly created: string; readonly proofValue: string; } /** * Optional sponsorship reference — draft §13.6. * * Present when the consumer expects a specific `SponsorshipMandate` to fund * the call. The authority MUST cross-check `hash` against the canonical copy * of the mandate and reject on mismatch, defeating any attempt to widen caps * by tampering with a local copy. When the field is absent, the authority MAY * still auto-discover an eligible sponsorship from its own index; the field is * an explicit hint, not the sole gate. * * NOT YET NORMATIVE — pending promotion of `sponsorship-mandate-v0.1` draft. */ export interface SponsorshipReference { readonly id: string; /** Canonical hash of the mandate, format `"sha256:" + hex`. */ readonly hash: string; } export interface SignedEnvelope { readonly "aithos-envelope": "0.1.0"; readonly iss: string; readonly aud: string; readonly method: string; readonly iat: number; readonly exp: number; readonly nonce: string; /** `"sha256-" + lowercase hex SHA-256 of rfc8785(params without _envelope)`. */ readonly params_hash: string; readonly mandate?: Mandate; /** Draft §13.6 — sponsorship reference, optional and back-compatible. */ readonly sponsorship?: SponsorshipReference; readonly proof: EnvelopeProof; } export type EnvelopeErrorCode = -32010 | -32011 | -32012 | -32013 | -32040 | -32041 | -32042 | -32603; export interface AithosError { readonly code: EnvelopeErrorCode; readonly message: string; readonly data?: Record; } /** * Methods that MUST be signed by `#root` when the subject signs directly * (no mandate). Spec §11.7 signing-purpose table. Some of these are also * non-delegable (see `NEVER_DELEGABLE_METHODS`); others (`publish_tombstone`) * may be delegated to an agent carrying the appropriate scope. */ export declare const ROOT_ONLY_DIRECT_METHODS: ReadonlySet; /** * Methods that can NEVER be invoked under a mandate. Spec §11.6 last two * rows — "never delegable". An envelope carrying a mandate for one of these * MUST be rejected with `AITHOS_INSUFFICIENT_SCOPE`. */ export declare const NEVER_DELEGABLE_METHODS: ReadonlySet; /** * Compute the `params_hash` field for a given tool payload. * * The payload MUST be `params` WITHOUT `_envelope` — the envelope cannot * hash itself (circular reference). In practice both the signer and the * verifier strip `_envelope` via destructuring before calling this helper. */ export declare function envelopeParamsHash(params: unknown): string; /** * Canonical JSON bytes covered by `proof.proofValue`. Matches the * substitute-then-canonicalize pattern from §5.1.1: blank the signature * field, JCS-canonicalize, produce UTF-8 bytes, sign/verify those bytes. */ export declare function envelopeSigningBytes(env: SignedEnvelope): Uint8Array; export interface SignEnvelopeArgs { /** Subject DID whose state will be mutated — never the delegate's DID. */ readonly iss: string; /** Absolute URL of the target endpoint (scheme + host + path, no query, no fragment). */ readonly aud: string; /** Fully-qualified tool name, identical to the JSON-RPC `method`. */ readonly method: string; /** Tool payload (i.e. `params` WITHOUT `_envelope`). */ readonly params: unknown; /** * Ed25519 signing material for one of the subject's sphere keys. * * - `seed`: the 32-byte private seed. * - `verificationMethod`: DID URL into the subject's DID document * verification method set — e.g. `did:aithos:#public`. */ readonly sphereKey: { readonly seed: Uint8Array; readonly verificationMethod: string; }; /** Envelope lifetime. Defaults to 60s (§11.10 recommends short TTLs). */ readonly ttlSeconds?: number; /** Clock override for deterministic testing. */ readonly now?: Date; /** Nonce override. Defaults to a freshly minted ULID. */ readonly nonce?: string; /** * Optional sponsorship reference — draft §13.6. When present, the field is * carried in the signed envelope and the authority may apply the indicated * sponsorship if eligible. */ readonly sponsorship?: SponsorshipReference; } export declare function signEnvelope(args: SignEnvelopeArgs): SignedEnvelope; export interface SignEnvelopeWithMandateArgs { readonly iss: string; readonly aud: string; readonly method: string; readonly params: unknown; /** * Ed25519 signing material for the delegate key named in the mandate's * `grantee.pubkey`. `pubkeyMultibase` is the `z…` form (matches * `mandate.grantee.pubkey` exactly). */ readonly delegateKey: { readonly seed: Uint8Array; readonly pubkeyMultibase: string; }; readonly mandate: Mandate; readonly ttlSeconds?: number; readonly now?: Date; readonly nonce?: string; /** Optional sponsorship reference — draft §13.6. */ readonly sponsorship?: SponsorshipReference; } export declare function signEnvelopeWithMandate(args: SignEnvelopeWithMandateArgs): SignedEnvelope; /** * Build the canonical UNSIGNED envelope — every field populated except * `proof.proofValue`, which is left blank (`""`) per the §5.1.1 * substitute-then-canonicalize pattern. This is the single source of truth * for envelope assembly: both the seed-based signers and the pluggable * async signer ({@link signEnvelopeWith}) build their bytes from here, so * any signing path produces byte-identical wire output for identical input. * * Callers obtain the bytes to sign via {@link envelopeSigningBytes} and * attach the resulting signature with {@link attachProof}. */ export declare function buildUnsignedEnvelope(args: { iss: string; aud: string; method: string; params: unknown; ttlSeconds: number | undefined; now: Date | undefined; nonce: string | undefined; verificationMethod: string; mandate: Mandate | undefined; sponsorship: SponsorshipReference | undefined; }): SignedEnvelope; /** Attach a raw Ed25519 signature to an unsigned envelope (base64url proofValue). */ export declare function attachProof(unsigned: SignedEnvelope, signature: Uint8Array): SignedEnvelope; /** * Pluggable-signer envelope helper. Identical wire output to * {@link signEnvelope} / {@link signEnvelopeWithMandate} but the Ed25519 * signing operation is injected as an async callback instead of taking a * raw seed. This lets hosts that hold non-extractable keys (e.g. WebCrypto * `crypto.subtle`, the Aithos SDK's `EnvelopeSigner`) sign without ever * surfacing seed bytes — while sharing this module's canonicalization so * their envelopes can never drift from the seed-based path. * * For an owner-path call, pass the subject's `did#sphere` as * `verificationMethod` and omit `mandate`. For a delegate-path call, pass * the delegate's bare multibase as `verificationMethod` and the signed * `mandate`; the `sign` callback MUST use the delegate's key. */ export interface SignEnvelopeWithArgs { readonly iss: string; readonly aud: string; readonly method: string; readonly params: unknown; /** `did#sphere` (owner path) or bare multibase (delegate path). */ readonly verificationMethod: string; /** Sign the given canonical bytes with the appropriate Ed25519 key. */ readonly sign: (bytes: Uint8Array) => Promise | Uint8Array; readonly ttlSeconds?: number; readonly now?: Date; readonly nonce?: string; /** Present only on the delegate path (§11.6). */ readonly mandate?: Mandate; /** Optional sponsorship reference — draft §13.6. */ readonly sponsorship?: SponsorshipReference; } export declare function signEnvelopeWith(args: SignEnvelopeWithArgs): Promise; /** * Replay-protection cache contract — spec §11.5. * * `putIfAbsent` MUST perform an atomic conditional insert: * - `true` → the key was new and has been committed with TTL `expiresAtSeconds`. * - `false` → the key already existed; the caller MUST reject the request. * * A throw from this method is treated as "cache unreachable", which per * §11.10 MUST fail closed (internal error `-32603`) rather than letting the * write through. */ export interface EnvelopeReplayCache { putIfAbsent(key: string, expiresAtSeconds: number): Promise; } export interface VerifyEnvelopeContext { /** Server canonical URL for the path that received the request. */ readonly expectedAud: string; /** JSON-RPC `method` the client invoked. */ readonly expectedMethod: string; /** Tool payload, `_envelope` already stripped (§11.4 step 5). */ readonly params: unknown; /** Unix seconds. Defaults to `Math.floor(Date.now() / 1000)`. */ readonly nowSeconds?: number; /** Fetch the current DID document of `iss`. Return `null` when unresolvable. */ resolveIssuerDoc(iss: string): Promise; /** Look up a local revocation for the given mandate id. Optional; absent ≡ none. */ findRevocation?(mandateId: string): Promise; /** Replay cache — spec §11.5. */ readonly replay: EnvelopeReplayCache; } export type VerifyEnvelopeResult = { readonly ok: true; readonly issuer: string; readonly mandateId?: string; /** Resolved signer Ed25519 public key (32 bytes). Useful for per-tool audit. */ readonly signerKey: Uint8Array; } | { readonly ok: false; readonly error: AithosError; }; /** * Verify a signed envelope, performing the 9 steps of spec §11.4 in order. * * The first failure short-circuits; later steps are NOT run. That matches * what the spec asks for ("MUST perform these steps, in order") and keeps * side-effects — specifically the replay-cache commit — gated behind all * prior checks passing. * * On success, returns the verified issuer DID, optional mandate id, and the * raw 32-byte Ed25519 public key that was used to sign. Callers are still * responsible for enforcing payload-level scope rules (§11.6, §11.7 per-zone * checks) that the envelope alone cannot know about. */ export declare function verifyEnvelope(envelope: SignedEnvelope, ctx: VerifyEnvelopeContext): Promise; /** * Helper for callers that start from a raw Ed25519 seed and need the * multibase form (`z…`) that mandates and envelope proofs reference. */ export declare function delegateMultibaseFromSeed(seed: Uint8Array): string;