Presentamos Achronyme — un lenguaje para pruebas zero-knowledge. Lee el anuncio arrow_right_alt

Akron VM y Bytecode

Máquina virtual de propósito general basada en registros: opcodes, codificación de valores y formato binario.

Akron es la VM de bytecode de propósito general de Achronyme — un intérprete basado en registros que ejecuta archivos .achb producidos por el compilador de bytecode. Corre el lenguaje Achronyme en tiempo de ejecución (ach run) y evalúa bloques prove {} en modo VM.

Akron está emparejado con Artik, la VM dedicada a cómputo de testigos. La división es intencional: Akron maneja scripting y estado de heap mutable con GC, mientras que Artik maneja la matemática de testigos sin efectos secundarios, sin heap ni GC.

Arquitectura

Fuente (.ach)
    |
    v
Compilador de Bytecode -> Prototipos de funcion + bytecode
    |
    v
Serializador -> archivo binario .achb
    |
    v
Cargador -> heap + pila + frames de Akron
    |
    v
Interprete -> Ejecucion basada en registros

Estructura de la VM

Akron {
    heap: Heap,              // arenas tipadas + GC
    stack: [Value; 65536],   // pila de registros fija
    frames: Vec<CallFrame>,  // pila de llamadas
    globals: Vec<GlobalEntry>,  // variables globales
    natives: Vec<NativeObj>,    // funciones integradas
    open_upvalues: lista enlazada, // variables de pila capturadas
    stress_mode: bool,          // forzar GC en cada ciclo
}

Frames de Llamada

Cada llamada a función apila un CallFrame:

CallFrame {
    closure: u32,   // handle a Closure en el heap
    ip: usize,      // puntero de instruccion
    base: usize,    // offset base en la pila
    dest_reg: usize, // donde almacenar el valor de retorno
}

El registro R[i] en el frame actual mapea a stack[frame.base + i].

Representación de Valores

Los valores son enteros de 64 bits etiquetados — sin boxing para tipos comunes:

Bits 63..60 = etiqueta de 4 bits
Bits 59..0  = payload de 60 bits

Etiquetas

EtiquetaNombrePayload
0INTentero con signo i60 (en linea)
1NIL-
2FALSE-
3TRUE-
4STRINGhandle u32 -> arena de strings
5LISThandle u32 -> arena de listas
6MAPhandle u32 -> arena de mapas
7FUNCTIONhandle u32 -> arena de funciones
8FIELDhandle u32 -> arena de campos
9PROOFhandle u32 -> arena de pruebas
10NATIVEhandle u32 -> tabla de nativos
11CLOSUREhandle u32 -> arena de closures
12ITERhandle u32 -> arena de iteradores
14BYTEShandle u32 -> arena de bytes (constantes ProveIR)
15CIRCOM_HANDLEhandle u32 -> plantillas Circom

Los enteros (etiqueta 0) son el tipo mas comun — usar la etiqueta 0 significa que no se necesita enmascaramiento para el caso comun.

Rango de enteros: -2^59 a 2^59 - 1 (576,460,752,303,423,487). El desbordamiento genera IntegerOverflow.

Codificación de Instrucciones

Cada instrucción es un u32 en uno de dos formatos:

Formato ABC

[opcode:8][A:8][B:8][C:8]

Usado para instrucciones de 3 operandos como Add R[A] = R[B] + R[C].

Formato ABx

[opcode:8][A:8][Bx:16]

Usado para instrucciones con un operando de 16 bits, como LoadConst R[A] = K[Bx] o Jump IP = Bx.

Opcodes

Constantes y Movimientos

OpcodeCodigoFormatoDescripcion
LoadConst0ABxR[A] = K[Bx] — cargar del pool de constantes
LoadTrue1AR[A] = true
LoadFalse2AR[A] = false
LoadNil3AR[A] = nil
Move5ABR[A] = R[B]

Aritmética

OpcodeCodigoFormatoDescripcion
Add10ABCR[A] = R[B] + R[C]
Sub11ABCR[A] = R[B] - R[C]
Mul12ABCR[A] = R[B] * R[C]
Div13ABCR[A] = R[B] / R[C]
Mod14ABCR[A] = R[B] % R[C]
Pow15ABCR[A] = R[B] ^ R[C]
Neg16ABR[A] = -R[B]

Comparación y Lógica

OpcodeCodigoFormatoDescripcion
Eq20ABCR[A] = R[B] == R[C]
Lt21ABCR[A] = R[B] < R[C]
Gt22ABCR[A] = R[B] > R[C]
NotEq23ABCR[A] = R[B] != R[C]
Le24ABCR[A] = R[B] <= R[C]
Ge25ABCR[A] = R[B] >= R[C]
LogNot26ABR[A] = !R[B]

Closures y Upvalues

OpcodeCodigoFormatoDescripcion
GetUpvalue34ABR[A] = Upvalue[B]
SetUpvalue35ABUpvalue[B] = R[A]
CloseUpvalue36ACerrar upvalue en slot de pila A

