OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / packages / blind-ipc / private-ipc-v2-contract.js

1156 lines · javascript ref:
import b4a from 'b4a'
import {
  blindErrorV1,
  blindReceiptV1,
  decodeCanonical,
  encodeCanonical,
  putCellV1
} from '@hiverelay/blind-protocol'
import {
  FAMILY,
  FRAME_KIND,
  OPERATION,
  OUTER_CLASS,
  STREAM_WIRE_CLASS,
  TRANSPORT_ID,
  TRANSPORT_SUPPORT,
  operationBit,
  operationProfile
} from '@hiverelay/blind-protocol/wire-runtime-authority'
import { ENDPOINT_ROLE } from '@hiverelay/blind-protocol/registry'
import { decodeOuterEnvelope } from '@hiverelay/blind-protocol/outer-envelope'
import { privateBlake2b256 } from './private-hashes.js'
import {
  PRIVATE_IPC_SCHEMAS,
  privateIpcRegistryEncoding,
  privateIpcRegistryValue
} from './registry.js'
import { LOCAL_ABORT_CODE } from './policy.js'

const FORMAT_DOMAIN = b4a.from('hiverelay.blind.private-ipc-format-hash.v2', 'ascii')
const VECTOR_DOMAIN = b4a.from('hiverelay.blind.private-ipc-vector-set-hash.v2', 'ascii')
const TLS_EXPORTER_CONTEXT_DOMAIN = b4a.from('hiverelay.blind.tls-exporter-context.v2', 'ascii')
const PUBLIC_SESSION_BINDING_DOMAIN = b4a.from('hiverelay.blind.public-session-binding.v2', 'ascii')
const LOCAL_OPEN_BINDING_DOMAIN = b4a.from('hiverelay.blind.local-staged-open-binding.v2', 'ascii')
const REPLAY_TUPLE_DOMAIN = b4a.from('hiverelay.blind.local-staged-replay-tuple.v2', 'ascii')
const MAX_U64 = (1n << 64n) - 1n
const MAX_PRIVATE_IPC_REGISTRY_BYTES = 1024 * 1024

export const PRIVATE_IPC_V2_MAGIC = 'hiverelay-blind-private-ipc-v2'
export const PRIVATE_IPC_V2_FORMAT_VERSION = 2
export const TLS_EXPORTER_LABEL_V2 = 'EXPORTER-HiveRelay-Blind-Staged-Cell-Put-v2'

export const LOCAL_TRANSPORT_AUTHORITY_KIND_V2 = Object.freeze({
  TLS_EXPORTER_BY_PEERCRED_EDGE: 1,
  NOISE_TRANSCRIPT_BY_PEERCRED_EDGE: 2
})

export const LOCAL_STAGED_REQUEST_KIND_V2 = Object.freeze({
  STAGED_CELL_PUT_OUTER_ENVELOPE_V1: 1
})

export const LOCAL_STAGED_RESULT_KIND_V2 = Object.freeze({
  CELL_PUT_OUTER_RESULT_ENVELOPE_V1: 1
})

export const LOCAL_IPC_CHANNEL_CLASS_V2 = Object.freeze({ LOCAL_64K: 1 })
export const LOCAL_STAGED_DIRECTION_V2 = Object.freeze({ REQUEST: 1, RESULT: 2 })
export const LOCAL_STAGED_FRAME_KIND_V2 = Object.freeze({ CONTENT: 1, ABORT: 2 })
export const LOCAL_STAGED_FLAG_V2 = Object.freeze({ FIN: 0x01 })
export const LOCAL_READY_CONTROL_KIND_V2 = Object.freeze({ PROBE: 1, ACK: 2 })

export const LOCAL_IPC_FEATURE_V2 = Object.freeze({
  STAGED_CELL_PUT: 0x01,
  FULL_OUTER_ENVELOPE: 0x02,
  PEERCRED_EDGE_AUTHORITY: 0x04,
  TLS_EXPORTER_BINDING: 0x08,
  PRECOMMIT_OUTER_CLASS_AUTHORITY: 0x10,
  OUTER_RESULT_ENVELOPE: 0x20
})

export const REQUIRED_LOCAL_IPC_FEATURE_BITS_V2 = Object.values(LOCAL_IPC_FEATURE_V2)
  .reduce((mask, bit) => mask | bit, 0)
export const CELL_PUT_OPERATION_BIT_V2 = operationBit(FAMILY.CELL, OPERATION.CELL.PUT)
export const CELL_PUT_ENDPOINT_ROLE_BIT_V2 = ENDPOINT_ROLE.STORAGE

if (CELL_PUT_OPERATION_BIT_V2 === 0) throw new Error('generated CELL.PUT operation bit is absent')

const cellPutProfile = operationProfile(FAMILY.CELL, OPERATION.CELL.PUT)
if (!cellPutProfile) throw new Error('generated CELL.PUT operation profile is absent')

export const PRIVATE_IPC_V2_LIMITS = Object.freeze({
  TRANSPORT_BINDING_BYTES: 162,
  STAGED_OPEN_HEADER_BYTES: 38,
  STAGED_OPEN_BYTES: 200,
  STAGED_FRAME_HEADER_BYTES: 20,
  LOCAL_FRAME_BYTES: 65_535,
  LOCAL_FRAME_CONTENT_BYTES: 65_515,
  READY_PROBE_BYTES: 95,
  READY_ACK_BYTES: 133,
  OPEN_DEADLINE_MILLIS: 15_000,
  READY_DEADLINE_MILLIS: 2_000,
  TLS_EXPORTER_BYTES: 32,
  TLS_EXPORTER_CONTEXT_BYTES: 32,
  PUBLIC_SESSION_BINDING_HASH_BYTES: 32,
  OUTER_HEADER_BYTES: 6,
  DISPATCH_HEADER_BYTES: 45,
  CELL_PUT_MAX_RESULT_BODY_BYTES: cellPutProfile.maxResultBodyBytes,
  CELL_PUT_WORST_CASE_RESULT_ENVELOPE_BYTES: 6 + 45 + cellPutProfile.maxResultBodyBytes,
  CELL_PUT_WORST_CASE_MINIMUM_OUTER_CLASS: 3
})

export const PRIVATE_IPC_V2_REPLAY_POLICY = Object.freeze({
  capacity: 4096,
  acceptedRecordMaximumTtlMillis: 15_000,
  freshEntryExpiry: 'exact-open-deadline',
  recoveredEntryMinimumRetentionMillis: 15_000,
  recoveredRetentionBasis: 'conservative-startup-fence-not-accepted-record-ttl',
  startupWriteQuarantineMillis: 15_000,
  quarantineReadyAck: 'suppress-or-refuse',
  quarantineReadinessBrand: 'withheld',
  quarantineZeroWriteBitsAckPermitted: false,
  liveEntryEvictionPermitted: false,
  authorityKind: 'module-private-branded-journal-and-one-use-consume-receipt'
})

export const PRIVATE_IPC_V2_STAGED_CELL_PUT_POLICY = Object.freeze({
  initialOuterClasses: Object.freeze([3, 4, 5, 6]),
  initialMinimumOuterClass: 3,
  resultSizingAuthority: 'fixed-generated-worst-case-only',
  fixedMaximumResultBodyBytes: PRIVATE_IPC_V2_LIMITS.CELL_PUT_MAX_RESULT_BODY_BYTES,
  fixedRequiredResultEnvelopeBytes: PRIVATE_IPC_V2_LIMITS.CELL_PUT_WORST_CASE_RESULT_ENVELOPE_BYTES,
  minimumReadyDescriptorSequence: 1,
  atomicCommitRecordKind: 'PUT_ATOMIC_COMMITTED',
  v2EmitsLegacyReservationWal: false,
  legacyReservationWalRecoveryCompatible: true,
  preEofAdmission: 'owned-prefix-side-effect-free-branded-preflight-only',
  preEofStorage: 'reversible-ephemeral-staging-only',
  cancellationFence: 'under-canonical-locks-immediately-before-non-cancellable-publish-and-commit-unit',
  nonCancellableCommitUnit: 'publish-through-put-atomic-committed-fsync-and-apply',
  walPrewriteFence: 'internal-writer-and-commit-invariants-only-never-caller-cancellation',
  publicResultRequires: 'exact-outer-plus-request-fin-plus-edge-write-half-close-plus-daemon-observed-authenticated-peer-eof-plus-canonical-revalidation',
  requestCompletion: Object.freeze({
    sequence: Object.freeze([
      'exact-outer-request-fin',
      'edge-write-half-close',
      'daemon-observed-authenticated-peer-eof',
      'canonical-post-eof-revalidation'
    ]),
    edgeResponseHalfReadableUntilTerminal: true,
    daemonEofAuthority: 'module-private-same-native-peercred-authenticated-stream-eof-after-request-fin',
    callerEofAssertionPermitted: false,
    frameVerifierMintsEofAuthority: false,
    commitBeforeDaemonObservedEofPermitted: false,
    negativeSemantics: Object.freeze({
      eofBeforeFin: 'generic-local-abort-no-public-error-no-commit',
      finWithoutEof: 'caller-cancellation-or-deadline-then-generic-local-abort-no-public-error-no-commit',
      requestDataAfterFin: 'generic-local-abort-no-public-error-no-commit',
      resultBeforeDaemonObservedEof: 'forbidden-runtime-conformance-failure',
      responseHalfClosedBeforeTerminal: 'caller-cancelled-pre-boundary-discards-post-boundary-commit-completes-without-result'
    })
  })
})

