import { type MlKemBackend, type MlKemParameterSet, type MlKemSuiteDescriptor } from "./mlkem"; import type { LibCrypto } from "./libcrypto"; /** * Sparse post-quantum healing state machine. * * This module deliberately does not own transport or persistence. Callers must: * * 1. authenticate/decrypt every inbound record with the current outer channel * before calling an `acceptAuthenticated*` method; * 2. persist prepared state before putting its record on the network; * 3. encrypt an ADVANCE under its `fromEpoch` key before committing it; and * 4. gate application traffic while `trafficBlocked` is true. * * There is no classical or lower-parameter fallback. The room-selected suite * supplied to the constructor is checked against both FIPS 203 sizes and the * backend. Every ADVANCE embeds the complete OFFER it answers. That makes the * exact suite, channel binding, epochs, counters, public key, and ciphertext a * single deterministic KDF transcript and gives the state machine an exact * byte string with which to reject replays and forks. */ export declare const PQ_HEALING_BINDING_BYTES = 32; export declare const PQ_HEALING_ROOT_BYTES = 32; export declare const PQ_HEALING_RECORD_HEADER_BYTES = 64; export declare const PQ_HEALING_ACK_BYTES = 64; export declare const PQ_HEALING_SNAPSHOT_FORMAT_VERSION = 1; export type PqHealingTurn = "local" | "remote"; export type PqHealingPhase = "idle" | "outbound-offer-prepared" | "outbound-offer-dispatched" | "inbound-offer" | "outbound-advance-prepared" | "outbound-advance-awaiting-ack" | "inbound-advance-prepared" | "inbound-advance-awaiting-ack-dispatch" | "destroyed"; export type PqHealingErrorCode = "binding-mismatch" | "counter-gap" | "destroyed" | "epoch-gap" | "fork" | "invalid-record" | "invalid-state" | "overflow" | "replay" | "suite-mismatch" | "wrong-turn"; export declare class PqHealingError extends Error { readonly code: PqHealingErrorCode; constructor(code: PqHealingErrorCode, message: string); } export interface PqHealingAdvanceAcknowledgement { /** * The newly committed epoch. The transport acknowledgement must be * authenticated under this epoch, proving that the offerer decapsulated. */ readonly epoch: bigint; /** Sender counter of the ADVANCE being acknowledged. */ readonly advanceCounter: bigint; } export interface PqHealingOfferRecord { readonly type: "offer"; readonly parameterSet: MlKemParameterSet; readonly binding: Uint8Array; readonly senderCounter: bigint; readonly fromEpoch: bigint; readonly toEpoch: bigint; readonly publicKey: Uint8Array; } export interface PqHealingAdvanceRecord { readonly type: "advance"; readonly parameterSet: MlKemParameterSet; readonly binding: Uint8Array; readonly senderCounter: bigint; readonly fromEpoch: bigint; readonly toEpoch: bigint; /** The complete, canonical OFFER answered by this record. */ readonly offerBytes: Uint8Array; readonly offer: PqHealingOfferRecord; readonly ciphertext: Uint8Array; } export type PqHealingRecord = PqHealingOfferRecord | PqHealingAdvanceRecord; export interface PqHealingMachineOptions

{ readonly module: LibCrypto; readonly backend: MlKemBackend

; /** * Authenticated room-selected suite. This is an input, never a negotiated * result. It must exactly match the backend's parameter set and FIPS sizes. */ readonly suite: Readonly>; /** * Non-secret, transcript-derived edge binding (for example a truncation of * the authenticated handshake/channel-input hash). */ readonly binding: Uint8Array; /** Current, separate PQ root. The constructor takes an owned copy. */ readonly rootKey: Uint8Array; /** Which side is allowed to emit the first/next OFFER. */ readonly nextOfferer: PqHealingTurn; readonly epoch?: bigint; readonly localCounter?: bigint; readonly remoteCounter?: bigint; } export interface PqHealingRestoreOptions

{ readonly module: LibCrypto; readonly backend: MlKemBackend

; readonly suite: Readonly>; /** Authenticated expected edge binding; snapshots from another edge fail. */ readonly binding: Uint8Array; } export type PqHealingSnapshotPhase = { readonly kind: "idle"; } | { readonly kind: "outbound-offer-prepared" | "outbound-offer-dispatched"; readonly offer: Uint8Array; readonly secretKey: Uint8Array; } | { readonly kind: "inbound-offer"; readonly offer: Uint8Array; } | { readonly kind: "outbound-advance-prepared"; readonly advance: Uint8Array; readonly nextRoot: Uint8Array; } | { readonly kind: "outbound-advance-awaiting-ack"; readonly advance: Uint8Array; } | { readonly kind: "inbound-advance-prepared"; readonly advance: Uint8Array; readonly secretKey: Uint8Array; readonly nextRoot: Uint8Array; } | { readonly kind: "inbound-advance-awaiting-ack-dispatch"; readonly advance: Uint8Array; }; /** * Owned, plaintext checkpoint of the complete store-free PQ machine. * * Durable integration normally checkpoints only phases whose corresponding * sealed outbox frame is committed in the same transaction. The two * `*-prepared` phases are intentionally representable for clone/rollback and * fault-injection tests, but are transaction-local and must never be persisted * alone or dispatched after restoration without the exact sealed frame. */ export interface PqHealingSnapshot

