Documentation Index
10 min readChapter 2

2. The Kortana Virtual Machine (KVM)

The Kortana Virtual Machine (KVM) is the low-level, high-performance execution engine designed specifically for the Kortana blockchain network. It serves as the target execution environment for smart contracts written in Quorlin, while maintaining full interoperability with Ethereum Virtual Machine (EVM) standards and tooling.

Unlike traditional stack-based virtual machines, the KVM adopts a register-based architecture combined with a fixed 32-bit instruction encoding scheme. By operating directly on a fixed set of general-purpose 256-bit registers, the KVM eliminates the stack manipulation overhead (such as PUSH, POP, SWAP, and DUP operations) characteristic of legacy stack architectures, enabling streamlined execution paths and reduced bytecode footprint.


2.1 Architectural Overview

The KVM is structured around three core concepts: native 256-bit word processing, a explicit register file, and state interaction via a host layer.

       +-------------------------------------------------------+
       |                  KVM Execution Engine                 |
       |                                                       |
       |  +------------------+        +---------------------+  |
       |  |  Register File   |        |  Constant Pool      |  |
       |  |  (r0 - r31)      |        |  (32-byte words)    |  |
       |  +------------------+        +---------------------+  |
       |                                                       |
       |  +-------------------------------------------------+  |
       |  |  Linear Memory Space (Byte-Addressable)         |  |
       |  +-------------------------------------------------+  |
       +--------------------------+----------------------------+
                                  |
                                  v
       +-------------------------------------------------------+
       |                     State Host                        |
       |                                                       |
       |  +-------------------+      +----------------------+  |
       |  | Unified State Trie|      | Call Dispatcher      |  |
       |  | (Storage Slots)   |      | (Inter-contract)     |  |
       |  +-------------------+      +----------------------+  |
       +-------------------------------------------------------+

Key Components:

  1. Register Bank (r0r31): 32 virtual registers, each capable of holding a native 256-bit unsigned or signed integer (uint256_t).
  2. Fixed Instruction Length: Every instruction is encoded into exactly 4 bytes (32 bits), formatted in big-endian byte order.
  3. Linear Memory: Byte-addressable, dynamically expandable memory workspace used for temporary data layout, array operations, and standard call payloads.
  4. Constant Pool: A specialized contiguous region inside the module binary containing 256-bit wide constants loaded via index rather than immediate inline values.
  5. State Host Interface: A unified abstraction layer bridging bytecode execution to Kortana's persistent world state trie and external contract dispatching.

2.2 KVM Binary Module Structure (.kvm)

A compiled KVM program is structured as a single contiguous binary module. The format enforces strict structural layout, fixed field sizes, and big-endian byte order throughout to simplify validation prior to module invocation.

Header Layout

The binary starts with an 18-byte fixed-size header (kHeaderSize = 18):

Offset (Bytes)Field SizeNameType / EncodingDescription
0..34 bytesmagicchar[4]Constant identifier bytes: "KVM\0"
4..52 bytesversionuint16_t (BE)KVM bytecode version specification
6..94 bytesconstant_countuint32_t (BE)Number of 32-byte entries in the Constant Pool
10..134 bytesinstruction_countuint32_t (BE)Total number of 32-bit instructions in the Code Section
14..174 bytesentry_pointuint32_t (BE)Instruction index where execution starts

Following the 18-byte header, the binary contains two contiguous data sections:

+-------------------------------------------------------------------+
|  Header (18 Bytes)                                                |
|  "KVM\0" | Version | Constant Count | Instruction Count | Entry   |
+-------------------------------------------------------------------+
|  Constant Pool Section                                            |
|  [32-Byte Word 0] [32-Byte Word 1] ... [32-Byte Word N-1]        |
+-------------------------------------------------------------------+
|  Code Section                                                     |
|  [4-Byte Instruction 0] [4-Byte Instruction 1] ... [Instruction M]|
+-------------------------------------------------------------------+
  1. Constant Pool: Array of size constant_count * 32 bytes. Each constant is a 256-bit integer stored in big-endian ordering.
  2. Code Section: Array of size instruction_count * 4 bytes. Each element represents a decoded 32-bit KVM instruction.

2.3 Instruction Set Architecture (ISA) & Formats

The KVM ISA uses a 32-bit instruction layout split into defined bit-fields. Registers are addressed using 5-bit identifiers (0 through 31).

Bit:   31       24 23     19 18     14 13      9 8               0
       +----------+---------+---------+---------+-----------------+