if (PRIVATE_IPC_V2_LIMITS.CELL_PUT_WORST_CASE_RESULT_ENVELOPE_BYTES !== 16_435 ||
    OUTER_CLASS[2] !== 16_384 || OUTER_CLASS[3] !== 65_536) {
  throw new Error('generated CELL.PUT response-fit authority changed')
}

export const PRIVATE_IPC_V2_ADDITIONAL_SCHEMAS = Object.freeze([
  Object.freeze({
    schemaId: 8,
    schemaName: 'LocalTransportBindingV2',
    fields: Object.freeze([
      'version:u8=2', 'authorityKind:u8[1..2]',
      'edgeProcessNonce:fixed32[nonzero]', 'localChannelNonce:fixed32[nonzero]',
      'transportProfileHash:fixed32[nonzero]', 'publicSessionBindingHash:fixed32[nonzero]',
      'openBindingHash:fixed32[nonzero]', 'exactBytes:162',
      'contract-validation:non-authoritative-binding-only',
      'runtime-authority:native-peercred-plus-validated-binding-outside-contract',
      'tls-or-noise-binding:session-material-not-independent-edge-proof'
    ])
  }),
  Object.freeze({
    schemaId: 9,
    schemaName: 'LocalStagedCellPutOpenV2',
    fields: Object.freeze([
      'totalLength:u32be=196', 'version:u8=2',
      'requestKind:u8=STAGED_CELL_PUT_OUTER_ENVELOPE_V1',
      'resultKind:u8=CELL_PUT_OUTER_RESULT_ENVELOPE_V1',
      'authorityKind:u8=TLS_EXPORTER_BY_PEERCRED_EDGE',
      'transportId:u8=HTTPS_DIRECT', 'transportSupportBit:u16be=DIRECT_HTTP',
      'endpointId:u8[1..255]', 'outerClass:u8[1..6]',
      'initial-CELL.PUT-policy:outerClass-u8[3..6]',
      'result-sizing:fixed-generated-worst-case-16435-bytes',
      'ipcChannelClass:u8=LOCAL_64K', 'acceptedMonotonicMillis:u64be',
      'openDeadlineMonotonicMillis:u64be[accepted+1..15000]',
      'requestEnvelopeBytes:u32be=OUTER_CLASS[outerClass]',
      'contextLength:u32be=162', 'context:LocalTransportBindingV2',
      'request-envelope:exact-REQUEST-CELL.PUT-full-BlindOuterEnvelopeV1',
      'result-envelope:same-class-correlated-RESPONSE-or-ERROR',
      'exactHeaderBytesIncludingPrefix:38', 'exactBytes:200'
    ])
  }),
  Object.freeze({
    schemaId: 10,
    schemaName: 'LocalStagedCellPutFrameV2',
    fields: Object.freeze([
      'totalLength:u32be=16+bodyLength', 'version:u8=2',
      'direction:u8[1-request|2-result]', 'frameKind:u8[1-content|2-abort]',
      'sequence:u64be[first0-exact+1-per-direction]', 'flags:u8[FIN-only]',
      'bodyLength:u32be[0..65515]', 'bytes:bytes[bodyLength]',
      'CONTENT:1..65515|zero-only-with-FIN',
      'ABORT:flags0|exactly-one-registered-generic-abort-code-byte',
      'request-direction:full-REQUEST-CELL.PUT-outer-envelope',
      'result-direction:same-class-correlated-RESPONSE-or-ERROR-outer-envelope',
      'exactHeaderBytesIncludingPrefix:20'
    ])
  }),
  Object.freeze({
    schemaId: 11,
    schemaName: 'LocalReadyProbeV2',
    fields: Object.freeze([
      'totalLength:u32be=91', 'version:u8=2', 'controlKind:u8=PROBE',
      'endpointId:u8[1..255]', 'edgeProcessNonce:fixed32[nonzero]',
      'launchTopologyHash:fixed32[nonzero]', 'edgeFeatureBits:u32be=required-v2-mask',
      'requestedWriteOperationBits:u32be=CELL.PUT-bit',
      'acceptedMonotonicMillis:u64be',
      'absoluteDeadlineMonotonicMillis:u64be=accepted+2000', 'exactBytes:95'
    ])
  }),
  Object.freeze({
    schemaId: 12,
    schemaName: 'LocalReadyAckV2',
    fields: Object.freeze([
      'totalLength:u32be=129', 'version:u8=2', 'controlKind:u8=ACK',
      'endpointId:u8[1..255]', 'edgeProcessNonce:fixed32[nonzero]',
      'launchTopologyHash:fixed32[nonzero]', 'descriptorSequence:u64be[nonzero]',
      'descriptorHash:fixed32[nonzero]', 'readyRoleBits:u16be[descriptor-subset]',
      'readyOperationBits:u32be[descriptor-subset]',
      'readyWriteOperationBits:u32be=CELL.PUT-bit-and-readyOperationBits-subset',
      'readyIpcFeatureBits:u32be=required-v2-mask',
      'expiresMonotonicMillis:u64be[descriptor-and-probe-freshness]', 'exactBytes:133'
    ])
  })
])

export const PRIVATE_IPC_V2_SCHEMAS = Object.freeze([
  ...PRIVATE_IPC_SCHEMAS,
  ...PRIVATE_IPC_V2_ADDITIONAL_SCHEMAS
])

export const PRIVATE_IPC_V2_TRANSPORT_BINDING_RULES = Object.freeze({
  [TRANSPORT_ID.HTTPS_DIRECT]: Object.freeze({
    transportSupportBit: TRANSPORT_SUPPORT.DIRECT_HTTP,
    authorityKind: LOCAL_TRANSPORT_AUTHORITY_KIND_V2.TLS_EXPORTER_BY_PEERCRED_EDGE,
    sessionBinding: 'tls-exporter-32',
    peerCredentialRequired: true
  }),
  [TRANSPORT_ID.DIRECT_PROTOMUX_NOISE]: Object.freeze({
    transportSupportBit: TRANSPORT_SUPPORT.DIRECT_NATIVE,
    authorityKind: LOCAL_TRANSPORT_AUTHORITY_KIND_V2.NOISE_TRANSCRIPT_BY_PEERCRED_EDGE,
    sessionBinding: 'noise-final-transcript-hash-32',
    peerCredentialRequired: true
  })
})

function fail (message, code = 'BAD_PRIVATE_IPC_V2_CONTRACT') {
  const error = new Error(message)
  error.code = code
  throw error
}

function asBuffer (value, field) {
  if (!value || typeof value.byteLength !== 'number') fail(`${field} must be bytes`)
  if (b4a.isBuffer(value)) return value
  if (ArrayBuffer.isView(value)) return b4a.from(value.buffer, value.byteOffset, value.byteLength)
  return b4a.from(value)
}

function snapshot (value, field) {
  return b4a.from(asBuffer(value, field))
}

function isZero (bytes) {
  for (const byte of bytes) if (byte !== 0) return false
  return true
}

function fixed (value, length, field, nonzero = true) {
  const bytes = snapshot(value, field)
  if (bytes.byteLength !== length) fail(`${field} must be exactly ${length} bytes`)
  if (nonzero && isZero(bytes)) fail(`${field} must be nonzero`)
  return bytes
}

function u8 (value, field, minimum = 0, maximum = 0xff) {
  if (!Number.isInteger(value) || value < minimum || value > maximum) fail(`${field} is outside ${minimum}..${maximum}`)
  return value
}

