/** * T3 — E2EEnvelope wire codec. * * RECONCILIATION: the frozen `relay-contracts` §4.4 surface ALREADY owns the envelope binary * layout and the deterministic per-seq nonce (`encodeEnvelope`/`decodeEnvelope`/`nonceForSeq`, * 14-byte header: seq(8)‖nonceLen(1)‖ciphertextLen(4)‖tagLen(1) then nonce‖ciphertext‖tag). * The plan's stale T3 byte layout (envVersion/aeadId) is SUPERSEDED — relay-contracts owns the * shape (INDEX §2.1), so P4 CONSUMES/RE-EXPORTS it and never redefines it. This module only adds * a boundary guard that re-throws the contract's decode error as a P4-typed `EnvelopeFormatError` * and enforces a hard frame-size cap (anti-overrun; the alg is carried by the key/session, not the * wire, so there is no unchecked wire-length allocation). */ import type { E2EEnvelope } from 'relay-contracts' import { ContractDecodeError, decodeEnvelope as decodeEnvelopeRaw, encodeEnvelope as encodeEnvelopeRaw, nonceForSeq, } from 'relay-contracts' import { EnvelopeFormatError } from './errors.js' /** Hard upper bound on a decoded frame (guards a decompression-bomb-style length overrun). */ export const MAX_FRAME_BYTES = 4 * 1024 * 1024 export { nonceForSeq } /** Encode a §4.4 E2EEnvelope to its frozen wire bytes (delegates to relay-contracts). */ export function encodeEnvelope(env: E2EEnvelope): Uint8Array { const bytes = encodeEnvelopeRaw(env) if (bytes.length > MAX_FRAME_BYTES) { throw new EnvelopeFormatError(`encoded frame ${bytes.length} exceeds cap ${MAX_FRAME_BYTES}`) } return bytes } /** Decode wire bytes into a §4.4 E2EEnvelope; malformed input ⇒ typed `EnvelopeFormatError`. */ export function decodeEnvelope(buf: Uint8Array): E2EEnvelope { if (buf.length > MAX_FRAME_BYTES) { throw new EnvelopeFormatError(`frame ${buf.length} exceeds cap ${MAX_FRAME_BYTES}`) } try { return decodeEnvelopeRaw(buf) } catch (err) { if (err instanceof ContractDecodeError) { throw new EnvelopeFormatError(err.message) } throw err } }