Chapter 36. Loading Precompiled and Signed Bytecode
Goal
By the end of this chapter you will be able to load precompiled bytecode, load signed bytecode against a trust matrix, and understand the trust-skip constructor.
Loading precompiled bytecode
A host with a precompiled .kel.bin file, produced by keleusma compile
or by a build pipeline, skips the lex, parse, and compile phases:
#![allow(unused)]
fn main() {
let bytes = std::fs::read("script.kel.bin")?;
let mut vm = Vm::load_bytes(&bytes, &arena)?;
}
Vm::load_bytes validates the wire-format framing, runs structural
verification, runs resource-bounds verification, and returns the VM. A
framing failure is VmError::LoadError; an analysis failure is
VmError::VerifyError. The verification is the same as for a
source-compiled module; loading bytecode does not skip the safety
checks, only the compilation.
Loading signed bytecode
A module compiled from a signed entry function carries a
FLAG_REQUIRES_SIGNATURE bit, and Vm::load_bytes refuses it, directing
the caller to the signed path. A signed module loads through
Vm::load_signed_bytes, which takes a slice of trusted public keys:
#![allow(unused)]
fn main() {
let pub_bytes: [u8; 32] = std::fs::read("pub.bin")?.try_into().unwrap();
let key = ed25519_dalek::VerifyingKey::from_bytes(&pub_bytes)?;
let mut vm = Vm::load_signed_bytes(&signed_bytes, &arena, &[key])?;
}
The slice is the trust matrix. The module loads if its signature verifies against any key in the slice. An empty slice rejects every signed module. The matrix is copied onto the constructed VM, so later signed hot-swap loads inherit the same keys.
A host that boots from an unsigned baseline and accepts only signed updates afterward registers keys after construction:
#![allow(unused)]
fn main() {
let mut vm = Vm::new(unsigned_baseline_module, &arena)?;
vm.register_verifying_key(operator_key);
}
The trust-skip constructor
Vm::new_unchecked skips the resource-bounds verification. Structural
verification still runs, because the execution loop depends on it for
memory safety.
#![allow(unused)]
fn main() {
let vm = unsafe { Vm::new_unchecked(module, &arena) };
}
It is marked unsafe to capture a trust contract: the caller attests
that the bytecode’s resource bounds were verified earlier, at build time.
The intended use is a build pipeline that verifies once and ships
bytecode that need not be re-verified on every load. Using it to admit a
program that would fail the safe verifier is intentional misuse outside
the language’s guarantees, and it is documented as such. The bounded-time
and bounded-memory guarantees of Part V hold under Vm::new and weaken
to host attestation under Vm::new_unchecked.
What you now know
Vm::load_bytesloads a precompiled.kel.bin, verifying it the same as a source-compiled module.Vm::load_signed_bytesloads signed bytecode against a slice of trusted public keys.register_verifying_keyadds keys to a VM after construction.Vm::new_uncheckedskips the resource-bounds check under an explicit,unsafetrust contract.
The next chapter replaces a running module with a new one.