function u16 (value, field) {
  if (!Number.isInteger(value) || value < 0 || value > 0xffff) fail(`${field} is outside u16`)
  return value
}

function u32 (value, field) {
  if (!Number.isInteger(value) || value < 0 || value > 0xffffffff) fail(`${field} is outside u32`)
  return value
}

function u64 (value, field, nonzero = false) {
  if (typeof value === 'number') {
    if (!Number.isSafeInteger(value) || value < 0) fail(`${field} must be an unsigned safe integer or bigint`)
    value = BigInt(value)
  }
  if (typeof value !== 'bigint' || value < 0n || value > MAX_U64 || (nonzero && value === 0n)) {
    fail(`${field} is outside ${nonzero ? 'nonzero ' : ''}u64`)
  }
  return value
}

function writeU16 (output, value, offset) {
  value = u16(value, 'u16')
  output[offset] = value >>> 8
  output[offset + 1] = value & 0xff
}

function readU16 (input, offset) {
  return input[offset] * 0x100 + input[offset + 1]
}

function writeU64 (output, value, offset) {
  value = u64(value, 'u64')
  for (let index = 7; index >= 0; index--) {
    output[offset + index] = Number(value & 0xffn)
    value >>= 8n
  }
}

function readU64 (input, offset) {
  let value = 0n
  for (let index = 0; index < 8; index++) value = (value << 8n) | BigInt(input[offset + index])
  return value
}

function u64Bytes (value) {
  const output = b4a.alloc(8)
  writeU64(output, value, 0)
  return output
}

function len64 (length) {
  return u64Bytes(BigInt(length))
}

function exactFrame (input, exactBytes, field) {
  const bytes = snapshot(input, field)
  if (bytes.byteLength !== exactBytes) fail(`${field} must be exactly ${exactBytes} bytes`)
  if (b4a.readUInt32BE(bytes, 0) !== exactBytes - 4) fail(`${field} totalLength is not exact`)
  return bytes
}

function fixedDeclaredLength (input, exactBytes, headerBytes, field, controlKind = null) {
  const bytes = snapshot(input, field)
  if (bytes.byteLength < 4) return null
  if (b4a.readUInt32BE(bytes, 0) !== exactBytes - 4) fail(`${field} has an impossible declared length`)
  if (bytes.byteLength < 5) return null
  if (bytes[4] !== 2) fail(`${field} is not version 2`, 'PRIVATE_IPC_V2_NO_FALLBACK')
  if (bytes.byteLength < headerBytes) return null
  if (controlKind !== null && bytes[5] !== controlKind) fail(`${field} has the wrong control kind`)
  return exactBytes
}

function declaredFrame (input, minimumBytes, maximumBytes, field) {
  const bytes = snapshot(input, field)
  if (bytes.byteLength < minimumBytes || bytes.byteLength > maximumBytes) {
    fail(`${field} is outside its complete-frame bound`)
  }
  if (b4a.readUInt32BE(bytes, 0) !== bytes.byteLength - 4) fail(`${field} totalLength is not exact`)
  return bytes
}

function exactEnum (values, value, field) {
  if (!Object.values(values).includes(value)) fail(`${field} is not registered`)
  return value
}

function enumBindings (name, values) {
  return {
    name,
    entries: Object.entries(values)
      .map(([entryName, raw]) => ({ name: entryName, id: Number(raw), value: Number(raw) }))
      .sort((left, right) => left.id - right.id || (left.name < right.name ? -1 : left.name > right.name ? 1 : 0))
  }
}

function namedBindings (name, values) {
  return {
    name,
    entries: Object.entries(values)
      .sort(([left], [right]) => left < right ? -1 : left > right ? 1 : 0)
      .map(([entryName, value], index) => ({ name: entryName, id: index + 1, value: Number(value) }))
  }
}

function encodeCompact (encoding, value) {
  const state = { start: 0, end: 0, buffer: null }
  encoding.preencode(state, value)
  state.buffer = b4a.alloc(state.end)
  state.start = 0
  encoding.encode(state, value)
  return state.buffer
}

function decodeCompact (encoding, input, field) {
  const bytes = snapshot(input, field)
  if (bytes.byteLength < 1 || bytes.byteLength > MAX_PRIVATE_IPC_REGISTRY_BYTES) fail(`${field} is outside its byte bound`)
  const state = { start: 0, end: bytes.byteLength, buffer: bytes }
  let value
  try {
    value = encoding.decode(state)
  } catch {
    fail(`${field} is truncated or malformed`)
  }
  if (state.start !== state.end) fail(`${field} has trailing bytes`)
  if (!b4a.equals(encodeCompact(encoding, value), bytes)) fail(`${field} is not canonical`)
  return { bytes, value }
}

export function privateIpcV2RegistryValue (wireAbiBytes) {
  const v1 = privateIpcRegistryValue(asBuffer(wireAbiBytes, 'public WIRE ABI'))
  return {
    magic: PRIVATE_IPC_V2_MAGIC,
    formatVersion: PRIVATE_IPC_V2_FORMAT_VERSION,
    wireAbiHash: b4a.from(v1.wireAbiHash),
    schemas: PRIVATE_IPC_V2_SCHEMAS,
    importedWireBindings: [
      ...v1.importedWireBindings,
      enumBindings('FRAME_KIND', FRAME_KIND),
      enumBindings('OPERATION_CELL', OPERATION.CELL)
    ],
    localBindings: [
      ...v1.localBindings,
      enumBindings('v2TransportAuthorityKind', LOCAL_TRANSPORT_AUTHORITY_KIND_V2),
      enumBindings('v2RequestKind', LOCAL_STAGED_REQUEST_KIND_V2),
      enumBindings('v2ResultKind', LOCAL_STAGED_RESULT_KIND_V2),
      enumBindings('v2IpcChannelClass', LOCAL_IPC_CHANNEL_CLASS_V2),
      enumBindings('v2Direction', LOCAL_STAGED_DIRECTION_V2),
      enumBindings('v2FrameKind', LOCAL_STAGED_FRAME_KIND_V2),
      enumBindings('v2Flag', LOCAL_STAGED_FLAG_V2),
      enumBindings('v2ReadyControlKind', LOCAL_READY_CONTROL_KIND_V2),
      enumBindings('v2IpcFeature', LOCAL_IPC_FEATURE_V2),
      namedBindings('v2CellPutAuthority', {
        CELL_PUT_FAMILY_ID: FAMILY.CELL,
        CELL_PUT_OPERATION_ID: OPERATION.CELL.PUT,
        CELL_PUT_OPERATION_BIT: CELL_PUT_OPERATION_BIT_V2,
        CELL_PUT_REQUEST_FRAME_KIND: FRAME_KIND.REQUEST,
        CELL_PUT_RESPONSE_FRAME_KIND: FRAME_KIND.RESPONSE,
        CELL_PUT_ERROR_FRAME_KIND: FRAME_KIND.ERROR,
        STORAGE_ROLE_BIT: CELL_PUT_ENDPOINT_ROLE_BIT_V2
      }),
      namedBindings('v2Limits', PRIVATE_IPC_V2_LIMITS),
      namedBindings('v2RequiredBits', { REQUIRED_IPC_FEATURE_BITS: REQUIRED_LOCAL_IPC_FEATURE_BITS_V2 }),
      namedBindings('v2HttpsTransport', {
        AUTHORITY_KIND: LOCAL_TRANSPORT_AUTHORITY_KIND_V2.TLS_EXPORTER_BY_PEERCRED_EDGE,
        TRANSPORT_ID: TRANSPORT_ID.HTTPS_DIRECT,
        TRANSPORT_SUPPORT_BIT: TRANSPORT_SUPPORT.DIRECT_HTTP
      })
    ]
  }
}

export function encodePrivateIpcV2Registry (wireAbiBytes) {
  return encodeCompact(privateIpcRegistryEncoding, privateIpcV2RegistryValue(wireAbiBytes))
}

export function decodePrivateIpcV2Registry (input) {
  const decoded = decodeCompact(privateIpcRegistryEncoding, input, 'private IPC v2 registry')
  if (decoded.value.magic !== PRIVATE_IPC_V2_MAGIC || decoded.value.formatVersion !== PRIVATE_IPC_V2_FORMAT_VERSION) {
    fail('private IPC v2 registry has the wrong magic or version', 'PRIVATE_IPC_V2_NO_FALLBACK')
  }
  return decoded.value
}

