Archive Note: This document is historical and experimental. It is not normative for current T81 behavior. For authoritative definitions of ISA/VM behavior, refer to
../tisc-spec.mdand../t81vm-spec.md.
A Deterministic, Capability-Native, Axion-Governed Microkernel for T81-Class Machines
This archived reference captures the intended behavior of the Hanoi kernel proposal: architecture, boot flow, syscall interface, ABI, deterministic entropy model, CanonSeal key derivation, diagrams, and implementation scaffold.
This is the archived v0.1.1 snapshot.
Hanoi is a deterministic ternary microkernel serving as the constitutional OS substrate for the T81 ecosystem:
It is designed to be:
Hanoi is not a general-purpose OS.
It is the execution substrate for T81-class machines.
Violation of any invariant means the system is not Hanoi.
Result<T, HanoiError>.flowchart TD
HW["Ternary Hardware / Hanoi Simulator"]
TISC["TISC Execution Engine"]
K["Hanoi Kernel (Capability, CanonFS, Axion, Scheduler, Memory, Syscalls, DRBG/time)"]
U["Userland: T81VM + T81Lang Runtime"]
HW --> TISC --> K --> U
| Stage | Name | Action | Failure → |
|---|---|---|---|
| 0 | ROM Stub | Load first 729-tryte CanonBlock from boot medium | AXHALT |
| 1 | CanonVerify | Verify snapshot integrity via CanonHash-81 & CanonParity | AXHALT |
| 2 | Decompress | Inflate kernel image (LZ81/Z3std) → RAM | AXHALT |
| 3 | AxionSeal | Load Axion ethics module (Θ₁–Θ₉) and lock policies | AXHALT |
| 4 | CapabilityRoot | Mint root capability from snapshot hash | AXHALT |
| 5 | Mount CanonFS | Mount root snapshot at / (e.g., /snapshot/latest) |
AXHALT |
| 6 | Start T81VM | Exec CanonExec binary as PID 1 |
AXHALT |
| 7 | Enter Userspace | Begin deterministic global tick (Tick 0) | — |
On any failure:
AXHALT(reason):
freeze state → emit canonical lineage dump → halt permanently
sequenceDiagram
participant ROM as ROM Stub
participant Verify as CanonVerify
participant Axion as Axion Kernel
participant FS as CanonFS
participant VM as T81VM
ROM->>Verify: Load Boot Block
Verify->>Verify: Check CanonHash & Parity
Verify->>Axion: Load Kernel & Ethics Module
Axion->>Axion: Initialize Invariants (Θ₁–Θ₉)
Axion->>FS: Mount Root Snapshot
FS->>VM: Spawn PID 1 (CanonExec)
VM->>VM: Begin Execution (Tick 0)
Hanoi rejects Discretionary Access Control (DAC) and Access Control Lists (ACLs) in favor of Object Capabilities (OCap). Security is not a check on “who you are” but “what you hold”.
A capability is a tuple:
Cap := (ObjectRef, PermMask, ScopeID, AxionSig)
ObjectRef: CanonHash-81 of the target.PermMask: Bitmask of allowed operations (Read, Write, Exec, Grant).ScopeID: Topological region of the object graph.AxionSig: Cryptographic proof of validity.CapabilityRevoked.// Grant read access to a specific block
auto read_cap = kernel.grant_cap(target_block, PERM_READ);
if (!read_cap) return read_cap.error();
process.send(recipient_pid, *read_cap);
Storage is the single source of truth. By making the filesystem a Merkle-81 tree, the entire system state becomes a single hash.
CanonFS implements a content-addressed store.
Store: Hash -> CanonBlock
Writes do not mutate in place; they return a new SnapshotRef.
read_block fails with CanonCorruption.AXHALT).auto block = canonfs.read_block(file_hash);
// Automatically verified and repaired
Ethics and safety cannot be left to software conventions. They must be enforced by a privileged monitor that supervises execution.
Axion operates as a reference monitor M.
M(State, Op) -> { Allow, Deny(Reason), Rewrite(NewOp) }
AxionRejection.AXHALT).Nondeterministic interleaving is the root of most concurrency bugs. Hanoi schedules strictly by tick count.
Round-robin scheduling over 81 slots.
Schedule(Tick) -> Pid = ActivePids[Tick % 81]
State(Tick) is strictly a function of State(Tick-1).Manual memory management is unsafe. Hanoi uses a linear memory model backed by CanonFS for persistence.
Memory is a sequence of Pages.
Page := (CanonRef, Permissions)
Allocations are strictly strictly bump-pointer or COW from CanonFS.
auto region = memory.map_region(canon_ref, PERM_RW);
// region is now accessible in process address space
The kernel surface must be minimal and total. Every syscall returns a result, never undefined behavior.
Syscall: (OpCode, Args...) -> Result<Value, HanoiError>
Snapshots are the heart of Hanoi’s state management. A snapshot represents the entire persistent state of the system at a given moment.
stateDiagram-v2
[*] --> Pending: fork_snapshot()
Pending --> Committing: Axion Approval
Pending --> Discarded: Drop / Reject
Committing --> Active: switch_root()
Active --> Archived: new switch_root()
Active --> [*]: System Halt
Archived --> [*]: GC
auto fork_snapshot() -> expected<SnapshotRef, HanoiError>
Creates a mutable staging area (Copy-On-Write) from the current root. The new root is not yet visible to other processes.
CAP_SNAPSHOT_CREATE.auto commit_snapshot(SnapshotRef snapshot) -> expected<void, HanoiError>
Finalizes a pending snapshot, calculating the new Merkle root hash and persisting all dirty blocks.
snapshot is valid and owned by caller.
switch_root(snapshot: SnapshotRef)
-> Result<(), HanoiError>
Atomically:
This guarantees a fully immutable, deterministic root-switch.
All syscalls use the TISC syscall instruction. Arguments are passed in registers R0–R4. Return value in R0. Error code in R1 if R0 indicates failure.
| ID | Name | Signature | Notes |
|---|---|---|---|
| 0x00 | fork_snapshot | () -> Result<SnapshotRef, HanoiError> |
Create new snapshot root. |
| 0x01 | commit_snapshot | (snapshot) -> Result<(), HanoiError> |
Write snapshot to timeline. |
| 0x02 | switch_root | (snapshot) -> Result<(), HanoiError> |
Replace active snapshot (Axion-guarded). |
| 0x03 | spawn | (exec: CanonRef) -> Result<Pid, HanoiError> |
Launch T81VM instance. |
| 0x04 | read_block | (path) -> Result<ReadBlock, HanoiError> |
Auto-repair on read; ReadBlock includes repaired status. |
| 0x05 | read_object | (href) -> Result<CanonObject, HanoiError> |
Load + repair + decompress. |
| 0x06 | grant_cap | (cap) -> Result<CanonRef, HanoiError> |
Install capability. |
| 0x07 | revoke_cap | (href) -> Result<(), HanoiError> |
Publish tombstone. |
| 0x08 | yield_tick | () -> Result<(), HanoiError> |
Yield to next global tick. |
| 0x09 | map_region | (href) -> Result<RegionHandle, HanoiError> |
Map object. |
| 0x0A | seal_object | (href) -> Result<CanonRef, HanoiError> |
Wrap in CanonSeal. |
| 0x0B | unseal_object | (href) -> Result<CanonRef, HanoiError> |
Unseal using derived key. |
| 0x0C | drbg | () -> Result<DeterministicRandomTrytes, HanoiError> |
Deterministic entropy output. |
| 0x0D | parity_repair | (root) -> Result<(), HanoiError> |
Repair subtree. |
| 0x0E | halt | (reason) -> ! |
Permanent halt. |
Signature: fork_snapshot() -> expected<SnapshotRef, HanoiError>
CAP_SNAPSHOT_CREATE.Θ_RATE_LIMIT.auto sys_fork_snapshot() -> expected<SnapshotRef, HanoiError> {
auto current = fs::get_root();
auto new_cow = fs::cow_clone(current);
return new_cow.handle();
}
Signature: commit_snapshot(snapshot: SnapshotRef) -> expected<void, HanoiError>
snapshot - Handle to the pending snapshot.snapshot and has CAP_SNAPSHOT_COMMIT.auto sys_commit_snapshot(SnapshotRef handle) -> expected<void, HanoiError> {
auto snap = fs::get_pending(handle);
if (!snap) return unexpected(HanoiError::InvalidHandle);
if (auto err = axion::verify_integrity(*snap); !err)
return unexpected(err.error());
if (auto res = fs::persist(*snap); !res)
return unexpected(res.error());
return {};
}
Signature: switch_root(snapshot: SnapshotRef) -> expected<void, HanoiError>
snapshot - Handle to a committed snapshot.CAP_ROOT_SWITCH.snapshot is not in the canonical lineage or violates Θ_IMMUTABILITY.auto sys_switch_root(SnapshotRef handle) -> expected<void, HanoiError> {
auto snap = fs::get_committed(handle);
if (!snap) return unexpected(HanoiError::InvalidHandle);
if (auto err = axion::approve_transition(current_root(), *snap); !err)
return unexpected(err.error());
scheduler::suspend_all();
fs::set_root(*snap);
scheduler::resume_all();
return {};
}
Signature: spawn(exec: CanonRef) -> expected<Pid, HanoiError>
exec - Hash of the CanonExec object.CAP_EXEC for the object.auto sys_spawn(CanonRef exec_ref) -> expected<Pid, HanoiError> {
auto exec_obj = canonfs::load(exec_ref);
if (!exec_obj) return unexpected(exec_obj.error());
if (auto err = axion::verify_exec(*exec_obj); !err)
return unexpected(err.error());
auto pid = scheduler::allocate_slot();
if (!pid) return unexpected(pid.error());
Process process(*pid, *exec_obj);
scheduler::schedule(std::move(process));
return *pid;
}
Signature: read_block(path: CanonRef) -> expected<CanonBlock, HanoiError>
path - The content hash to read.CAP_READ for the object scope.auto sys_read_block(CanonRef hash) -> expected<CanonBlock, HanoiError> {
if (auto err = cap_mgr::check_access(hash, PERM_READ); !err)
return unexpected(err.error());
auto result = canonfs::fetch(hash);
if (!result && result.error() == HanoiError::Corrupt) {
return canonfs::repair(hash);
}
return result;
}
Signature: read_object(href: CanonRef) -> expected<CanonObject, HanoiError>
href - Object hash.CAP_READ.read_block but handles objects larger than 729 trytes (reassembly).auto sys_read_object(CanonRef hash) -> expected<CanonObject, HanoiError> {
auto root_block = sys_read_block(hash);
if (!root_block) return unexpected(root_block.error());
if (root_block->is_multi_part()) {
return canonfs::reassemble(*root_block);
} else {
return CanonObject::from(*root_block);
}
}
Signature: grant_cap(cap: Capability) -> expected<CanonRef, HanoiError>
cap - The capability structure to grant.CAP_GRANT on the target object.auto sys_grant_cap(Capability cap) -> expected<CanonRef, HanoiError> {
if (auto err = cap_mgr::verify_ownership(current_pid(), cap.object); !err)
return unexpected(err.error());
if (auto err = axion::verify_delegation(cap); !err)
return unexpected(err.error());
auto signed_cap = cap_mgr::sign(cap);
return canonfs::store(signed_cap);
}
Signature: revoke_cap(href: CanonRef) -> expected<void, HanoiError>
href - Hash of the capability to revoke.auto sys_revoke_cap(CanonRef cap_hash) -> expected<void, HanoiError> {
if (auto err = cap_mgr::verify_granter(current_pid(), cap_hash); !err)
return unexpected(err.error());
cap_mgr::emit_revocation_tombstone(cap_hash);
return {};
}
Signature: yield_tick() -> void
void sys_yield() {
scheduler::current_process().tick_budget = 0;
scheduler::schedule_next();
}
Signature: map_region(href: CanonRef) -> expected<RegionHandle, HanoiError>
href - Object to map into address space.CAP_READ (and CAP_WRITE if COW).auto sys_map_region(CanonRef hash) -> expected<RegionHandle, HanoiError> {
auto size = canonfs::get_size(hash);
if (!size) return unexpected(size.error());
if (auto err = mem_mgr::check_budget(current_pid(), *size); !err)
return unexpected(err.error());
auto vaddr = mem_mgr::find_free_range(*size);
if (!vaddr) return unexpected(vaddr.error());
mem_mgr::map(*vaddr, hash);
return *vaddr;
}
Signature: seal_object(href: CanonRef) -> expected<CanonRef, HanoiError>
href - Object to seal.auto sys_seal_object(CanonRef href) -> expected<CanonRef, HanoiError> {
auto obj = canonfs::get(href);
if (!obj) return unexpected(obj.error());
auto key = kdf::derive_seal_key(href, current_snapshot_hash());
auto sealed = crypto::aead_seal(key, *obj);
return canonfs::store(sealed);
}
Signature: unseal_object(href: CanonRef) -> expected<CanonRef, HanoiError>
href - Sealed object hash.auto sys_unseal_object(CanonRef href) -> expected<CanonRef, HanoiError> {
auto sealed = canonfs::get(href);
if (!sealed) return unexpected(sealed.error());
auto key = kdf::derive_seal_key(sealed->identity, current_snapshot_hash());
auto plain = crypto::aead_open(key, *sealed);
if (!plain) return unexpected(plain.error());
return canonfs::store(*plain);
}
Signature: drbg() -> DeterministicRandomTrytes
auto sys_drbg() -> std::array<Tryte, 81> {
return crypto::drbg_next(current_pid());
}
Signature: parity_repair(root: CanonRef) -> expected<void, HanoiError>
root - Root of the subtree to repair.auto sys_parity_repair(CanonRef root) -> expected<void, HanoiError> {
auto tree = canonfs::walk(root);
if (tree.is_damaged()) {
auto parity = canonfs::fetch_parity(root);
if (!parity) return unexpected(parity.error());
if (auto err = reedsolomon::reconstruct(tree, *parity); !err)
return unexpected(err.error());
}
return {};
}
Signature: halt(reason: Tryte) -> !
reason - Status code.[[noreturn]] void sys_halt(Tryte reason) {
auto pid = current_pid();
scheduler::terminate(pid, reason);
if (pid == 1) {
kernel::panic("System Halted: {}", reason);
}
scheduler::schedule_next();
}
HanoiError :=
AxionRejection // Policy violation
| CapabilityMissing // Not authorized
| CapabilityRevoked // Was authorized, now revoked
| CanonCorruption // Hash mismatch / unrecoverable
| CanonMismatch // Type expectation failure
| InvalidExec // Malformed binary
| OutOfMemory // Heap exhaustion
| RepairError // Parity reconstruction failed
| SealError // Crypto failure
Hanoi has no nondeterministic time and no nondeterministic entropy.
There is no:
drbg() -> Result<DeterministicRandomTrytes, HanoiError>
Returns 81 trytes of pseudo-random data.
The generator uses a sponge construction (SHAKE-81 equivalent) initialized at boot and re-keyed at every snapshot commit.
state[0] = SHAKE-tryte(
snapshot_root_hash
|| AxionΘ_hash
|| process.pid
|| capability_envelope_hash
)
next_random() {
state[i+1] = SHAKE-tryte(state[i])
return state[i+1]
}
This ensures:
There is only:
global_tick (incremented by scheduler)
No wall-clock time exists inside Hanoi. Time is measured in logic gates, not seconds.
CanonSeal AEAD keys are not stored in memory.
They are derived deterministically per object, per snapshot.
We use HKDF (HMAC-based Key Derivation Function) adapted for tryte sequences.
seal_key = HKDF-tryte(
input = snapshot_hash
|| object_hash
|| AxionΘ
|| cap_tag,
info = "CanonSeal-v0.1",
len = 81_trytes
)
Input:
[0; 81] (Null hash)[1; 81][0; 10]Output (First 9 trytes):
[A, B, C, -1, 0, 1, M, N, O] (Hypothetical deterministic output)
This eliminates key management vulnerabilities entirely.
struct Process {
Pid pid; // Tryte identifier
CanonRef exec; // Code reference
RegionHandle region; // Memory map
CapabilitySet caps; // Held capabilities
TISC_Addr pc; // Program counter
uint8_t tick_budget; // Remaining ticks in quantum
};
The address space is linear, 81-tryte aligned.
+-----------------------+
| Text (sealed) |
+-----------------------+
| Data (sealed/raw) |
+-----------------------+
| Heap (COW via CanonFS)|
+-----------------------+
| Stack (linear type) |
+-----------------------+
| Register | Usage |
|---|---|
| R0–R3 | Argument passing / Return values |
| R4–R9 | General purpose |
| SP | Stack Pointer (grows down) |
| FP | Frame Pointer |
| PC | Program Counter |
| TR | Ternary Flag Register (Compare results) |
| CR | Capability Register (Current capability context) |
CanonExec ::= {
magic: "T81EXEC",
entry: TISC_Addr,
text: CanonRef, // Pointer to code block
data: CanonRef, // Pointer to initial data
caps: CanonRef, // Required capabilities manifesto
meta: CanonRef // Debug/Symbol info
}
Kernel verifies all hashes and asks Axion for approval before loading.
flowchart TD
HW["Hardware / Simulator"] --> TISC["TISC Engine"] --> K["Hanoi Kernel"] --> U["Userland (T81VM/T81Lang)"]
flowchart LR
ROM["ROM"] --> Verify["CanonVerify"] --> Decomp["Decompress"] --> Seal["AxionSeal"] --> Cap["CapabilityRoot"] --> Mount["Mount CanonFS"] --> Spawn["Spawn VM"] --> Tick["Deterministic Tick"]
flowchart LR
P1["Process"] --> K1["Kernel"] --> A["Axion"] --> K2["Kernel"] --> P2["Process"]
flowchart LR
R["read(path)"] --> C["CanonFS"] --> PR["parity repair"] --> D["decompress"] --> X["decrypt"] --> O["deliver CanonBlock"]
hanoi-rs/
├── Cargo.toml
├── src/
│ ├── main.cpp
│ ├── kernel/
│ │ ├── boot.cpp
│ │ ├── scheduler.cpp
│ │ ├── capability.cpp
│ │ ├── canonfs.cpp
│ │ ├── memory.cpp
│ │ ├── syscall.cpp
│ │ ├── axion.cpp
│ │ └── error.cpp
│ ├── tisc/
│ │ ├── execution.cpp
│ │ ├── registers.cpp
│ │ └── decoder.cpp
│ ├── drivers/
│ └── utils/
│ ├── base81.cpp
│ ├── tryte.cpp
│ └── parity.cpp
├── include/
│ ├── kernel/
│ │ ├── boot.hpp
│ │ ├── scheduler.hpp
│ │ ├── capability.hpp
│ │ ├── canonfs.hpp
│ │ ├── memory.hpp
│ │ ├── syscall.hpp
│ │ ├── axion.hpp
│ │ └── error.hpp
│ ├── tisc/
│ │ ├── execution.hpp
│ │ ├── registers.hpp
│ │ └── decoder.hpp
│ └── utils/
│ ├── base81.hpp
│ ├── tryte.hpp
│ └── parity.hpp
├── tests/
│ ├── boot_test.cpp
│ ├── syscall_test.cpp
│ ├── canonfs_test.cpp
│ └── axion_test.cpp
└── README.md
| Target | Status | Notes |
|---|---|---|
| Hanoi Simulator | Complete | Cycle-accurate reference impl |
| QEMU HanoiVM fork | Complete | x86-64 host emulation |
| Ternary FPGA board | Q1 2026 | Ice40-based proof of concept |
| Photonic T81 Core | Q3 2026 | Partner R&D (Experimental) |
With v0.1.1:
This document is retained for design history and does not supersede active normative specifications.