Skip to content

Sovereign Zero-Copy: std.mem.zerocopy

std.mem.zerocopy is Janus’s answer to the question can I treat this byte region as that struct? It combines two layers of discipline:

  • Layer Atype-soundness. The struct’s bit-level layout is what the type says it is (no implicit padding, no fields outside the type’s byte range, no field-by-field invariants that bit-comparison would miss). Rust’s zerocopy crate is the primary prior art.
  • Layer Bauthority. The byte stream is authorized to be reinterpreted as that struct. A manifest-bound capability token (ReinterpretCap[T]) says “this binary is allowed to interpret bytes as T from these source classes.” No ambient authority.

The four sub-modules:

ModuleLayerPurpose
std.mem.zerocopy.traitsAFromBytes / IntoBytes / Unaligned / TryFromBytes trait quartet — type-level evidence that a struct is soundly reinterpretable.
std.mem.zerocopy.provenanceBSourceClass enum + SourceSet bitset — the source-class lattice (Network / Disk / SharedMem / Pipe / Trusted) for cap source admission.
std.mem.zerocopy.capBReinterpretCap[T] struct + cap_from_manifest / cap_nallow / cap_allowed_sources_mask helpers — the manifest-bound authority token.
std.mem.zerocopy.eql_ctbothConstant-time byte equality (Layer 4 of the four-axis equality model) — std.mem.zerocopy.eql_ct.eql_ct.
std.mem.zerocopy.modbothModule surface — re-exports the four sub-modules.

Use std.mem.zerocopy when:

  • You’re parsing a wire protocol header from a byte stream (DMP, TLS, custom binary format).
  • You’re serializing a struct to a byte buffer (network send, file write).
  • You’re bridging a C FFI boundary and need to interpret a *u8 as a typed struct.
  • You’re implementing constant-time crypto operations (constant-time compare is the right primitive; std.mem.zerocopy.eql_ct is the canonical caller).

Do not use std.mem.zerocopy when:

  • The byte stream’s contents are untrusted AND you need the Layer A type invariants (padding, version field, discriminants) to hold. Use TryFromBytes + a validator first.
  • The byte stream’s source is untrusted AND you need Layer B authority to interpret it. The manifest cap MUST be present.
  • The byte stream is shorter than the struct. The len < size_of(T) check is mandatory.

The Layer A pattern: FromBytes + Unaligned

Section titled “The Layer A pattern: FromBytes + Unaligned”
use std.mem.zerocopy as zc
pub struct Header do
magic: u32,
length: u32,
payload_len: u32,
end
// Marker: this struct is layout-sound AND safely reinterpretable from
// any byte address (no alignment requirement). The derive is Phase 4
// compiler work; until then, the smoke hand-writes impls.
pub impl Header: zc.FromBytes + zc.Unaligned do
// ... derive(FromBytes, Unaligned) ...
end
// Reinterpret an unaligned byte slice as a Header reference.
pub func parse_header(view bytes: []const u8) -> *const Header do
if bytes.len < §size_of(Header) do return null end
return std.mem.realign[Header](bytes.ptr)
end

The trait bounds carry the safety property at the type level: a function that takes T: FromBytes has compile-time evidence that every bit pattern of T is a valid value. A function that takes T: Unaligned has compile-time evidence that T has no alignment requirement (so any byte address is a valid pointer to a T).

use std.mem.zerocopy.cap as zc_cap
// `hinge.kdl` declaration paired with this binary:
//
// capabilities {
// reinterpret {
// type "Header" fingerprint="<BLAKE3-HEX>" sources={ network disk }
// }
// }
//
// The runtime materializes a `ReinterpretCap[Header]` and passes it
// to `main` as a `view` parameter. User code receives the cap and
// can use it to authorize byte→Header reinterpretation.
pub func main(view header_cap: zc_cap.ReinterpretCap[Header]) -> i32
{.profile: sovereign.} do
// Layer B: the cap is bound to the manifest declaration. Field access
// (Layer A) is via the underlying struct; the cap is just the authority.
return 0
end

The cap object is only constructible by the runtime, an authority-narrowing helper, or a :sovereign-privileged issuer function — per SPEC-091 [CAP:3.1.1]. User code cannot construct a cap directly; the compiler rejects with E2601 (E_ZC_CAP_CONSTRUCTION_FORBIDDEN).

The cap carries:

  • schema_fingerprint_lo/hi — half the §sbi_fingerprint(T) hash. At the call site of authorized_ref_from_bytes[T], the runtime checks the fingerprint matches the destination type’s canonical hash.
  • allowed_sources_mask — bitmask over the Phase 7 source-class lattice. A cap.allowed_sources_mask containing Network permits reinterpretation of bytes tagged actual_source = Network.
  • issued_at, issuer, capabilities_mask — provenance + authority bits.