export function verifyPrivateIpcV2Registry (input, wireAbiBytes) {
  const bytes = snapshot(input, 'private IPC v2 registry')
  decodePrivateIpcV2Registry(bytes)
  const expected = encodePrivateIpcV2Registry(asBuffer(wireAbiBytes, 'public WIRE ABI'))
  if (!b4a.equals(bytes, expected)) fail('private IPC v2 registry does not equal the exact V1-plus-V2 authority')
  return decodePrivateIpcV2Registry(bytes)
}

export function hashPrivateIpcV2Registry (input) {
  const bytes = snapshot(input, 'private IPC v2 registry')
  return privateBlake2b256(b4a.concat([FORMAT_DOMAIN, len64(bytes.byteLength), bytes]))
}

export function hashPrivateIpcV2VectorManifest (input) {
  const bytes = snapshot(input, 'private IPC v2 vector manifest')
  return privateBlake2b256(b4a.concat([VECTOR_DOMAIN, len64(bytes.byteLength), bytes]))
}

function normalizedOpenFields (input) {
  if (!input || typeof input !== 'object') fail('staged CELL.PUT open must be an object')
  const accepted = u64(input.acceptedMonotonicMillis, 'acceptedMonotonicMillis')
  const deadline = u64(input.openDeadlineMonotonicMillis, 'openDeadlineMonotonicMillis')
  if (deadline <= accepted || deadline - accepted > BigInt(PRIVATE_IPC_V2_LIMITS.OPEN_DEADLINE_MILLIS)) {
    fail('staged CELL.PUT open deadline is inverted or exceeds 15000 ms')
  }
  const outerClass = u8(input.outerClass, 'outerClass', 1, 6)
  const value = {
    version: 2,
    requestKind: input.requestKind == null
      ? LOCAL_STAGED_REQUEST_KIND_V2.STAGED_CELL_PUT_OUTER_ENVELOPE_V1
      : exactEnum(LOCAL_STAGED_REQUEST_KIND_V2, input.requestKind, 'requestKind'),
    resultKind: input.resultKind == null
      ? LOCAL_STAGED_RESULT_KIND_V2.CELL_PUT_OUTER_RESULT_ENVELOPE_V1
      : exactEnum(LOCAL_STAGED_RESULT_KIND_V2, input.resultKind, 'resultKind'),
    authorityKind: input.authorityKind == null
      ? LOCAL_TRANSPORT_AUTHORITY_KIND_V2.TLS_EXPORTER_BY_PEERCRED_EDGE
      : exactEnum(LOCAL_TRANSPORT_AUTHORITY_KIND_V2, input.authorityKind, 'authorityKind'),
    transportId: input.transportId == null ? TRANSPORT_ID.HTTPS_DIRECT : u8(input.transportId, 'transportId'),
    transportSupportBit: input.transportSupportBit == null
      ? TRANSPORT_SUPPORT.DIRECT_HTTP
      : u16(input.transportSupportBit, 'transportSupportBit'),
    endpointId: u8(input.endpointId, 'endpointId', 1, 0xff),
    outerClass,
    ipcChannelClass: input.ipcChannelClass == null
      ? LOCAL_IPC_CHANNEL_CLASS_V2.LOCAL_64K
      : exactEnum(LOCAL_IPC_CHANNEL_CLASS_V2, input.ipcChannelClass, 'ipcChannelClass'),
    acceptedMonotonicMillis: accepted,
    openDeadlineMonotonicMillis: deadline,
    requestEnvelopeBytes: input.requestEnvelopeBytes == null
      ? OUTER_CLASS[outerClass]
      : u32(input.requestEnvelopeBytes, 'requestEnvelopeBytes'),
    contextLength: PRIVATE_IPC_V2_LIMITS.TRANSPORT_BINDING_BYTES
  }
  if (value.authorityKind !== LOCAL_TRANSPORT_AUTHORITY_KIND_V2.TLS_EXPORTER_BY_PEERCRED_EDGE ||
      value.transportId !== TRANSPORT_ID.HTTPS_DIRECT ||
      value.transportSupportBit !== TRANSPORT_SUPPORT.DIRECT_HTTP) {
    fail('HTTPS staged CELL.PUT accepts only HTTPS_DIRECT/DIRECT_HTTP with the TLS-exporter edge-attestation kind')
  }
  if (value.requestEnvelopeBytes !== OUTER_CLASS[outerClass]) fail('requestEnvelopeBytes must equal the exact selected public outer class')
  return value
}

export function encodeLocalStagedCellPutOpenFieldsV2 (input) {
  const value = normalizedOpenFields(input)
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_HEADER_BYTES - 4)
  output[0] = 2
  output[1] = value.requestKind
  output[2] = value.resultKind
  output[3] = value.authorityKind
  output[4] = value.transportId
  writeU16(output, value.transportSupportBit, 5)
  output[7] = value.endpointId
  output[8] = value.outerClass
  output[9] = value.ipcChannelClass
  writeU64(output, value.acceptedMonotonicMillis, 10)
  writeU64(output, value.openDeadlineMonotonicMillis, 18)
  b4a.writeUInt32BE(output, value.requestEnvelopeBytes, 26)
  b4a.writeUInt32BE(output, value.contextLength, 30)
  return output
}

export function encodeLocalTransportBindingV2 (input) {
  if (!input || typeof input !== 'object') fail('local transport binding must be an object')
  const authorityKind = exactEnum(LOCAL_TRANSPORT_AUTHORITY_KIND_V2, input.authorityKind, 'authorityKind')
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.TRANSPORT_BINDING_BYTES)
  output[0] = 2
  output[1] = authorityKind
  b4a.copy(fixed(input.edgeProcessNonce, 32, 'edgeProcessNonce'), output, 2)
  b4a.copy(fixed(input.localChannelNonce, 32, 'localChannelNonce'), output, 34)
  b4a.copy(fixed(input.transportProfileHash, 32, 'transportProfileHash'), output, 66)
  b4a.copy(fixed(input.publicSessionBindingHash, 32, 'publicSessionBindingHash'), output, 98)
  b4a.copy(fixed(input.openBindingHash, 32, 'openBindingHash'), output, 130)
  return output
}

export function decodeLocalTransportBindingV2 (input) {
  const bytes = snapshot(input, 'local transport binding v2')
  if (bytes.byteLength !== PRIVATE_IPC_V2_LIMITS.TRANSPORT_BINDING_BYTES || bytes[0] !== 2) {
    fail('local transport binding v2 has an invalid exact shape', 'PRIVATE_IPC_V2_NO_FALLBACK')
  }
  const value = {
    version: 2,
    authorityKind: exactEnum(LOCAL_TRANSPORT_AUTHORITY_KIND_V2, bytes[1], 'authorityKind'),
    edgeProcessNonce: fixed(bytes.subarray(2, 34), 32, 'edgeProcessNonce'),
    localChannelNonce: fixed(bytes.subarray(34, 66), 32, 'localChannelNonce'),
    transportProfileHash: fixed(bytes.subarray(66, 98), 32, 'transportProfileHash'),
    publicSessionBindingHash: fixed(bytes.subarray(98, 130), 32, 'publicSessionBindingHash'),
    openBindingHash: fixed(bytes.subarray(130, 162), 32, 'openBindingHash')
  }
  return Object.freeze(value)
}

export function deriveTlsExporterContextHashV2 (input) {
  const fields = encodeLocalStagedCellPutOpenFieldsV2(input.open)
  return privateBlake2b256(b4a.concat([
    TLS_EXPORTER_CONTEXT_DOMAIN,
    fixed(input.launchTopologyHash, 32, 'launchTopologyHash'),
    fields,
    fixed(input.edgeProcessNonce, 32, 'edgeProcessNonce'),
    fixed(input.localChannelNonce, 32, 'localChannelNonce')
  ]))
}

export function derivePublicSessionBindingHashV2 (input) {
  const authorityKind = exactEnum(LOCAL_TRANSPORT_AUTHORITY_KIND_V2, input.authorityKind, 'authorityKind')
  return privateBlake2b256(b4a.concat([
    PUBLIC_SESSION_BINDING_DOMAIN,
    b4a.from([authorityKind]),
    fixed(input.transportProfileHash, 32, 'transportProfileHash'),
    fixed(input.exporterContextHash, 32, 'exporterContextHash'),
    fixed(input.sessionBindingMaterial, 32, 'sessionBindingMaterial')
  ]))
}