{ readonly formatVersion: typeof PQ_HEALING_SNAPSHOT_FORMAT_VERSION; readonly parameterSet: P; readonly binding: Uint8Array; readonly rootKey: Uint8Array; readonly epoch: bigint; readonly localCounter: bigint; readonly remoteCounter: bigint; readonly nextOfferer: PqHealingTurn; readonly phase: PqHealingSnapshotPhase; readonly lastInboundOffer: Uint8Array | null; readonly lastInboundAdvance: Uint8Array | null; } export declare const getPqHealingRecordLengths: (suite: Readonly) => { readonly offer: number; readonly advance: number; }; /** * Encode the sole canonical PQ acknowledgement representation: * * `magic(4) | version(1) | type(1) | suite(1) | flags(1) | binding(32) | * advanceCounter(u64 BE) | epoch(u64 BE) | reserved(u64=0)`. */ export declare const encodePqHealingAck: (acknowledgement: unknown, suite: Readonly, binding: Uint8Array) => Uint8Array; /** Decode and validate an exact, edge- and suite-bound 64-byte ACK. */ export declare const decodePqHealingAck: (record: Uint8Array, suite: Readonly, binding: Uint8Array) => PqHealingAdvanceAcknowledgement; /** * Parse a canonical record without changing state. Integration code can use * this for routing and audit logs, but MUST still call the stateful * `acceptAuthenticated*` method only after outer authentication. */ export declare const inspectPqHealingRecord: (record: Uint8Array, suite: Readonly) => PqHealingRecord; /** * One directional-turn PQ healing machine for a single authenticated peer * edge. A room mesh owns one instance per edge; a room-wide policy supplies * the same exact ML-KEM parameter set to every instance. */ export declare class PqHealingMachine

{ #private; constructor(options: PqHealingMachineOptions

); static restore(snapshot: unknown, options: PqHealingRestoreOptions): PqHealingMachine; get suite(): Readonly>; get phase(): PqHealingPhase; get epoch(): bigint; get localCounter(): bigint; get remoteCounter(): bigint; get nextOfferer(): PqHealingTurn; /** * New-epoch messages must not race the control exchange across independent * WebRTC data channels. The integration must hold application traffic while * this is true. */ get trafficBlocked(): boolean; /** Explicit owned copy for the message-key combiner or encrypted checkpoint. */ copyRootKey(): Uint8Array; /** * Deep-copy the complete checkpoint, including pending ML-KEM secret keys. * See `PqHealingSnapshot`: prepared phases are transaction-local snapshots. */ snapshot(): PqHealingSnapshot

; /** Deep-clone this machine into independently owned secret buffers. */ clone(): PqHealingMachine

; /** * Consume an independently authenticated successor. Superseded live secrets * are wiped and `next` becomes destroyed without wiping the moved secrets. */ adopt(next: PqHealingMachine

): void; /** * Return the exact public record that should be sent/retransmitted. A caller * must never reconstruct a replacement after the original may have escaped. */ copyPendingOutboundRecord(): Uint8Array; prepareOffer(): Promise; /** * Mark the persisted OFFER as having possibly escaped to the network. After * this point it cannot be aborted or replaced; only its exact bytes may be * retransmitted. */ markOfferDispatched(): void; /** * Safe only while the caller can prove the OFFER has never been sent. * The pending ML-KEM secret key is wiped. */ abortUnsentOffer(): void; /** * Accept a full OFFER only after the outer AEAD has authenticated it. */ acceptAuthenticatedOffer(record: Uint8Array): void; /** * Prepare an ADVANCE and its candidate root. The caller must outer-encrypt * this exact record under `fromEpoch` before committing, then persist the * committed state and sealed record before sending. */ prepareAdvance(): Promise; /** * Commit the prepared root after the exact ADVANCE has already been sealed * under the old epoch. The returned record is the only record that may be * sent. Application traffic remains blocked until a new-epoch authenticated * acknowledgement is accepted. */ commitPreparedAdvance(): Uint8Array; /** * Close the responder side only after an acknowledgement authenticated under * the new epoch has been received. Exact epoch/counter binding prevents an * unrelated transport receipt from unlocking the next OFFER. */ acceptAuthenticatedAdvanceAcknowledgement(acknowledgement: unknown): void; /** * Accept a full ADVANCE only after its outer AEAD has authenticated it under * the old epoch. */ acceptAuthenticatedAdvance(record: Uint8Array): Promise; /** * Commit a successfully decapsulated ADVANCE. The returned binding must be * carried by an acknowledgement authenticated under the new epoch. Traffic * remains blocked until `markAdvanceAcknowledgementDispatched` is called. */ commitAcceptedAdvance(): PqHealingAdvanceAcknowledgement; /** * Mark the new-epoch acknowledgement as having escaped to the network. * Integration should persist that fact or retain a transport receipt cache * so an exact ADVANCE replay can be answered without rolling state back. */ markAdvanceAcknowledgementDispatched(acknowledgement: unknown): void; /** * Idempotent terminal cleanup. All live roots, candidate roots, and pending * ML-KEM secret keys are wiped. Public record copies may remain with callers. */ destroy(): void; } /** Store-free checkpoint helper with an owned result. */ export declare const snapshotPqHealing:

(machine: PqHealingMachine

) => PqHealingSnapshot

; /** Restore only after validating suite, binding, records, and phase invariants. */ export declare const restorePqHealing:

(snapshot: unknown, options: PqHealingRestoreOptions

) => PqHealingMachine

; /** Deep-clone for mutate/persist/adopt transaction flows. */ export declare const clonePqHealing:

(machine: PqHealingMachine

) => PqHealingMachine

; /** Consume `next` as the independently authenticated successor of `live`. */ export declare const adoptPqHealing:

(live: PqHealingMachine

, next: PqHealingMachine

) => void; /** * Wipe every byte buffer owned by a plaintext checkpoint, including the PQ * root, pending KEM secret key/candidate root, binding, and public records. */ export declare const wipePqHealingSnapshot: (snapshot: PqHealingSnapshot) => void;