The composition: authorized_ref_from_bytes[T]

Section titled “The composition: authorized_ref_from_bytes[T]”

The Layer A trait + Layer B cap compose into a single function that returns a :sovereign *T after both checks pass:

{.profile: sovereign.}
pub func authorized_ref_from_bytes[T: FromBytes](
cap: view ReinterpretCap[T],
bytes: []const u8,
actual_source: prov.SourceClass,
) -> !:sovereign *T
where S: SourceClass, Scap.allowed_sources
do
// Compile-time: §sbi_fingerprint(T) == cap.schema_fingerprint
// Runtime: actual_source ∈ cap.allowed_sources
if bytes.len < §size_of(T) do fail ZCError.InsufficientLength end
return std.mem.realign[T](bytes.ptr)?
end

This is Phase 6.3 (blocked on Phase 4 derive mechanism). Until it ships, use the Phase 6.2 helpers:

  • cap_from_manifest[T](...) -> ReinterpretCap[T] — runtime constructor
  • cap_narrow[T](self, narrower_sources_mask) -> ?ReinterpretCap[T] — monotonic narrowing
  • cap_allowed_sources_mask[T](self) -> u8 — raw-mask accessor

Rust’s zerocopy crate is a single layer (type-soundness). Janus’s std.mem.zerocopy adds the authority layer because the Janus safety model separates “the type is sound” from “the bytes are authorized”. Conflating these is the root cause of every memory-corruption CVE in the wild — the type was fine, the bytes weren’t what they claimed to be.

The manifest is the audit surface. A reviewer reads hinge.kdl and knows the binary’s full set of reinterpretation authorities before reading a single line of code. Compare to ambient-authority languages where the audit surface is “any function in the program could reinterpret any FromBytes type from any source.”

The Layer A pattern is :service-safe — type-sound reinterpretation is a normal operation. The Layer B pattern requires :sovereign because manifest-bound authority is operationally sensitive. The distinction is enforced at the function level via {.profile: sovereign.}:

// Service-safe: Layer A only.
pub func parse_header(view bytes: []const u8) -> ?*const Header do
if bytes.len < §size_of(Header) do return null end
return std.mem.realign[Header](bytes.ptr)
end
// Sovereign-only: Layer B authority.
pub func parse_authorized_frame(
view cap: zc_cap.ReinterpretCap[Header],
bytes: []const u8,
source: prov.SourceClass,
) -> !*const Header {.profile: sovereign.} do
if cap.allowed_sources_mask & (1 << source_to_bit(source)) == 0 do
fail ZCError.UnauthorizedSource
end
return parse_header(bytes)
end

The compiler enforces that cap-bearing parameters and authorized_* function bodies are :sovereign only. This is the practical enforcement of the doctrine that the cap should not be passed to untrusted code.

janus-lang/examples/zerocopy_dmp_frame.jan ships a complete DMP frame parser using the Phase 6.6 surface. The example pairs a hinge.kdl reinterpret block with a binary that uses ReinterpretCap[DMPFrame] to authorize Layer B reinterpretation. See the file for the full declaration, the construction pattern, and the cap-narrowing verification.

Full normative specification in Janus/.agents/specs/_CURRENT/SPEC-245-std-mem-zerocopy.md. The spec is structured in three layers: §2 (Layer A), §3 (Layer B), §4 (Safe API).

The doc is rounded out by:

  • Janus/.agents/specs/_AMENDMENT/SPEC-091-amendment-A-reinterpret-capability.md — Amendment-A which adds the .reinterpret class to SPEC-091’s capability universe (RATIFIED 2026-06-25).
  • Janus/.agents/specs/_PROPOSED/SPEC-equality-model.md — the four-axis equality model whose Axis 4 (std.mem.zerocopy.eql_ct) is the canonical constant-time byte comparison.

Phase 6.5 ships three implementable BDD scenarios at janus-lang/tests/spec_245/phase6/:

  • cap_245_603_from_manifest_round_trip.jancap_from_manifest[T] field round-trip.
  • cap_245_606_narrow_monotonic.jancap_narrow[T] monotonic narrowing (valid + widening + empty + same set).
  • cap_245_610_q1_lifetime.jan — Q1 lifetime guarantee: cap stays valid across loop iterations.

Seven additional scenarios are documented in cap_245_deferred_scenarios.jan with their specific blockers (runtime materialization, Sema E2601, Phase 4 derive, SPEC-085 intent, etc.).