TritFS: Designing a Filesystem
for Ternary Storage

What changes when storage addresses use trits instead of bits — from inode design and space allocation to journalling semantics and character encoding. Building the bridge between raw ternary storage and usable data.

The Filesystem Problem

A filesystem is the bridge between raw storage and structured data. It answers the questions every program asks: Where is my file? How large is it? Which blocks on disk belong to it? Is this block free or occupied? What is the file's name, and how do I find it in a directory hierarchy?

Every modern filesystem — ext4, NTFS, APFS, ZFS — answers these questions assuming binary addressing. Block addresses are binary integers. Free-space maps are bitmaps (one bit per block: free or used). Inode numbers are binary. Directory entries are indexed by binary hash functions.

None of these assumptions hold when storage is ternary. If the underlying hardware uses balanced ternary addressing — as the PANINI processor and T3ISA define — then the filesystem must be redesigned from first principles. That is what TritFS does.

Trit-Based Addressing: 3n Instead of 2n

In binary, an n-bit address can reference 2n locations. In balanced ternary, an n-trit address references 3n locations — but with a twist. Balanced ternary addresses are signed: they range from −(3n−1)/2 to +(3n−1)/2, centred on zero.

Address WidthBinary RangeBalanced Ternary RangeTernary Locations
80 to 255−3,280 to +3,2806,561
160 to 65,535−21.5M to +21.5M43,046,721
270 to 134M−3.8T to +3.8T7.6 × 1012
Table 1: Address space comparison. A 27-trit ternary address covers 7.6 trillion locations — 56x more than a 27-bit binary address.

The 27-trit address width is not arbitrary — it matches the T3ISA register width (33 = 27 trits per register), so a single register holds a full address. The resulting address space of 327 = 7,625,597,484,987 locations is vastly larger than the equivalent binary width, which is one of the density advantages of ternary encoding.

Inode Design Considerations

In traditional Unix filesystems, an inode is a fixed-size data structure that describes a file: its size, permissions, timestamps, and the list of data blocks it occupies. The inode number is a binary integer used as an index into the inode table.

In TritFS, inode numbers are balanced ternary values. This has a subtle but important consequence: inode 0 is a valid, usable inode, not a sentinel value. In many binary filesystems, inode 0 is reserved or unused because zero is treated as "null." In balanced ternary, zero is just the middle value — it has no special null semantics. If you need a null sentinel, you can use a value outside the valid range, but you do not lose inode 0.

The inode itself stores block pointers as balanced ternary addresses. Direct block pointers, single-indirect, and double-indirect pointers follow the same hierarchy as traditional Unix inodes — but each pointer is a trit-addressed value pointing into the ternary block space.

Space Allocation: Beyond Bitmaps

Binary filesystems track free space using bitmaps: one bit per block, where 0 means free and 1 means allocated (or vice versa). This is efficient because each bit is the minimum unit of information needed to track a two-state property.

In a ternary filesystem, each block position in the allocation map holds a trit — three states instead of two. The obvious question is: what does the third state represent?

Two states (free and allocated) are sufficient for basic block tracking. But filesystems have long struggled with intermediate states — blocks that are "in transition" during a write operation, blocks reserved for a file that is being extended, or blocks that are being freed but cannot be reused until a journal commit completes. In binary bitmaps, these intermediate states require separate data structures or journal entries to track.

A ternary allocation map offers a natural third state, eliminating the need for some of these auxiliary structures. The specific semantics of the three states in TritFS are defined in Patent P8, but the principle is straightforward: three states in the hardware should be reflected in three states in the allocation map.

Journalling with Three States

Journalling filesystems protect against data corruption by recording intended changes before applying them. The journal entry lifecycle in a binary filesystem is typically two-state: a transaction is either "committed" or "not committed." Some filesystems add soft states (e.g., ext4's "running," "committing," "finished"), but these are encoded as multi-bit fields, not single-bit flags.

With a trit-state journal, each transaction entry inherently supports three states in its most basic flag field. Consider the general problem: a filesystem operation (say, writing a block) needs to transition through stages — intent recorded, data written, metadata updated. In a binary journal, tracking these stages requires multiple flag bits or sequential log entries. A ternary journal flag can encode three stages in a single trit.

The specific three-state journalling protocol used in TritFS is the subject of Patent P8, Claims 7-8. What I can say here is that the protocol reduces journal overhead compared to binary equivalents by encoding more state information per journal entry field.

The ASCII Encoding Challenge

Filesystems store filenames, and filenames are character strings. ASCII defines 128 characters (7-bit encoding). How do you encode ASCII in balanced ternary?

The mathematics is direct:

How many trits to encode 128 characters?

  log₃(128) = ln(128) / ln(3) ≈ 4.42

  → 4 trits encode 3⁴ = 81 values  (not enough)
  → 5 trits encode 3⁵ = 243 values (sufficient!)

  5 trits per character, with 243 − 128 = 115 spare codes
  available for ternary-native extensions.

Five trits per ASCII character is slightly more efficient than 7 bits when measured in information density: 5 trits carry 5 × log2(3) = 7.92 bits of information, encoding 128 characters with room to spare. The 115 unused codes can accommodate extended character sets, control sequences, or ternary-specific symbols without needing a separate encoding like UTF-8.

TritFS filenames use this 5-trit-per-character encoding. Maximum filename length follows from the directory entry size, which is defined in trit-aligned units.

Directory Structure: Enter the Trit-Trie

Directory lookup — finding a file by name — is one of the most performance-critical filesystem operations. Binary filesystems use various strategies: linear search (simple but slow), hash tables (fast but unordered), or B-trees (ordered and fast, but complex).

For a ternary filesystem with trit-encoded filenames, there is a natural data structure: the trie (prefix tree), where each node has exactly three children — one per trit value (−1, 0, +1). This "trit-trie" provides O(k) lookup time where k is the key length, with no hash collisions and natural lexicographic ordering.

The trit-trie is sufficiently important that it has its own patent (P9) and its own blog post (coming soon). TritFS Claim 9 explicitly references the trit-trie as the directory index structure, creating a continuation dependency between P8 and P9.

What TritFS Defines

Putting it all together, TritFS specifies:

The complete specification is Patent P8, filed under IPC G06F 16/10 (file systems). TritFS is not a theoretical exercise — it is the filesystem that THATTE-OS uses for persistent storage, and its structures are compiled into the kernel's mem.t3b module.

Key Takeaways
  • Ternary addressing gives 3n locations per n-trit address — exponentially denser than binary
  • Ternary allocation maps offer a natural third state for block status tracking
  • ASCII encodes in 5 trits per character (243 codes), with 115 spare codes for extensions
  • Trit-tries (Patent P9) provide O(k) directory lookup with no hash collisions
  • TritFS is the first filesystem designed from scratch for balanced ternary storage hardware
← PANINI 3-FET SRAM CVD Chirality Control →