left: "module verifier_addr::fri_layer {\n // This line is used for generating constants DO NOT REMOVE!\n // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000\n const COMMITMENT_MASK: u256 = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000000;\n // 0\n const FRI_CTX_TO_COSET_EVALUATIONS_OFFSET: u256 = 0x0;\n // FRI_GROUP_SIZE\n const FRI_CTX_TO_FRI_GROUP_OFFSET: u256 = 0x200;\n // FRI_CTX_TO_FRI_GROUP_OFFSET + FRI_GROUP_SIZE\n const FRI_CTX_TO_FRI_HALF_INV_GROUP_OFFSET: u256 = 0x400;\n // 0x5ec467b88826aba4537602d514425f3b0bdf467bbf302458337c45f6021e539\n const FRI_GROUP_GEN: u256 = 0x5ec467b88826aba4537602d514425f3b0bdf467bbf302458337c45f6021e539;\n // 4\n const FRI_MAX_STEP_SIZE: u256 = 0x4;\n // 3 * 0x20\n const FRI_QUEUE_SLOT_SIZE_IN_BYTES: u256 = 0x60;\n // 2^FRI_MAX_STEP_SIZE\n const MAX_COSET_SIZE: u256 = 0x10;\n // 0x40\n const MERKLE_SLOT_SIZE_IN_BYTES: u64 = 0x40;\n // 1\n const ONE_VAL: u256 = 0x1;\n // End of generating constants!\n\n use aptos_std::aptos_hash::keccak256;\n use aptos_std::from_bcs::to_u256;\n use aptos_std::math128::pow;\n\n use lib_addr::bitwise::not;\n use lib_addr::endia_encode::to_big_endian;\n use lib_addr::memory::{Memory, mload, mloadrange, mstore};\n use verifier_addr::fri_transform::{transform_coset};\n use verifier_addr::prime_field_element_0::{fmul, fpow, k_modulus, one_val};\n /*\n Gathers the \"cosetSize\" elements that belong the coset of the first element in the FRI queue.\n The elements are written to 'evaluationsOnCosetPtr'.\n\n The coset elements are read either from the FriQueue or from the verifier channel\n depending on whether the required element are in queue or not.\n\n Returns\n newFriQueueHead - The update FRI queue head i.e.\n friQueueHead + FRI_QUEUE_SLOT_SIZE_IN_BYTES * (# elements that were taken from the queue).\n cosetIdx - the start index of the coset that was gathered.\n cosetOffset - the xInv field element that corresponds to cosetIdx.\n */\n public fun gather_coset_inputs(\n memory: &mut Memory,\n channel_ptr: u256,\n fri_group_ptr: u256,\n evaluations_on_coset_ptr: u256,\n fri_queue_head: u256,\n coset_size: u256\n ): (u256, u256, u256) {\n let new_fri_queue_head: u256;\n let coset_idx: u256;\n let coset_off_set: u256;\n\n let queue_item_idx = mload(memory, fri_queue_head);\n // The coset index is represented by the most significant bits of the queue item index.;\n // The coset index is represented by the most significant bits of the queue item index.\n coset_idx = queue_item_idx & not(coset_size - 1);\n let next_coset_idx = coset_idx + coset_size;\n\n // Get the algebraic coset offset:\n // I.e. given c*g^(-k) compute c, where\n // g is the generator of the coset group.\n // k is bitReverse(offsetWithinCoset, log2(cosetSize)).\n //\n // To do this we multiply the algebraic coset offset at the top of the queue (c*g^(-k))\n // by the group element that corresponds to the index inside the coset (g^k).\n\n // (c*g^(-k))=\n let fri_queue = mload(memory, fri_queue_head + 0x40);\n // (g^k)=\n\n let queue_item = mload(memory, fri_group_ptr + (queue_item_idx - coset_idx) * 0x20);\n coset_off_set = fmul(fri_queue, queue_item);\n\n\n let proof_ptr = mload(memory, channel_ptr);\n\n let index = coset_idx;\n while (index < next_coset_idx) {\n // Inline channel operation:\n // Assume we are going to read the next element from the proof.\n // If this is not the case add(proofPtr, 0x20) will be reverted.\n let field_element_ptr = proof_ptr;\n proof_ptr = proof_ptr + 0x20;\n\n // Load the next index from the queue and check if it is our sibling.\n if (index == queue_item_idx) {\n // Take element from the queue rather than from the proof\n // and convert it back to Montgomery form for Merkle verification.\n field_element_ptr = fri_queue_head + 0x20;\n\n // Revert the read from proof.\n proof_ptr = proof_ptr - 0x20;\n\n // Reading the next index here is safe due to the\n // delimiter after the queries.\n fri_queue_head = fri_queue_head + FRI_QUEUE_SLOT_SIZE_IN_BYTES;\n queue_item_idx = mload(memory, fri_queue_head);\n };\n\n let field_element = mload(memory, field_element_ptr);\n mstore(memory, evaluations_on_coset_ptr, field_element % k_modulus());\n evaluations_on_coset_ptr = evaluations_on_coset_ptr + 0x20;\n\n index = index + 1;\n };\n mstore(memory, channel_ptr, proof_ptr);\n new_fri_queue_head = fri_queue_head;\n\n (new_fri_queue_head, coset_idx, coset_off_set)\n }\n\n public fun bit_reverse(\n num: u256,\n number_of_bits: u256\n ): u256 {\n assert!((number_of_bits == 256 || num < (pow(2, (number_of_bits as u128)) as u256)), 1);\n let n = num;\n let r = 0 ;\n let k = 0;\n while (k < number_of_bits) {\n r = (r * 2) | (n % 2);\n n = n / 2;\n k = k + 1;\n };\n r\n }\n\n /*\n Initializes the FRI group and half inv group in the FRI context.\n */\n public fun init_fri_group(\n memory: &mut Memory,\n fri_ctx: u256\n ) {\n let fri_group_ptr = fri_ctx + FRI_CTX_TO_FRI_GROUP_OFFSET;\n let fri_half_inv_group_ptr = fri_ctx + FRI_CTX_TO_FRI_HALF_INV_GROUP_OFFSET;\n\n // FRI_GROUP_GEN is the coset generator.\n // Raising it to the (MAX_COSET_SIZE - 1) power gives us the inverse.\n let gen_fri_group = FRI_GROUP_GEN;\n let gen_fri_group_inv = fpow(gen_fri_group, (MAX_COSET_SIZE - 1));\n\n let last_val = one_val();\n let last_val_inv = one_val();\n\n // ctx[mmHalfFriInvGroup + 0] = ONE_VAL;\n mstore(memory, fri_half_inv_group_ptr, last_val_inv);\n // ctx[mmFriGroup + 0] = ONE_VAL;\n mstore(memory, fri_group_ptr, last_val);\n // ctx[mmFriGroup + 1] = fsub(0, ONE_VAL);\n mstore(memory, fri_group_ptr + 0x20, k_modulus() - last_val);\n\n // To compute [1, -1 (== g^n/2), g^n/4, -g^n/4, ...]\n // we compute half the elements and derive the rest using negation.\n let half_coset_size = MAX_COSET_SIZE / 2;\n\n let i = 1;\n while (i < half_coset_size) {\n // TODO: check next 3 lines\n last_val = fmul(last_val, gen_fri_group);\n last_val_inv = fmul(last_val_inv, gen_fri_group_inv);\n let idx = bit_reverse(i, FRI_MAX_STEP_SIZE - 1);\n\n mstore(memory, fri_half_inv_group_ptr + idx * 0x20, last_val_inv);\n mstore(memory, fri_group_ptr + idx * 0x40, last_val);\n mstore(memory, fri_group_ptr + idx * 0x40 + 0x20, k_modulus() - last_val);\n\n i = i + 1;\n };\n }\n /*\n Computes the FRI step with eta = log2(friCosetSize) for all the live queries.\n\n The inputs for the current layer are read from the FRI queue and the inputs\n for the next layer are written to the same queue (overwriting the input).\n See friVerifyLayers for the description for the FRI queue.\n\n The function returns the number of live queries remaining after computing the FRI step.\n\n The number of live queries decreases whenever multiple query points in the same\n coset are reduced to a single query in the next FRI layer.\n\n As the function computes the next layer it also collects that data from\n the previous layer for Merkle verification.\n */\n public fun compute_next_layer(\n memory: &mut Memory,\n channel_ptr: u256,\n fri_queue_ptr: u256,\n merkle_queue_ptr: u256,\n n_queries: u256,\n fri_ctx: u256,\n fri_eval_point: u256,\n fri_coset_size: u256,\n ): u256 {\n let evaluation_on_coset_ptr = fri_ctx + FRI_CTX_TO_COSET_EVALUATIONS_OFFSET;\n\n // The inputs are read from the Fri queue and the result is written same queue.\n // The inputs are never overwritten since gatherCosetInputs reads at least one element and\n // transformCoset writes exactly one element.\n let input_ptr = fri_queue_ptr;\n let input_end = input_ptr + (FRI_QUEUE_SLOT_SIZE_IN_BYTES * n_queries);\n let output_ptr = fri_queue_ptr;\n\n\n while (input_ptr < input_end) {\n let coset_offset;\n let index;\n (input_ptr, index, coset_offset) = gather_coset_inputs(\n memory,\n channel_ptr,\n fri_ctx + FRI_CTX_TO_FRI_GROUP_OFFSET,\n evaluation_on_coset_ptr,\n input_ptr,\n fri_coset_size\n );\n\n\n // Compute the index of the coset evaluations in the Merkle queue.\n index = index / fri_coset_size;\n\n // Add (index, keccak256(evaluationsOnCoset)) to the Merkle queue.\n mstore(memory, merkle_queue_ptr, index);\n let keccak_input = mloadrange(memory, evaluation_on_coset_ptr, fri_coset_size * 0x20);\n\n mstore(memory, merkle_queue_ptr + 0x20, COMMITMENT_MASK & to_u256(to_big_endian(\n keccak256(keccak_input))));\n merkle_queue_ptr = merkle_queue_ptr + (MERKLE_SLOT_SIZE_IN_BYTES as u256);\n\n let (fri_value, fri_inversed_point) = transform_coset(\n memory,\n fri_ctx + FRI_CTX_TO_FRI_HALF_INV_GROUP_OFFSET,\n evaluation_on_coset_ptr,\n coset_offset,\n fri_eval_point,\n fri_coset_size\n );\n\n mstore(memory, output_ptr, index);\n mstore(memory, output_ptr + 0x20, fri_value);\n mstore(memory, output_ptr + 0x40, fri_inversed_point);\n\n output_ptr = output_ptr + FRI_QUEUE_SLOT_SIZE_IN_BYTES;\n };\n\n return (output_ptr - fri_queue_ptr) / FRI_QUEUE_SLOT_SIZE_IN_BYTES\n }\n}\n"