Funciones

OpcodeCodigoFormatoDescripcion
Return54ARetornar R[A] del frame actual
Call55ABCR[A] = Call(R[B], R[B+1]..R[B+C-1])
Closure56ABxR[A] = Closure(K[Bx])

Flujo de Control

OpcodeCodigoFormatoDescripcion
Jump60BxIP = Bx
JumpIfFalse61ABxSi !R[A] entonces IP = Bx
GetIter65ABR[A] = Iterator(R[B])
ForIter66ABxSiguiente elemento o saltar a Bx

Globales

OpcodeCodigoFormatoDescripcion
DefGlobalVar98ABxDefinir global mutable
DefGlobalLet99ABxDefinir global inmutable
GetGlobal100ABxR[A] = Global[K[Bx]]
SetGlobal101ABxGlobal[K[Bx]] = R[A]
Print102AImprimir R[A]

Estructuras de Datos

OpcodeCodigoFormatoDescripcion
BuildList150ABCR[A] = [R[B]..R[B+C-1]]
BuildMap151ABCR[A] = {R[B]:R[B+1], ...}
GetIndex152ABCR[A] = R[B][R[C]]
SetIndex153ABCR[A][R[B]] = R[C]

ZK y Despacho

OpcodeCodigoFormatoDescripcion
Prove160-Compilar + verificar circuito ZK
MethodCall161ABCDespacho de metodo R[A] = R[B].metodo(args)
CallCircomTemplate162ABCInvocar un handle de plantilla Circom registrado

Especiales

OpcodeCodigoDescripcion
Nop255Sin operacion

Objetos de Función

Cada función compilada produce un struct Function en el heap:

Function {
    name: String,        // para depuracion
    arity: u8,           // conteo de parametros
    max_slots: u16,      // uso pico de registros
    chunk: Vec<u32>,     // instrucciones de bytecode
    constants: Vec<Value>, // pool de constantes
    upvalue_info: Vec<u8>, // pares [is_local, index]
    line_info: Vec<u32>, // numero de linea por instruccion
}

El vector line_info es paralelo a chunk — cada instrucción tiene un número de línea fuente para reporte de errores.

Formato Binario (.achb)

El formato de archivo .achb (versión 9):

Magic:    b"ACH\x09"          (4 bytes)
Metadata: max_slots (u16 LE)

Global Strings:
    count (u32 LE)
    por cada uno: length (u32 LE) + bytes UTF-8

Global Constants:
    count (u32 LE)
    por cada uno: tag (u8) + payload
        INT (0):    i64 LE
        STRING (1): handle u32 LE
        FIELD (8):  4 x u64 LE (limbs Montgomery)
        BYTES (14): u32 LE length + bytes (blobs ProveIR)
        NIL (255):  (sin payload)

Prototypes:
    count (u32 LE)
    por cada uno:
        name_len (u32 LE) + bytes del nombre
        arity (u8)
        max_slots (u16 LE)
        const_count (u32 LE) + constantes
        upvalue_count (u32 LE) + info de upvalue
        bytecode_len (u32 LE) + instrucciones (u32 LE cada una)

Main Bytecode:
    instruction_count (u32 LE)
    instrucciones (u32 LE cada una)

El formato es compatible con el módulo loader de Akron, que deserializa en objetos del heap.

Disposición de Variables Globales

Indice: 0..22       23..
        Nativos     Globales de usuario

Los primeros 23 slots (0-22) están reservados para funciones nativas. Las globales definidas por el usuario comienzan en el índice 23 (USER_GLOBAL_START).

Relación con Artik

Akron y Artik son VMs hermanas con roles disjuntos:

AkronArtik
Scripting de proposito general + prove {}Computo de testigos para circuitos
Valores etiquetados, 13+ tiposSolo field elements + enteros de ancho fijo
GC mark-sweep, arenas tipadasSin heap, sin GC
~40 opcodes, formato de 3 operandos~25 opcodes, registros tipados
Invocado por ach run, modo VMDespachado desde R1CS witness-gen (WitnessOp::ArtikCall)

Ver VM de Testigos Artik para los detalles del camino de testigos.

Archivos Fuente

ComponenteArchivo
Opcodesakron/src/opcode.rs
Interprete VMakron/src/machine/vm.rs
Frames de llamadaakron/src/machine/frame.rs
Bucle del interpreteakron/src/machine/interpreter.rs
Despacho de nativosakron/src/specs.rs
Metodos de prototipoakron/src/machine/methods/
Codificacion de valoresmemory/src/value.rs
Struct Functionmemory/src/heap.rs
Compilador de bytecodeakronc/src/codegen.rs
Compilador de funcionesakronc/src/function_compiler.rs
Serializador binariocli/src/commands/compile.rs
Cargador binarioakron/src/loader.rs
Navigation