R-Type |  Opcode  |   Rd    |   Rs1   |   Rs2   |      Funct      |
       +----------+---------+---------+---------+-----------------+

I-Type |  Opcode  |   Rd    |   Rs1   |           Imm14           |
       +----------+---------+---------+---------------------------+

J-Type |  Opcode  |                    Imm24                      |
       +----------+-----------------------------------------------+

Bit-Field Definitions

  • Opcode (8 bits, Shift 24): Identifies the instruction operation.
  • Rd (5 bits, Shift 19, Mask 0x1F): Target destination register identifier.
  • Rs1 (5 bits, Shift 14, Mask 0x1F): First source register identifier.
  • Rs2 (5 bits, Shift 9, Mask 0x1F): Second source register identifier.
  • Funct (9 bits, Mask 0x1FF): Secondary function code for specialized arithmetic or bitwise modes.
  • Imm14 (14 bits, Mask 0x3FFF): Immediate 14-bit unsigned numeric payload.
  • Imm24 (24 bits, Mask 0xFFFFFF): Immediate 24-bit control flow target index or constant reference.

Instruction Formats Summary

FormatOperand TypesExample OpcodesDescription
Format::NoneNoneStop, Ret, InvalidZero-operand execution terminators or state aborts.
Format::RRd, Rs1, Rs2, FunctAdd, Sub, Mul, Div, Lt, Eq, And, MLoad, MStoreThree-register and two-register operations.
Format::IRd, Rs1, Imm14LoadIOperates on destination register using source register and a 14-bit immediate.
Format::JImm24Jump / Branch TargetsExecution relocations or absolute jumps specified via 24-bit imm.

2.4 256-Bit Arithmetic Engine

KVM handles 256-bit operations natively. Internal calculations use a four-limb representation (uint256_t) consisting of four 64-bit unsigned integers.

Signed Arithmetic Semantics

KVM standardizes signed operations (such as SDiv, SMod, SLt, SGt, and SignExtend) using two's complement representation.

Negative Value Identification

A word is identified as negative if its most significant bit (bit 255, located in limb 3) is set: $$\text{is_negative}(V) \iff (V.limb[3] \gg 63) \neq 0$$

Signed Comparison (SLt)

When evaluating $a < b$ under signed conditions:

  1. If the signs of $a$ and $b$ differ, the negative value is strictly smaller.
  2. If $a$ and $b$ share the same sign, standard unsigned magnitude ordering holds.

Signed Division Corner Case (signed_div)

Division by zero returns zero: $$\text{signed_div}(a, 0) = 0$$

For standard signed division ($a / b$), if $a = \text{INT_MIN}$ (where bit 255 is set and all other bits are 0: 0x8000000000000000000000000000000000000000000000000000000000000000) and $b = -1$ (0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF), calculating the true quotient results in $2^{255}$, which exceeds the representable 256-bit signed range. KVM handles this explicitly without throwing a machine fault, defining the result as: $$\text{signed_div}(\text{INT_MIN}, -1) = \text{INT_MIN}$$

Address and Word Conversion

Addresses in Kortana are 20 bytes (160 bits) in length. Conversion rules between addresses and 256-bit KVM words are deterministic:

  • Address to Word (address_to_word): Left-padded with 12 zero-bytes to form a 32-byte big-endian word.
  • Word to Address (address_from_word): Truncated to extract the lower 20 bytes (bytes offset 12 to 31) of the 32-byte word.

2.5 Gas Accounting and Execution Cost

Execution in KVM is gas-metered to ensure execution bounds. Every instruction consumes gas based on its computational complexity.

Cost Categories

+-------------------+---------------------------------------------------------+
| Cost Tier         | Covered Opcodes / Behavior                              |
+-------------------+---------------------------------------------------------+
| kGasZero (0)      | Stop, Return, Revert, Invalid                           |
| kGasVeryLow       | Add, Sub, Lt, Gt, SLt, SGt, Eq, IsZero, And, Or, Xor,    |
|                   | Not, Byte, Shl, Shr, Sar, Mov, LoadK, LoadI, MLoad,      |
|                   | MStore, MStore8, CallDataLoad                           |
| kGasLow           | Mul, Div, SDiv, Mod, SMod                               |
+-------------------+---------------------------------------------------------+

Gas Accounting Rules

  1. Halting Opcodes (Stop, Return, Revert): Priced at kGasZero base cost. This guarantees that contract execution termination costs remain uniform regardless of how a contract exits.
  2. Invalid Opcode (Invalid): Emits a kGasZero base cost metric during parsing, but during execution, the interpreter consumes all remaining gas allocated to the context, trapping the execution unit.
  3. Storage Access Gas (set_storage): Storage mutation is priced dynamically by querying the current state trie via StateHost. Mutating an empty slot (0 $\to$ non-zero) incurs a higher gas cost than overwriting an existing non-zero value.

