Skip to main content
Version: 0.1.0-alpha.4 (alpha)

Budgeted cryptographic randomness

The configured RandomProvider implements the existing latent:random/random@0.1.0 interface: bytes(length) and u64-value(). Both require an exact import, a current broker plan, the installed provider identity and an operation grant with resource kind random. Guest input cannot select a generator, source, seed or provider. An uninstalled import fails preparation.

Composition and authority​

An embedding constructs RandomProvider::system(&broker, epoch, limits) and installs its returned Arc with ActivationCapabilityRuntime::install_random. Its reference() supplies the provider profile, configuration digest and epoch for the existing durable binding and plan compiler. Production uses the system-random-v1 profile. Changing limits changes the configuration digest; replacement follows normal provider retirement and binding revision rules. This provider is available through the Rust embedding and the opt-in random installation in standalone provider configuration. Configuration installs the provider, not guest authority: exact host bindings, deployment grants and current policy are still required.

The owner has fixed configuration and numeric counters. There is no service generator, entropy file descriptor, thread, task, timer, seed or guest instance. Prepared components can retain the shared owner; each invocation still opens a fresh broker session and Wasmtime Store. Sessions from another installation, tenant or activation cannot transfer permission or remaining allowance.

Source and bounds​

On Linux the provider calls the kernel through rustix::rand::getrandom with NONBLOCK, in chunks of at most 256 bytes. An unavailable entropy source, interrupted syscall, unexpected short read or other error fails the whole call. There is no retry loop, device-file fallback or insecure flag. See the Linux getrandom contract and rustix API. Other targets use the OS source selected by getrandom::fill. The nonblocking Linux profile is not a hard scheduling guarantee for every OS. Source failures never fall back to time, IDs or a predictable PRNG.

Limit or chargeContract
Per callDefault and hard maximum 4,096 bytes; configurable down to 8.
Per activationDefault and hard maximum 65,536 bytes; may be reduced to the per-call maximum. Shared by both methods.
u64-valueExactly 8 source bytes, interpreted in little-endian order.
bytes(0)Empty successful result with no entropy call; still requires a grant and host-call fuel.
CPU fuel100 + requested bytes, reserved through the original ledger before output allocation or entropy. Fuel is accounting work, not a time unit.
OutputExact requested capacity, plus normal broker input/metadata/call reservations, acquired before allocation.
Other countersNo child call, outbound request, state, blob, log or effect charge.

Pending calls reserve their aggregate allowance. Dropping a call before entropy starts releases that allowance. Once the source is attempted, its requested bytes remain spent even if the source fails or cancellation prevents delivery. The allowance lives in the original session, not the public activation ID or prepared cache. Reusing either starts a fresh allowance. Zero-length repetitions remain bounded by fuel and broker call/handle/metadata limits.

Success retains its original output owner through guest canonical lowering and Store destruction. Cancellation and errors wipe an unfinished host buffer before releasing its reservation. Guest-visible bytes belong to ordinary guest memory; the provider makes no promise that application copies are securely erased.

Outcomes and observability​

invalid-length reports a request above the per-call limit. budget-exhausted reports aggregate, fuel, buffer or broker capacity exhaustion. unavailable reports a source or provider/authorization failure: the frozen 0.1.0 variant has no separate permission-denied case. Cancellation, session closure and deadline expiry are also checked at the host return boundary and stop guest execution. No partial random result is returned after a failed source operation.

snapshot() exposes fixed counters for the two operations, generated byte count and the three failure classes. Generated bytes need not have reached the guest; these are diagnostic counters and confer no authority. Required capability audit must admit a durable attempt before source access. Its request digest covers the operation and requested length, never generated output. Outcomes use HostCompleted or Rejected; terminal durability follows the existing audit contract. Neither diagnostics nor audit contain generated bytes, their digest, a seed, guest labels or provider error text.

The optional Cargo test-support feature exposes explicit trusted RandomProvider::for_test construction under a distinct test-random-v1 identity. Node configuration cannot select it; system always uses the OS even when that feature is built. Injected test code must return promptly. This seam does not implement durable workflow replay or deterministic production entropy.

Verification​

cargo test -p latent-wasmtime --test random --locked -- --test-threads=1
cargo test -p latent-capabilities --lib --locked

Executed canonical ABI guests cover both methods, zero/max/over length, shared aggregate exhaustion and reset on a reused cell, denied and retired authority, source failure, cancellation, policy revocation and required audit redaction. Ownership checks cover abandoned pending work, spent failed attempts, fuel prepayment and held results after session closure. A separate real OS source test checks bounded buffer completion. These tests make no statistical claim about cryptographic quality and require no load benchmark.