/** * Canonical JSON with stable (sorted) key order. MUST match the `canonicalJson` * in governanceChain.zerodev.ts exactly — it is the preimage of `targetHash`, so * any divergence changes the hash owners signed and breaks verification. */ export declare function canonicalJsonGov(value: unknown): string; export interface FlowsGovernanceOp { chainId: number; /** The governed SCA address (EIP-712 verifyingContract). */ scaAddress: string; /** The op kind, e.g. 'policy.change' — hashed as keccak256(utf8(kind)). */ kind: string; /** The op target (the policy.change diff + toDoc/toDocHash) — hashed canonically. */ target: unknown; requiredN: number; nonce: number; } /** * Reconstruct the domain-separated `FlowsGovernance` hash an owner signs for a * Class B (off-chain) governance op. Returns a 0x-prefixed 32-byte hex string, * identical to viem `hashTypedData` over the same domain/types/message. */ export declare function flowsGovernanceHash(op: FlowsGovernanceOp): string; /** * A TRUSTED on-chain guardian (one signer in the SCA weighted-validator config). * The seat sources these from chain — the host never gets to assert who they are. * Identity is the on-chain key itself (EOA address / passkey P-256 pubkey); there * is no host-supplied owner id in the trust path. */ export interface QuorumOwner { keyType: 'eoa' | 'passkey' | string; /** EOA: the guardian's 0x address. */ address?: string | null; /** Passkey: the registered P-256 public key coordinates (0x-hex, 32 bytes each). */ pubKeyX?: string | null; pubKeyY?: string | null; } /** A WebAuthn assertion (passkey co-signature). base64url-encoded per WebAuthn JSON. */ export interface QuorumWebAuthnAssertion { credentialId?: string; authenticatorData: string; clientDataJSON: string; signature: string; } /** * One co-signature on the op. The signer's identity is RECOVERED from the * signature and matched against the trusted guardian set — there is no trusted * host-supplied owner id (an optional `ownerId` may ride along for audit only). */ export interface QuorumSignature { /** EOA: 0x + 65-byte (r||s||v) personal_sign over the op hash. */ signature?: string; /** Passkey: the WebAuthn assertion over the op hash. */ webauthn?: QuorumWebAuthnAssertion; /** Audit hint only — NOT used for verification or counting. */ ownerId?: string; } export interface QuorumWebAuthnConfig { /** Accepted clientData.origin values (pinned). */ allowedOrigins: string[]; /** Default relying-party id when an owner row has none. */ rpId: string; } export type QuorumReason = 'wrong_op_hash' | 'target_unbound' | 'wrong_kind' | 'below_quorum' | 'threshold_mismatch' | 'bad_threshold'; export interface VerifyQuorumInput extends FlowsGovernanceOp { /** The hash the host claims the owners signed — re-derived and checked here. */ expectedOpHash: string; /** The content hash of the policy doc the seat is about to register (binding). */ toDocHash: string; /** * The TRUSTED guardian set — the SCA's on-chain weighted-validator signers. * SECURITY: this MUST be sourced from chain by the seat (readOnchainQuorumConfig), * NOT echoed from the host request. Each co-signature's signer is RECOVERED and * matched against this set; counting is deduped by on-chain identity, so a host * cannot forge an owner, relabel one, or list one guardian twice to inflate the * count. */ owners: QuorumOwner[]; /** * The TRUSTED current threshold (N in "N of M") — the SCA's on-chain * weighted-validator threshold, sourced from chain (same rule as `owners`). The * op's signed `requiredN` must equal this, and the count of distinct matched * guardians must reach it. */ threshold: number; /** The collected co-signatures (signer identity is recovered, not asserted). */ signatures: QuorumSignature[]; webauthn: QuorumWebAuthnConfig; } export interface QuorumResult { ok: boolean; reason?: QuorumReason; /** The distinct owner ids whose co-signatures verified. */ verifiedSigners: string[]; } /** * The authoritative in-TEE quorum check for a governed policy loosening. Verifies * (1) the op hash is the one the owners actually signed, (2) the signed op declares * a requiredN equal to the TRUSTED on-chain threshold, (3) the toDocHash INSIDE the * signed target equals the doc the seat will register, (4) at least `threshold` * DISTINCT guardians from the trusted on-chain set produced a valid co-signature * (signers recovered, deduped by on-chain identity). Fail-closed: malformed → not ok. * * SECURITY CONTRACT: `owners` + `threshold` are the trust root and MUST be sourced * from the on-chain SCA config by the caller, never from the host request. Given a * host-controlled owner set this function is NOT a security boundary (the host * would just sign with its own "owner"). See VerifyQuorumInput.owners. */ export declare function verifyGovernanceQuorum(input: VerifyQuorumInput): QuorumResult;