2.6 StateHost and Unified State Trie Integration

The KVM interpreter communicates with the underlying Kortana state through a host context instance known as StateHost.

// Interaction model simplified from kvm/state_host.cpp class StateHost { public: Result<uint256_t> get_storage(const Address& address, const uint256_t& key) const; Result<uint256_t> set_storage(const Address& address, const uint256_t& key, const uint256_t& value); CallResult call(const CallRequest& request); private: state::WorldState& world_; BlockContext block_; ICallDispatcher* dispatcher_; };

Key Responsibilities of StateHost

  • Unified State Trie Interface: Reads and writes to persistent storage (get_storage, set_storage) interact directly with Kortana's core WorldState trie structure.
  • Cross-Contract Execution Dispatching: Inter-contract calls are forwarded through ICallDispatcher::dispatch, enabling KVM bytecode to call external contracts regardless of whether they are compiled from Quorlin or standard EVM bytecode.
  • Block Context Provisioning: Supplies environment parameters such as block height, timestamp, gas limit, and recent block hash lookups.

2.7 Pipeline: Quorlin Source to KVM Execution

To demonstrate how Quorlin source code compiles down to executable KVM module components, consider the following token contract written in Quorlin:

contract Vault { number totalAssets; map<address, number> assetBalances; event Deposit(address indexed user, number amount); constructor { totalAssets = 0; } reads number getBalance(address user) { return assetBalances[user]; } writes truth deposit(number amount) { require amount > 0, "invalid deposit amount"; number current = assetBalances[caller]; assetBalances[caller] = current + amount; totalAssets = totalAssets + amount; emit Deposit(caller, amount); return yes; } }

Compilation Stages

The Quorlin compiler processes this contract through four sequential phases:

Source (.ql) ---> [ 1. Lexer ] ---> Token Stream
                  [ 2. Parser ] ---> AST (SourceUnit)
                  [ 3. Sema ]   ---> Analyzed AST (Type Verification)
                  [ 4. Codegen] ---> KVM Binary Module (.kvm)
  1. Lexical Analysis (Lexer): Converts Quorlin source code text into a stream of typed Token structures, recognizing language keywords (contract, reads, writes, require, emit, caller).
  2. Syntactic Parsing (Parser): Translates tokens into an Abstract Syntax Tree (SourceUnit). Resolves high-level Quorlin types into concrete internal type bindings:
    • number $\to$ Type::U256 (ABI mapping: uint256)
    • truth $\to$ Type::Bool (ABI mapping: bool)
    • address $\to$ Type::Address (ABI mapping: address)
    • text $\to$ Type::Text (ABI mapping: string)
  3. Semantic Analysis (Analyzer): Performs type checking, verifies identifier declarations, ensures mutability compliance (checking that reads functions perform no state mutations), and calculates storage slot positions.
  4. Code Generation (CodeGenerator):
    • Generates fixed-width 32-bit instructions (r_form, i_form, j_form).
    • Registers constants into the KVM Constant Pool array.
    • Emits function entry points, dispatch tables based on EVM-compatible 4-byte selector hashes, and fixup instruction branch targets.
    • Emits the 18-byte .kvm module header alongside ABI declarations.

2.8 Type System & Ethereum ABI Compatibility

Although Quorlin uses developer-friendly type names, the ABI generator maps all types directly to standard Ethereum ABI representation to guarantee interoperability across external tooling, RPC providers, and wallet software.

Quorlin Keyword TypeInternal Type EnumEthereum ABI Type NameKVM Register Representation
numberType::U256"uint256"256-bit Unsigned Integer
truthType::Bool"bool"0 (no) or 1 (yes) in 256-bit word
addressType::Address"address"20-byte payload left-padded to 32 bytes
textType::Text"string"Pointer / Length reference in byte memory
nothingType::Void"void"Unused / No return value

Function Selector Computation

Function selectors in Quorlin are generated using the standard 4-byte Keccak-256 hash of the canonical function signature:

$$\text{Selector} = \text{Keccak256}(\text{"transfer(address,uint256)"})[0..3]$$

Because the ABI generator translates internal types to standard ABI names (e.g., using uint256 instead of number), Quorlin smart contracts maintain native compatibility with traditional EVM calls and ecosystem tools.