Sovereign Zero-Copy: std.mem.zerocopy
Sovereign Zero-Copy: std.mem.zerocopy
Section titled “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 A — type-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
zerocopycrate is the primary prior art. - Layer B — authority. 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 asTfrom these source classes.” No ambient authority.
The four sub-modules:
| Module | Layer | Purpose |
|---|---|---|
std.mem.zerocopy.traits | A | FromBytes / IntoBytes / Unaligned / TryFromBytes trait quartet — type-level evidence that a struct is soundly reinterpretable. |
std.mem.zerocopy.provenance | B | SourceClass enum + SourceSet bitset — the source-class lattice (Network / Disk / SharedMem / Pipe / Trusted) for cap source admission. |
std.mem.zerocopy.cap | B | ReinterpretCap[T] struct + cap_from_manifest / cap_nallow / cap_allowed_sources_mask helpers — the manifest-bound authority token. |
std.mem.zerocopy.eql_ct | both | Constant-time byte equality (Layer 4 of the four-axis equality model) — std.mem.zerocopy.eql_ct.eql_ct. |
std.mem.zerocopy.mod | both | Module surface — re-exports the four sub-modules. |
When to reach for std.mem.zerocopy
Section titled “When to reach for std.mem.zerocopy”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
*u8as a typed struct. - You’re implementing constant-time crypto operations (constant-time compare is the right primitive;
std.mem.zerocopy.eql_ctis 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)endThe 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).
The Layer B pattern: ReinterpretCap[T]
Section titled “The Layer B pattern: ReinterpretCap[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 0endThe 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 ofauthorized_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. Acap.allowed_sources_maskcontainingNetworkpermits reinterpretation of bytes taggedactual_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, S ∈ cap.allowed_sourcesdo // 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)?endThis 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 constructorcap_narrow[T](self, narrower_sources_mask) -> ?ReinterpretCap[T]— monotonic narrowingcap_allowed_sources_mask[T](self) -> u8— raw-mask accessor
Why two layers
Section titled “Why two layers”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.”
Profile gating
Section titled “Profile gating”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)endThe 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.
Worked example: DMP frame parsing
Section titled “Worked example: DMP frame parsing”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.
SPEC-245 reference
Section titled “SPEC-245 reference”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.reinterpretclass 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.
BDD scenarios (Phase 6.5)
Section titled “BDD scenarios (Phase 6.5)”Phase 6.5 ships three implementable BDD scenarios at
janus-lang/tests/spec_245/phase6/:
cap_245_603_from_manifest_round_trip.jan—cap_from_manifest[T]field round-trip.cap_245_606_narrow_monotonic.jan—cap_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.).