export function deriveLocalStagedOpenBindingHashV2 (input) {
  const fields = encodeLocalStagedCellPutOpenFieldsV2(input.open)
  const authorityKind = exactEnum(LOCAL_TRANSPORT_AUTHORITY_KIND_V2, input.authorityKind, 'authorityKind')
  return privateBlake2b256(b4a.concat([
    LOCAL_OPEN_BINDING_DOMAIN,
    fixed(input.launchTopologyHash, 32, 'launchTopologyHash'),
    fields,
    b4a.from([authorityKind]),
    fixed(input.edgeProcessNonce, 32, 'edgeProcessNonce'),
    fixed(input.localChannelNonce, 32, 'localChannelNonce'),
    fixed(input.transportProfileHash, 32, 'transportProfileHash'),
    fixed(input.publicSessionBindingHash, 32, 'publicSessionBindingHash')
  ]))
}

export function encodeLocalStagedCellPutOpenV2 (input) {
  const fields = encodeLocalStagedCellPutOpenFieldsV2(input)
  const context = encodeLocalTransportBindingV2(input.context)
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_BYTES)
  b4a.writeUInt32BE(output, output.byteLength - 4, 0)
  b4a.copy(fields, output, 4)
  b4a.copy(context, output, PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_HEADER_BYTES)
  return output
}

export function readLocalStagedCellPutOpenLengthV2 (input) {
  const bytes = snapshot(input, 'local staged CELL.PUT open v2 prefix/header')
  const length = fixedDeclaredLength(bytes, PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_BYTES,
    PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_HEADER_BYTES, 'local staged CELL.PUT open v2 prefix/header')
  if (length === null) return null
  const raw = {
    requestKind: bytes[5],
    resultKind: bytes[6],
    authorityKind: bytes[7],
    transportId: bytes[8],
    transportSupportBit: readU16(bytes, 9),
    endpointId: bytes[11],
    outerClass: bytes[12],
    ipcChannelClass: bytes[13],
    acceptedMonotonicMillis: readU64(bytes, 14),
    openDeadlineMonotonicMillis: readU64(bytes, 22),
    requestEnvelopeBytes: b4a.readUInt32BE(bytes, 30)
  }
  normalizedOpenFields(raw)
  if (b4a.readUInt32BE(bytes, 34) !== PRIVATE_IPC_V2_LIMITS.TRANSPORT_BINDING_BYTES) {
    fail('local staged CELL.PUT open contextLength is not exact')
  }
  return length
}

export function decodeLocalStagedCellPutOpenV2 (input) {
  readLocalStagedCellPutOpenLengthV2(input)
  const bytes = exactFrame(input, PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_BYTES, 'local staged CELL.PUT open v2')
  if (bytes[4] !== 2) fail('local staged CELL.PUT open is not version 2', 'PRIVATE_IPC_V2_NO_FALLBACK')
  const raw = {
    requestKind: bytes[5],
    resultKind: bytes[6],
    authorityKind: bytes[7],
    transportId: bytes[8],
    transportSupportBit: readU16(bytes, 9),
    endpointId: bytes[11],
    outerClass: bytes[12],
    ipcChannelClass: bytes[13],
    acceptedMonotonicMillis: readU64(bytes, 14),
    openDeadlineMonotonicMillis: readU64(bytes, 22),
    requestEnvelopeBytes: b4a.readUInt32BE(bytes, 30)
  }
  if (b4a.readUInt32BE(bytes, 34) !== PRIVATE_IPC_V2_LIMITS.TRANSPORT_BINDING_BYTES) {
    fail('local staged CELL.PUT open contextLength is not exact')
  }
  const value = normalizedOpenFields(raw)
  const context = decodeLocalTransportBindingV2(bytes.subarray(PRIVATE_IPC_V2_LIMITS.STAGED_OPEN_HEADER_BYTES))
  if (context.authorityKind !== value.authorityKind) fail('open and transport binding authority kinds differ')
  return Object.freeze({ ...value, context })
}

export function validateLocalStagedCellPutOpenBindingV2 (input, options) {
  const open = input && input.context
    ? decodeLocalStagedCellPutOpenV2(encodeLocalStagedCellPutOpenV2(input))
    : decodeLocalStagedCellPutOpenV2(input)
  if (!options || typeof options !== 'object') fail('binding validation options are required')
  const optionKeys = Object.keys(options).sort()
  if (optionKeys.length !== 2 || optionKeys[0] !== 'launchTopologyHash' || optionKeys[1] !== 'transportProfileHash') {
    fail('binding validation accepts exactly launchTopologyHash and transportProfileHash')
  }
  const expectedTopology = fixed(options.launchTopologyHash, 32, 'launchTopologyHash')
  const expectedProfile = fixed(options.transportProfileHash, 32, 'transportProfileHash')
  if (!b4a.equals(open.context.transportProfileHash, expectedProfile)) fail('transport profile hash does not match')
  const expectedOpenBinding = deriveLocalStagedOpenBindingHashV2({
    open,
    launchTopologyHash: expectedTopology,
    authorityKind: open.authorityKind,
    edgeProcessNonce: open.context.edgeProcessNonce,
    localChannelNonce: open.context.localChannelNonce,
    transportProfileHash: open.context.transportProfileHash,
    publicSessionBindingHash: open.context.publicSessionBindingHash
  })
  if (!b4a.equals(open.context.openBindingHash, expectedOpenBinding)) fail('local staged open binding hash does not match')
  return Object.freeze({
    validationKind: 'NON_AUTHORITATIVE_BINDING_VALIDATION_V2',
    authorityGranted: false,
    peerCredentialsObserved: false,
    endpointId: open.endpointId,
    outerClass: open.outerClass,
    transportProfileHash: b4a.from(open.context.transportProfileHash),
    publicSessionBindingHash: b4a.from(open.context.publicSessionBindingHash),
    openBindingHash: b4a.from(open.context.openBindingHash),
    replayTupleHash: replayTupleHashV2(open.context),
    runtimeRequirement: 'observe-native-peer-credentials-before-minting-process-private-authority'
  })
}

export function replayTupleHashV2 (input) {
  const context = input && input.version === 2 && input.publicSessionBindingHash
    ? input
    : decodeLocalTransportBindingV2(input)
  return privateBlake2b256(b4a.concat([
    REPLAY_TUPLE_DOMAIN,
    fixed(context.edgeProcessNonce, 32, 'edgeProcessNonce'),
    fixed(context.localChannelNonce, 32, 'localChannelNonce'),
    fixed(context.publicSessionBindingHash, 32, 'publicSessionBindingHash')
  ]))
}

export function encodeLocalStagedCellPutFrameV2 (input) {
  if (!input || typeof input !== 'object') fail('local staged CELL.PUT frame must be an object')
  const direction = exactEnum(LOCAL_STAGED_DIRECTION_V2, input.direction, 'direction')
  const frameKind = exactEnum(LOCAL_STAGED_FRAME_KIND_V2, input.frameKind, 'frameKind')
  const sequence = u64(input.sequence, 'sequence')
  const flags = input.flags == null ? 0 : u8(input.flags, 'flags')
  if ((flags & ~LOCAL_STAGED_FLAG_V2.FIN) !== 0) fail('frame has a reserved flag')
  const body = input.bytes == null ? b4a.alloc(0) : snapshot(input.bytes, 'frame bytes')
  if (body.byteLength > PRIVATE_IPC_V2_LIMITS.LOCAL_FRAME_CONTENT_BYTES) fail('frame body exceeds 65515 bytes')
  if (frameKind === LOCAL_STAGED_FRAME_KIND_V2.CONTENT) {
    if (body.byteLength === 0 && flags !== LOCAL_STAGED_FLAG_V2.FIN) fail('zero CONTENT is legal only with FIN')
  } else {
    if (flags !== 0 || body.byteLength !== 1 || !Object.values(LOCAL_ABORT_CODE).includes(body[0])) {
      fail('ABORT must have zero flags and exactly one registered generic abort code')
    }
  }
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES + body.byteLength)
  b4a.writeUInt32BE(output, output.byteLength - 4, 0)
  output[4] = 2
  output[5] = direction
  output[6] = frameKind
  writeU64(output, sequence, 7)
  output[15] = flags
  b4a.writeUInt32BE(output, body.byteLength, 16)
  b4a.copy(body, output, PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES)
  return output
}

