From dc0b15785c2fab3139cb6af4e1670e9fe5690888 Mon Sep 17 00:00:00 2001 From: DavePearce Date: Wed, 26 Aug 2026 17:36:58 +1200 Subject: [PATCH 1/6] feat: support sharding of interpreter() function This puts in place support for sharding on the interpreter() function. This is done by converting the interpreter loop into a recursive "no return" function call. The key about this approach, is that it makes it relatively simple to then shard the interpreter() function. NOTE: this also updates ZkC to version v1.2.30, since only this version supports "no return" functions. Signed-off-by: DavePearce --- arithmetization/Makefile | 2 +- arithmetization/src/main/lib/keccak/impl.zkc | 12 +++--- .../src/main/riscv/interpreter.zkc | 22 +++++++++- arithmetization/src/main/riscv/main.zkc | 41 +------------------ 4 files changed, 29 insertions(+), 48 deletions(-) diff --git a/arithmetization/Makefile b/arithmetization/Makefile index cb14585af5..bedefaca48 100644 --- a/arithmetization/Makefile +++ b/arithmetization/Makefile @@ -11,7 +11,7 @@ REPO_ROOT := $(abspath $(MAKEFILE_DIR)/..) ZKC ?= $(REPO_ROOT)/zkc ZKC_REPO ?= https://github.com/LFDT-Lineth/zkc.git # Optional: pin a commit or branch (e.g. 763f30878e5fc260f0d88863c9883c904f8fc056). Leave empty for default branch. -ZKC_REF ?= v1.2.29 +ZKC_REF ?= v1.2.30 # Used to install Sail for ACT4 host builds. ACT4_RISCV_DIR ?= $(HOME)/riscv diff --git a/arithmetization/src/main/lib/keccak/impl.zkc b/arithmetization/src/main/lib/keccak/impl.zkc index 0af099a13f..0797a0bde6 100644 --- a/arithmetization/src/main/lib/keccak/impl.zkc +++ b/arithmetization/src/main/lib/keccak/impl.zkc @@ -193,7 +193,7 @@ fn kec_theta() { for i_minus_one:u5 = 0; i_minus_one<5; i_minus_one = i_minus_one + 1 { var i:u5 = i_minus_one + 1 - keccak_state[D + (mod5(i) as u7)] = keccak_state[C + (i_minus_one as u7)] ^ bit_rotl64(keccak_state[C + (mod5(i + 1) as u7)], 1) + keccak_state[D + (mod5[i] as u7)] = keccak_state[C + (i_minus_one as u7)] ^ bit_rotl64(keccak_state[C + (mod5[i + 1] as u7)], 1) } for j:u7 = 0; j<5; j = j + 1 { @@ -211,11 +211,11 @@ fn kec_theta() { fn kec_rho() { for j:u3 = 0; j<5; j = j + 1 { - keccak_state[ROW0 + (j as u7)] = bit_rotl64(keccak_state[ROW0 + (j as u7)], rot_offset(0, j)) - keccak_state[ROW1 + (j as u7)] = bit_rotl64(keccak_state[ROW1 + (j as u7)], rot_offset(1, j)) - keccak_state[ROW2 + (j as u7)] = bit_rotl64(keccak_state[ROW2 + (j as u7)], rot_offset(2, j)) - keccak_state[ROW3 + (j as u7)] = bit_rotl64(keccak_state[ROW3 + (j as u7)], rot_offset(3, j)) - keccak_state[ROW4 + (j as u7)] = bit_rotl64(keccak_state[ROW4 + (j as u7)], rot_offset(4, j)) + keccak_state[ROW0 + (j as u7)] = bit_rotl64(keccak_state[ROW0 + (j as u7)], rot_offset[0, j]) + keccak_state[ROW1 + (j as u7)] = bit_rotl64(keccak_state[ROW1 + (j as u7)], rot_offset[1, j]) + keccak_state[ROW2 + (j as u7)] = bit_rotl64(keccak_state[ROW2 + (j as u7)], rot_offset[2, j]) + keccak_state[ROW3 + (j as u7)] = bit_rotl64(keccak_state[ROW3 + (j as u7)], rot_offset[3, j]) + keccak_state[ROW4 + (j as u7)] = bit_rotl64(keccak_state[ROW4 + (j as u7)], rot_offset[4, j]) } } diff --git a/arithmetization/src/main/riscv/interpreter.zkc b/arithmetization/src/main/riscv/interpreter.zkc index 3a294a4253..55242ac91f 100644 --- a/arithmetization/src/main/riscv/interpreter.zkc +++ b/arithmetization/src/main/riscv/interpreter.zkc @@ -188,9 +188,27 @@ include "../lib/io/write_output.zkc" // The tiers above list explicit semantic opcodes (`*_WB`, branches, stores, // precompiles, …); anything not matched there eventually reaches the // `interpreter_c` default and behaves as a no-op. -// -fn interpreter(index:u64, pc:Address, output_write_address:OutputAddress) -> (new_pc:Address, new_output_write_address:OutputAddress) { +fn interpreter(clk:u32, base:Address, pc:Address, output_write_address:OutputAddress) -> ! { + var new_output_write_address:OutputAddress + var new_pc:Address + var index:u62 + var rem:u2 + // determine index of predecoded program + index::rem = pc - base + // + printf "\n----------------------------------------------------------------- PC=%d, clock cycle: %d\n", pc, clk + // Execute current instruction + new_pc, new_output_write_address = interpreter_a(index as u64, pc, output_write_address) + // Check for termination + if new_pc != MAX_UINT_64 { + // Execute next instruction + interpreter!(clk + 1, base, new_pc, new_output_write_address) + } + // Termination + done +} +fn interpreter_a(index:u64, pc:Address, output_write_address:OutputAddress) -> (new_pc:Address, new_output_write_address:OutputAddress) { var compute_op:ComputeOp var imm:DoubleWord var rs1:Register diff --git a/arithmetization/src/main/riscv/main.zkc b/arithmetization/src/main/riscv/main.zkc index 4585673eb1..740f2d87b8 100644 --- a/arithmetization/src/main/riscv/main.zkc +++ b/arithmetization/src/main/riscv/main.zkc @@ -76,43 +76,6 @@ fn main() { // -- PREDECODING SECTION END-- // -- NO PREDECODING -- - main_loop(entry_point, base) + interpreter!(0, base, entry_point, 0) // -- NO PREDECODING END-- -} - -// -- PREDECODING SECTION -- -// fn main_loop(entry_point:u64, base:u64, exec_end:u64) { -// -- PREDECODING SECTION END-- - -// -- NO PREDECODING -- -fn main_loop(entry_point:u64, base:u64) { - // -- NO PREDECODING END-- - var clock_cycle:u32 = 0 - var output_write_address:OutputAddress = 0 - var pc:Address = entry_point - - // We interpret pc == MAX_UINT_64 as the stop signal, which is set by the ecall instruction - while pc != MAX_UINT_64 { - var index:u62 - var rem:u2 - // rem is the remainder of pc - base divided by 4 - index::rem = pc - base - - // NOTE: This section pertains to the predecoding justification - // It is pending decision and is commented for now. - // Execution must stay inside the span justified by predecoding, at 4-byte - // aligned PCs, so decoded[(pc - base) / 4] matches the row checked at pc. - // if pc= exec_end || rem != 0 { - // printf "[ERROR] pc outside executable span (pc=%d base=%d exec_end=%d)\n", pc, base, exec_end - // fail - // } - - // clock cycle starts at 1 - clock_cycle = clock_cycle + 1 - printf "\n----------------------------------------------------------------- PC=%d, clock cycle: %d\n", pc, clock_cycle - - // update pc and output_write_address - pc, output_write_address = interpreter(index as u64, pc, output_write_address) - } -} - +} \ No newline at end of file From 34ca457abc0bbd3b92760068f70270824fc02237 Mon Sep 17 00:00:00 2001 From: DavePearce Date: Wed, 26 Aug 2026 19:30:05 +1200 Subject: [PATCH 2/6] fix: return comment re: justification This puts back a comment removed regarding the justification. Signed-off-by: DavePearce --- arithmetization/src/main/riscv/interpreter.zkc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/arithmetization/src/main/riscv/interpreter.zkc b/arithmetization/src/main/riscv/interpreter.zkc index 55242ac91f..eda93d5bc9 100644 --- a/arithmetization/src/main/riscv/interpreter.zkc +++ b/arithmetization/src/main/riscv/interpreter.zkc @@ -195,6 +195,14 @@ fn interpreter(clk:u32, base:Addr var rem:u2 // determine index of predecoded program index::rem = pc - base + // NOTE: This section pertains to the predecoding justification + // It is pending decision and is commented for now. + // Execution must stay inside the span justified by predecoding, at 4-byte + // aligned PCs, so decoded[(pc - base) / 4] matches the row checked at pc. + // if pc= exec_end || rem != 0 { + // printf "[ERROR] pc outside executable span (pc=%d base=%d exec_end=%d)\n", pc, base, exec_end + // fail + // } // printf "\n----------------------------------------------------------------- PC=%d, clock cycle: %d\n", pc, clk // Execute current instruction From 1f60ea432c14d7cb05c4178c7cc4a50df9c97071 Mon Sep 17 00:00:00 2001 From: amkCha <29160563+amkCha@users.noreply.github.com> Date: Wed, 26 Aug 2026 10:58:32 +0200 Subject: [PATCH 3/6] feat: no proof works, naming for comment changes Signed-off-by: amkCha <29160563+amkCha@users.noreply.github.com> --- arithmetization/src/main/common/constants.zkc | 4 ++-- arithmetization/src/main/common/inputs.zkc | 4 ++-- .../src/main/riscv/interpreter.zkc | 13 ++++++------ arithmetization/src/main/riscv/main.zkc | 21 ++++++++++--------- .../src/main/riscv/utils/sign_extend.zkc | 8 +++---- 5 files changed, 26 insertions(+), 24 deletions(-) diff --git a/arithmetization/src/main/common/constants.zkc b/arithmetization/src/main/common/constants.zkc index fe94a1913a..46ea45db48 100644 --- a/arithmetization/src/main/common/constants.zkc +++ b/arithmetization/src/main/common/constants.zkc @@ -421,7 +421,7 @@ const J_TYPE:Type = 6 // treat them as such — advance PC by 4, do nothing else. const MISC_MEM_TYPE:Type = 7 -// -- PREDECODING SECTION -- +// -- PREDECODING PROOF SECTION -- // static instruction_type_from_opcode(opcode:Opcode) -> (instruction_type:Type) { // UNDEFINED_TYPE, // 0b0000000 // UNDEFINED_TYPE, // 0b0000001 @@ -552,4 +552,4 @@ const MISC_MEM_TYPE:Type = 7 // UNDEFINED_TYPE, // 0b1111110 // UNDEFINED_TYPE, // 0b1111111 // } -// -- PREDECODING SECTION END-- +// -- PREDECODING PROOF SECTION END-- diff --git a/arithmetization/src/main/common/inputs.zkc b/arithmetization/src/main/common/inputs.zkc index 60449c9f15..6e36ec16cb 100644 --- a/arithmetization/src/main/common/inputs.zkc +++ b/arithmetization/src/main/common/inputs.zkc @@ -11,10 +11,10 @@ pub input entry_point_and_blobs_count(i:u1) -> (entry_point:Address, blobs_count // RAM offset where each blob must be written and number of bytes in each blob pub input blobs_offset_and_size(i:u64) -> (blob_offset:Address, blob_size:Length) -// -- PREDECODING SECTION -- +// -- PREDECODING PROOF SECTION -- // Whether blob i holds executable (SHF_EXECINSTR) section bytes (1) or data (0). // pub input blobs_executable(i:u64) -> (executable:u1) -// -- PREDECODING SECTION END-- +// -- PREDECODING PROOF SECTION END-- // Concatenated bytes for all sparse memory blobs, in blob order pub input blobs_data(i:Address) -> (byte:u8) diff --git a/arithmetization/src/main/riscv/interpreter.zkc b/arithmetization/src/main/riscv/interpreter.zkc index eda93d5bc9..99633d9066 100644 --- a/arithmetization/src/main/riscv/interpreter.zkc +++ b/arithmetization/src/main/riscv/interpreter.zkc @@ -188,29 +188,30 @@ include "../lib/io/write_output.zkc" // The tiers above list explicit semantic opcodes (`*_WB`, branches, stores, // precompiles, …); anything not matched there eventually reaches the // `interpreter_c` default and behaves as a no-op. -fn interpreter(clk:u32, base:Address, pc:Address, output_write_address:OutputAddress) -> ! { + +fn interpreter(clock_cycle:u32, base:Address, pc:Address, output_write_address:OutputAddress) -> ! { + var new_output_write_address:OutputAddress var new_pc:Address var index:u62 var rem:u2 // determine index of predecoded program index::rem = pc - base - // NOTE: This section pertains to the predecoding justification - // It is pending decision and is commented for now. + // -- PREDECODING PROOF SECTION -- // Execution must stay inside the span justified by predecoding, at 4-byte // aligned PCs, so decoded[(pc - base) / 4] matches the row checked at pc. // if pc= exec_end || rem != 0 { // printf "[ERROR] pc outside executable span (pc=%d base=%d exec_end=%d)\n", pc, base, exec_end // fail // } - // - printf "\n----------------------------------------------------------------- PC=%d, clock cycle: %d\n", pc, clk + // -- PREDECODING PROOF SECTION END-- + printf "\n----------------------------------------------------------------- PC=%d, clock cycle: %d\n", pc, clock_cycle // Execute current instruction new_pc, new_output_write_address = interpreter_a(index as u64, pc, output_write_address) // Check for termination if new_pc != MAX_UINT_64 { // Execute next instruction - interpreter!(clk + 1, base, new_pc, new_output_write_address) + interpreter!(clock_cycle + 1, base, new_pc, new_output_write_address) } // Termination done diff --git a/arithmetization/src/main/riscv/main.zkc b/arithmetization/src/main/riscv/main.zkc index 740f2d87b8..47393709c4 100644 --- a/arithmetization/src/main/riscv/main.zkc +++ b/arithmetization/src/main/riscv/main.zkc @@ -13,11 +13,11 @@ include "utils/register_utils.zkc" include "memory.zkc" include "../lib/poseidon2/ram.zkc" -// -- PREDECODING SECTION -- +// -- PREDECODING PROOF SECTION -- // include "../predecoding/predecoding.zkc" // include "../predecoding/read_instruction.zkc" // include "../predecoding/executable_region.zkc" -// -- PREDECODING SECTION END-- +// -- PREDECODING PROOF SECTION END-- // TODO @Ghost fn main() { @@ -37,10 +37,10 @@ fn main() { // This section is pending decision and is commented for now. // It can be done once per guest upgrade. // To re-enable predecoding : - // - uncomment all sections labeled from "PREDECODING SECTION" - // to "PREDECODING SECTION END" - // - comment the section labeled from "NO PREDECODING" - // to "NO PREDECODING END" + // - uncomment all sections labeled from "PREDECODING PROOF SECTION" + // to "PREDECODING PROOF SECTION END" + // - comment the section labeled from "NO PREDECODING PROOF" + // to "NO PREDECODING PROOF END" // var pc_predecoding:Address = base // var exec_end:Address = executable_region_end() @@ -71,11 +71,12 @@ fn main() { // Execution of the program // ========================== - // -- PREDECODING SECTION -- + // -- PREDECODING PROOF SECTION -- // main_loop(entry_point, base, exec_end) - // -- PREDECODING SECTION END-- + // -- PREDECODING PROOF SECTION END-- - // -- NO PREDECODING -- + // -- NO PREDECODING PROOF -- + // parameters: clock_cycle, base, pc, output_write_address interpreter!(0, base, entry_point, 0) - // -- NO PREDECODING END-- + // -- NO PREDECODING PROOF END-- } \ No newline at end of file diff --git a/arithmetization/src/main/riscv/utils/sign_extend.zkc b/arithmetization/src/main/riscv/utils/sign_extend.zkc index 3811bc26a3..da46808473 100644 --- a/arithmetization/src/main/riscv/utils/sign_extend.zkc +++ b/arithmetization/src/main/riscv/utils/sign_extend.zkc @@ -34,7 +34,7 @@ fn sgn_extension_u32_u64(value:u32) -> (ext_value:u64) { } } -// -- PREDECODING SECTION -- +// -- PREDECODING PROOF SECTION -- //#[inline] // fn sgn_extension_u21_u64(value:u21) -> (ext_value:u64) { // var sign:u1, tmp:u20 @@ -47,7 +47,7 @@ fn sgn_extension_u32_u64(value:u32) -> (ext_value:u64) { // ext_value = (value as u64) // } // } -// -- PREDECODING SECTION END-- +// -- PREDECODING PROOF SECTION END-- //#[inline] fn sgn_extension_u16_u64(value:u16) -> (ext_value:u64) { @@ -62,7 +62,7 @@ fn sgn_extension_u16_u64(value:u16) -> (ext_value:u64) { } } -// -- PREDECODING SECTION -- +// -- PREDECODING PROOF SECTION -- //#[inline] // fn sgn_extension_u12_u64(value:u12) -> (ext_value:u64) { // var sign:u1, tmp:u11 @@ -75,7 +75,7 @@ fn sgn_extension_u16_u64(value:u16) -> (ext_value:u64) { // ext_value = (value as u64) // } // } -// -- PREDECODING SECTION END-- +// -- PREDECODING PROOF SECTION END-- //#[inline] fn sgn_extension_u8_u64(value:u8) -> (ext_value:u64) { From add815f69d3d774cd983d525f1b6f79a50efecbe Mon Sep 17 00:00:00 2001 From: amkCha <29160563+amkCha@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:16:13 +0200 Subject: [PATCH 4/6] fix: justification proof Signed-off-by: amkCha <29160563+amkCha@users.noreply.github.com> --- .../src/main/predecoding/predecoding.zkc | 2 +- arithmetization/src/main/riscv/interpreter.zkc | 13 +++++++++++++ arithmetization/src/main/riscv/main.zkc | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/arithmetization/src/main/predecoding/predecoding.zkc b/arithmetization/src/main/predecoding/predecoding.zkc index 4ff513fe5c..d564cf3c8d 100644 --- a/arithmetization/src/main/predecoding/predecoding.zkc +++ b/arithmetization/src/main/predecoding/predecoding.zkc @@ -23,7 +23,7 @@ fn predecoding(pc:Address, instruction:Instruction) { var rd_decoded:Register compute_op, imm_decoded, rs1_decoded, rs2_decoded, rd_decoded = decoded[(pc - instruction_base[0]) / 4] - var instruction_type:Type = instruction_type_from_opcode(opcode) + var instruction_type:Type = instruction_type_from_opcode[opcode] switch instruction_type { case B_TYPE: { check_b_type(instruction_parameters, opcode, compute_op, rs1_decoded, rs2_decoded, imm_decoded) diff --git a/arithmetization/src/main/riscv/interpreter.zkc b/arithmetization/src/main/riscv/interpreter.zkc index 99633d9066..d3988fd837 100644 --- a/arithmetization/src/main/riscv/interpreter.zkc +++ b/arithmetization/src/main/riscv/interpreter.zkc @@ -189,7 +189,13 @@ include "../lib/io/write_output.zkc" // precompiles, …); anything not matched there eventually reaches the // `interpreter_c` default and behaves as a no-op. +// -- PREDECODING PROOF SECTION -- +// fn interpreter(clock_cycle:u32, base:Address, pc:Address, exec_end:Address, output_write_address:OutputAddress) -> ! { +// -- PREDECODING PROOF SECTION END-- + +// -- NO PREDECODING PROOF SECTION -- fn interpreter(clock_cycle:u32, base:Address, pc:Address, output_write_address:OutputAddress) -> ! { +// -- NO PREDECODING PROOF SECTION END-- var new_output_write_address:OutputAddress var new_pc:Address @@ -211,7 +217,14 @@ fn interpreter(clock_cycle:u32, b // Check for termination if new_pc != MAX_UINT_64 { // Execute next instruction + + // -- PREDECODING PROOF SECTION -- + // interpreter!(clock_cycle + 1, base, new_pc, exec_end, new_output_write_address) + // -- PREDECODING PROOF SECTION END-- + + // -- NO PREDECODING PROOF SECTION -- interpreter!(clock_cycle + 1, base, new_pc, new_output_write_address) + // -- NO PREDECODING PROOF SECTION END-- } // Termination done diff --git a/arithmetization/src/main/riscv/main.zkc b/arithmetization/src/main/riscv/main.zkc index 47393709c4..1797095904 100644 --- a/arithmetization/src/main/riscv/main.zkc +++ b/arithmetization/src/main/riscv/main.zkc @@ -72,7 +72,8 @@ fn main() { // ========================== // -- PREDECODING PROOF SECTION -- - // main_loop(entry_point, base, exec_end) + // parameters: clock_cycle, base, pc, exec_end, output_write_address + // interpreter!(0, base, entry_point, exec_end, 0) // -- PREDECODING PROOF SECTION END-- // -- NO PREDECODING PROOF -- From 175ab4b09184fe9663040f58179dbc752ba5819b Mon Sep 17 00:00:00 2001 From: amkCha <29160563+amkCha@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:25:48 +0200 Subject: [PATCH 5/6] fix: lint Signed-off-by: amkCha <29160563+amkCha@users.noreply.github.com> --- arithmetization/src/main/riscv/interpreter.zkc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arithmetization/src/main/riscv/interpreter.zkc b/arithmetization/src/main/riscv/interpreter.zkc index d3988fd837..5cfca11002 100644 --- a/arithmetization/src/main/riscv/interpreter.zkc +++ b/arithmetization/src/main/riscv/interpreter.zkc @@ -195,7 +195,7 @@ include "../lib/io/write_output.zkc" // -- NO PREDECODING PROOF SECTION -- fn interpreter(clock_cycle:u32, base:Address, pc:Address, output_write_address:OutputAddress) -> ! { -// -- NO PREDECODING PROOF SECTION END-- + // -- NO PREDECODING PROOF SECTION END-- var new_output_write_address:OutputAddress var new_pc:Address From 0e5a88ff8a94c5c0811eb3e4ec8ae506ea0735ff Mon Sep 17 00:00:00 2001 From: amkCha <29160563+amkCha@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:32:44 +0200 Subject: [PATCH 6/6] fix: batched keccak Signed-off-by: amkCha <29160563+amkCha@users.noreply.github.com> --- .../src/test/zkc/keccakf/keccakf_batched.zkc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arithmetization/src/test/zkc/keccakf/keccakf_batched.zkc b/arithmetization/src/test/zkc/keccakf/keccakf_batched.zkc index 0089f6656e..25fbf90d01 100644 --- a/arithmetization/src/test/zkc/keccakf/keccakf_batched.zkc +++ b/arithmetization/src/test/zkc/keccakf/keccakf_batched.zkc @@ -194,7 +194,7 @@ fn theta() { for i_minus_one:u5 = 0; i_minus_one<5; i_minus_one = i_minus_one + 1 { var i:u5 = i_minus_one + 1 - keccak_state[D + (mod5(i) as u7)] = keccak_state[C + (i_minus_one as u7)] ^ bit_rotl64(keccak_state[C + (mod5(i + 1) as u7)], 1) + keccak_state[D + (mod5[i] as u7)] = keccak_state[C + (i_minus_one as u7)] ^ bit_rotl64(keccak_state[C + (mod5[i + 1] as u7)], 1) } for j:u7 = 0; j<5; j = j + 1 { @@ -211,11 +211,11 @@ fn theta() { fn rho() { for j:u3 = 0; j<5; j = j + 1 { - keccak_state[ROW0 + (j as u7)] = bit_rotl64(keccak_state[ROW0 + (j as u7)], rot_offset(0, j)) - keccak_state[ROW1 + (j as u7)] = bit_rotl64(keccak_state[ROW1 + (j as u7)], rot_offset(1, j)) - keccak_state[ROW2 + (j as u7)] = bit_rotl64(keccak_state[ROW2 + (j as u7)], rot_offset(2, j)) - keccak_state[ROW3 + (j as u7)] = bit_rotl64(keccak_state[ROW3 + (j as u7)], rot_offset(3, j)) - keccak_state[ROW4 + (j as u7)] = bit_rotl64(keccak_state[ROW4 + (j as u7)], rot_offset(4, j)) + keccak_state[ROW0 + (j as u7)] = bit_rotl64(keccak_state[ROW0 + (j as u7)], rot_offset[0, j]) + keccak_state[ROW1 + (j as u7)] = bit_rotl64(keccak_state[ROW1 + (j as u7)], rot_offset[1, j]) + keccak_state[ROW2 + (j as u7)] = bit_rotl64(keccak_state[ROW2 + (j as u7)], rot_offset[2, j]) + keccak_state[ROW3 + (j as u7)] = bit_rotl64(keccak_state[ROW3 + (j as u7)], rot_offset[3, j]) + keccak_state[ROW4 + (j as u7)] = bit_rotl64(keccak_state[ROW4 + (j as u7)], rot_offset[4, j]) } }