diff --git a/src/lib.zig b/src/lib.zig index 99f06139..a62cc5be 100644 --- a/src/lib.zig +++ b/src/lib.zig @@ -1,5 +1,6 @@ pub const vm = struct { pub usingnamespace @import("vm/core.zig"); + pub usingnamespace @import("vm/core_test.zig"); pub usingnamespace @import("vm/config.zig"); pub usingnamespace @import("vm/error.zig"); pub usingnamespace @import("vm/instructions.zig"); diff --git a/src/math/crypto/signatures.zig b/src/math/crypto/signatures.zig new file mode 100644 index 00000000..23ba0273 --- /dev/null +++ b/src/math/crypto/signatures.zig @@ -0,0 +1,14 @@ +const std = @import("std"); +const Felt252 = @import("../fields/starknet.zig"); + +const ArrayList = std.ArrayList; + +/// Stark ECDSA signature +pub const Signature = struct { + const Self = @This(); + + /// The `r` value of a signature + r: ArrayList(Felt252), + /// The `s` value of a signature + s: ArrayList(Felt252), +}; diff --git a/src/vm/builtins/bitwise/bitwise.zig b/src/vm/builtins/bitwise/bitwise.zig index 6c6ef4a0..60bec3dc 100644 --- a/src/vm/builtins/bitwise/bitwise.zig +++ b/src/vm/builtins/bitwise/bitwise.zig @@ -17,7 +17,11 @@ const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; // ***************************************************************************** // Error type to represent different error conditions during bitwise builtin. -pub const Error = error{ InvalidBitwiseIndex, UnsupportedNumberOfBits, InvalidAddressForBitwise }; +pub const BitwiseError = error{ + InvalidBitwiseIndex, + UnsupportedNumberOfBits, + InvalidAddressForBitwise, +}; /// Each bitwise operation consists of 5 cells (two inputs and three outputs - and, or, xor). // comment credit to: https://github.com/starkware-libs/cairo-lang/blob//src/starkware/cairo/lang/builtins/bitwise/instance_def.py#L4 @@ -32,17 +36,17 @@ const BITWISE_INPUT_CELLS_PER_INSTANCE = 2; /// - memory: The cairo memory where addresses are looked up /// # Returns /// The felt as an integer. -fn getValue(address: Relocatable, memory: *Memory) Error!u256 { +fn getValue(address: Relocatable, memory: *Memory) BitwiseError!u256 { var value = memory.get(address) catch { - return Error.InvalidAddressForBitwise; + return BitwiseError.InvalidAddressForBitwise; }; var felt = value.tryIntoFelt() catch { - return Error.InvalidAddressForBitwise; + return BitwiseError.InvalidAddressForBitwise; }; if (felt.toInteger() > std.math.pow(u256, 2, BITWISE_TOTAL_N_BITS)) { - return Error.UnsupportedNumberOfBits; + return BitwiseError.UnsupportedNumberOfBits; } return felt.toInteger(); @@ -54,16 +58,16 @@ fn getValue(address: Relocatable, memory: *Memory) Error!u256 { /// - memory: The cairo memory where addresses are looked up /// # Returns /// The deduced value as a `MaybeRelocatable` -pub fn deduce(address: Relocatable, memory: *Memory) Error!MaybeRelocatable { +pub fn deduce(address: Relocatable, memory: *Memory) BitwiseError!MaybeRelocatable { const index = address.offset % CELLS_PER_BITWISE; if (index < BITWISE_INPUT_CELLS_PER_INSTANCE) { - return Error.InvalidBitwiseIndex; + return BitwiseError.InvalidBitwiseIndex; } // calculate offset const x_offset = address.subUint(index) catch { - return Error.InvalidBitwiseIndex; + return BitwiseError.InvalidBitwiseIndex; }; const y_offset = try x_offset.addUint(1); @@ -74,7 +78,7 @@ pub fn deduce(address: Relocatable, memory: *Memory) Error!MaybeRelocatable { 2 => x & y, // and 3 => x ^ y, // xor 4 => x | y, // or - else => return Error.InvalidBitwiseIndex, + else => return BitwiseError.InvalidBitwiseIndex, }; return MaybeRelocatable{ .felt = Felt252.fromInteger(res) }; @@ -97,7 +101,7 @@ test "deduce when address.offset less than BITWISE_INPUT_CELLS_PER_INSTANCE" { var address = Relocatable.new(0, 5); // then - try expectError(Error.InvalidBitwiseIndex, deduce(address, mem)); + try expectError(BitwiseError.InvalidBitwiseIndex, deduce(address, mem)); } test "deduce when address points to nothing in memory" { @@ -111,7 +115,7 @@ test "deduce when address points to nothing in memory" { var address = Relocatable.new(0, 3); // then - try expectError(Error.InvalidAddressForBitwise, deduce(address, mem)); + try expectError(BitwiseError.InvalidAddressForBitwise, deduce(address, mem)); } test "deduce when address points to relocatable variant of MaybeRelocatable " { @@ -127,7 +131,7 @@ test "deduce when address points to relocatable variant of MaybeRelocatable " { try mem.set(Relocatable.new(0, 5), newFromRelocatable(address)); // then - try expectError(Error.InvalidAddressForBitwise, deduce(address, mem)); + try expectError(BitwiseError.InvalidAddressForBitwise, deduce(address, mem)); } test "deduce when address points to felt greater than BITWISE_TOTAL_N_BITS" { @@ -147,7 +151,7 @@ test "deduce when address points to felt greater than BITWISE_TOTAL_N_BITS" { ), fromU256(number)); // then - try expectError(Error.UnsupportedNumberOfBits, deduce(address, mem)); + try expectError(BitwiseError.UnsupportedNumberOfBits, deduce(address, mem)); } // happy path tests graciously ported from https://github.com/lambdaclass/cairo-vm_in_go/blob/main/pkg/builtins/bitwise_test.go#L13 diff --git a/src/vm/builtins/builtin_runner/bitwise.zig b/src/vm/builtins/builtin_runner/bitwise.zig new file mode 100644 index 00000000..b44199a7 --- /dev/null +++ b/src/vm/builtins/builtin_runner/bitwise.zig @@ -0,0 +1,61 @@ +const bitwise_instance_def = @import("../../types/bitwise_instance_def.zig"); + +/// Bitwise built-in runner +pub const BitwiseBuiltinRunner = struct { + const Self = @This(); + + /// Ratio + ratio: ?u32, + /// Base + base: usize, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Built-in bitwise instance + bitwise_builtin: bitwise_instance_def.BitwiseInstanceDef, + /// Stop pointer + stop_ptr: ?usize, + /// Included boolean flag + included: bool, + /// Number of instance per component + instances_per_component: u32, + + /// Create a new BitwiseBuiltinRunner instance. + /// + /// This function initializes a new `BitwiseBuiltinRunner` instance with the provided + /// `instance_def` and `included` values. + /// + /// # Arguments + /// + /// - `instance_def`: A pointer to the `BitwiseInstanceDef` for this runner. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `BitwiseBuiltinRunner` instance. + pub fn new( + instance_def: *bitwise_instance_def.BitwiseInstanceDef, + included: bool, + ) Self { + return .{ + .ratio = instance_def.ratio, + .base = 0, + .cell_per_instance = bitwise_instance_def.CELLS_PER_BITWISE, + .n_input_cells = bitwise_instance_def.INPUT_CELLS_PER_BITWISE, + .bitwise_builtin = instance_def, + .stop_ptr = null, + .included = included, + .instances_per_component = 1, + }; + } + + /// Get the base value of this runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/builtin_runner.zig b/src/vm/builtins/builtin_runner/builtin_runner.zig new file mode 100644 index 00000000..4d801fa2 --- /dev/null +++ b/src/vm/builtins/builtin_runner/builtin_runner.zig @@ -0,0 +1,54 @@ +const BitwiseBuiltinRunner = @import("./bitwise.zig").BitwiseBuiltinRunner; +const EcOpBuiltinRunner = @import("./ec_op.zig").EcOpBuiltinRunner; +const HashBuiltinRunner = @import("./hash.zig").HashBuiltinRunner; +const KeccakBuiltinRunner = @import("./keccak.zig").KeccakBuiltinRunner; +const OutputBuiltinRunner = @import("./output.zig").OutputBuiltinRunner; +const PoseidonBuiltinRunner = @import("./poseidon.zig").PoseidonBuiltinRunner; +const RangeCheckBuiltinRunner = @import("./range_check.zig").RangeCheckBuiltinRunner; +const SegmentArenaBuiltinRunner = @import("./segment_arena.zig").SegmentArenaBuiltinRunner; +const SignatureBuiltinRunner = @import("./signature.zig").SignatureBuiltinRunner; + +/// Built-in runner +pub const BuiltinRunner = union(enum) { + const Self = @This(); + + /// Bitwise built-in runner for bitwise operations. + Bitwise: BitwiseBuiltinRunner, + /// EC Operation built-in runner for elliptic curve operations. + EcOp: EcOpBuiltinRunner, + /// Hash built-in runner for hash operations. + Hash: HashBuiltinRunner, + /// Output built-in runner for output operations. + Output: OutputBuiltinRunner, + /// Range Check built-in runner for range check operations. + RangeCheck: RangeCheckBuiltinRunner, + /// Keccak built-in runner for Keccak operations. + Keccak: KeccakBuiltinRunner, + /// Signature built-in runner for signature operations. + Signature: SignatureBuiltinRunner, + /// Poseidon built-in runner for Poseidon operations. + Poseidon: PoseidonBuiltinRunner, + /// Segment Arena built-in runner for segment arena operations. + SegmentArena: SegmentArenaBuiltinRunner, + + /// Get the base value of the built-in runner. + /// + /// This function returns the base value specific to the type of built-in runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn base(self: *const Self) usize { + return switch (self.*) { + .Bitwise => |*bitwise| bitwise.get_base(), + .EcOp => |*ec| ec.get_base(), + .Hash => |*hash| hash.get_base(), + .Output => |*output| output.get_base(), + .RangeCheck => |*range_check| range_check.get_base(), + .Keccak => |*keccak| keccak.get_base(), + .Signature => |*signature| signature.get_base(), + .Poseidon => |*poseidon| poseidon.get_base(), + .SegmentArena => |*segment_arena| segment_arena.get_base(), + }; + } +}; diff --git a/src/vm/builtins/builtin_runner/ec_op.zig b/src/vm/builtins/builtin_runner/ec_op.zig new file mode 100644 index 00000000..19c314e7 --- /dev/null +++ b/src/vm/builtins/builtin_runner/ec_op.zig @@ -0,0 +1,72 @@ +const std = @import("std"); +const ec_op_instance_def = @import("../../types/ec_op_instance_def.zig"); +const relocatable = @import("../../memory/relocatable.zig"); +const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; + +const AutoHashMap = std.AutoHashMap; +const Allocator = std.mem.Allocator; + +/// EC Operation built-in runner +pub const EcOpBuiltinRunner = struct { + const Self = @This(); + + /// Ratio + ratio: ?u32, + /// Base + base: usize, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Built-in EC Operation instance + ec_op_builtin: ec_op_instance_def.EcOpInstanceDef, + /// Stop pointer + stop_ptr: ?usize, + /// Included boolean flag + included: bool, + /// Number of instance per component + instances_per_component: u32, + /// Cache + cache: AutoHashMap(relocatable.Relocatable, Felt252), + + /// Create a new ECOpBuiltinRunner instance. + /// + /// This function initializes a new `EcOpBuiltinRunner` instance with the provided + /// `allocator`, `instance_def`, and `included` values. + /// + /// # Arguments + /// + /// - `allocator`: An allocator for initializing the cache. + /// - `instance_def`: A pointer to the `EcOpInstanceDef` for this runner. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `EcOpBuiltinRunner` instance. + pub fn new( + allocator: Allocator, + instance_def: *ec_op_instance_def.EcOpInstanceDef, + included: bool, + ) Self { + return .{ + .ratio = instance_def.ratio, + .base = 0, + .n_input_cells = ec_op_instance_def.INPUT_CELLS_PER_EC_OP, + .cell_per_instance = ec_op_instance_def.CELLS_PER_EC_OP, + .ec_op_builtin = instance_def, + .stop_ptr = null, + .included = included, + .instances_per_component = 1, + .cache = AutoHashMap(relocatable.Relocatable, Felt252).init(allocator), + }; + } + + /// Get the base value of this runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/hash.zig b/src/vm/builtins/builtin_runner/hash.zig new file mode 100644 index 00000000..6095ee57 --- /dev/null +++ b/src/vm/builtins/builtin_runner/hash.zig @@ -0,0 +1,67 @@ +const std = @import("std"); +const pedersen_instance_def = @import("../../types/pedersen_instance_def.zig"); + +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; + +/// Hash built-in runner +pub const HashBuiltinRunner = struct { + const Self = @This(); + + /// Base + base: usize, + /// Ratio + ratio: ?u32, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Stop pointer + stop_ptr: ?usize, + /// Included boolean flag + included: bool, + /// Number of instance per component + instances_per_component: u32, + /// Vector for verified addresses + verified_addresses: ArrayList(bool), + + /// Create a new HashBuiltinRunner instance. + /// + /// This function initializes a new `HashBuiltinRunner` instance with the provided + /// `allocator`, `ratio`, and `included` values. + /// + /// # Arguments + /// + /// - `allocator`: An allocator for initializing the `verified_addresses` list. + /// - `ratio`: An optional 32-bit unsigned integer representing the ratio. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `HashBuiltinRunner` instance. + pub fn new( + allocator: Allocator, + ratio: ?u32, + included: bool, + ) Self { + return .{ + .base = 0, + .ratio = ratio, + .cells_per_instance = pedersen_instance_def.CELLS_PER_HASH, + .n_input_cells = pedersen_instance_def.INPUT_CELLS_PER_HASH, + .stop_ptr = null, + .included = included, + .instances_per_component = 1, + .verified_addresses = ArrayList(bool).init(allocator), + }; + } + + /// Get the base value of this runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/keccak.zig b/src/vm/builtins/builtin_runner/keccak.zig new file mode 100644 index 00000000..9416b84b --- /dev/null +++ b/src/vm/builtins/builtin_runner/keccak.zig @@ -0,0 +1,74 @@ +const std = @import("std"); +const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; +const relocatable = @import("../../memory/relocatable.zig"); +const keccak_instance_def = @import("../../types/keccak_instance_def.zig"); + +const ArrayList = std.ArrayList; +const AutoHashMap = std.AutoHashMap; +const Allocator = std.mem.Allocator; + +/// Keccak built-in runner +pub const KeccakBuiltinRunner = struct { + const Self = @This(); + + /// Ratio + ratio: ?u32, + /// Base + base: usize, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Stop pointer + stop_ptr: usize, + /// Included boolean flag + included: bool, + state_rep: ArrayList(u32), + /// Number of instances per component + instances_per_component: u32, + /// Cache + /// + /// Hashmap between an address in some memory segment and `Felt252` field element + cache: AutoHashMap(relocatable.Relocatable, Felt252), + + /// Create a new KeccakBuiltinRunner instance. + /// + /// This function initializes a new `KeccakBuiltinRunner` instance with the provided + /// `allocator`, `instance_def`, and `included` values. + /// + /// # Arguments + /// + /// - `allocator`: An allocator for initializing the cache. + /// - `instance_def`: A pointer to the `KeccakInstanceDef` for this runner. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `KeccakBuiltinRunner` instance. + pub fn new( + allocator: Allocator, + instance_def: *keccak_instance_def.KeccakInstanceDef, + included: bool, + ) Self { + return .{ + .ratio = instance_def.ratio, + .base = 0, + .n_input_cells = @as(u32, instance_def._state_rep.items.len), + .cell_per_instance = instance_def.cells_per_builtin(), + .stop_ptr = null, + .included = included, + .state_rep = instance_def._state_rep, + .instances_per_component = instance_def._instance_per_component, + .cache = AutoHashMap(relocatable.Relocatable, Felt252).init(allocator), + }; + } + + /// Get the base value of this Keccak runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/output.zig b/src/vm/builtins/builtin_runner/output.zig new file mode 100644 index 00000000..a8eb4483 --- /dev/null +++ b/src/vm/builtins/builtin_runner/output.zig @@ -0,0 +1,39 @@ +/// Output built-in runner +pub const OutputBuiltinRunner = struct { + const Self = @This(); + + /// Base + base: usize, + /// Stop pointer + stop_ptr: ?usize, + /// Included boolean flag + included: bool, + + /// Create a new OutputBuiltinRunner instance. + /// + /// This function initializes a new `OutputBuiltinRunner` instance with the provided `included` value. + /// + /// # Arguments + /// + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `OutputBuiltinRunner` instance. + pub fn new(included: bool) Self { + return .{ + .base = 0, + .stop_ptr = null, + .included = included, + }; + } + + /// Get the base value of this output runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/poseidon.zig b/src/vm/builtins/builtin_runner/poseidon.zig new file mode 100644 index 00000000..d99e2417 --- /dev/null +++ b/src/vm/builtins/builtin_runner/poseidon.zig @@ -0,0 +1,71 @@ +const std = @import("std"); +const relocatable = @import("../../memory/relocatable.zig"); +const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; +const poseidon_instance_def = @import("../../types/poseidon_instance_def.zig"); + +const AutoHashMap = std.AutoHashMap; +const Allocator = std.mem.Allocator; + +/// Poseidon built-in runner +pub const PoseidonBuiltinRunner = struct { + const Self = @This(); + + /// Base + base: usize, + /// Ratio + ratio: ?u32, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Stop pointer + stop_ptr: ?usize, + /// Included boolean flag + included: bool, + /// Cache + /// + /// Hashmap between an address in some memory segment and `Felt252` field element + cache: AutoHashMap(relocatable.Relocatable, Felt252), + /// Number of instances per component + instances_per_component: u32, + + /// Create a new PoseidonBuiltinRunner instance. + /// + /// This function initializes a new `PoseidonBuiltinRunner` instance with the provided + /// `allocator`, `ratio`, and `included` values. + /// + /// # Arguments + /// + /// - `allocator`: An allocator for initializing the cache. + /// - `ratio`: An optional 32-bit unsigned integer representing the ratio. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `PoseidonBuiltinRunner` instance. + pub fn new( + allocator: Allocator, + ratio: ?u32, + included: bool, + ) Self { + return .{ + .base = 0, + .ratio = ratio, + .cell_per_instance = poseidon_instance_def.CELLS_PER_POSEIDON, + .n_input_cells = poseidon_instance_def.INPUT_CELLS_PER_POSEIDON, + .stop_ptr = null, + .included = included, + .cache = AutoHashMap(relocatable.Relocatable, Felt252).init(allocator), + .instances_per_component = 1, + }; + } + + /// Get the base value of this Poseidon runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/range_check.zig b/src/vm/builtins/builtin_runner/range_check.zig new file mode 100644 index 00000000..da384138 --- /dev/null +++ b/src/vm/builtins/builtin_runner/range_check.zig @@ -0,0 +1,68 @@ +const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; +const range_check_instance_def = @import("../../types/range_check_instance_def.zig"); + +/// Range check built-in runner +pub const RangeCheckBuiltinRunner = struct { + const Self = @This(); + + /// Ratio + ratio: ?u32, + /// Base + base: usize, + /// Stop pointer + stop_ptr: ?usize, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Felt252 field element bound + _bound: ?Felt252, + /// Included boolean flag + included: bool, + /// Number of parts + n_parts: u32, + /// Number of instances per component + instances_per_component: u32, + + /// Create a new RangeCheckBuiltinRunner instance. + /// + /// This function initializes a new `RangeCheckBuiltinRunner` instance with the provided + /// `ratio`, `n_parts`, and `included` values. + /// + /// # Arguments + /// + /// - `ratio`: An optional 32-bit unsigned integer representing the ratio. + /// - `n_parts`: The number of parts for range check operations. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `RangeCheckBuiltinRunner` instance. + pub fn new( + ratio: ?u32, + n_parts: u32, + included: bool, + ) Self { + return .{ + .ratio = ratio, + .base = 0, + .stop_ptr = null, + .cell_per_instance = range_check_instance_def.CELLS_PER_RANGE_CHECK, + .n_input_cells = range_check_instance_def.CELLS_PER_RANGE_CHECK, + // TODO: implement shl logic: https://github.com/lambdaclass/cairo-vm/blob/e6171d66a64146acc16d5512766ae91ae044f297/vm/src/vm/runners/builtin_runner/range_check.rs#L48-L53 + ._bound = null, + .included = included, + .n_parts = n_parts, + .instances_per_component = 1, + }; + } + + /// Get the base value of this range check runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/builtins/builtin_runner/segment_arena.zig b/src/vm/builtins/builtin_runner/segment_arena.zig new file mode 100644 index 00000000..c3dff8aa --- /dev/null +++ b/src/vm/builtins/builtin_runner/segment_arena.zig @@ -0,0 +1,58 @@ +const relocatable = @import("../../memory/relocatable.zig"); + +/// Arena builtin size +const ARENA_BUILTIN_SIZE: u32 = 3; +// The size of the builtin segment at the time of its creation. +const INITIAL_SEGMENT_SIZE: usize = @as( + usize, + ARENA_BUILTIN_SIZE, +); + +/// Segment Arena built-in runner +pub const SegmentArenaBuiltinRunner = struct { + const Self = @This(); + + /// Base + base: relocatable.Relocatable, + /// Included boolean flag + included: bool, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells per instance + n_input_cells_per_instance: u32, + /// Stop pointer + stop_ptr: ?usize, + + /// Create a new SegmentArenaBuiltinRunner instance. + /// + /// This function initializes a new `SegmentArenaBuiltinRunner` instance with the provided `included` value. + /// + /// # Arguments + /// + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `SegmentArenaBuiltinRunner` instance. + pub fn new(included: bool) Self { + return .{ + .base = relocatable.Relocatable.default(), + .included = included, + .cell_per_instance = ARENA_BUILTIN_SIZE, + .n_input_cells_per_instance = ARENA_BUILTIN_SIZE, + .stop_ptr = null, + }; + } + + /// Get the base segment index of this segment arena runner. + /// + /// # Returns + /// + /// The base segment index as a `usize`. + pub fn get_base(self: *const Self) usize { + return @as( + usize, + self.base.segment_index, + ); + } +}; diff --git a/src/vm/builtins/builtin_runner/signature.zig b/src/vm/builtins/builtin_runner/signature.zig new file mode 100644 index 00000000..9141041b --- /dev/null +++ b/src/vm/builtins/builtin_runner/signature.zig @@ -0,0 +1,69 @@ +const std = @import("std"); +const Signature = @import("../../../math/crypto/signatures.zig").Signature; +const relocatable = @import("../../memory/relocatable.zig"); +const Felt252 = @import("../../../math/fields/starknet.zig").Felt252; +const ecdsa_instance_def = @import("../../types/ecdsa_instance_def.zig"); + +const AutoHashMap = std.AutoHashMap; +const Allocator = std.mem.Allocator; + +/// Signature built-in runner +pub const SignatureBuiltinRunner = struct { + const Self = @This(); + + /// Included boolean flag + included: bool, + /// Ratio + ratio: ?u32, + /// Base + base: usize, + /// Number of cells per instance + cells_per_instance: u32, + /// Number of input cells + n_input_cells: u32, + /// Total number of bits + _total_n_bits: u32, + /// Stop pointer + stop_ptr: ?usize, + /// Number of instances per component + instances_per_component: u32, + /// Signatures HashMap + signatures: AutoHashMap(relocatable.Relocatable, Signature), + + /// Create a new SignatureBuiltinRunner instance. + /// + /// This function initializes a new `SignatureBuiltinRunner` instance with the provided + /// `allocator`, `instance_def`, and `included` values. + /// + /// # Arguments + /// + /// - `allocator`: An allocator for initializing the `signatures` HashMap. + /// - `instance_def`: A pointer to the `EcdsaInstanceDef` for this runner. + /// - `included`: A boolean flag indicating whether this runner is included. + /// + /// # Returns + /// + /// A new `SignatureBuiltinRunner` instance. + pub fn new(allocator: Allocator, instance_def: *ecdsa_instance_def.EcdsaInstanceDef, included: bool) Self { + return .{ + .included = included, + .ratio = instance_def.ratio, + .base = 0, + .cell_per_instance = 2, + .n_input_cells = 2, + ._total_n_bits = 251, + .stop_ptr = null, + .instances_per_component = 1, + .signatures = AutoHashMap(relocatable.Relocatable, Signature).init(allocator), + }; + } + + /// Get the base value of this signature runner. + /// + /// # Returns + /// + /// The base value as a `usize`. + pub fn get_base(self: *const Self) usize { + return self.base; + } +}; diff --git a/src/vm/core.zig b/src/vm/core.zig index 97fb2bf0..1ad7b714 100644 --- a/src/vm/core.zig +++ b/src/vm/core.zig @@ -1,6 +1,5 @@ // Core imports. const std = @import("std"); -const expect = @import("std").testing.expect; const Allocator = std.mem.Allocator; const ArrayList = std.ArrayList; const starknet_felt = @import("../math/fields/starknet.zig"); @@ -16,6 +15,10 @@ const CairoVMError = @import("error.zig").CairoVMError; const Config = @import("config.zig").Config; const TraceContext = @import("trace_context.zig").TraceContext; const build_options = @import("../build_options.zig"); +const BuiltinRunner = @import("./builtins/builtin_runner/builtin_runner.zig").BuiltinRunner; +const builtin = @import("./builtins/bitwise/bitwise.zig"); +const Felt252 = @import("../math/fields/starknet.zig").Felt252; +const HashBuiltinRunner = @import("./builtins/builtin_runner/hash.zig").HashBuiltinRunner; const Instruction = @import("instructions.zig").Instruction; /// Represents the Cairo VM. @@ -30,6 +33,8 @@ pub const CairoVM = struct { allocator: Allocator, /// The run context. run_context: *RunContext, + /// ArrayList of built-in runners + builtin_runners: ArrayList(BuiltinRunner), /// The memory segment manager. segments: *segments.MemorySegmentManager, /// Whether the run is finished or not. @@ -63,6 +68,7 @@ pub const CairoVM = struct { return Self{ .allocator = allocator, .run_context = run_context, + .builtin_runners = ArrayList(BuiltinRunner).init(allocator), .segments = memory_segment_manager, .is_run_finished = false, .trace_context = trace_context, @@ -77,6 +83,8 @@ pub const CairoVM = struct { self.run_context.deinit(); // Deallocate trace self.trace_context.deinit(); + // Deallocate built-in runners + self.builtin_runners.deinit(); } // ************************************************************ @@ -205,22 +213,6 @@ pub const CairoVM = struct { _ = op_o; } - /// Applies the corresponding builtin's deduction rules if addr's segment index corresponds to a builtin segment - /// Returns null if there is no deduction for the address - /// # Arguments - /// - `address`: The address to deduce. - /// # Returns - /// - `MaybeRelocatable`: The deduced value. - /// TODO: Implement this. - pub fn deduceMemoryCell( - self: *Self, - address: Relocatable, - ) !?MaybeRelocatable { - _ = address; - _ = self; - return null; - } - /// Updates the value of PC according to the executed instruction. /// # Arguments /// - `instruction`: The instruction that was executed. @@ -390,6 +382,32 @@ pub const CairoVM = struct { pub fn getPc(self: *const Self) Relocatable { return self.run_context.pc.*; } + + /// Applies the corresponding builtin's deduction rules if addr's segment index corresponds to a builtin segment + /// Returns null if there is no deduction for the address + /// # Arguments + /// - `address`: The address to deduce. + /// # Returns + /// - `MaybeRelocatable`: The deduced value. + pub fn deduceMemoryCell( + self: *Self, + address: Relocatable, + ) CairoVMError!?MaybeRelocatable { + for (self.builtin_runners.items) |builtin_item| { + if (@as( + u64, + builtin_item.base(), + ) == address.segment_index) { + return builtin.deduce( + address, + self.segments.memory, + ) catch { + return CairoVMError.RunnerError; + }; + } + } + return null; + } }; /// Compute the result operand for a given instruction on op 0 and op 1. @@ -547,7 +565,7 @@ pub fn deduceOp1( // ***************************************************************************** /// Represents the operands for an instruction. -const OperandsResult = struct { +pub const OperandsResult = struct { const Self = @This(); dst: MaybeRelocatable, @@ -576,1107 +594,3 @@ const Op0Result = struct { op_0: MaybeRelocatable, res: MaybeRelocatable, }; - -// ************************************************************ -// * TESTS * -// ************************************************************ -const expectEqual = std.testing.expectEqual; -const expectError = std.testing.expectError; - -test "update pc regular no imm" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Regular; - instruction.op_1_addr = instructions.Op1Src.AP; - const operands = OperandsResult.default(); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 1, - ); -} - -test "update pc regular with imm" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Regular; - instruction.op_1_addr = instructions.Op1Src.Imm; - const operands = OperandsResult.default(); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 2, - ); -} - -test "update pc jump with operands res null" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jump; - var operands = OperandsResult.default(); - operands.res = null; - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError(error.ResUnconstrainedUsedWithPcUpdateJump, vm.updatePc( - &instruction, - operands, - )); -} - -test "update pc jump with operands res not relocatable" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jump; - var operands = OperandsResult.default(); - operands.res = relocatable.fromU64(0); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError(error.PcUpdateJumpResNotRelocatable, vm.updatePc( - &instruction, - operands, - )); -} - -test "update pc jump with operands res relocatable" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jump; - var operands = OperandsResult.default(); - operands.res = relocatable.newFromRelocatable(Relocatable.new( - 0, - 42, - )); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 42, - ); -} - -test "update pc jump rel with operands res null" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.JumpRel; - var operands = OperandsResult.default(); - operands.res = null; - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError(error.ResUnconstrainedUsedWithPcUpdateJumpRel, vm.updatePc( - &instruction, - operands, - )); -} - -test "update pc jump rel with operands res not felt" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.JumpRel; - var operands = OperandsResult.default(); - operands.res = relocatable.newFromRelocatable(Relocatable.new( - 0, - 42, - )); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError(error.PcUpdateJumpRelResNotFelt, vm.updatePc( - &instruction, - operands, - )); -} - -test "update pc jump rel with operands res felt" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.JumpRel; - var operands = OperandsResult.default(); - operands.res = relocatable.fromU64(42); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 42, - ); -} - -test "update pc update jnz with operands dst zero" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jnz; - var operands = OperandsResult.default(); - operands.dst = relocatable.fromU64(0); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 2, - ); -} - -test "update pc update jnz with operands dst not zero op1 not felt" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jnz; - var operands = OperandsResult.default(); - operands.dst = relocatable.fromU64(1); - operands.op_1 = relocatable.newFromRelocatable(Relocatable.new( - 0, - 42, - )); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError( - error.TypeMismatchNotFelt, - vm.updatePc( - &instruction, - operands, - ), - ); -} - -test "update pc update jnz with operands dst not zero op1 felt" { - - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.pc_update = instructions.PcUpdate.Jnz; - var operands = OperandsResult.default(); - operands.dst = relocatable.fromU64(1); - operands.op_1 = relocatable.fromU64(42); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updatePc( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const pc = vm.getPc(); - try expectEqual( - pc.offset, - 42, - ); -} - -test "update ap add with operands res unconstrained" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.ap_update = instructions.ApUpdate.Add; - var operands = OperandsResult.default(); - operands.res = null; // Simulate unconstrained res - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try expectError(error.ApUpdateAddResUnconstrained, vm.updateAp( - &instruction, - operands, - )); -} - -test "update ap add1" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.ap_update = instructions.ApUpdate.Add1; - var operands = OperandsResult.default(); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updateAp( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the AP offset was incremented by 1. - const ap = vm.getAp(); - try expectEqual( - ap.offset, - 1, - ); -} - -test "update ap add2" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.ap_update = instructions.ApUpdate.Add2; - var operands = OperandsResult.default(); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updateAp( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the AP offset was incremented by 2. - const ap = vm.getAp(); - try expectEqual( - ap.offset, - 2, - ); -} - -test "update fp appplus2" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.fp_update = instructions.FpUpdate.APPlus2; - var operands = OperandsResult.default(); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updateFp( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the FP offset was incremented by 2. - const fp = vm.getFp(); - try expectEqual( - fp.offset, - 2, - ); -} - -test "update fp dst relocatable" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.fp_update = instructions.FpUpdate.Dst; - var operands = OperandsResult.default(); - operands.dst = relocatable.newFromRelocatable(Relocatable.new( - 0, - 42, - )); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updateFp( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the FP offset was incremented by 2. - const fp = vm.getFp(); - try expectEqual( - fp.offset, - 42, - ); -} - -test "update fp dst felt" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction.default(); - instruction.fp_update = instructions.FpUpdate.Dst; - var operands = OperandsResult.default(); - operands.dst = relocatable.fromU64(42); - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - try vm.updateFp( - &instruction, - operands, - ); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the FP offset was incremented by 2. - const fp = vm.getFp(); - try expectEqual( - fp.offset, - 42, - ); -} - -test "trace is enabled" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - - // Create a new VM instance. - var config = Config{ .proof_mode = false, .enable_trace = true }; - - var vm = try CairoVM.init( - allocator, - config, - ); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - // Do nothing - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Check that trace was initialized - if (!vm.trace_context.isEnabled()) { - return error.TraceShouldHaveBeenEnabled; - } -} - -test "trace is disabled" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - // Do nothing - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Check that trace was initialized - if (vm.trace_context.isEnabled()) { - return error.TraceShouldHaveBeenDisabled; - } -} - -// This instruction is used in the functions that test the `deduceOp1` function. Only the -// `opcode` and `res_logic` fields are usually changed. -const deduceOp1TestInstr = instructions.Instruction{ - .off_0 = 1, - .off_1 = 2, - .off_2 = 3, - .dst_reg = .FP, - .op_0_reg = .AP, - .op_1_addr = .AP, - .res_logic = .Add, - .pc_update = .Jump, - .ap_update = .Regular, - .fp_update = .Regular, - .opcode = .Call, -}; - -test "deduceOp1 when opcode == .Call" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .Call; - - const tuple = try deduceOp1(&instr, null, null); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference - const expectedRes: ?MaybeRelocatable = null; - try expectEqual(expectedOp1, op1); - try expectEqual(expectedRes, res); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic == .Add, input is felt" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Add; - - const dst = relocatable.fromU64(3); - const op0 = relocatable.fromU64(2); - - const tuple = try deduceOp1(&instr, &dst, &op0); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expect(op1.?.eq(relocatable.fromU64(1))); - try expect(res.?.eq(relocatable.fromU64(3))); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic == .Mul, non-zero op0" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Mul; - - const dst = relocatable.fromU64(4); - const op0 = relocatable.fromU64(2); - - const op1_and_result = try deduceOp1(&instr, &dst, &op0); - const op1 = op1_and_result[0]; - const res = op1_and_result[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expect(op1.?.eq(relocatable.fromU64(2))); - try expect(res.?.eq(relocatable.fromU64(4))); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic == .Mul, zero op0" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Mul; - - const dst = relocatable.fromU64(4); - const op0 = relocatable.fromU64(0); - - const tuple = try deduceOp1(&instr, &dst, &op0); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference - const expectedRes: ?MaybeRelocatable = null; - try expectEqual(expectedOp1, op1); - try expectEqual(expectedRes, res); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic = .Mul, no input" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Mul; - - const tuple = try deduceOp1(&instr, null, null); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference - const expectedRes: ?MaybeRelocatable = null; - try expectEqual(expectedOp1, op1); - try expectEqual(expectedRes, res); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic == .Op1, no dst" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing. - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Op1; - - const op0 = relocatable.fromU64(0); - - const tuple = try deduceOp1(&instr, null, &op0); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference - const expectedRes: ?MaybeRelocatable = null; - try expectEqual(expectedOp1, op1); - try expectEqual(expectedRes, res); -} - -test "deduceOp1 when opcode == .AssertEq, res_logic == .Op1, no op0" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Nothing/ - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - var instr = deduceOp1TestInstr; - instr.opcode = .AssertEq; - instr.res_logic = .Op1; - - const dst = relocatable.fromU64(7); - - const tuple = try deduceOp1(&instr, &dst, null); - const op1 = tuple[0]; - const res = tuple[1]; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expect(op1.?.eq(relocatable.fromU64(7))); - try expect(res.?.eq(relocatable.fromU64(7))); -} - -test "set get value in vm memory" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - // ************************************************************ - // * TEST BODY * - // ************************************************************ - _ = vm.segments.addSegment(); - _ = vm.segments.addSegment(); - - const address = Relocatable.new(1, 0); - const value = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(42)); - - _ = try vm.segments.memory.set(address, value); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - // Verify the value is correctly set to 42. - const actual_value = try vm.segments.memory.get(address); - const expected_value = value; - try expectEqual(expected_value, actual_value); -} - -test "compute res op1 works" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Op1, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); - const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); - - const actual_res = try computeRes(&instruction, value_op0, value_op1); - const expected_res = value_op1; - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectEqual(expected_res, actual_res); -} - -test "compute res add felts works" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Add, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); - const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); - - const actual_res = try computeRes(&instruction, value_op0, value_op1); - const expected_res = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(5)); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectEqual(expected_res, actual_res); -} - -test "compute res add felt to offset works" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Add, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = Relocatable.new(1, 1); - const op0 = relocatable.newFromRelocatable(value_op0); - - const op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); - - const actual_res = try computeRes(&instruction, op0, op1); - const res = Relocatable.new(1, 4); - const expected_res = relocatable.newFromRelocatable(res); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectEqual(expected_res, actual_res); -} - -test "compute res add fails two relocs" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Add, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = Relocatable.new(1, 0); - const value_op1 = Relocatable.new(1, 1); - - const op0 = relocatable.newFromRelocatable(value_op0); - const op1 = relocatable.newFromRelocatable(value_op1); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectError(error.AddRelocToRelocForbidden, computeRes(&instruction, op0, op1)); -} - -test "compute res mul works" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Mul, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); - const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); - - const actual_res = try computeRes(&instruction, value_op0, value_op1); - const expected_res = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(6)); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectEqual(expected_res, actual_res); -} - -test "compute res mul fails two relocs" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Mul, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = Relocatable.new(1, 0); - const value_op1 = Relocatable.new(1, 1); - - const op0 = relocatable.newFromRelocatable(value_op0); - const op1 = relocatable.newFromRelocatable(value_op1); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectError(error.MulRelocForbidden, computeRes(&instruction, op0, op1)); -} - -test "compute res mul fails felt and reloc" { - // ************************************************************ - // * SETUP TEST CONTEXT * - // ************************************************************ - // Initialize an allocator. - var allocator = std.testing.allocator; - var instruction = Instruction{ - .off_0 = 0, - .off_1 = 1, - .off_2 = 2, - .dst_reg = instructions.Register.AP, - .op_0_reg = instructions.Register.AP, - .op_1_addr = instructions.Op1Src.AP, - .res_logic = instructions.ResLogic.Mul, - .pc_update = instructions.PcUpdate.Regular, - .ap_update = instructions.ApUpdate.Regular, - .fp_update = instructions.FpUpdate.Regular, - .opcode = instructions.Opcode.NOp, - }; - - // Create a new VM instance. - var vm = try CairoVM.init(allocator, .{}); - defer vm.deinit(); - - vm.run_context.ap.* = Relocatable.new(1, 0); - // ************************************************************ - // * TEST BODY * - // ************************************************************ - - const value_op0 = Relocatable.new(1, 0); - const op0 = relocatable.newFromRelocatable(value_op0); - const op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); - - // ************************************************************ - // * TEST CHECKS * - // ************************************************************ - try expectError(error.MulRelocForbidden, computeRes(&instruction, op0, op1)); -} diff --git a/src/vm/core_test.zig b/src/vm/core_test.zig new file mode 100644 index 00000000..b42ac72c --- /dev/null +++ b/src/vm/core_test.zig @@ -0,0 +1,1187 @@ +// Core imports. +const std = @import("std"); +const Allocator = std.mem.Allocator; +const ArrayList = std.ArrayList; +const starknet_felt = @import("../math/fields/starknet.zig"); + +// Local imports. +const segments = @import("memory/segments.zig"); +const relocatable = @import("memory/relocatable.zig"); +const MaybeRelocatable = relocatable.MaybeRelocatable; +const Relocatable = relocatable.Relocatable; +const instructions = @import("instructions.zig"); +const RunContext = @import("run_context.zig").RunContext; +const CairoVMError = @import("error.zig").CairoVMError; +const Config = @import("config.zig").Config; +const TraceContext = @import("trace_context.zig").TraceContext; +const build_options = @import("../build_options.zig"); +const BuiltinRunner = @import("./builtins/builtin_runner/builtin_runner.zig").BuiltinRunner; +const builtin = @import("./builtins/bitwise/bitwise.zig"); +const Felt252 = @import("../math/fields/starknet.zig").Felt252; +const HashBuiltinRunner = @import("./builtins/builtin_runner/hash.zig").HashBuiltinRunner; +const Instruction = @import("instructions.zig").Instruction; +const CairoVM = @import("core.zig").CairoVM; +const computeRes = @import("core.zig").computeRes; +const OperandsResult = @import("core.zig").OperandsResult; +const deduceOp1 = @import("core.zig").deduceOp1; + +// ************************************************************ +// * TESTS * +// ************************************************************ +const expect = std.testing.expect; +const expectEqual = std.testing.expectEqual; +const expectError = std.testing.expectError; + +test "CairoVM: deduceMemoryCell no builtin" { + var vm = try CairoVM.init( + std.testing.allocator, + .{}, + ); + defer vm.deinit(); + try expectEqual( + @as(?MaybeRelocatable, null), + try vm.deduceMemoryCell(Relocatable.new( + 0, + 0, + )), + ); +} + +test "CairoVM: deduceMemoryCell builtin valid" { + var vm = try CairoVM.init( + std.testing.allocator, + .{}, + ); + defer vm.deinit(); + try vm.builtin_runners.append(BuiltinRunner{ .Hash = HashBuiltinRunner.new( + std.testing.allocator, + 8, + true, + ) }); + try vm.segments.memory.set( + Relocatable.new( + 0, + 5, + ), + relocatable.fromFelt(Felt252.fromInteger(10)), + ); + try vm.segments.memory.set( + Relocatable.new( + 0, + 6, + ), + relocatable.fromFelt(Felt252.fromInteger(12)), + ); + try vm.segments.memory.set( + Relocatable.new( + 0, + 7, + ), + relocatable.fromFelt(Felt252.fromInteger(0)), + ); + try expectEqual( + MaybeRelocatable{ .felt = Felt252.fromInteger(8) }, + (try vm.deduceMemoryCell(Relocatable.new( + 0, + 7, + ))).?, + ); +} + +test "update pc regular no imm" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Regular; + instruction.op_1_addr = instructions.Op1Src.AP; + const operands = OperandsResult.default(); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 1, + ); +} + +test "update pc regular with imm" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Regular; + instruction.op_1_addr = instructions.Op1Src.Imm; + const operands = OperandsResult.default(); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 2, + ); +} + +test "update pc jump with operands res null" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jump; + var operands = OperandsResult.default(); + operands.res = null; + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError(error.ResUnconstrainedUsedWithPcUpdateJump, vm.updatePc( + &instruction, + operands, + )); +} + +test "update pc jump with operands res not relocatable" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jump; + var operands = OperandsResult.default(); + operands.res = relocatable.fromU64(0); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError(error.PcUpdateJumpResNotRelocatable, vm.updatePc( + &instruction, + operands, + )); +} + +test "update pc jump with operands res relocatable" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jump; + var operands = OperandsResult.default(); + operands.res = relocatable.newFromRelocatable(Relocatable.new( + 0, + 42, + )); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 42, + ); +} + +test "update pc jump rel with operands res null" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.JumpRel; + var operands = OperandsResult.default(); + operands.res = null; + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError(error.ResUnconstrainedUsedWithPcUpdateJumpRel, vm.updatePc( + &instruction, + operands, + )); +} + +test "update pc jump rel with operands res not felt" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.JumpRel; + var operands = OperandsResult.default(); + operands.res = relocatable.newFromRelocatable(Relocatable.new( + 0, + 42, + )); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError(error.PcUpdateJumpRelResNotFelt, vm.updatePc( + &instruction, + operands, + )); +} + +test "update pc jump rel with operands res felt" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.JumpRel; + var operands = OperandsResult.default(); + operands.res = relocatable.fromU64(42); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 42, + ); +} + +test "update pc update jnz with operands dst zero" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jnz; + var operands = OperandsResult.default(); + operands.dst = relocatable.fromU64(0); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 2, + ); +} + +test "update pc update jnz with operands dst not zero op1 not felt" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jnz; + var operands = OperandsResult.default(); + operands.dst = relocatable.fromU64(1); + operands.op_1 = relocatable.newFromRelocatable(Relocatable.new( + 0, + 42, + )); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError( + error.TypeMismatchNotFelt, + vm.updatePc( + &instruction, + operands, + ), + ); +} + +test "update pc update jnz with operands dst not zero op1 felt" { + + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.pc_update = instructions.PcUpdate.Jnz; + var operands = OperandsResult.default(); + operands.dst = relocatable.fromU64(1); + operands.op_1 = relocatable.fromU64(42); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updatePc( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const pc = vm.getPc(); + try expectEqual( + pc.offset, + 42, + ); +} + +test "update ap add with operands res unconstrained" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.ap_update = instructions.ApUpdate.Add; + var operands = OperandsResult.default(); + operands.res = null; // Simulate unconstrained res + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try expectError(error.ApUpdateAddResUnconstrained, vm.updateAp( + &instruction, + operands, + )); +} + +test "update ap add1" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.ap_update = instructions.ApUpdate.Add1; + var operands = OperandsResult.default(); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updateAp( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the AP offset was incremented by 1. + const ap = vm.getAp(); + try expectEqual( + ap.offset, + 1, + ); +} + +test "update ap add2" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.ap_update = instructions.ApUpdate.Add2; + var operands = OperandsResult.default(); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updateAp( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the AP offset was incremented by 2. + const ap = vm.getAp(); + try expectEqual( + ap.offset, + 2, + ); +} + +test "update fp appplus2" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.fp_update = instructions.FpUpdate.APPlus2; + var operands = OperandsResult.default(); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updateFp( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the FP offset was incremented by 2. + const fp = vm.getFp(); + try expectEqual( + fp.offset, + 2, + ); +} + +test "update fp dst relocatable" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.fp_update = instructions.FpUpdate.Dst; + var operands = OperandsResult.default(); + operands.dst = relocatable.newFromRelocatable(Relocatable.new( + 0, + 42, + )); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updateFp( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the FP offset was incremented by 2. + const fp = vm.getFp(); + try expectEqual( + fp.offset, + 42, + ); +} + +test "update fp dst felt" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction.default(); + instruction.fp_update = instructions.FpUpdate.Dst; + var operands = OperandsResult.default(); + operands.dst = relocatable.fromU64(42); + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + try vm.updateFp( + &instruction, + operands, + ); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the FP offset was incremented by 2. + const fp = vm.getFp(); + try expectEqual( + fp.offset, + 42, + ); +} + +test "trace is enabled" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + + // Create a new VM instance. + var config = Config{ .proof_mode = false, .enable_trace = true }; + + var vm = try CairoVM.init( + allocator, + config, + ); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + // Do nothing + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Check that trace was initialized + if (!vm.trace_context.isEnabled()) { + return error.TraceShouldHaveBeenEnabled; + } +} + +test "trace is disabled" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + // Do nothing + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Check that trace was initialized + if (vm.trace_context.isEnabled()) { + return error.TraceShouldHaveBeenDisabled; + } +} + +// This instruction is used in the functions that test the `deduceOp1` function. Only the +// `opcode` and `res_logic` fields are usually changed. +const deduceOp1TestInstr = instructions.Instruction{ + .off_0 = 1, + .off_1 = 2, + .off_2 = 3, + .dst_reg = .FP, + .op_0_reg = .AP, + .op_1_addr = .AP, + .res_logic = .Add, + .pc_update = .Jump, + .ap_update = .Regular, + .fp_update = .Regular, + .opcode = .Call, +}; + +test "deduceOp1 when opcode == .Call" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .Call; + + const tuple = try deduceOp1(&instr, null, null); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference + const expectedRes: ?MaybeRelocatable = null; + try expectEqual(expectedOp1, op1); + try expectEqual(expectedRes, res); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic == .Add, input is felt" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Add; + + const dst = relocatable.fromU64(3); + const op0 = relocatable.fromU64(2); + + const tuple = try deduceOp1(&instr, &dst, &op0); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expect(op1.?.eq(relocatable.fromU64(1))); + try expect(res.?.eq(relocatable.fromU64(3))); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic == .Mul, non-zero op0" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Mul; + + const dst = relocatable.fromU64(4); + const op0 = relocatable.fromU64(2); + + const op1_and_result = try deduceOp1(&instr, &dst, &op0); + const op1 = op1_and_result[0]; + const res = op1_and_result[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expect(op1.?.eq(relocatable.fromU64(2))); + try expect(res.?.eq(relocatable.fromU64(4))); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic == .Mul, zero op0" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Mul; + + const dst = relocatable.fromU64(4); + const op0 = relocatable.fromU64(0); + + const tuple = try deduceOp1(&instr, &dst, &op0); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference + const expectedRes: ?MaybeRelocatable = null; + try expectEqual(expectedOp1, op1); + try expectEqual(expectedRes, res); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic = .Mul, no input" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Mul; + + const tuple = try deduceOp1(&instr, null, null); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference + const expectedRes: ?MaybeRelocatable = null; + try expectEqual(expectedOp1, op1); + try expectEqual(expectedRes, res); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic == .Op1, no dst" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing. + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Op1; + + const op0 = relocatable.fromU64(0); + + const tuple = try deduceOp1(&instr, null, &op0); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + const expectedOp1: ?MaybeRelocatable = null; // temp var needed for type inference + const expectedRes: ?MaybeRelocatable = null; + try expectEqual(expectedOp1, op1); + try expectEqual(expectedRes, res); +} + +test "deduceOp1 when opcode == .AssertEq, res_logic == .Op1, no op0" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Nothing/ + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + var instr = deduceOp1TestInstr; + instr.opcode = .AssertEq; + instr.res_logic = .Op1; + + const dst = relocatable.fromU64(7); + + const tuple = try deduceOp1(&instr, &dst, null); + const op1 = tuple[0]; + const res = tuple[1]; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expect(op1.?.eq(relocatable.fromU64(7))); + try expect(res.?.eq(relocatable.fromU64(7))); +} + +test "set get value in vm memory" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + // ************************************************************ + // * TEST BODY * + // ************************************************************ + _ = vm.segments.addSegment(); + _ = vm.segments.addSegment(); + + const address = Relocatable.new(1, 0); + const value = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(42)); + + _ = try vm.segments.memory.set(address, value); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + // Verify the value is correctly set to 42. + const actual_value = try vm.segments.memory.get(address); + const expected_value = value; + try expectEqual(expected_value, actual_value); +} + +test "compute res op1 works" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Op1, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); + const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); + + const actual_res = try computeRes(&instruction, value_op0, value_op1); + const expected_res = value_op1; + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectEqual(expected_res, actual_res); +} + +test "compute res add felts works" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Add, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); + const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); + + const actual_res = try computeRes(&instruction, value_op0, value_op1); + const expected_res = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(5)); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectEqual(expected_res, actual_res); +} + +test "compute res add felt to offset works" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Add, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = Relocatable.new(1, 1); + const op0 = relocatable.newFromRelocatable(value_op0); + + const op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); + + const actual_res = try computeRes(&instruction, op0, op1); + const res = Relocatable.new(1, 4); + const expected_res = relocatable.newFromRelocatable(res); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectEqual(expected_res, actual_res); +} + +test "compute res add fails two relocs" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Add, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = Relocatable.new(1, 0); + const value_op1 = Relocatable.new(1, 1); + + const op0 = relocatable.newFromRelocatable(value_op0); + const op1 = relocatable.newFromRelocatable(value_op1); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectError(error.AddRelocToRelocForbidden, computeRes(&instruction, op0, op1)); +} + +test "compute res mul works" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Mul, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); + const value_op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(3)); + + const actual_res = try computeRes(&instruction, value_op0, value_op1); + const expected_res = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(6)); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectEqual(expected_res, actual_res); +} + +test "compute res mul fails two relocs" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Mul, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = Relocatable.new(1, 0); + const value_op1 = Relocatable.new(1, 1); + + const op0 = relocatable.newFromRelocatable(value_op0); + const op1 = relocatable.newFromRelocatable(value_op1); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectError(error.MulRelocForbidden, computeRes(&instruction, op0, op1)); +} + +test "compute res mul fails felt and reloc" { + // ************************************************************ + // * SETUP TEST CONTEXT * + // ************************************************************ + // Initialize an allocator. + var allocator = std.testing.allocator; + var instruction = Instruction{ + .off_0 = 0, + .off_1 = 1, + .off_2 = 2, + .dst_reg = instructions.Register.AP, + .op_0_reg = instructions.Register.AP, + .op_1_addr = instructions.Op1Src.AP, + .res_logic = instructions.ResLogic.Mul, + .pc_update = instructions.PcUpdate.Regular, + .ap_update = instructions.ApUpdate.Regular, + .fp_update = instructions.FpUpdate.Regular, + .opcode = instructions.Opcode.NOp, + }; + + // Create a new VM instance. + var vm = try CairoVM.init(allocator, .{}); + defer vm.deinit(); + + vm.run_context.ap.* = Relocatable.new(1, 0); + // ************************************************************ + // * TEST BODY * + // ************************************************************ + + const value_op0 = Relocatable.new(1, 0); + const op0 = relocatable.newFromRelocatable(value_op0); + const op1 = relocatable.fromFelt(starknet_felt.Felt252.fromInteger(2)); + + // ************************************************************ + // * TEST CHECKS * + // ************************************************************ + try expectError(error.MulRelocForbidden, computeRes(&instruction, op0, op1)); +} diff --git a/src/vm/error.zig b/src/vm/error.zig index 5a256f0d..53d8157b 100644 --- a/src/vm/error.zig +++ b/src/vm/error.zig @@ -7,6 +7,7 @@ pub const CairoVMError = error{ InstructionEncodingError, ParseResLogicError, TypeMismatchNotFelt, + RunnerError, TypeMismatchNotRelocatable, ValueTooLarge, }; diff --git a/src/vm/types/bitwise_instance_def.zig b/src/vm/types/bitwise_instance_def.zig new file mode 100644 index 00000000..92fc4903 --- /dev/null +++ b/src/vm/types/bitwise_instance_def.zig @@ -0,0 +1,12 @@ +/// Number of cells by bitwise operation +pub const CELLS_PER_BITWISE: u32 = 5; +/// Number of input cells by bitwise operation +pub const INPUT_CELLS_PER_BITWISE: u32 = 2; + +/// Represents a Bitwise Instance Definition. +pub const BitwiseInstanceDef = struct { + /// Ratio + ratio: ?u32, + /// The number of bits in a single field element that are supported by the bitwise builtin. + total_n_bits: u32, +}; diff --git a/src/vm/types/ec_op_instance_def.zig b/src/vm/types/ec_op_instance_def.zig new file mode 100644 index 00000000..afaa09ec --- /dev/null +++ b/src/vm/types/ec_op_instance_def.zig @@ -0,0 +1,15 @@ +/// Each EC operation P + m * Q = R contains 7 cells: +/// P_x, P_y, Q_x, Q_y, m, R_x, R_y. +pub const CELLS_PER_EC_OP: u32 = 7; +/// Number of input cells per EC operation +pub const INPUT_CELLS_PER_EC_OP: u32 = 5; + +/// Represents a EC Operation Instance Definition. +pub const EcOpInstanceDef = struct { + /// Ratio + ratio: ?u32, + /// Size of coefficient. + scalar_height: u32, + /// Scalar bits + _scalar_bits: u32, +}; diff --git a/src/vm/types/ecdsa_instance_def.zig b/src/vm/types/ecdsa_instance_def.zig new file mode 100644 index 00000000..31a16dd4 --- /dev/null +++ b/src/vm/types/ecdsa_instance_def.zig @@ -0,0 +1,11 @@ +/// Represents a ECDSA Instance Definition. +pub const EcdsaInstanceDef = struct { + /// Ratio + ratio: ?u32, + /// Split to this many different components - for optimization. + _repetitions: u32, + /// Size of hash. + _height: u32, + /// Number of hash bits + _n_hash_bits: u32, +}; diff --git a/src/vm/types/keccak_instance_def.zig b/src/vm/types/keccak_instance_def.zig new file mode 100644 index 00000000..5d435bf2 --- /dev/null +++ b/src/vm/types/keccak_instance_def.zig @@ -0,0 +1,22 @@ +const std = @import("std"); + +const ArrayList = std.ArrayList; + +/// Represents a Keccak Instance Definition. +pub const KeccakInstanceDef = struct { + const Self = @This(); + + /// Ratio + ratio: ?u32, + /// The input and output are 1600 bits that are represented using a sequence of field elements in the following pattern. + /// + /// For example [64] * 25 means 25 field elements each containing 64 bits. + _state_rep: ArrayList(u32), + /// Should equal n_diluted_bits. + _instance_per_component: u32, + + /// Number of cells per built in + pub fn cells_per_builtin(self: *Self) u32 { + return 2 * @as(u32, self._state_rep.items.len); + } +}; diff --git a/src/vm/types/pedersen_instance_def.zig b/src/vm/types/pedersen_instance_def.zig new file mode 100644 index 00000000..e4a5ccff --- /dev/null +++ b/src/vm/types/pedersen_instance_def.zig @@ -0,0 +1,24 @@ +const std = @import("std"); + +/// Each hash consists of 3 cells (two inputs and one output). +pub const CELLS_PER_HASH: u32 = 3; +/// Number of input cells per hash. +pub const INPUT_CELLS_PER_HASH: u32 = 2; + +/// Represents a Pedersen Instance Definition. +pub const PedersenInstanceDef = struct { + /// Ratio + ratio: ?u32, + /// Split to this many different components - for optimization. + _repetitions: u32, + /// Size of hash. + _element_height: u32, + /// Size of hash in bits. + _element_bits: u32, + /// Number of inputs for hash. + _n_inputs: u32, + /// The upper bound on the hash inputs. + /// + /// If None, the upper bound is 2^element_bits. + _hash_limit: std.math.big.int.Managed, +}; diff --git a/src/vm/types/poseidon_instance_def.zig b/src/vm/types/poseidon_instance_def.zig new file mode 100644 index 00000000..b97cf539 --- /dev/null +++ b/src/vm/types/poseidon_instance_def.zig @@ -0,0 +1,10 @@ +/// Number of cells per Poseidon +pub const CELLS_PER_POSEIDON: u32 = 6; +/// Number of input cells per Poseidon +pub const INPUT_CELLS_PER_POSEIDON: u32 = 3; + +/// Represents a Poseidon Instance Definition. +pub const PoseidonInstanceDef = struct { + /// Ratio + ratio: ?u32, +}; diff --git a/src/vm/types/range_check_instance_def.zig b/src/vm/types/range_check_instance_def.zig new file mode 100644 index 00000000..1de7fe68 --- /dev/null +++ b/src/vm/types/range_check_instance_def.zig @@ -0,0 +1,12 @@ +/// Number of cells per range check +pub const CELLS_PER_RANGE_CHECK: u32 = 1; + +/// Represents a Range Check Instance Definition. +pub const RangeCheckInstanceDef = struct { + /// Ratio + ratio: ?u32, + /// Number of 16-bit range checks that will be used for each instance of the builtin. + /// + /// For example, n_parts=8 defines the range [0, 2^128). + n_parts: u32, +};