export function readLocalStagedCellPutFrameLengthV2 (input) {
  const bytes = snapshot(input, 'local staged CELL.PUT frame v2 prefix/header')
  if (bytes.byteLength < 4) return null
  const length = b4a.readUInt32BE(bytes, 0) + 4
  if (length < PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES || length > PRIVATE_IPC_V2_LIMITS.LOCAL_FRAME_BYTES) {
    fail('local staged CELL.PUT frame has an impossible declared length')
  }
  if (bytes.byteLength < 5) return null
  if (bytes[4] !== 2) fail('local staged CELL.PUT frame is not version 2', 'PRIVATE_IPC_V2_NO_FALLBACK')
  if (bytes.byteLength < PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES) return null
  exactEnum(LOCAL_STAGED_DIRECTION_V2, bytes[5], 'direction')
  const frameKind = exactEnum(LOCAL_STAGED_FRAME_KIND_V2, bytes[6], 'frameKind')
  if ((bytes[15] & ~LOCAL_STAGED_FLAG_V2.FIN) !== 0) fail('frame has a reserved flag')
  const bodyLength = b4a.readUInt32BE(bytes, 16)
  if (bodyLength !== length - PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES ||
      bodyLength > PRIVATE_IPC_V2_LIMITS.LOCAL_FRAME_CONTENT_BYTES) {
    fail('local staged CELL.PUT frame bodyLength contradicts its declaration')
  }
  if (frameKind === LOCAL_STAGED_FRAME_KIND_V2.ABORT && (bytes[15] !== 0 || bodyLength !== 1)) {
    fail('ABORT header must declare zero flags and exactly one code byte')
  }
  if (frameKind === LOCAL_STAGED_FRAME_KIND_V2.CONTENT && bodyLength === 0 && bytes[15] !== LOCAL_STAGED_FLAG_V2.FIN) {
    fail('zero CONTENT is legal only with FIN')
  }
  return length
}

export function decodeLocalStagedCellPutFrameV2 (input) {
  readLocalStagedCellPutFrameLengthV2(input)
  const bytes = declaredFrame(input, PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES,
    PRIVATE_IPC_V2_LIMITS.LOCAL_FRAME_BYTES, 'local staged CELL.PUT frame v2')
  if (bytes[4] !== 2) fail('local staged CELL.PUT frame is not version 2', 'PRIVATE_IPC_V2_NO_FALLBACK')
  const bodyLength = b4a.readUInt32BE(bytes, 16)
  if (bytes.byteLength !== PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES + bodyLength) {
    fail('local staged CELL.PUT frame bodyLength is not exact')
  }
  const value = {
    version: 2,
    direction: bytes[5],
    frameKind: bytes[6],
    sequence: readU64(bytes, 7),
    flags: bytes[15],
    bytes: b4a.from(bytes.subarray(PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES))
  }
  encodeLocalStagedCellPutFrameV2(value)
  return Object.freeze(value)
}

export function decodeLocalStagedCellPutFramesV2 (input, options = {}) {
  const bytes = snapshot(input, 'staged CELL.PUT frame buffer')
  const allowIncomplete = options.allowIncomplete === true
  const frames = []
  let offset = 0
  while (offset < bytes.byteLength) {
    if (bytes.byteLength - offset < 4) {
      if (allowIncomplete) break
      fail('staged CELL.PUT frame buffer ends in a partial prefix')
    }
    const length = b4a.readUInt32BE(bytes, offset) + 4
    if (length < PRIVATE_IPC_V2_LIMITS.STAGED_FRAME_HEADER_BYTES || length > PRIVATE_IPC_V2_LIMITS.LOCAL_FRAME_BYTES) {
      fail('staged CELL.PUT frame declaration is outside its bound')
    }
    if (offset + length > bytes.byteLength) {
      if (allowIncomplete) break
      fail('staged CELL.PUT frame buffer ends in a partial frame')
    }
    frames.push(decodeLocalStagedCellPutFrameV2(bytes.subarray(offset, offset + length)))
    offset += length
  }
  return Object.freeze({ frames: Object.freeze(frames), remainder: b4a.from(bytes.subarray(offset)) })
}

export function verifyLocalStagedCellPutExchangeV2 (openInput, frameInputs) {
  const open = openInput && openInput.context ? openInput : decodeLocalStagedCellPutOpenV2(openInput)
  if (!Array.isArray(frameInputs) || frameInputs.length < 1) fail('staged CELL.PUT exchange requires frames')
  let phase = LOCAL_STAGED_DIRECTION_V2.REQUEST
  let requestSequence = 0n
  let resultSequence = 0n
  let requestBytes = 0
  let resultBytes = 0
  let requestFinished = false
  let resultFinished = false
  let aborted = false
  for (const frameInput of frameInputs) {
    const frame = frameInput && frameInput.version === 2 ? frameInput : decodeLocalStagedCellPutFrameV2(frameInput)
    if (aborted || resultFinished) fail('frame follows terminal exchange state')
    if (frame.direction !== phase) fail('frame direction violates request/result state')
    const expectedSequence = phase === LOCAL_STAGED_DIRECTION_V2.REQUEST ? requestSequence : resultSequence
    if (frame.sequence !== expectedSequence) fail('frame sequence is not first-zero exact +1')
    if (phase === LOCAL_STAGED_DIRECTION_V2.REQUEST) requestSequence++
    else resultSequence++
    if (frame.frameKind === LOCAL_STAGED_FRAME_KIND_V2.ABORT) {
      aborted = true
      continue
    }
    if (phase === LOCAL_STAGED_DIRECTION_V2.REQUEST) requestBytes += frame.bytes.byteLength
    else resultBytes += frame.bytes.byteLength
    if ((frame.flags & LOCAL_STAGED_FLAG_V2.FIN) !== 0) {
      if (phase === LOCAL_STAGED_DIRECTION_V2.REQUEST) {
        if (requestBytes !== open.requestEnvelopeBytes) fail('request FIN does not complete the exact full outer envelope')
        requestFinished = true
        phase = LOCAL_STAGED_DIRECTION_V2.RESULT
      } else {
        if (resultBytes !== OUTER_CLASS[open.outerClass]) fail('result FIN does not complete the exact same-class outer envelope')
        resultFinished = true
      }
    }
  }
  if (!aborted && (!requestFinished || !resultFinished)) fail('staged CELL.PUT exchange is incomplete')
  return Object.freeze({ requestBytes, resultBytes, requestFinished, resultFinished, aborted })
}

export function verifyStagedCellPutPublicOuterEnvelopeV2 (input, openInput, direction, requestId = null) {
  const open = openInput && openInput.context ? openInput : decodeLocalStagedCellPutOpenV2(openInput)
  direction = exactEnum(LOCAL_STAGED_DIRECTION_V2, direction, 'direction')
  const outerEnvelope = snapshot(input, 'public outer envelope')
  let decoded
  try {
    decoded = decodeOuterEnvelope(outerEnvelope, { copyInner: true, copyBody: true })
  } catch {
    fail('staged CELL.PUT bytes are not one canonical public outer envelope')
  }
  if (decoded.outerClass !== open.outerClass || outerEnvelope.byteLength !== open.requestEnvelopeBytes) {
    fail('staged CELL.PUT public outer envelope does not match the selected class')
  }
  const frame = decoded.frame
  if (frame.familyId !== FAMILY.CELL || frame.operationId !== OPERATION.CELL.PUT) {
    fail('staged public dispatch is not exact CELL.PUT')
  }
  if (frame.flags !== 0 || frame.streamId !== 0n || frame.sequence !== 0n) {
    fail('staged CELL.PUT requires unary zero-flags/stream/sequence invariants')
  }
  if (direction === LOCAL_STAGED_DIRECTION_V2.REQUEST) {
    if (frame.frameKind !== FRAME_KIND.REQUEST) fail('staged CELL.PUT request is not a REQUEST dispatch')
  } else {
    if (frame.frameKind !== FRAME_KIND.RESPONSE && frame.frameKind !== FRAME_KIND.ERROR) {
      fail('staged CELL.PUT result is not a RESPONSE or ERROR dispatch')
    }
    const expectedRequestId = fixed(requestId, 16, 'requestId')
    if (!b4a.equals(frame.requestId, expectedRequestId)) fail('staged CELL.PUT result requestId is not correlated')
  }
  const bodySchema = direction === LOCAL_STAGED_DIRECTION_V2.REQUEST
    ? putCellV1
    : frame.frameKind === FRAME_KIND.RESPONSE
      ? blindReceiptV1
      : blindErrorV1
  const bodySchemaName = direction === LOCAL_STAGED_DIRECTION_V2.REQUEST
    ? 'PutCellV1'
    : frame.frameKind === FRAME_KIND.RESPONSE
      ? 'BlindReceiptV1'
      : 'BlindErrorV1'
  let canonicalBody
  try {
    canonicalBody = encodeCanonical(bodySchema, decodeCanonical(bodySchema, frame.body, { copyBytes: true }))
  } catch {
    fail(`staged CELL.PUT ${frame.frameKind === FRAME_KIND.ERROR ? 'error' : direction === LOCAL_STAGED_DIRECTION_V2.REQUEST ? 'request' : 'response'} body is not exact canonical ${bodySchemaName}`)
  }
  if (!b4a.equals(canonicalBody, frame.body)) {
    fail(`staged CELL.PUT body does not re-encode as exact canonical ${bodySchemaName}`)
  }
  const verifiedFrame = Object.freeze({
    version: frame.version,
    frameKind: frame.frameKind,
    familyId: frame.familyId,
    operationId: frame.operationId,
    flags: frame.flags,
    requestId: b4a.from(frame.requestId),
    streamId: frame.streamId,
    sequence: frame.sequence,
    body: b4a.from(canonicalBody)
  })
  return Object.freeze({ outerClass: decoded.outerClass, frame: verifiedFrame, bodySchemaName })
}

