/** * ECIES envelopes for encrypted job requests and results. * * Request plaintext is UTF-8 JSON with object keys sorted recursively and * array order preserved. Result bodies use a hybrid streaming envelope: * ECIES wraps a random AES key, nonce prefix, and result metadata, while fixed * chunks of the body are sealed independently with AES-256-GCM. The Request * ciphertext is base64 of `iv || ephemPub || ct || mac`, as specified by the * ECIES provider interface. Result ciphertext is the raw hybrid byte sequence * stored in object storage. The Gateway hashes raw ciphertext bytes, not * plaintext. * The builder verifies the decrypted result's job ID, scope, and version * bindings. The PS worker verifies * `auth.bodyHash === sha256(canonicalJobRequestBytes(request))`; the Gateway * never sees the plaintext. Flow: personal-server-ts * `docs/260903-jobs-contract.md`, section 1. * * @category Cryptography */ import { type Hex } from "viem"; import { type ECIESProvider } from "../ecies/interface.js"; import { type JobRequest, type JobRequestEnvelope, type JobResult } from "../../protocol/jobs.js"; /** Current hybrid sealed-result wire-format version. */ export declare const JOB_RESULT_FORMAT_VERSION = 2; /** Plaintext bytes authenticated independently in each result frame. */ export declare const JOB_RESULT_CHUNK_BYTES: number; /** Result fields authenticated for every encrypted body chunk. */ export type JobResultMetadata = Omit; /** Streaming sealer output. Write the header before transformed body frames. */ export interface SealedJobResultStream { header: Uint8Array; transform: TransformStream; } /** Verified metadata and incrementally decrypted result body. */ export interface OpenedJobResultStream { metadata: JobResultMetadata; body: ReadableStream; } /** Builder-visible bindings checked before any result body chunk is yielded. */ export interface JobResultExpectation { jobId: string; scope?: string; version?: string | null; } /** A job envelope or result did not match the jobs protocol. */ export declare class JobEnvelopeError extends Error { constructor(message: string); } /** * Returns the canonical UTF-8 JSON bytes committed to by the auth body hash. * * @param request - Job request to validate and serialize canonically. * @returns Recursively key-sorted, whitespace-free UTF-8 JSON bytes. * @throws {JobEnvelopeError} If the request does not match the protocol schema. */ export declare function canonicalJobRequestBytes(request: JobRequest): Uint8Array; /** * Encrypts a validated job request envelope for a Personal Server enclave. * * The PS worker verifies * `auth.bodyHash === sha256(canonicalJobRequestBytes(request))`; the Gateway * never sees the plaintext. * * @param envelope - Request and builder Web3Signed authorization to encrypt. * @param enclavePublicKey - Public key returned by `GET /v1/identity?owner=`. * @param ecies - Injected ECIES implementation. * @returns Base64 ciphertext encoded as `iv || ephemPub || ct || mac`. * @throws {JobEnvelopeError} If the envelope or request is invalid. * @throws If ECIES encryption fails or the enclave public key is invalid. * * @example * ```ts * const identity = await fetch(`/v1/identity?owner=${owner}`).then((response) => * response.json(), * ); * const requestCiphertext = await sealJobRequest( * requestEnvelope, * identity.publicKey, * ecies, * ); * await fetch("/v1/jobs", { * method: "POST", * body: JSON.stringify({ ...submission, requestCiphertext }), * }); * ``` */ export declare function sealJobRequest(envelope: JobRequestEnvelope, enclavePublicKey: Hex, ecies: ECIESProvider): Promise; /** * Decrypts and validates a job request envelope inside the enclave. * * @param ciphertext - Base64 `iv || ephemPub || ct || mac` ciphertext. * @param privateKey - Enclave key bytes, supplied as `Uint8Array` so the agent can zero them after use. * @param ecies - Injected ECIES implementation. * @returns The validated request envelope exactly as parsed from plaintext. * @throws {JobEnvelopeError} If plaintext is malformed or fails schema validation. * @throws If ciphertext decoding or ECIES decryption fails. */ export declare function openJobRequest(ciphertext: string, privateKey: Uint8Array, ecies: ECIESProvider): Promise; /** Create a bounded-memory hybrid sealer for a job result body. */ export declare function sealJobResultStream(metadataValue: JobResultMetadata, builderPublicKey: Hex, ecies: ECIESProvider): Promise; /** * Encrypts a validated job result for its builder and describes the ciphertext. * * This compatibility wrapper drives {@link sealJobResultStream} and allocates * the final sealed byte array once. `hash` and `size` retain their Gateway * object-storage semantics. */ export declare function sealJobResult(result: JobResult, builderPublicKey: Hex, ecies: ECIESProvider): Promise<{ bytes: Uint8Array; hash: Hex; size: number; }>; /** Open and authenticate a hybrid job result without buffering its body. */ export declare function openJobResultStream(bytesStream: ReadableStream, builderPrivateKey: Hex, ecies: ECIESProvider, expect: JobResultExpectation): Promise; /** * Decrypts a job result and verifies its builder-visible protocol bindings. * * The builder private key is a `Hex` wallet key. For `expect.version`, * `undefined` skips the check while `null` requires a null result version. * * @param sealedBytes - Raw hybrid sealed-result bytes. * @param builderPrivateKey - Builder's wallet private key as hex. * @param ecies - Injected ECIES implementation. * @param expect - Required job ID and optional scope and version bindings. * @returns The validated result when every supplied binding matches. * @throws {JobEnvelopeError} If plaintext is malformed, invalid, or a binding differs. * @throws If ciphertext decoding or ECIES decryption fails. * * @example * ```ts * const sealedBytes = new Uint8Array(await response.arrayBuffer()); * const result = await openJobResult(sealedBytes, key, ecies, { * jobId, * scope, * }); * const text = new TextDecoder().decode(result.body); * ``` */ export declare function openJobResult(sealedBytes: Uint8Array, builderPrivateKey: Hex, ecies: ECIESProvider, expect: JobResultExpectation): Promise;