Main Abstraction
Engagement report · Case study

Access-control libraries for the Logos Execution Zone

Two foundational SPEL libraries, delivered from written requirement to verified on-chain deployment.

ClientLogos (open RFP)
ScopeRFP-001, RFP-002
StackRust · RISC Zero zkVM · SPEL / LEZ
Engagement2026
LicenseMIT and Apache 2.0

Every program on a new execution layer needs the same access-control building blocks. Without a shared, reviewed version, each team reimplements them by hand and each copy is audited separately. This engagement delivered two of those blocks, an admin authority and a freeze authority, as reusable libraries, and verified each privileged operation on a running chain.

Context

The Logos Execution Zone (LEZ) is an SVM-style execution layer that runs programs as RISC Zero guests. Programs require a standard mechanism to restrict privileged instructions to an authority, and a standard emergency stop. The platform uses a hash-based account model with no Solana-style on-curve distinction, so established patterns were reinterpreted for the target rather than ported, and the programs compile to a zkVM guest rather than to native code.

Deliverables

Figure 1. Test coverage by component (60 tests)
51015 admin-authority lib 19 freeze-authority lib 23 admin example 6 annotated examples 8 freeze example 4
Host unit and integration tests, run in CI on every push. Continuous integration is green; lint and format are clean.

Methodology

Each requirement was built test-first: a failing test, then the implementation. The sample programs were then compiled to RISC Zero guests, packaged in the R0BF binary format, and deployed to a locally run LEZ sequencer in standalone mode. Transactions were built and signed through the framework's CLI and submitted to the sequencer, with every result read back from on-chain account state and the execution log. Continuous integration runs the tests, format, and lint on every push.

Verification and results

Every privileged instruction in both libraries was exercised end to end on the sequencer, including the negative cases. Each row below corresponds to one or more submitted transactions whose effect was confirmed against on-chain account state and the execution log.

Figure 2. On-chain verification coverage
LibraryInstructionPositive pathRejection path
admininitializeverifiedn/a
set_counter (gated)verifiednon-admin, revoked
transfer_adminverifiedn/a
revoke_adminverifiedpost-revoke lockout
freezeinitializeverifiedn/a
freeze / unfreezeverifiedfrozen write blocked
set_freeze_authorityverifiedformer authority
revoke_freeze_authorityverifiedrevoked authority
freeze_accountverified (claim + cycle)n/a
unfreeze_accountverifiedn/a
All ten instructions and every rejection path verified on-chain. The admin lifecycle (set, transfer, revoke) and the freeze breaker (program-wide and per-account) were each driven through their full state space.
Figure 3. State machines exercised on-chain
ADMIN AUTHORITY UninitializedActive(A)Active(B)Revoked (None) initializetransferrevoke FREEZE BREAKER OperationalFrozen freezeunfreeze while Frozen: gated writes rejected, state unchanged
Both machines were driven through every transition on-chain, including the rejections that hold the invariants (a non-admin cannot act; a frozen program rejects gated writes and mutates no state).
Figure 4. Adversarial scenarios submitted on-chain
THE GATE non-admin calls a gated instruction former admin acts after a transfer any caller after revoke a gated write while the program is frozen a non-authority freezes the program rejected · 1008 rejected · 1008 rejected · 1008 rejected · 2002 rejected · 1008 no state change
Each adversarial attempt was submitted to the sequencer and rejected; rejected transactions changed no state. Codes are the libraries' namespaced errors (admin 10xx, freeze 20xx).

Two issues found and fixed

Running against a live sequencer surfaced two issues. The framework's CLI could not submit a class of instruction argument that its own code generator produces; we found the root cause, wrote the fix, verified it against the running chain, and prepared it as an upstream contribution. Separately, our own per-account freeze passed every unit test but failed on-chain on the first freeze of an account: the marker account was written before it was claimed, which the unit tests did not catch because they construct state directly. We corrected the handler to claim the marker on first use, rebuilt, redeployed, and reverified the full freeze, unfreeze, and re-freeze cycle.

Performance and overhead

The access-control check adds a fixed, predictable cost: one account reference per gated instruction (the config PDA), measured at 32 bytes, with no change to instruction data. Per-account freeze adds a second reference. The overhead therefore scales linearly with the number of gated instructions in a transaction and is independent of program logic.

Figure 5. Added transaction size vs. gated instructions
064128192 bytes added 2468 gated instructions in a transaction 32 B / instruction64 B (per-account)
Linear, program-independent overhead. Measured with the framework's dry-run against the generated IDL; storage is 33 bytes for the admin config and about 34 for the freeze config.

Outcome

Two access-control libraries, taken from a written requirement to a deployment verified on-chain.