export function encodeLocalReadyProbeV2 (input) {
  if (!input || typeof input !== 'object') fail('local ready probe v2 must be an object')
  const accepted = u64(input.acceptedMonotonicMillis, 'acceptedMonotonicMillis')
  const deadline = u64(input.absoluteDeadlineMonotonicMillis, 'absoluteDeadlineMonotonicMillis')
  if (deadline !== accepted + BigInt(PRIVATE_IPC_V2_LIMITS.READY_DEADLINE_MILLIS)) {
    fail('local ready probe deadline must equal accepted+2000')
  }
  const featureBits = u32(input.edgeFeatureBits, 'edgeFeatureBits')
  const writeBits = u32(input.requestedWriteOperationBits, 'requestedWriteOperationBits')
  if (featureBits !== REQUIRED_LOCAL_IPC_FEATURE_BITS_V2 || writeBits !== CELL_PUT_OPERATION_BIT_V2) {
    fail('local ready probe must request the exact initial V2 feature and CELL.PUT write bits')
  }
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.READY_PROBE_BYTES)
  b4a.writeUInt32BE(output, output.byteLength - 4, 0)
  output[4] = 2
  output[5] = LOCAL_READY_CONTROL_KIND_V2.PROBE
  output[6] = u8(input.endpointId, 'endpointId', 1, 0xff)
  b4a.copy(fixed(input.edgeProcessNonce, 32, 'edgeProcessNonce'), output, 7)
  b4a.copy(fixed(input.launchTopologyHash, 32, 'launchTopologyHash'), output, 39)
  b4a.writeUInt32BE(output, featureBits, 71)
  b4a.writeUInt32BE(output, writeBits, 75)
  writeU64(output, accepted, 79)
  writeU64(output, deadline, 87)
  return output
}

export function readLocalReadyProbeLengthV2 (input) {
  return fixedDeclaredLength(input, PRIVATE_IPC_V2_LIMITS.READY_PROBE_BYTES, 7,
    'local ready probe v2 prefix/header', LOCAL_READY_CONTROL_KIND_V2.PROBE)
}

export function decodeLocalReadyProbeV2 (input) {
  readLocalReadyProbeLengthV2(input)
  const bytes = exactFrame(input, PRIVATE_IPC_V2_LIMITS.READY_PROBE_BYTES, 'local ready probe v2')
  if (bytes[4] !== 2) fail('local ready probe is not version 2', 'PRIVATE_IPC_V2_NO_FALLBACK')
  if (bytes[5] !== LOCAL_READY_CONTROL_KIND_V2.PROBE) fail('local ready probe has the wrong control kind')
  const value = {
    version: 2,
    controlKind: bytes[5],
    endpointId: bytes[6],
    edgeProcessNonce: b4a.from(bytes.subarray(7, 39)),
    launchTopologyHash: b4a.from(bytes.subarray(39, 71)),
    edgeFeatureBits: b4a.readUInt32BE(bytes, 71),
    requestedWriteOperationBits: b4a.readUInt32BE(bytes, 75),
    acceptedMonotonicMillis: readU64(bytes, 79),
    absoluteDeadlineMonotonicMillis: readU64(bytes, 87)
  }
  encodeLocalReadyProbeV2(value)
  return Object.freeze(value)
}

export function encodeLocalReadyAckV2 (input) {
  if (!input || typeof input !== 'object') fail('local ready ACK v2 must be an object')
  const readyRoleBits = u16(input.readyRoleBits, 'readyRoleBits')
  const readyOperationBits = u32(input.readyOperationBits, 'readyOperationBits')
  const readyWriteOperationBits = u32(input.readyWriteOperationBits, 'readyWriteOperationBits')
  const readyIpcFeatureBits = u32(input.readyIpcFeatureBits, 'readyIpcFeatureBits')
  if (readyWriteOperationBits !== CELL_PUT_OPERATION_BIT_V2 ||
      (readyWriteOperationBits & readyOperationBits) !== readyWriteOperationBits) {
    fail('ready write bits must be the exact initial CELL.PUT bit and a ready-operation subset')
  }
  if (readyIpcFeatureBits !== REQUIRED_LOCAL_IPC_FEATURE_BITS_V2) fail('ready IPC feature bits must equal the required V2 mask')
  if ((readyRoleBits & CELL_PUT_ENDPOINT_ROLE_BIT_V2) === 0) fail('ready role bits omit STORAGE')
  const output = b4a.alloc(PRIVATE_IPC_V2_LIMITS.READY_ACK_BYTES)
  b4a.writeUInt32BE(output, output.byteLength - 4, 0)
  output[4] = 2
  output[5] = LOCAL_READY_CONTROL_KIND_V2.ACK
  output[6] = u8(input.endpointId, 'endpointId', 1, 0xff)
  b4a.copy(fixed(input.edgeProcessNonce, 32, 'edgeProcessNonce'), output, 7)
  b4a.copy(fixed(input.launchTopologyHash, 32, 'launchTopologyHash'), output, 39)
  writeU64(output, u64(input.descriptorSequence, 'descriptorSequence', true), 71)
  b4a.copy(fixed(input.descriptorHash, 32, 'descriptorHash'), output, 79)
  writeU16(output, readyRoleBits, 111)
  b4a.writeUInt32BE(output, readyOperationBits, 113)
  b4a.writeUInt32BE(output, readyWriteOperationBits, 117)
  b4a.writeUInt32BE(output, readyIpcFeatureBits, 121)
  writeU64(output, u64(input.expiresMonotonicMillis, 'expiresMonotonicMillis', true), 125)
  return output
}

export function readLocalReadyAckLengthV2 (input) {
  return fixedDeclaredLength(input, PRIVATE_IPC_V2_LIMITS.READY_ACK_BYTES, 7,
    'local ready ACK v2 prefix/header', LOCAL_READY_CONTROL_KIND_V2.ACK)
}

export function decodeLocalReadyAckV2 (input) {
  readLocalReadyAckLengthV2(input)
  const bytes = exactFrame(input, PRIVATE_IPC_V2_LIMITS.READY_ACK_BYTES, 'local ready ACK v2')
  if (bytes[4] !== 2) fail('local ready ACK is not version 2', 'PRIVATE_IPC_V2_NO_FALLBACK')
  if (bytes[5] !== LOCAL_READY_CONTROL_KIND_V2.ACK) fail('local ready ACK has the wrong control kind')
  const value = {
    version: 2,
    controlKind: bytes[5],
    endpointId: bytes[6],
    edgeProcessNonce: b4a.from(bytes.subarray(7, 39)),
    launchTopologyHash: b4a.from(bytes.subarray(39, 71)),
    descriptorSequence: readU64(bytes, 71),
    descriptorHash: b4a.from(bytes.subarray(79, 111)),
    readyRoleBits: readU16(bytes, 111),
    readyOperationBits: b4a.readUInt32BE(bytes, 113),
    readyWriteOperationBits: b4a.readUInt32BE(bytes, 117),
    readyIpcFeatureBits: b4a.readUInt32BE(bytes, 121),
    expiresMonotonicMillis: readU64(bytes, 125)
  }
  encodeLocalReadyAckV2(value)
  return Object.freeze(value)
}

