From 6cf462adc51224495500c5984eac4742d04700af Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Wed, 19 Jun 2024 21:03:14 +0200 Subject: [PATCH 1/6] #519 improve set integration bench closes #519 issue --- build.zig.zon | 4 +-- src/vm/memory/memory.zig | 63 ++++++++++------------------------- src/vm/memory/relocatable.zig | 11 +++++- 3 files changed, 29 insertions(+), 49 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index 6c1a1c83..db74dd41 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -14,8 +14,8 @@ .hash = "1220ab73fb7cc11b2308edc3364988e05efcddbcac31b707f55e6216d1b9c0da13f1", }, .starknet = .{ - .url = "https://github.com/StringNick/starknet-zig/archive/8cfb4286ffda4ad2781647c3d96b2aec8ccfeb32.zip", - .hash = "122026eaa24834fd2e2cc7e8b6c4eefb03dda08158a2844615f189758fa24d32fc44", + .url = "https://github.com/StringNick/starknet-zig/archive/57810b7a64364f1bf12725ba823385c2a213bfa5.zip", + .hash = "1220d848be799ff21a80c6751c088ea619891ec450f20017cc7aa5cbbeb5904ae8b8", }, }, } diff --git a/src/vm/memory/memory.zig b/src/vm/memory/memory.zig index a022ce46..162986f6 100644 --- a/src/vm/memory/memory.zig +++ b/src/vm/memory/memory.zig @@ -23,7 +23,7 @@ const RangeCheckBuiltinRunner = @import("../builtins/builtin_runner/range_check. // Function that validates a memory address and returns a list of validated adresses pub const validation_rule = *const fn (Allocator, *Memory, Relocatable) anyerror!std.ArrayList(Relocatable); -pub const MemoryCell = struct { +pub const MemoryCell = extern struct { /// Represents a memory cell that holds relocation information and access status. const Self = @This(); const ACCESS_MASK: u64 = 1 << 62; @@ -103,8 +103,12 @@ pub const MemoryCell = struct { /// # Returns /// /// Returns `true` if both MemoryCell instances are equal, otherwise `false`. - pub fn eql(self: Self, other: Self) bool { - return std.mem.eql(u64, self.data[0..], other.data[0..]); + pub fn eql(self: *const Self, other: *const Self) bool { + inline for (0..4) |i| { + if (self.data[i] != other.data[i]) return false; + } + + return true; } /// Checks equality between slices of MemoryCell instances. @@ -124,7 +128,7 @@ pub const MemoryCell = struct { if (a.len != b.len) return false; if (a.ptr == b.ptr) return true; - for (a, b) |a_elem, b_elem| { + for (a, b) |*a_elem, *b_elem| { if (!a_elem.eql(b_elem)) return false; } @@ -609,20 +613,11 @@ pub const Memory = struct { /// # Returns /// /// Returns the segment of MemoryCell items if it exists, or `null` if not found. - fn getSegmentAtIndex(self: *Self, idx: i64) ?[]MemoryCell { - return switch (idx < 0) { - true => blk: { - const i: usize = @intCast(-(idx + 1)); - break :blk if (i < self.temp_data.items.len) - self.temp_data.items[i].items - else - null; - }, - false => if (idx < self.data.items.len) - self.data.items[@intCast(idx)].items - else - null, - }; + inline fn getSegmentAtIndex(self: *const Self, idx: i64) ?[]MemoryCell { + return if (idx < 0) { + const i: usize = @bitCast(-(idx + 1)); + return if (i >= self.temp_data.items.len) null else self.temp_data.items[i].items; + } else if (idx >= self.data.items.len) null else self.data.items[@intCast(idx)].items; } /// Compares two memory segments within the VM's memory starting from specified addresses @@ -663,12 +658,6 @@ pub const Memory = struct { const l_idx = lhs.offset + i; const r_idx = rhs.offset + i; - // std.log.err("lhs: {any}, rhs: {any}, i: {any}, {any}", .{ - // if (l_idx < ls.len) ls[l_idx] else MemoryCell.NONE, if (r_idx < rs.len) rs[r_idx] else MemoryCell.NONE, i, MemoryCell.cmp( - // if (l_idx < ls.len) ls[l_idx] else MemoryCell.NONE, - // if (r_idx < rs.len) rs[r_idx] else MemoryCell.NONE, - // ), - // }); return switch (MemoryCell.cmp( if (l_idx < ls.len) ls[l_idx] else MemoryCell.NONE, if (r_idx < rs.len) rs[r_idx] else MemoryCell.NONE, @@ -700,42 +689,24 @@ pub const Memory = struct { /// # Returns /// /// Returns `true` if segments are equal up to the specified length, otherwise `false`. - pub fn memEq(self: *Self, lhs: Relocatable, rhs: Relocatable, len: usize) !bool { + pub fn memEq(self: *const Self, lhs: Relocatable, rhs: Relocatable, len: usize) !bool { // Check if the left and right addresses are the same, in which case the segments are equal. if (lhs.eq(rhs)) return true; - // Get the segment starting from the left-hand address. - const l: ?[]MemoryCell = if (self.getSegmentAtIndex(lhs.segment_index)) |s| - // Check if the offset is within the bounds of the segment. - if (lhs.offset < s.len) s[lhs.offset..] else null - else - null; - // Get the segment starting from the right-hand address. - const r: ?[]MemoryCell = if (self.getSegmentAtIndex(rhs.segment_index)) |s| - // Check if the offset is within the bounds of the segment. - if (rhs.offset < s.len) s[rhs.offset..] else if (l == null) return true else return false - else if (l == null) return true else return false; + const r: ?[]MemoryCell = self.getSegmentAtIndex(rhs.segment_index); // If the left segment exists, perform further checks. - if (l) |ls| { + if (self.getSegmentAtIndex(lhs.segment_index)) |ls| { // If the right segment also exists, compare the segments up to the specified length. if (r) |rs| { - // Determine the actual lengths to compare. - const lhs_len = @min(ls.len, len); - const rhs_len = @min(rs.len, len); - - // Compare slices of MemoryCell items up to the specified length. - if (lhs_len != rhs_len) return false; - - return MemoryCell.eqlSlice(ls[0..lhs_len], rs[0..rhs_len]); + return MemoryCell.eqlSlice(ls[lhs.offset .. lhs.offset + len], rs[rhs.offset .. rhs.offset + len]); } // If only the left segment exists, return false. return false; } - // If the left segment does not exist, return true only if the right segment is also null. return r == null; } diff --git a/src/vm/memory/relocatable.zig b/src/vm/memory/relocatable.zig index 96bd4672..a9e538df 100644 --- a/src/vm/memory/relocatable.zig +++ b/src/vm/memory/relocatable.zig @@ -312,7 +312,16 @@ pub const MaybeRelocatable = union(enum) { /// * `true` if the two instances are equal. /// * `false` otherwise. pub fn eq(self: Self, other: Self) bool { - return std.meta.eql(self, other); + return switch (self) { + inline .felt => |f| switch (other) { + inline .felt => |f1| f.eql(f1), + else => false, + }, + inline .relocatable => |r| switch (other) { + inline .relocatable => |r1| r.eq(r1), + else => false, + }, + }; } /// Determines if self is less than other. From 1a4fe1a8007fbe304be2b93dbf224eb526b6e3d1 Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Wed, 19 Jun 2024 22:29:28 +0200 Subject: [PATCH 2/6] fix + improved perf --- src/hint_processor/set.zig | 17 ++++++++-- src/vm/core_test.zig | 4 +-- src/vm/memory/memory.zig | 68 +++++++++++++++++++++++++++++++------- 3 files changed, 73 insertions(+), 16 deletions(-) diff --git a/src/hint_processor/set.zig b/src/hint_processor/set.zig index 23bfd51e..6ce4c6c1 100644 --- a/src/hint_processor/set.zig +++ b/src/hint_processor/set.zig @@ -12,6 +12,7 @@ const HintProcessor = @import("hint_processor_def.zig").CairoVMHintProcessor; const HintData = @import("hint_processor_def.zig").HintData; const Relocatable = @import("../vm/memory/relocatable.zig").Relocatable; const MaybeRelocatable = @import("../vm/memory/relocatable.zig").MaybeRelocatable; +const MemoryCell = @import("../vm/memory/memory.zig").MemoryCell; const Felt252 = @import("../math/fields/starknet.zig").Felt252; const hint_codes = @import("builtin_hint_codes.zig"); const MathError = @import("../vm/error.zig").MathError; @@ -60,10 +61,22 @@ pub fn setAdd( // Calculate the range limit. const range_limit = (try set_end_ptr.sub(set_ptr)).offset; + // load all list, and then we compare elements + var elm_segment = vm.segments.memory.getSegmentAtIndex(elm_ptr.segment_index) orelse return error.InvalidSetRange1; + + if (elm_segment.len < elm_ptr.offset + elm_size) return error.InvalidSetRange2; + + var set_segment = vm.segments.memory.getSegmentAtIndex(set_ptr.segment_index) orelse return error.InvalidSetRange3; + + if (set_ptr.offset + range_limit > set_segment.len) return error.InvalidSetRange4; + + elm_segment = elm_segment[elm_ptr.offset .. elm_ptr.offset + elm_size]; + set_segment = set_segment[set_ptr.offset .. set_ptr.offset + range_limit]; + // Iterate over the set elements. - for (0..range_limit) |i| { + for (0..range_limit / elm_size) |i| { // Check if the element is in the set. - if (try vm.memEq(elm_ptr, try set_ptr.addUint(elm_size * i), elm_size)) { + if (MemoryCell.eqlSlice(elm_segment, set_segment[i * elm_size .. (i + 1) * elm_size])) { // Insert index of the element into the virtual machine. try hint_utils.insertValueFromVarName( allocator, diff --git a/src/vm/core_test.zig b/src/vm/core_test.zig index ff677121..1af05223 100644 --- a/src/vm/core_test.zig +++ b/src/vm/core_test.zig @@ -3666,7 +3666,7 @@ test "CairoVM: runInstruction without any insertion in the memory" { // Compare each cell in VM's memory with the corresponding cell in the expected memory. for (vm.segments.memory.data.items, 0..) |d, i| { for (d.items, 0..) |cell, j| { - try expect(cell.eql(expected_memory.data.items[i].items[j])); + try expect(cell.eql(&expected_memory.data.items[i].items[j])); } } } @@ -3839,7 +3839,7 @@ test "CairoVM: runInstruction with Op0 being deduced" { // Compare each cell in VM's memory with the corresponding cell in the expected memory. for (vm.segments.memory.data.items, 0..) |d, i| { for (d.items, 0..) |cell, j| { - try expect(cell.eql(expected_memory.data.items[i].items[j])); + try expect(cell.eql(&expected_memory.data.items[i].items[j])); } } } diff --git a/src/vm/memory/memory.zig b/src/vm/memory/memory.zig index 162986f6..03d38d2f 100644 --- a/src/vm/memory/memory.zig +++ b/src/vm/memory/memory.zig @@ -613,7 +613,7 @@ pub const Memory = struct { /// # Returns /// /// Returns the segment of MemoryCell items if it exists, or `null` if not found. - inline fn getSegmentAtIndex(self: *const Self, idx: i64) ?[]MemoryCell { + pub inline fn getSegmentAtIndex(self: *const Self, idx: i64) ?[]MemoryCell { return if (idx < 0) { const i: usize = @bitCast(-(idx + 1)); return if (i >= self.temp_data.items.len) null else self.temp_data.items[i].items; @@ -693,21 +693,35 @@ pub const Memory = struct { // Check if the left and right addresses are the same, in which case the segments are equal. if (lhs.eq(rhs)) return true; + // Get the segment starting from the left-hand address. + const l: ?[]MemoryCell = if (self.getSegmentAtIndex(lhs.segment_index)) |s| + // Check if the offset is within the bounds of the segment. + if (lhs.offset < s.len) s[lhs.offset..] else null + else + null; + // Get the segment starting from the right-hand address. - const r: ?[]MemoryCell = self.getSegmentAtIndex(rhs.segment_index); + const r: ?[]MemoryCell = if (self.getSegmentAtIndex(rhs.segment_index)) |s| + // Check if the offset is within the bounds of the segment. + if (rhs.offset < s.len) s[rhs.offset..] else return l == null + else + return l == null; // If the left segment exists, perform further checks. - if (self.getSegmentAtIndex(lhs.segment_index)) |ls| { + if (l) |ls| { // If the right segment also exists, compare the segments up to the specified length. - if (r) |rs| { - return MemoryCell.eqlSlice(ls[lhs.offset .. lhs.offset + len], rs[rhs.offset .. rhs.offset + len]); - } + // Determine the actual lengths to compare. + const lhs_len = @min(ls.len, len); + const rhs_len = @min(r.?.len, len); - // If only the left segment exists, return false. - return false; + // Compare slices of MemoryCell items up to the specified length. + if (lhs_len != rhs_len) return false; + + return MemoryCell.eqlSlice(ls[0..lhs_len], r.?[0..rhs_len]); } - return r == null; + // If only the left segment exists, return false. + return false; } /// Retrieves a range of memory values starting from a specified address. @@ -740,6 +754,36 @@ pub const Memory = struct { return values; } + /// Retrieves a range of memory values starting from a specified address. + /// + /// # Arguments + /// + /// * `allocator`: The allocator used for the memory allocation of the returned list. + /// * `address`: The starting address in the memory from which the range is retrieved. + /// * `size`: The size of the range to be retrieved. + /// + /// # Returns + /// + /// Returns a list containing memory values retrieved from the specified range starting at the given address. + /// The list may contain `MemoryCell.NONE` elements for inaccessible memory positions. + /// + /// # Errors + /// + /// Returns an error if there are any issues encountered during the retrieval of the memory range. + pub fn getRangeRaw( + self: *Self, + allocator: Allocator, + address: Relocatable, + size: usize, + ) !std.ArrayList(?MaybeRelocatable) { + var values = std.ArrayList(?MaybeRelocatable).init(allocator); + errdefer values.deinit(); + for (0..size) |i| { + try values.append(self.get(try address.addUint(i))); + } + return values; + } + /// Counts the number of accessed addresses within a specified segment in the VM memory. /// /// # Arguments @@ -2397,9 +2441,9 @@ test "MemoryCell: eql function" { memoryCell4.markAccessed(); // Test checks - try expect(memoryCell1.eql(memoryCell2)); - try expect(!memoryCell1.eql(memoryCell3)); - try expect(!memoryCell1.eql(memoryCell4)); + try expect(memoryCell1.eql(&memoryCell2)); + try expect(!memoryCell1.eql(&memoryCell3)); + try expect(!memoryCell1.eql(&memoryCell4)); } test "MemoryCell: eqlSlice should return false if slice len are not the same" { From 88c8d186e1027ee562547df426249f921acaa438 Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Wed, 19 Jun 2024 22:33:56 +0200 Subject: [PATCH 3/6] fix error name --- src/hint_processor/set.zig | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/hint_processor/set.zig b/src/hint_processor/set.zig index 6ce4c6c1..cfb5b732 100644 --- a/src/hint_processor/set.zig +++ b/src/hint_processor/set.zig @@ -62,13 +62,13 @@ pub fn setAdd( const range_limit = (try set_end_ptr.sub(set_ptr)).offset; // load all list, and then we compare elements - var elm_segment = vm.segments.memory.getSegmentAtIndex(elm_ptr.segment_index) orelse return error.InvalidSetRange1; + var elm_segment = vm.segments.memory.getSegmentAtIndex(elm_ptr.segment_index) orelse return HintError.InvalidSetRange; - if (elm_segment.len < elm_ptr.offset + elm_size) return error.InvalidSetRange2; + if (elm_segment.len < elm_ptr.offset + elm_size) return HintError.InvalidSetRange; - var set_segment = vm.segments.memory.getSegmentAtIndex(set_ptr.segment_index) orelse return error.InvalidSetRange3; + var set_segment = vm.segments.memory.getSegmentAtIndex(set_ptr.segment_index) orelse return HintError.InvalidSetRange; - if (set_ptr.offset + range_limit > set_segment.len) return error.InvalidSetRange4; + if (set_ptr.offset + range_limit > set_segment.len) return HintError.InvalidSetRange; elm_segment = elm_segment[elm_ptr.offset .. elm_ptr.offset + elm_size]; set_segment = set_segment[set_ptr.offset .. set_ptr.offset + range_limit]; From 6329127479a2e894210d8ecf365e2bdc06223622 Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Thu, 20 Jun 2024 01:30:40 +0200 Subject: [PATCH 4/6] rm unused --- src/vm/memory/memory.zig | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/vm/memory/memory.zig b/src/vm/memory/memory.zig index 03d38d2f..c6934eac 100644 --- a/src/vm/memory/memory.zig +++ b/src/vm/memory/memory.zig @@ -754,36 +754,6 @@ pub const Memory = struct { return values; } - /// Retrieves a range of memory values starting from a specified address. - /// - /// # Arguments - /// - /// * `allocator`: The allocator used for the memory allocation of the returned list. - /// * `address`: The starting address in the memory from which the range is retrieved. - /// * `size`: The size of the range to be retrieved. - /// - /// # Returns - /// - /// Returns a list containing memory values retrieved from the specified range starting at the given address. - /// The list may contain `MemoryCell.NONE` elements for inaccessible memory positions. - /// - /// # Errors - /// - /// Returns an error if there are any issues encountered during the retrieval of the memory range. - pub fn getRangeRaw( - self: *Self, - allocator: Allocator, - address: Relocatable, - size: usize, - ) !std.ArrayList(?MaybeRelocatable) { - var values = std.ArrayList(?MaybeRelocatable).init(allocator); - errdefer values.deinit(); - for (0..size) |i| { - try values.append(self.get(try address.addUint(i))); - } - return values; - } - /// Counts the number of accessed addresses within a specified segment in the VM memory. /// /// # Arguments From d6951749d43c760cc6971d1cd0c6d77134fc9707 Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Mon, 24 Jun 2024 19:02:27 +0200 Subject: [PATCH 5/6] poseidon benchmark impr --- build.zig.zon | 4 +-- .../builtin_runner/builtin_runner.zig | 1 + src/vm/builtins/builtin_runner/poseidon.zig | 34 +++++++------------ src/vm/memory/memory.zig | 12 +++++-- src/vm/run_context.zig | 2 +- 5 files changed, 27 insertions(+), 26 deletions(-) diff --git a/build.zig.zon b/build.zig.zon index db74dd41..7f6085d4 100644 --- a/build.zig.zon +++ b/build.zig.zon @@ -14,8 +14,8 @@ .hash = "1220ab73fb7cc11b2308edc3364988e05efcddbcac31b707f55e6216d1b9c0da13f1", }, .starknet = .{ - .url = "https://github.com/StringNick/starknet-zig/archive/57810b7a64364f1bf12725ba823385c2a213bfa5.zip", - .hash = "1220d848be799ff21a80c6751c088ea619891ec450f20017cc7aa5cbbeb5904ae8b8", + .url = "https://github.com/StringNick/starknet-zig/archive/7d51aed59982146df3581d3d3320d509b0b10f54.zip", + .hash = "1220b00c055ce40da237598e0f1c8758e3434470be648816fa4701a09f683146d4cd", }, }, } diff --git a/src/vm/builtins/builtin_runner/builtin_runner.zig b/src/vm/builtins/builtin_runner/builtin_runner.zig index c604d445..2f352bf3 100644 --- a/src/vm/builtins/builtin_runner/builtin_runner.zig +++ b/src/vm/builtins/builtin_runner/builtin_runner.zig @@ -182,6 +182,7 @@ pub const BuiltinRunner = union(BuiltinName) { pub fn cellsPerInstance(self: *const BuiltinRunner) u32 { return switch (self.*) { .Output => 0, + .Poseidon => 6, inline else => |*builtin| builtin.cells_per_instance, }; } diff --git a/src/vm/builtins/builtin_runner/poseidon.zig b/src/vm/builtins/builtin_runner/poseidon.zig index 0e54628f..14887aca 100644 --- a/src/vm/builtins/builtin_runner/poseidon.zig +++ b/src/vm/builtins/builtin_runner/poseidon.zig @@ -35,10 +35,6 @@ pub const PoseidonBuiltinRunner = struct { base: usize = 0, /// Ratio ratio: ?u32, - /// Number of cells per instance - cells_per_instance: u32 = poseidon_instance_def.CELLS_PER_POSEIDON, - /// Number of input cells - n_input_cells: u32 = poseidon_instance_def.INPUT_CELLS_PER_POSEIDON, /// Stop pointer stop_ptr: ?usize = null, /// Included boolean flag @@ -201,7 +197,7 @@ pub const PoseidonBuiltinRunner = struct { return std.math.divCeil( usize, try self.getUsedCells(segments), - self.cells_per_instance, + 6, ); } @@ -226,32 +222,27 @@ pub const PoseidonBuiltinRunner = struct { address: Relocatable, memory: *Memory, ) !?MaybeRelocatable { + _ = allocator; // autofix // Calculate the index of the memory cell. - const index = @mod( + const index: usize = @mod( @as(usize, @intCast(address.offset)), - @as(usize, @intCast(self.cells_per_instance)), + poseidon_instance_def.CELLS_PER_POSEIDON, ); // Check if the index corresponds to an input cell, if so, return null. - if (index < self.n_input_cells) return null; + if (index < poseidon_instance_def.INPUT_CELLS_PER_POSEIDON) return null; // Check if the cell value is already cached, if so, return it. if (self.cache.get(address)) |felt| return .{ .felt = felt }; // Calculate the addresses for the first input cell and first output cell. const first_input_addr = try address.subUint(index); - const first_output_addr = try first_input_addr.addUint(self.n_input_cells); + const first_output_addr = try first_input_addr.addUint(poseidon_instance_def.INPUT_CELLS_PER_POSEIDON); // Initialize an array list to store input cell values. - var input_felts = try ArrayList(Felt252).initCapacity(allocator, self.n_input_cells); - defer input_felts.deinit(); - // Iterate over input cells, retrieve their values, and append them to the array list. - for (0..self.n_input_cells) |i| { - const val = memory.get(try first_input_addr.addUint(i)) orelse return null; - try input_felts.append(val.intoFelt() catch - return RunnerError.BuiltinExpectedInteger); - } + var input_felts = memory.getFeltRange(first_input_addr, poseidon_instance_def.INPUT_CELLS_PER_POSEIDON) catch return RunnerError.BuiltinExpectedInteger; + defer input_felts.deinit(); // Perform Poseidon permutation computation on the input cells. // TODO: optimize to use pointer on state @@ -261,11 +252,12 @@ pub const PoseidonBuiltinRunner = struct { PoseidonHasher.permuteComp(); - @memcpy(input_felts.items[0..3], PoseidonHasher.state[0..3]); - // Iterate over input cells and cache their computed values. - for (0..self.n_input_cells, input_felts.items) |i, elem| { - try self.cache.put(try first_output_addr.addUint(i), elem); + inline for (0..3) |i| { + try self.cache.put( + try first_output_addr.addUint(i), + PoseidonHasher.state[i], + ); } // Return the cached value for the specified memory cell address. diff --git a/src/vm/memory/memory.zig b/src/vm/memory/memory.zig index c6934eac..9110accd 100644 --- a/src/vm/memory/memory.zig +++ b/src/vm/memory/memory.zig @@ -839,8 +839,16 @@ pub const Memory = struct { ); errdefer values.deinit(); - for (0..size) |i| { - try values.append(try self.getFelt(try address.addUint(i))); + var segment = self.getSegmentAtIndex(address.segment_index) orelse return MemoryError.UnknownMemoryCell; + if (segment.len < address.offset + size) return MemoryError.UnknownMemoryCell; + + for (segment[address.offset .. address.offset + size]) |cell| { + if (cell.getValue()) |mr| { + switch (mr) { + inline .felt => |f| values.appendAssumeCapacity(f), + inline else => return MemoryError.ExpectedInteger, + } + } else return MemoryError.UnknownMemoryCell; } return values; diff --git a/src/vm/run_context.zig b/src/vm/run_context.zig index 2e3421bc..47fd2336 100644 --- a/src/vm/run_context.zig +++ b/src/vm/run_context.zig @@ -67,7 +67,7 @@ pub const RunContext = struct { try base_addr.subUint(@abs(instruction.off_0)) else // Convert i16 to u64 safely - try base_addr.addUint(@bitCast(instruction.off_0)); + try base_addr.addUint(@intCast(instruction.off_0)); } /// Compute OP 0 address for a given instruction. From bae87c66db61f0a406588e2689189efd192ca8c6 Mon Sep 17 00:00:00 2001 From: Nikita Orlov Date: Wed, 26 Jun 2024 12:03:08 +0200 Subject: [PATCH 6/6] fix test, rm unused --- src/poseidon_consts_gen.zig | 141 ------------------ .../builtin_runner/builtin_runner.zig | 1 + src/vm/builtins/builtin_runner/poseidon.zig | 4 +- 3 files changed, 4 insertions(+), 142 deletions(-) delete mode 100644 src/poseidon_consts_gen.zig diff --git a/src/poseidon_consts_gen.zig b/src/poseidon_consts_gen.zig deleted file mode 100644 index 2986653a..00000000 --- a/src/poseidon_consts_gen.zig +++ /dev/null @@ -1,141 +0,0 @@ -/// Generating constants for poseidon hashing function -/// All memory allocation is on arena allocator -/// -const std = @import("std"); -const Felt252 = @import("./math/fields/starknet.zig").Felt252; -const Allocator = std.mem.Allocator; - -const round_constants_block = "/// based on https://github.com/starkware-industries/poseidon/blob/5403dff9ff4eadb07deb5c0a43e88bedb011deb8/poseidon3.txt\n" ++ - "///\n///\n/// This file is autogenerated by poseidon_consts_gen.zig\n///\n///\n" ++ - "const Felt252 = @import(\"../../../fields/starknet.zig\").Felt252;\n\npub const POSEIDON_COMPRESSED_ROUND_CONSTS: [{d}]Felt252 = .{{\n {s}\n }};" ++ - "\n\npub const POSEIDON_FULL_ROUNDS: usize = {d};\n\npub const POSEIDON_PARTIAL_ROUNDS: usize = {d};\n\n"; - -const round_constants_block_item = ".{{ .fe = [4]u64{{ {}, {}, {}, {}, }} }},\n"; - -const ConfigJSON = struct { - full_rounds: usize, - partial_rounds: usize, - round_keys: [][3]u256, -}; - -// generateRoundConstantBlock - injecting compressed round constants and config into template -// result slice owner is caller, so it should be deinit by caller -fn generateRoundConstantBlock(allocator: Allocator, config: ConfigJSON, round_keys: []Felt252) ![]const u8 { - var array_tpl = std.ArrayList(u8).init(allocator); - defer array_tpl.deinit(); - - for (round_keys) |round_key| { - const value = round_key.fe; - // writing array felt item - try std.fmt.format(array_tpl.writer(), round_constants_block_item, .{ - value[0], - value[1], - value[2], - value[3], - }); - } - - var result = std.ArrayList(u8).init(allocator); - - try std.fmt.format(result.writer(), round_constants_block, .{ - round_keys.len, - try array_tpl.toOwnedSlice(), - config.full_rounds, - config.partial_rounds, - }); - - return try result.toOwnedSlice(); -} - -// parseConfig - parsing config from json, allocator should be arena allocator -fn parseConfig(allocator: Allocator, json_spec: []const u8) !ConfigJSON { - return try std.json.parseFromSliceLeaky( - ConfigJSON, - allocator, - json_spec, - .{ .allocate = std.json.AllocWhen.alloc_always }, - ); -} - -// compressRoundConstants - compressing round constants -// caller is owner of result slice and should deinit it -fn compressRoundConstants(allocator: Allocator, config: ConfigJSON, round_constants: [][3]Felt252) ![]Felt252 { - var result = std.ArrayList(Felt252).init(allocator); - - for (round_constants[0 .. config.full_rounds / 2]) |rk| { - inline for (0..3) |i| { - try result.append(rk[i]); - } - } - - var idx = config.full_rounds / 2; - - var state = [_]Felt252{Felt252.zero()} ** 3; - - // Add keys for partial rounds - for (0..config.partial_rounds) |_| { - inline for (0..3) |i| { - state[i] = Felt252.add(state[i], round_constants[idx][i]); - } - - // Add last state - try result.append(state[2]); - - // Reset last state - state[2] = Felt252.zero(); - - const st = Felt252.add(Felt252.add(state[0], state[1]), state[2]); - - // MixLayer - state[0] = Felt252.add(st, Felt252.mul(Felt252.two(), state[0])); - state[1] = Felt252.sub(st, Felt252.mul(Felt252.two(), state[1])); - state[2] = Felt252.sub(st, Felt252.mul(Felt252.two(), state[2])); - - idx += 1; - } - - // Add keys for first of the last full rounds - inline for (0..3) |i| { - state[i] = Felt252.add(state[i], round_constants[idx][i]); - try result.append(state[i]); - } - - for (round_constants[config.full_rounds / 2 + config.partial_rounds + 1 ..]) |rk| { - try result.appendSlice(&rk); - } - - return try result.toOwnedSlice(); -} - -// parseNumbersToFieldElement - parsing numbers to field element -// caller is owner of result slice and should deinit it -fn parseNumbersToFieldElement(allocator: Allocator, keys: [][3]u256) ![][3]Felt252 { - var result = try allocator.alloc([3]Felt252, keys.len); - - for (keys, 0..) |key, idx| { - for (key, 0..) |k, idy| { - result[idx][idy] = Felt252.fromInt(u256, k); - } - } - - return result; -} - -pub fn main() !void { - var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); - defer arena.deinit(); - const allocator = arena.allocator(); - - // writing constants for poseidon - const config = try parseConfig(allocator, @embedFile("./math/crypto/poseidon/gen/config.json")); - - const round_consts = try parseNumbersToFieldElement(allocator, config.round_keys); - - const compressed_round_consts = try compressRoundConstants(allocator, config, round_consts); - - const result = try generateRoundConstantBlock(allocator, config, compressed_round_consts); - - var file = try std.fs.cwd().openFile("./src/math/crypto/poseidon/gen/constants.zig", .{ .mode = .write_only }); - - try file.writer().writeAll(result); -} diff --git a/src/vm/builtins/builtin_runner/builtin_runner.zig b/src/vm/builtins/builtin_runner/builtin_runner.zig index 2f352bf3..2654cd87 100644 --- a/src/vm/builtins/builtin_runner/builtin_runner.zig +++ b/src/vm/builtins/builtin_runner/builtin_runner.zig @@ -608,6 +608,7 @@ pub const BuiltinRunner = union(BuiltinName) { return switch (self.*) { .Output => 0, .SegmentArena => |*segment_arena| segment_arena.n_input_cells_per_instance, + .Poseidon => PoseidonBuiltinRunner.INPUT_CELLS_PER_POSEIDON, inline else => |*builtin| builtin.n_input_cells, }; } diff --git a/src/vm/builtins/builtin_runner/poseidon.zig b/src/vm/builtins/builtin_runner/poseidon.zig index 14887aca..c7cb97f7 100644 --- a/src/vm/builtins/builtin_runner/poseidon.zig +++ b/src/vm/builtins/builtin_runner/poseidon.zig @@ -31,6 +31,8 @@ const expectEqualSlices = std.testing.expectEqualSlices; pub const PoseidonBuiltinRunner = struct { const Self = @This(); + pub const INPUT_CELLS_PER_POSEIDON = poseidon_instance_def.INPUT_CELLS_PER_POSEIDON; + /// Base base: usize = 0, /// Ratio @@ -153,7 +155,7 @@ pub const PoseidonBuiltinRunner = struct { // Calculate the expected stop pointer value based on the number of used instances. const stop_ptr = stop_pointer.offset; - if (stop_ptr != try self.getUsedInstances(segments) * self.cells_per_instance) + if (stop_ptr != try self.getUsedInstances(segments) * poseidon_instance_def.CELLS_PER_POSEIDON) return RunnerError.InvalidStopPointer; // Set the stop pointer and return the address of the stop pointer.