export function localReadyDecisionV2 (probeInput, ackInput, descriptor, nowMonotonicMillis) {
  const probe = probeInput && probeInput.version === 2 ? probeInput : decodeLocalReadyProbeV2(probeInput)
  const ack = ackInput && ackInput.version === 2 ? ackInput : decodeLocalReadyAckV2(ackInput)
  const now = u64(nowMonotonicMillis, 'nowMonotonicMillis')
  const reasons = []
  if (probe.endpointId !== ack.endpointId) reasons.push('endpoint-mismatch')
  if (!b4a.equals(probe.edgeProcessNonce, ack.edgeProcessNonce)) reasons.push('edge-nonce-mismatch')
  if (!b4a.equals(probe.launchTopologyHash, ack.launchTopologyHash)) reasons.push('topology-mismatch')
  if (now < probe.acceptedMonotonicMillis) reasons.push('not-yet-valid')
  if (now >= probe.absoluteDeadlineMonotonicMillis || now >= ack.expiresMonotonicMillis) reasons.push('expired')
  if (!descriptor || typeof descriptor !== 'object') reasons.push('descriptor-absent')
  else {
    const sequence = u64(descriptor.sequence, 'descriptor.sequence', true)
    const expires = u64(descriptor.expiresMonotonicMillis, 'descriptor.expiresMonotonicMillis', true)
    const descriptorHash = fixed(descriptor.hash, 32, 'descriptor.hash')
    const roleBits = u16(descriptor.roleBits, 'descriptor.roleBits')
    const operationBits = u32(descriptor.enabledOperationBits, 'descriptor.enabledOperationBits')
    if (ack.descriptorSequence !== sequence || !b4a.equals(ack.descriptorHash, descriptorHash)) reasons.push('descriptor-freshness-mismatch')
    if ((ack.readyRoleBits & ~roleBits) !== 0 || (ack.readyRoleBits & CELL_PUT_ENDPOINT_ROLE_BIT_V2) === 0) reasons.push('descriptor-role-subset-mismatch')
    if ((ack.readyOperationBits & ~operationBits) !== 0 || (ack.readyWriteOperationBits & ~operationBits) !== 0) reasons.push('descriptor-operation-subset-mismatch')
    if (ack.expiresMonotonicMillis > expires) reasons.push('descriptor-expiry-mismatch')
    if (now >= expires) reasons.push('descriptor-expired')
  }
  if (probe.edgeFeatureBits !== REQUIRED_LOCAL_IPC_FEATURE_BITS_V2 ||
      ack.readyIpcFeatureBits !== REQUIRED_LOCAL_IPC_FEATURE_BITS_V2) reasons.push('feature-bits-missing-or-unknown')
  if (probe.requestedWriteOperationBits !== CELL_PUT_OPERATION_BIT_V2 ||
      ack.readyWriteOperationBits !== CELL_PUT_OPERATION_BIT_V2 ||
      (ack.readyWriteOperationBits & ack.readyOperationBits) !== ack.readyWriteOperationBits) reasons.push('write-readiness-mismatch')
  return Object.freeze({ ready: reasons.length === 0, reasons: Object.freeze(reasons) })
}

export function localIpcChannelClassForOuterClassV2 (outerClass) {
  u8(outerClass, 'outerClass', 1, 6)
  return LOCAL_IPC_CHANNEL_CLASS_V2.LOCAL_64K
}

export function cellPutWorstCaseResultFitsOuterClassV2 (outerClass) {
  outerClass = u8(outerClass, 'outerClass', 1, 6)
  return PRIVATE_IPC_V2_LIMITS.CELL_PUT_WORST_CASE_RESULT_ENVELOPE_BYTES <= OUTER_CLASS[outerClass]
}

export function initialStagedCellPutOuterClassSupportedV2 (outerClass) {
  outerClass = u8(outerClass, 'outerClass', 1, 6)
  return outerClass >= PRIVATE_IPC_V2_STAGED_CELL_PUT_POLICY.initialMinimumOuterClass
}

export function assertPrecommitCellPutResultFitV2 (outerClass, ...unsupportedPrediction) {
  if (unsupportedPrediction.length !== 0) {
    fail('private IPC v2 result sizing is fixed to the generated worst case and accepts no predicted-result input',
      'PRIVATE_IPC_V2_FIXED_RESULT_SIZING')
  }
  if (!initialStagedCellPutOuterClassSupportedV2(outerClass)) {
    fail('initial staged CELL.PUT requires public outer class 3 through 6 under fixed worst-case result sizing',
      'PRIVATE_IPC_V2_PRECOMMIT_RESULT_CLASS')
  }
  if (!cellPutWorstCaseResultFitsOuterClassV2(outerClass)) {
    fail('fixed worst-case CELL.PUT correlated result does not fit selected outer class before commit',
      'PRIVATE_IPC_V2_PRECOMMIT_RESULT_CLASS')
  }
  return outerClass
}

export const PRIVATE_IPC_V2_CONTRACT = Object.freeze({
  magic: PRIVATE_IPC_V2_MAGIC,
  formatVersion: PRIVATE_IPC_V2_FORMAT_VERSION,
  schemaIds: Object.freeze(PRIVATE_IPC_V2_ADDITIONAL_SCHEMAS.map(schema => schema.schemaId)),
  schemaCount: PRIVATE_IPC_V2_SCHEMAS.length,
  v1SchemaCount: PRIVATE_IPC_SCHEMAS.length,
  v1FallbackPermitted: false,
  contractLayerMintsRuntimeAuthority: false,
  callerPeerCredentialAssertionAccepted: false,
  bindingValidationIsAuthoritative: false,
  publicWireOperation: Object.freeze({
    familyId: FAMILY.CELL,
    operationId: OPERATION.CELL.PUT,
    operationBit: CELL_PUT_OPERATION_BIT_V2,
    requestFrameKind: FRAME_KIND.REQUEST,
    resultFrameKinds: Object.freeze([FRAME_KIND.RESPONSE, FRAME_KIND.ERROR]),
    endpointRoleBit: ENDPOINT_ROLE.STORAGE
  }),
  httpsTransport: Object.freeze({
    transportId: TRANSPORT_ID.HTTPS_DIRECT,
    transportSupportBit: TRANSPORT_SUPPORT.DIRECT_HTTP,
    authorityKind: LOCAL_TRANSPORT_AUTHORITY_KIND_V2.TLS_EXPORTER_BY_PEERCRED_EDGE,
    tlsExporterLabel: TLS_EXPORTER_LABEL_V2,
    tlsExporterBytes: PRIVATE_IPC_V2_LIMITS.TLS_EXPORTER_BYTES
  }),
  localChannelClassByOuterClass: Object.freeze(Object.fromEntries(
    Object.keys(OUTER_CLASS).map(outerClass => [outerClass, LOCAL_IPC_CHANNEL_CLASS_V2.LOCAL_64K])
  )),
  precommitOrder: Object.freeze([
    'native-peer-credentials', 'exact-v2-open', 'transport-profile', 'launch-topology',
    'endpoint', 'open-deadline', 'initial-cell-put-outer-class-3-through-6',
    'open-binding', 'branded-persisted-descriptor-floor-readiness-sequence-at-least-1',
    'counter-only-memory-reservation', 'durable-replay-consume', 'first-request-body-pull',
    'owned-prefix-side-effect-free-branded-admission-preflight',
    'reversible-ephemeral-body-staging', 'exact-outer-request-fin',
    'edge-write-half-close-response-half-readable',
    'daemon-observed-authenticated-peer-eof', 'canonical-post-eof-revalidation',
    'final-caller-cancellation-and-lifecycle-fence-before-publish',
    'non-cancellable-publish-and-put-atomic-committed', 'sign-and-same-class-result'
  ]),
  nonceLifecycle: Object.freeze({
    edgeProcessNonce: 'os-csprng-once-after-start-or-fork-stable-until-process-exit-never-persisted-or-reused',
    localChannelNonce: 'fresh-os-csprng-for-every-open-attempt-never-reused'
  }),
  replayPolicy: PRIVATE_IPC_V2_REPLAY_POLICY,
  stagedCellPutPolicy: PRIVATE_IPC_V2_STAGED_CELL_PUT_POLICY,
  requiredFeatureBits: REQUIRED_LOCAL_IPC_FEATURE_BITS_V2,
  limits: PRIVATE_IPC_V2_LIMITS
})

export { LOCAL_ABORT_CODE, OUTER_CLASS, STREAM_WIRE_CLASS, TRANSPORT_ID, TRANSPORT_SUPPORT }