diff --git a/CMakeLists.txt b/CMakeLists.txt index 13e226f6..6dac4382 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,12 @@ set(CMAKE_CXX_EXTENSIONS Off) add_compile_options(-Wall -Wextra -Wconversion -Wno-sign-conversion -Wno-unknown-pragmas) +include(HunterGate) +HunterGate( + URL "https://github.com/ruslo/hunter/archive/v0.20.24.tar.gz" + SHA1 "3e2037a462bcf2ec3440f60298d933e74ffd4df3" +) + project(evm2wasm) include(ProjectBinaryen) diff --git a/README.md b/README.md index 52770b20..4cfe9cc0 100644 --- a/README.md +++ b/README.md @@ -36,12 +36,20 @@ $ bin/evm2wasm.js -e `evm_bytecode_file` -o `wasm_output_file` --wast --charge-p * To lint run `npm run lint` * And make sure you test with `npm test` and `npm run vmTests` which runs the offical Ethereum test suite -The above build command will invoke `wasm/generateInterface.js` which generates `wasm/wast.json` containing a +The above build command will invoke `wasm/generateInterface.js` which generates `wasm/wast.json` and `include/wast.h` containing a Webassembly function corresponding to each EVM opcode. -The core logic of the evm2wasm compiler is in `index.js`, which iterates the input EMV bytecode and generates +The core logic of the evm2wasm compiler is in `index.js` (Javascript frontend) or `libs/evm2wasm/evm2wasm.cpp` (C++ fronetend), which iterates the input EMV bytecode and generates a Webassembly output by invoking each of the above generated Webassembly functions and concatenating them into the output. +To build the C++ frontend: +``` +$ mkdir build +$ cd build +$ cmake .. +$ make +``` + # API [./docs/](./docs/index.md) diff --git a/circle.yml b/circle.yml index 4f39718c..999128b2 100644 --- a/circle.yml +++ b/circle.yml @@ -27,17 +27,32 @@ defaults: build-hera: &build-hera run: - name: "build hera" + name: "Build hera" working_directory: ~ command: | git clone https://github.com/ewasm/hera cd hera - git reset 817d85bb4f09d24f11ddfc67bcc548032f708cfc --hard + git reset ef3c17f3d4fec8abb6d2901bc363a7461fa1a9d9 --hard git submodule update --init --recursive cmake -DBUILD_SHARED_LIBS=ON . make -j8 mv ~/evm2wasm/hera/src/libhera.so ~/libhera.so + build-hera-cpp: &build-hera-cpp + run: + name: "Build hera (with builtin evm2wasm)" + working_directory: ~ + command: | + git clone https://github.com/ewasm/hera + cd hera + git reset ef3c17f3d4fec8abb6d2901bc363a7461fa1a9d9 --hard + git submodule update --init --recursive + rm -rf evm2wasm + ln -s /home/builder/evm2wasm evm2wasm + cmake -DBUILD_SHARED_LIBS=ON -DCMAKE_TOOLCHAIN_FILE=evm2wasm/cmake/toolchains/cxx11-pic.cmake . + make -j8 + mv ~/evm2wasm/hera/src/libhera.so ~/libhera.so + vm-tests: &vm-tests run: name: "Run ethereum VM tests" @@ -76,6 +91,22 @@ defaults: testeth -t GeneralStateTests/stMemoryTest -- --testpath ~/tests --singlenet "Byzantium" --singletest "memReturn" --vm ~/libhera.so --evmc evm2wasm.js=true echo "ran the state tests." + state-tests: &state-tests-cpp + run: + name: "Run Ethereum state tests" + working_directory: ~/build + command: | + echo 'export PATH=~/evm2wasm/bin:$PATH' >> $BASH_ENV + source $BASH_ENV + echo "running testeth command..." + testeth -t GeneralStateTests/stExample -- --testpath ~/tests --singlenet "Byzantium" --singletest "add11" --vm ~/libhera.so --evmc evm2wasm.cpp=true + #testeth -t GeneralStateTests/stStackTests -- --testpath ~/tests --singlenet "Byzantium" --vm ~/libhera.so --evmc evm2wasm.cpp=true + testeth -t GeneralStateTests/stBadOpcode -- --testpath ~/tests --singlenet "Byzantium" --vm ~/libhera.so --evmc evm2wasm.cpp=true + testeth -t GeneralStateTests/stCallCodes -- --testpath ~/tests --singlenet "Byzantium" --singletest "callcall_00" --vm ~/libhera.so --evmc evm2wasm.cpp=true + testeth -t GeneralStateTests/stCallCodes -- --testpath ~/tests --singlenet "Byzantium" --singletest "callcallcode_01" --vm ~/libhera.so --evmc evm2wasm.cpp=true + testeth -t GeneralStateTests/stMemoryTest -- --testpath ~/tests --singlenet "Byzantium" --singletest "memReturn" --vm ~/libhera.so --evmc evm2wasm.cpp=true + echo "ran the state tests." + cli-tests: &cli-tests run: name: "Basic CLI validation" @@ -84,7 +115,7 @@ defaults: bin/evm2wasm.js 600160020200 --trace build/tools/evm2wasm/evm2wasm <(echo "600160020200") - state-test-steps: &state-test-steps + js-state-test-steps: &js-state-test-steps - checkout - *npm-install - *lint @@ -99,17 +130,39 @@ defaults: # - *store-hera - *state-tests + cpp-state-test-steps: &cpp-state-test-steps + - checkout + - *npm-install + - *lint + - *validate-build + - *clone-tests + #- *build-cpp + #- *cli-tests # weird chars mess up the console + #- *vm-tests # vm-tests temporarily disabled until ewasm-kernel is fixed + # - *print-cpp-hera-version + - *install-cpp-ethereum + - *build-hera-cpp + # - *store-hera + - *state-tests-cpp + version: 2 jobs: # to run this using local circleci tool, rename Ewasm-Tests to `build` then do `circleci build -c circle.yml` - build: + build-js: + working_directory: ~/evm2wasm + docker: + - image: cdetrio/nodejs-cpp-build-env + steps: *js-state-test-steps + + build-cpp: working_directory: ~/evm2wasm docker: - image: cdetrio/nodejs-cpp-build-env - steps: *state-test-steps + steps: *cpp-state-test-steps workflows: version: 2 evm2wasm-build: jobs: - - build + - build-js + - build-cpp diff --git a/cmake/HunterGate.cmake b/cmake/HunterGate.cmake new file mode 100644 index 00000000..c24c0e57 --- /dev/null +++ b/cmake/HunterGate.cmake @@ -0,0 +1,543 @@ +# Copyright (c) 2013-2017, Ruslan Baratov +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, this +# list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +# This is a gate file to Hunter package manager. +# Include this file using `include` command and add package you need, example: +# +# cmake_minimum_required(VERSION 3.0) +# +# include("cmake/HunterGate.cmake") +# HunterGate( +# URL "https://github.com/path/to/hunter/archive.tar.gz" +# SHA1 "798501e983f14b28b10cda16afa4de69eee1da1d" +# ) +# +# project(MyProject) +# +# hunter_add_package(Foo) +# hunter_add_package(Boo COMPONENTS Bar Baz) +# +# Projects: +# * https://github.com/hunter-packages/gate/ +# * https://github.com/ruslo/hunter + +option(HUNTER_ENABLED "Enable Hunter package manager support" ON) +if(HUNTER_ENABLED) + if(CMAKE_VERSION VERSION_LESS "3.0") + message(FATAL_ERROR "At least CMake version 3.0 required for hunter dependency management." + " Update CMake or set HUNTER_ENABLED to OFF.") + endif() +endif() + +include(CMakeParseArguments) # cmake_parse_arguments + +option(HUNTER_STATUS_PRINT "Print working status" ON) +option(HUNTER_STATUS_DEBUG "Print a lot info" OFF) +option(HUNTER_TLS_VERIFY "Enable/disable TLS certificate checking on downloads" ON) + +set(HUNTER_WIKI "https://github.com/ruslo/hunter/wiki") + +function(hunter_gate_status_print) + foreach(print_message ${ARGV}) + if(HUNTER_STATUS_PRINT OR HUNTER_STATUS_DEBUG) + message(STATUS "[hunter] ${print_message}") + endif() + endforeach() +endfunction() + +function(hunter_gate_status_debug) + foreach(print_message ${ARGV}) + if(HUNTER_STATUS_DEBUG) + string(TIMESTAMP timestamp) + message(STATUS "[hunter *** DEBUG *** ${timestamp}] ${print_message}") + endif() + endforeach() +endfunction() + +function(hunter_gate_wiki wiki_page) + message("------------------------------ WIKI -------------------------------") + message(" ${HUNTER_WIKI}/${wiki_page}") + message("-------------------------------------------------------------------") + message("") + message(FATAL_ERROR "") +endfunction() + +function(hunter_gate_internal_error) + message("") + foreach(print_message ${ARGV}) + message("[hunter ** INTERNAL **] ${print_message}") + endforeach() + message("[hunter ** INTERNAL **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("error.internal") +endfunction() + +function(hunter_gate_fatal_error) + cmake_parse_arguments(hunter "" "WIKI" "" "${ARGV}") + string(COMPARE EQUAL "${hunter_WIKI}" "" have_no_wiki) + if(have_no_wiki) + hunter_gate_internal_error("Expected wiki") + endif() + message("") + foreach(x ${hunter_UNPARSED_ARGUMENTS}) + message("[hunter ** FATAL ERROR **] ${x}") + endforeach() + message("[hunter ** FATAL ERROR **] [Directory:${CMAKE_CURRENT_LIST_DIR}]") + message("") + hunter_gate_wiki("${hunter_WIKI}") +endfunction() + +function(hunter_gate_user_error) + hunter_gate_fatal_error(${ARGV} WIKI "error.incorrect.input.data") +endfunction() + +function(hunter_gate_self root version sha1 result) + string(COMPARE EQUAL "${root}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("root is empty") + endif() + + string(COMPARE EQUAL "${version}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("version is empty") + endif() + + string(COMPARE EQUAL "${sha1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("sha1 is empty") + endif() + + string(SUBSTRING "${sha1}" 0 7 archive_id) + + if(EXISTS "${root}/cmake/Hunter") + set(hunter_self "${root}") + else() + set( + hunter_self + "${root}/_Base/Download/Hunter/${version}/${archive_id}/Unpacked" + ) + endif() + + set("${result}" "${hunter_self}" PARENT_SCOPE) +endfunction() + +# Set HUNTER_GATE_ROOT cmake variable to suitable value. +function(hunter_gate_detect_root) + # Check CMake variable + string(COMPARE NOTEQUAL "${HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "${HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by cmake variable") + return() + endif() + + # Check environment variable + string(COMPARE NOTEQUAL "$ENV{HUNTER_ROOT}" "" not_empty) + if(not_empty) + set(HUNTER_GATE_ROOT "$ENV{HUNTER_ROOT}" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT detected by environment variable") + return() + endif() + + # Check HOME environment variable + string(COMPARE NOTEQUAL "$ENV{HOME}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{HOME}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug("HUNTER_ROOT set using HOME environment variable") + return() + endif() + + # Check SYSTEMDRIVE and USERPROFILE environment variable (windows only) + if(WIN32) + string(COMPARE NOTEQUAL "$ENV{SYSTEMDRIVE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{SYSTEMDRIVE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using SYSTEMDRIVE environment variable" + ) + return() + endif() + + string(COMPARE NOTEQUAL "$ENV{USERPROFILE}" "" result) + if(result) + set(HUNTER_GATE_ROOT "$ENV{USERPROFILE}/.hunter" PARENT_SCOPE) + hunter_gate_status_debug( + "HUNTER_ROOT set using USERPROFILE environment variable" + ) + return() + endif() + endif() + + hunter_gate_fatal_error( + "Can't detect HUNTER_ROOT" + WIKI "error.detect.hunter.root" + ) +endfunction() + +macro(hunter_gate_lock dir) + if(NOT HUNTER_SKIP_LOCK) + if("${CMAKE_VERSION}" VERSION_LESS "3.2") + hunter_gate_fatal_error( + "Can't lock, upgrade to CMake 3.2 or use HUNTER_SKIP_LOCK" + WIKI "error.can.not.lock" + ) + endif() + hunter_gate_status_debug("Locking directory: ${dir}") + file(LOCK "${dir}" DIRECTORY GUARD FUNCTION) + hunter_gate_status_debug("Lock done") + endif() +endmacro() + +function(hunter_gate_download dir) + string( + COMPARE + NOTEQUAL + "$ENV{HUNTER_DISABLE_AUTOINSTALL}" + "" + disable_autoinstall + ) + if(disable_autoinstall AND NOT HUNTER_RUN_INSTALL) + hunter_gate_fatal_error( + "Hunter not found in '${dir}'" + "Set HUNTER_RUN_INSTALL=ON to auto-install it from '${HUNTER_GATE_URL}'" + "Settings:" + " HUNTER_ROOT: ${HUNTER_GATE_ROOT}" + " HUNTER_SHA1: ${HUNTER_GATE_SHA1}" + WIKI "error.run.install" + ) + endif() + string(COMPARE EQUAL "${dir}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("Empty 'dir' argument") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_SHA1 empty") + endif() + + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" is_bad) + if(is_bad) + hunter_gate_internal_error("HUNTER_GATE_URL empty") + endif() + + set(done_location "${dir}/DONE") + set(sha1_location "${dir}/SHA1") + + set(build_dir "${dir}/Build") + set(cmakelists "${dir}/CMakeLists.txt") + + hunter_gate_lock("${dir}") + if(EXISTS "${done_location}") + # while waiting for lock other instance can do all the job + hunter_gate_status_debug("File '${done_location}' found, skip install") + return() + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(MAKE_DIRECTORY "${build_dir}") # check directory permissions + + # Disabling languages speeds up a little bit, reduces noise in the output + # and avoids path too long windows error + file( + WRITE + "${cmakelists}" + "cmake_minimum_required(VERSION 3.0)\n" + "project(HunterDownload LANGUAGES NONE)\n" + "include(ExternalProject)\n" + "ExternalProject_Add(\n" + " Hunter\n" + " URL\n" + " \"${HUNTER_GATE_URL}\"\n" + " URL_HASH\n" + " SHA1=${HUNTER_GATE_SHA1}\n" + " DOWNLOAD_DIR\n" + " \"${dir}\"\n" + " TLS_VERIFY\n" + " ${HUNTER_TLS_VERIFY}\n" + " SOURCE_DIR\n" + " \"${dir}/Unpacked\"\n" + " CONFIGURE_COMMAND\n" + " \"\"\n" + " BUILD_COMMAND\n" + " \"\"\n" + " INSTALL_COMMAND\n" + " \"\"\n" + ")\n" + ) + + if(HUNTER_STATUS_DEBUG) + set(logging_params "") + else() + set(logging_params OUTPUT_QUIET) + endif() + + hunter_gate_status_debug("Run generate") + + # Need to add toolchain file too. + # Otherwise on Visual Studio + MDD this will fail with error: + # "Could not find an appropriate version of the Windows 10 SDK installed on this machine" + if(EXISTS "${CMAKE_TOOLCHAIN_FILE}") + get_filename_component(absolute_CMAKE_TOOLCHAIN_FILE "${CMAKE_TOOLCHAIN_FILE}" ABSOLUTE) + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=${absolute_CMAKE_TOOLCHAIN_FILE}") + else() + # 'toolchain_arg' can't be empty + set(toolchain_arg "-DCMAKE_TOOLCHAIN_FILE=") + endif() + + string(COMPARE EQUAL "${CMAKE_MAKE_PROGRAM}" "" no_make) + if(no_make) + set(make_arg "") + else() + # Test case: remove Ninja from PATH but set it via CMAKE_MAKE_PROGRAM + set(make_arg "-DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM}") + endif() + + execute_process( + COMMAND + "${CMAKE_COMMAND}" + "-H${dir}" + "-B${build_dir}" + "-G${CMAKE_GENERATOR}" + "${toolchain_arg}" + ${make_arg} + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Configure project failed") + endif() + + hunter_gate_status_print( + "Initializing Hunter workspace (${HUNTER_GATE_SHA1})" + " ${HUNTER_GATE_URL}" + " -> ${dir}" + ) + execute_process( + COMMAND "${CMAKE_COMMAND}" --build "${build_dir}" + WORKING_DIRECTORY "${dir}" + RESULT_VARIABLE download_result + ${logging_params} + ) + + if(NOT download_result EQUAL 0) + hunter_gate_internal_error("Build project failed") + endif() + + file(REMOVE_RECURSE "${build_dir}") + file(REMOVE_RECURSE "${cmakelists}") + + file(WRITE "${sha1_location}" "${HUNTER_GATE_SHA1}") + file(WRITE "${done_location}" "DONE") + + hunter_gate_status_debug("Finished") +endfunction() + +# Must be a macro so master file 'cmake/Hunter' can +# apply all variables easily just by 'include' command +# (otherwise PARENT_SCOPE magic needed) +macro(HunterGate) + if(HUNTER_GATE_DONE) + # variable HUNTER_GATE_DONE set explicitly for external project + # (see `hunter_download`) + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() + + # First HunterGate command will init Hunter, others will be ignored + get_property(_hunter_gate_done GLOBAL PROPERTY HUNTER_GATE_DONE SET) + + if(NOT HUNTER_ENABLED) + # Empty function to avoid error "unknown function" + function(hunter_add_package) + endfunction() + + set( + _hunter_gate_disabled_mode_dir + "${CMAKE_CURRENT_LIST_DIR}/cmake/Hunter/disabled-mode" + ) + if(EXISTS "${_hunter_gate_disabled_mode_dir}") + hunter_gate_status_debug( + "Adding \"disabled-mode\" modules: ${_hunter_gate_disabled_mode_dir}" + ) + list(APPEND CMAKE_PREFIX_PATH "${_hunter_gate_disabled_mode_dir}") + endif() + elseif(_hunter_gate_done) + hunter_gate_status_debug("Secondary HunterGate (use old settings)") + hunter_gate_self( + "${HUNTER_CACHED_ROOT}" + "${HUNTER_VERSION}" + "${HUNTER_SHA1}" + _hunter_self + ) + include("${_hunter_self}/cmake/Hunter") + else() + set(HUNTER_GATE_LOCATION "${CMAKE_CURRENT_LIST_DIR}") + + string(COMPARE NOTEQUAL "${PROJECT_NAME}" "" _have_project_name) + if(_have_project_name) + hunter_gate_fatal_error( + "Please set HunterGate *before* 'project' command. " + "Detected project: ${PROJECT_NAME}" + WIKI "error.huntergate.before.project" + ) + endif() + + cmake_parse_arguments( + HUNTER_GATE "LOCAL" "URL;SHA1;GLOBAL;FILEPATH" "" ${ARGV} + ) + + string(COMPARE EQUAL "${HUNTER_GATE_SHA1}" "" _empty_sha1) + string(COMPARE EQUAL "${HUNTER_GATE_URL}" "" _empty_url) + string( + COMPARE + NOTEQUAL + "${HUNTER_GATE_UNPARSED_ARGUMENTS}" + "" + _have_unparsed + ) + string(COMPARE NOTEQUAL "${HUNTER_GATE_GLOBAL}" "" _have_global) + string(COMPARE NOTEQUAL "${HUNTER_GATE_FILEPATH}" "" _have_filepath) + + if(_have_unparsed) + hunter_gate_user_error( + "HunterGate unparsed arguments: ${HUNTER_GATE_UNPARSED_ARGUMENTS}" + ) + endif() + if(_empty_sha1) + hunter_gate_user_error("SHA1 suboption of HunterGate is mandatory") + endif() + if(_empty_url) + hunter_gate_user_error("URL suboption of HunterGate is mandatory") + endif() + if(_have_global) + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has GLOBAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has GLOBAL)") + endif() + endif() + if(HUNTER_GATE_LOCAL) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has LOCAL)") + endif() + if(_have_filepath) + hunter_gate_user_error("Unexpected FILEPATH (already has LOCAL)") + endif() + endif() + if(_have_filepath) + if(_have_global) + hunter_gate_user_error("Unexpected GLOBAL (already has FILEPATH)") + endif() + if(HUNTER_GATE_LOCAL) + hunter_gate_user_error("Unexpected LOCAL (already has FILEPATH)") + endif() + endif() + + hunter_gate_detect_root() # set HUNTER_GATE_ROOT + + # Beautify path, fix probable problems with windows path slashes + get_filename_component( + HUNTER_GATE_ROOT "${HUNTER_GATE_ROOT}" ABSOLUTE + ) + hunter_gate_status_debug("HUNTER_ROOT: ${HUNTER_GATE_ROOT}") + if(NOT HUNTER_ALLOW_SPACES_IN_PATH) + string(FIND "${HUNTER_GATE_ROOT}" " " _contain_spaces) + if(NOT _contain_spaces EQUAL -1) + hunter_gate_fatal_error( + "HUNTER_ROOT (${HUNTER_GATE_ROOT}) contains spaces." + "Set HUNTER_ALLOW_SPACES_IN_PATH=ON to skip this error" + "(Use at your own risk!)" + WIKI "error.spaces.in.hunter.root" + ) + endif() + endif() + + string( + REGEX + MATCH + "[0-9]+\\.[0-9]+\\.[0-9]+[-_a-z0-9]*" + HUNTER_GATE_VERSION + "${HUNTER_GATE_URL}" + ) + string(COMPARE EQUAL "${HUNTER_GATE_VERSION}" "" _is_empty) + if(_is_empty) + set(HUNTER_GATE_VERSION "unknown") + endif() + + hunter_gate_self( + "${HUNTER_GATE_ROOT}" + "${HUNTER_GATE_VERSION}" + "${HUNTER_GATE_SHA1}" + _hunter_self + ) + + set(_master_location "${_hunter_self}/cmake/Hunter") + if(EXISTS "${HUNTER_GATE_ROOT}/cmake/Hunter") + # Hunter downloaded manually (e.g. by 'git clone') + set(_unused "xxxxxxxxxx") + set(HUNTER_GATE_SHA1 "${_unused}") + set(HUNTER_GATE_VERSION "${_unused}") + else() + get_filename_component(_archive_id_location "${_hunter_self}/.." ABSOLUTE) + set(_done_location "${_archive_id_location}/DONE") + set(_sha1_location "${_archive_id_location}/SHA1") + + # Check Hunter already downloaded by HunterGate + if(NOT EXISTS "${_done_location}") + hunter_gate_download("${_archive_id_location}") + endif() + + if(NOT EXISTS "${_done_location}") + hunter_gate_internal_error("hunter_gate_download failed") + endif() + + if(NOT EXISTS "${_sha1_location}") + hunter_gate_internal_error("${_sha1_location} not found") + endif() + file(READ "${_sha1_location}" _sha1_value) + string(COMPARE EQUAL "${_sha1_value}" "${HUNTER_GATE_SHA1}" _is_equal) + if(NOT _is_equal) + hunter_gate_internal_error( + "Short SHA1 collision:" + " ${_sha1_value} (from ${_sha1_location})" + " ${HUNTER_GATE_SHA1} (HunterGate)" + ) + endif() + if(NOT EXISTS "${_master_location}") + hunter_gate_user_error( + "Master file not found:" + " ${_master_location}" + "try to update Hunter/HunterGate" + ) + endif() + endif() + include("${_master_location}") + set_property(GLOBAL PROPERTY HUNTER_GATE_DONE YES) + endif() +endmacro() diff --git a/cmake/ProjectBinaryen.cmake b/cmake/ProjectBinaryen.cmake index c7d602df..fd84b070 100644 --- a/cmake/ProjectBinaryen.cmake +++ b/cmake/ProjectBinaryen.cmake @@ -38,12 +38,12 @@ set(binaryen_other_libraries ExternalProject_Add(binaryen PREFIX ${prefix} - DOWNLOAD_NAME binaryen-1.37.35.tar.gz + DOWNLOAD_NAME binaryen-1.38.9.tar.gz DOWNLOAD_DIR ${prefix}/downloads SOURCE_DIR ${source_dir} BINARY_DIR ${binary_dir} - URL https://github.com/WebAssembly/binaryen/archive/1.37.35.tar.gz - URL_HASH SHA256=19439e41dc576446eaae0c4a8e07d4cd4c40aea7dfb0a6475b925686852f8006 + URL https://github.com/WebAssembly/binaryen/archive/1.38.9.tar.gz + URL_HASH SHA256=f8c6d4deb83dba8709c4df9f7983080ec0f9412e88899767ed2815b911ce1ebd CMAKE_ARGS -DCMAKE_INSTALL_PREFIX= -DCMAKE_BUILD_TYPE=Release diff --git a/cmake/toolchains/cxx11-pic.cmake b/cmake/toolchains/cxx11-pic.cmake new file mode 100644 index 00000000..2e5d3c8d --- /dev/null +++ b/cmake/toolchains/cxx11-pic.cmake @@ -0,0 +1,5 @@ +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED TRUE) +set(CMAKE_CXX_EXTENSIONS OFF) + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) diff --git a/include/evm2wasm.h b/include/evm2wasm.h index c12ef5f6..8a0afd0b 100644 --- a/include/evm2wasm.h +++ b/include/evm2wasm.h @@ -1,14 +1,380 @@ #pragma once +#include +#include #include +#include #include -namespace evm2wasm { +namespace evm2wasm +{ +enum class opcodeEnum +{ + STOP, + ADD, + MUL, + SUB, + DIV, + SDIV, + MOD, + SMOD, + ADDMOD, + MULMOD, + EXP, + SIGNEXTEND, + LT, + GT, + SLT, + SGT, + EQ, + ISZERO, + AND, + OR, + XOR, + NOT, + BYTE, + SHA3, + ADDRESS, + BALANCE, + ORIGIN, + CALLER, + CALLVALUE, + CALLDATALOAD, + CALLDATASIZE, + CALLDATACOPY, + CODESIZE, + CODECOPY, + GASPRICE, + EXTCODESIZE, + EXTCODECOPY, + BLOCKHASH, + COINBASE, + TIMESTAMP, + NUMBER, + DIFFICULTY, + GASLIMIT, + POP, + MLOAD, + MSTORE, + MSTORE8, + SLOAD, + SSTORE, + JUMP, + JUMPI, + PC, + MSIZE, + GAS, + JUMPDEST, + PUSH, + DUP, + SWAP, + LOG, + CREATE, + CALL, + CALLCODE, + RETURN, + DELEGATECALL, + SELFDESTRUCT, + INVALID, + bswap_i32, + bswap_i64, + bswap_m128, + bswap_m160, + bswap_m256, + callback, + callback_128, + callback_160, + callback_256, + callback_32, + check_overflow, + check_overflow_i64, + gte_256, + gte_320, + gte_512, + iszero_256, + iszero_320, + iszero_512, + keccak, + memcpy, + memset, + memusegas, + mod_320, + mod_512, + mul_256 +}; + +// maps the async ops to their call back function +static std::map callbackFuncs = { + {opcodeEnum::SSTORE, "$callback"}, + {opcodeEnum::SLOAD, "$callback_256"}, + {opcodeEnum::CREATE, "$callback_160"}, + {opcodeEnum::CALL, "$callback_32"}, + {opcodeEnum::DELEGATECALL, "$callback"}, + {opcodeEnum::CALLCODE, "$callback_32"}, + {opcodeEnum::EXTCODECOPY, "$callback"}, + {opcodeEnum::EXTCODESIZE, "$callback_32"}, + {opcodeEnum::CODECOPY, "$callback"}, + {opcodeEnum::CODESIZE, "$callback_32"}, + {opcodeEnum::BALANCE, "$callback_128"}, + {opcodeEnum::BLOCKHASH, "$callback_256"}}; + +typedef std::tuple Opcode; +static std::map> codes = { + {0x00, Opcode{opcodeEnum::STOP, 0, 0, 0}}, + {0x01, Opcode{opcodeEnum::ADD, 3, 2, 1}}, + {0x02, Opcode{opcodeEnum::MUL, 5, 2, 1}}, + {0x03, Opcode{opcodeEnum::SUB, 3, 2, 1}}, + {0x04, Opcode{opcodeEnum::DIV, 5, 2, 1}}, + {0x05, Opcode{opcodeEnum::SDIV, 5, 2, 1}}, + {0x06, Opcode{opcodeEnum::MOD, 5, 2, 1}}, + {0x07, Opcode{opcodeEnum::SMOD, 5, 2, 1}}, + {0x08, Opcode{opcodeEnum::ADDMOD, 8, 3, 1}}, + {0x09, Opcode{opcodeEnum::MULMOD, 8, 3, 1}}, + {0x0a, Opcode{opcodeEnum::EXP, 10, 2, 1}}, + {0x0b, Opcode{opcodeEnum::SIGNEXTEND, 5, 2, 1}}, + + // 0x10 range - bit ops + {0x10, Opcode{opcodeEnum::LT, 3, 2, 1}}, + {0x11, Opcode{opcodeEnum::GT, 3, 2, 1}}, + {0x12, Opcode{opcodeEnum::SLT, 3, 2, 1}}, + {0x13, Opcode{opcodeEnum::SGT, 3, 2, 1}}, + {0x14, Opcode{opcodeEnum::EQ, 3, 2, 1}}, + {0x15, Opcode{opcodeEnum::ISZERO, 3, 1, 1}}, + {0x16, Opcode{opcodeEnum::AND, 3, 2, 1}}, + {0x17, Opcode{opcodeEnum::OR, 3, 2, 1}}, + {0x18, Opcode{opcodeEnum::XOR, 3, 2, 1}}, + {0x19, Opcode{opcodeEnum::NOT, 3, 1, 1}}, + {0x1a, Opcode{opcodeEnum::BYTE, 3, 2, 1}}, + + // 0x20 range - crypto + {0x20, Opcode{opcodeEnum::SHA3, 30, 2, 1}}, + + // 0x30 range - closure state + {0x30, Opcode{opcodeEnum::ADDRESS, 0, 0, 1}}, + {0x31, Opcode{opcodeEnum::BALANCE, 0, 1, 1}}, + {0x32, Opcode{opcodeEnum::ORIGIN, 0, 0, 1}}, + {0x33, Opcode{opcodeEnum::CALLER, 0, 0, 1}}, + {0x34, Opcode{opcodeEnum::CALLVALUE, 0, 0, 1}}, + {0x35, Opcode{opcodeEnum::CALLDATALOAD, 0, 1, 1}}, + {0x36, Opcode{opcodeEnum::CALLDATASIZE, 0, 0, 1}}, + {0x37, Opcode{opcodeEnum::CALLDATACOPY, 0, 3, 0}}, + {0x38, Opcode{opcodeEnum::CODESIZE, 0, 0, 1}}, + {0x39, Opcode{opcodeEnum::CODECOPY, 0, 3, 0}}, + {0x3a, Opcode{opcodeEnum::GASPRICE, 0, 0, 1}}, + {0x3b, Opcode{opcodeEnum::EXTCODESIZE, 0, 1, 1}}, + {0x3c, Opcode{opcodeEnum::EXTCODECOPY, 0, 4, 0}}, + + // "0x40" range - block operations + {0x40, Opcode{opcodeEnum::BLOCKHASH, 0, 1, 1}}, + {0x41, Opcode{opcodeEnum::COINBASE, 0, 0, 1}}, + {0x42, Opcode{opcodeEnum::TIMESTAMP, 0, 0, 1}}, + {0x43, Opcode{opcodeEnum::NUMBER, 0, 0, 1}}, + {0x44, Opcode{opcodeEnum::DIFFICULTY, 0, 0, 1}}, + {0x45, Opcode{opcodeEnum::GASLIMIT, 0, 0, 1}}, + + // 0x50 range - "storage" and execution + {0x50, Opcode{opcodeEnum::POP, 2, 1, 0}}, + {0x51, Opcode{opcodeEnum::MLOAD, 3, 1, 1}}, + {0x52, Opcode{opcodeEnum::MSTORE, 3, 2, 0}}, + {0x53, Opcode{opcodeEnum::MSTORE8, 3, 2, 0}}, + {0x54, Opcode{opcodeEnum::SLOAD, 0, 1, 1}}, + {0x55, Opcode{opcodeEnum::SSTORE, 0, 2, 0}}, + {0x56, Opcode{opcodeEnum::JUMP, 8, 0, 0}}, + {0x57, Opcode{opcodeEnum::JUMPI, 10, 0, 0}}, + {0x58, Opcode{opcodeEnum::PC, 2, 0, 1}}, + {0x59, Opcode{opcodeEnum::MSIZE, 2, 0, 1}}, + {0x5a, Opcode{opcodeEnum::GAS, 0, 0, 1}}, + {0x5b, Opcode{opcodeEnum::JUMPDEST, 0, 0, 0}}, + + // 0x60, range + {0x60, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x61, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x62, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x63, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x64, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x65, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x66, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x67, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x68, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x69, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6a, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6b, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6c, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6d, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6e, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x6f, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x70, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x71, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x72, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x73, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x74, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x75, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x76, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x77, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x78, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x79, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7a, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7b, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7c, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7d, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7e, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + {0x7f, Opcode{opcodeEnum::PUSH, 3, 0, 1}}, + + {0x80, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x81, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x82, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x83, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x84, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x85, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x86, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x87, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x88, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x89, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8a, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8b, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8c, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8d, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8e, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + {0x8f, Opcode{opcodeEnum::DUP, 3, 0, 1}}, + + {0x90, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x91, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x92, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x93, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x94, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x95, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x96, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x97, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x98, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x99, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9a, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9b, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9c, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9d, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9e, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + {0x9f, Opcode{opcodeEnum::SWAP, 3, 0, 0}}, + + {0xa0, Opcode{opcodeEnum::LOG, 0, 2, 0}}, + {0xa1, Opcode{opcodeEnum::LOG, 0, 3, 0}}, + {0xa2, Opcode{opcodeEnum::LOG, 0, 4, 0}}, + {0xa3, Opcode{opcodeEnum::LOG, 0, 5, 0}}, + {0xa4, Opcode{opcodeEnum::LOG, 0, 6, 0}}, + + // "0xf0" range - closures + {0xf0, Opcode{opcodeEnum::CREATE, 0, 3, 1}}, + {0xf1, Opcode{opcodeEnum::CALL, 0, 7, 1}}, + {0xf2, Opcode{opcodeEnum::CALLCODE, 0, 7, 1}}, + {0xf3, Opcode{opcodeEnum::RETURN, 0, 2, 0}}, + {0xf4, Opcode{opcodeEnum::DELEGATECALL, 0, 6, 1}}, + + // "0x70", range - other + {0xff, Opcode{opcodeEnum::SELFDESTRUCT, 0, 1, 0}}}; + +static std::map> depMap = { + {opcodeEnum::callback_256, {opcodeEnum::bswap_m256}}, + {opcodeEnum::callback_160, {opcodeEnum::bswap_m160}}, + {opcodeEnum::callback_128, {opcodeEnum::bswap_m128}}, + {opcodeEnum::bswap_m256, {opcodeEnum::bswap_i64}}, + {opcodeEnum::bswap_m128, {opcodeEnum::bswap_i64}}, + {opcodeEnum::bswap_m160, {opcodeEnum::bswap_i64, opcodeEnum::bswap_i32}}, + {opcodeEnum::keccak, {opcodeEnum::memcpy, opcodeEnum::memset}}, + {opcodeEnum::mod_320, {opcodeEnum::iszero_320, opcodeEnum::gte_320}}, + {opcodeEnum::mod_512, {opcodeEnum::iszero_512, opcodeEnum::gte_512}}, + {opcodeEnum::MOD, {opcodeEnum::iszero_256, opcodeEnum::gte_256}}, + {opcodeEnum::ADDMOD, {opcodeEnum::mod_320}}, + {opcodeEnum::MULMOD, {opcodeEnum::mod_512}}, + {opcodeEnum::SDIV, {opcodeEnum::iszero_256, opcodeEnum::gte_256}}, + {opcodeEnum::SMOD, {opcodeEnum::iszero_256, opcodeEnum::gte_256}}, + {opcodeEnum::DIV, {opcodeEnum::iszero_256, opcodeEnum::gte_256}}, + {opcodeEnum::EXP, {opcodeEnum::iszero_256, opcodeEnum::mul_256}}, + {opcodeEnum::MUL, {opcodeEnum::mul_256}}, + {opcodeEnum::ISZERO, {opcodeEnum::iszero_256}}, + {opcodeEnum::MSTORE, + {opcodeEnum::memusegas, opcodeEnum::bswap_m256, opcodeEnum::check_overflow}}, + {opcodeEnum::MLOAD, + {opcodeEnum::memusegas, opcodeEnum::bswap_m256, opcodeEnum::check_overflow}}, + {opcodeEnum::MSTORE8, {opcodeEnum::memusegas, opcodeEnum::check_overflow}}, + {opcodeEnum::CODECOPY, {opcodeEnum::callback, opcodeEnum::memusegas, opcodeEnum::check_overflow, + opcodeEnum::memset}}, + {opcodeEnum::CALLDATALOAD, + {opcodeEnum::bswap_m256, opcodeEnum::bswap_i64, opcodeEnum::check_overflow}}, + {opcodeEnum::CALLDATACOPY, + {opcodeEnum::memusegas, opcodeEnum::check_overflow, opcodeEnum::memset}}, + {opcodeEnum::CALLVALUE, {opcodeEnum::bswap_m128}}, + {opcodeEnum::EXTCODECOPY, {opcodeEnum::bswap_m256, opcodeEnum::callback, opcodeEnum::memusegas, + opcodeEnum::check_overflow, opcodeEnum::memset}}, + {opcodeEnum::EXTCODESIZE, {opcodeEnum::callback_32, opcodeEnum::bswap_m256}}, + {opcodeEnum::LOG, {opcodeEnum::memusegas, opcodeEnum::check_overflow}}, + {opcodeEnum::BLOCKHASH, {opcodeEnum::check_overflow, opcodeEnum::callback_256}}, + {opcodeEnum::SHA3, {opcodeEnum::memusegas, opcodeEnum::bswap_m256, opcodeEnum::check_overflow, + opcodeEnum::keccak}}, + {opcodeEnum::CALL, + {opcodeEnum::bswap_m256, opcodeEnum::memusegas, opcodeEnum::check_overflow_i64, + opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32}}, + {opcodeEnum::DELEGATECALL, {opcodeEnum::callback, opcodeEnum::memusegas, + opcodeEnum::check_overflow, opcodeEnum::memset, + opcodeEnum::check_overflow_i64}}, + {opcodeEnum::CALLCODE, + {opcodeEnum::bswap_m256, opcodeEnum::callback, opcodeEnum::memusegas, + opcodeEnum::check_overflow, opcodeEnum::memset, opcodeEnum::callback_32, + opcodeEnum::check_overflow_i64}}, + {opcodeEnum::CREATE, {opcodeEnum::bswap_m256, opcodeEnum::bswap_m160, opcodeEnum::callback_160, + opcodeEnum::memusegas, opcodeEnum::check_overflow}}, + {opcodeEnum::RETURN, {opcodeEnum::memusegas, opcodeEnum::check_overflow}}, + {opcodeEnum::BALANCE, {opcodeEnum::bswap_m256, opcodeEnum::callback_128}}, + {opcodeEnum::SELFDESTRUCT, {opcodeEnum::bswap_m256}}, + {opcodeEnum::SSTORE, {opcodeEnum::bswap_m256, opcodeEnum::callback}}, + {opcodeEnum::SLOAD, {opcodeEnum::callback_256}}, + {opcodeEnum::CODESIZE, {opcodeEnum::callback_32}}, + {opcodeEnum::DIFFICULTY, {opcodeEnum::bswap_m256}}, + {opcodeEnum::COINBASE, {opcodeEnum::bswap_m160}}, + {opcodeEnum::ORIGIN, {opcodeEnum::bswap_m160}}, + {opcodeEnum::ADDRESS, {opcodeEnum::bswap_m160}}, + {opcodeEnum::CALLER, {opcodeEnum::bswap_m160}}}; + +struct Op +{ + opcodeEnum name; + int fee; + int off; + int on; + size_t number; +}; + +struct JumpSegment +{ + size_t number; + std::string type; +}; + +struct WastCode +{ + std::string wast; + std::string imports; +}; std::string wast2wasm(const std::string& input, bool debug = false); -std::string evm2wast(const std::vector& input, bool tracing = false); +std::string evm2wast(const std::vector& input, bool tracing = false, bool useAsyncAPI = false, bool inlineOps = true, bool chargePerOp = true); std::string evmhex2wast(const std::string& input, bool tracing = false); std::string evm2wasm(const std::vector& input, bool tracing = false); std::string evmhex2wasm(const std::string& input, bool tracing = false); +std::string assembleSegments(const std::vector& segments); + +std::string opcodeToString(opcodeEnum opcode); + +Op opcodes(int op); + +size_t findNextJumpDest(const std::vector& evmCode, size_t i); + +std::set resolveFunctionDeps(const std::set& funcSet); + +std::tuple, std::vector> resolveFunctions( + const std::set& funcSet, std::map wastFiles); + +std::string buildModule(const std::vector& funcs, + const std::vector& imports, const std::vector& callbacks); + +std::string buildJumpMap(const std::vector& segments); + } diff --git a/include/wast-async.h b/include/wast-async.h new file mode 100644 index 00000000..b0e90bbf --- /dev/null +++ b/include/wast-async.h @@ -0,0 +1,438 @@ +#pragma once + +#include + +#include "evm2wasm.h" + +namespace evm2wasm +{ + static std::map wastAsyncInterface = + { + { + opcodeEnum::LOG, { + .wast = "(func $LOG\n (param $number i32)\n\n (local $offset i32)\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n (local $length i32)\n (local $length0 i64)\n (local $length1 i64)\n (local $length2 i64)\n (local $length3 i64)\n\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $length0 (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n (set_local $length1 (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $length2 (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $length3 (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n\n (set_local $length\n (call $check_overflow (get_local $length0)\n (get_local $length1)\n (get_local $length2)\n (get_local $length3)))\n\n (call $memusegas (get_local $offset) (get_local $length))\n\n (call $log \n (get_local $offset)\n (get_local $length)\n (get_local $number)\n (i32.sub (get_global $sp) (i32.const 64))\n (i32.sub (get_global $sp) (i32.const 96))\n (i32.sub (get_global $sp) (i32.const 128))\n (i32.sub (get_global $sp) (i32.const 160)))\n)\n", + .imports = "(import \"ethereum\" \"log\" (func $log (param i32 i32 i32 i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::CALLDATALOAD, { + .wast = ";; stack:\n;; 0: dataOffset\n(func $CALLDATALOAD\n (local $writeOffset i32)\n (local $writeOffset0 i64)\n (local $writeOffset1 i64)\n (local $writeOffset2 i64)\n (local $writeOffset3 i64)\n\n (set_local $writeOffset0 (i64.load (i32.add (get_global $sp) (i32.const 0))))\n (set_local $writeOffset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $writeOffset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $writeOffset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (i64.store (i32.add (get_global $sp) (i32.const 0)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n\n (set_local $writeOffset\n (call $check_overflow (get_local $writeOffset0)\n (get_local $writeOffset1)\n (get_local $writeOffset2)\n (get_local $writeOffset3)))\n\n (call $callDataCopy (get_global $sp) (get_local $writeOffset) (i32.const 32))\n ;; swap top stack item\n (drop (call $bswap_m256 (get_global $sp)))\n)\n", + .imports = "(import \"ethereum\" \"callDataCopy\" (func $callDataCopy (param i32 i32 i32) ))" + } +},{ + opcodeEnum::GAS, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GAS (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getGasLeft))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getGasLeft\" (func $getGasLeft (result i64)))" + } +},{ + opcodeEnum::ADDRESS, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $ADDRESS (call $getAddress (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getAddress\" (func $getAddress (param i32) ))" + } +},{ + opcodeEnum::BALANCE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $BALANCE (param $callback i32) (call $getBalance(get_global $sp) (i32.add (get_global $sp) (i32.const 0))(get_local $callback))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBalance\" (func $getBalance (param i32 i32 i32) ))" + } +},{ + opcodeEnum::ORIGIN, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $ORIGIN (call $getTxOrigin (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getTxOrigin\" (func $getTxOrigin (param i32) ))" + } +},{ + opcodeEnum::CALLER, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLER (call $getCaller (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getCaller\" (func $getCaller (param i32) ))" + } +},{ + opcodeEnum::CALLVALUE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLVALUE (call $getCallValue (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCallValue\" (func $getCallValue (param i32) ))" + } +},{ + opcodeEnum::CALLDATASIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLDATASIZE (i64.store\n (i32.add (get_global $sp) (i32.const 32))\n (i64.extend_u/i32\n (call $getCallDataSize)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCallDataSize\" (func $getCallDataSize (result i32)))" + } +},{ + opcodeEnum::CALLDATACOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLDATACOPY (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $callDataCopy(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8))))(get_local $length0)))", + .imports = "(import \"ethereum\" \"callDataCopy\" (func $callDataCopy (param i32 i32 i32) ))" + } +},{ + opcodeEnum::CODESIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CODESIZE (param $callback i32) (i64.store\n (i32.add (get_global $sp) (i32.const 32))\n (i64.extend_u/i32\n (call $getCodeSize(get_local $callback))))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCodeSize\" (func $getCodeSize (param i32) (result i32)))" + } +},{ + opcodeEnum::CODECOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CODECOPY (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $codeCopy(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8))))(get_local $length0)(get_local $callback)))", + .imports = "(import \"ethereum\" \"codeCopy\" (func $codeCopy (param i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::EXTCODESIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $EXTCODESIZE (param $callback i32) (i64.store\n (i32.add (get_global $sp) (i32.const 0))\n (i64.extend_u/i32\n (call $getExternalCodeSize(get_global $sp)(get_local $callback))))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getExternalCodeSize\" (func $getExternalCodeSize (param i32 i32) (result i32)))" + } +},{ + opcodeEnum::EXTCODECOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $EXTCODECOPY (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $externalCodeCopy(get_global $sp)(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40))))(get_local $length0)(get_local $callback)))", + .imports = "(import \"ethereum\" \"externalCodeCopy\" (func $externalCodeCopy (param i32 i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::GASPRICE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GASPRICE (call $getTxGasPrice(i32.add (get_global $sp) (i32.const 32))))", + .imports = "(import \"ethereum\" \"getTxGasPrice\" (func $getTxGasPrice (param i32) ))" + } +},{ + opcodeEnum::BLOCKHASH, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $BLOCKHASH (param $callback i32) (call $getBlockHash(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))) \n (i32.add (get_global $sp) \n (i32.const 0))(get_local $callback))\n (drop (call $bswap_m256 (i32.add (i32.const 32) (get_global $sp))))\n )", + .imports = "(import \"ethereum\" \"getBlockHash\" (func $getBlockHash (param i32 i32 i32) ))" + } +},{ + opcodeEnum::COINBASE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $COINBASE (call $getBlockCoinbase (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getBlockCoinbase\" (func $getBlockCoinbase (param i32) ))" + } +},{ + opcodeEnum::TIMESTAMP, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $TIMESTAMP (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockTimestamp))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockTimestamp\" (func $getBlockTimestamp (result i64)))" + } +},{ + opcodeEnum::NUMBER, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $NUMBER (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockNumber))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockNumber\" (func $getBlockNumber (result i64)))" + } +},{ + opcodeEnum::DIFFICULTY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $DIFFICULTY (call $getBlockDifficulty(i32.add (get_global $sp) (i32.const 32))))", + .imports = "(import \"ethereum\" \"getBlockDifficulty\" (func $getBlockDifficulty (param i32) ))" + } +},{ + opcodeEnum::GASLIMIT, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GASLIMIT (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockGasLimit))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockGasLimit\" (func $getBlockGasLimit (result i64)))" + } +},{ + opcodeEnum::CREATE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CREATE (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $create(get_global $sp)(get_local $offset0)(get_local $length0) (i32.add (get_global $sp) (i32.const -64))(get_local $callback))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -40)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const -44)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"create\" (func $create (param i32 i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::CALL, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALL (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $call(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"call\" (func $call (param i64 i32 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::CALLCODE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLCODE (param $callback i32)(local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callCode(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"callCode\" (func $callCode (param i64 i32 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::DELEGATECALL, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (param $callback i32)(local $offset0 i32)(local $length0 i32)(local $offset1 i32)(local $length1 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0)))(set_local $offset1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -160)))\n (i64.load (i32.add (get_global $sp) (i32.const -152)))\n (i64.load (i32.add (get_global $sp) (i32.const -144)))\n (i64.load (i32.add (get_global $sp) (i32.const -136)))))(set_local $length1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -192)))\n (i64.load (i32.add (get_global $sp) (i32.const -184)))\n (i64.load (i32.add (get_global $sp) (i32.const -176)))\n (i64.load (i32.add (get_global $sp) (i32.const -168)))))\n (call $memusegas (get_local $offset1) (get_local $length1))\n (set_local $offset1 (i32.add (get_global $memstart) (get_local $offset1))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $offset1)(get_local $length1)(get_local $callback)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::SSTORE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SSTORE (param $callback i32) (call $storageStore(get_global $sp)(i32.add (get_global $sp) (i32.const -32))(get_local $callback)))", + .imports = "(import \"ethereum\" \"storageStore\" (func $storageStore (param i32 i32 i32) ))" + } +},{ + opcodeEnum::SLOAD, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SLOAD (param $callback i32) (call $storageLoad(get_global $sp) \n (i32.add (get_global $sp) \n (i32.const 0))(get_local $callback))\n (drop (call $bswap_m256 (i32.add (i32.const 32) (get_global $sp))))\n )", + .imports = "(import \"ethereum\" \"storageLoad\" (func $storageLoad (param i32 i32 i32) ))" + } +},{ + opcodeEnum::SELFDESTRUCT, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SELFDESTRUCT (call $selfDestruct(get_global $sp)))", + .imports = "(import \"ethereum\" \"selfDestruct\" (func $selfDestruct (param i32) ))" + } +},{ + opcodeEnum::RETURN, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $RETURN (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $return(get_local $offset0)(get_local $length0)))", + .imports = "(import \"ethereum\" \"return\" (func $return (param i32 i32) ))" + } +},{ + opcodeEnum::ADD, { + .wast = "(func $ADD\n (local $sp i32)\n\n (local $a i64)\n (local $c i64)\n (local $d i64)\n (local $carry i64)\n\n (set_local $sp (get_global $sp))\n \n ;; d c b a\n ;; pop the stack \n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_local $sp) (i32.const 8)))\n\n ;; d \n (set_local $carry (i64.add (get_local $d) (i64.load (i32.sub (get_local $sp) (i32.const 24)))))\n ;; save d to mem\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $carry))\n ;; check for overflow\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $carry) (get_local $d))))\n\n ;; c use $d as reg\n (set_local $d (i64.add (i64.load (i32.sub (get_local $sp) (i32.const 16))) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $carry))))\n (set_local $d (i64.add (get_local $c) (get_local $d)))\n ;; store the result\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $d))\n ;; check overflow\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $c))) (get_local $carry)))\n\n ;; b\n ;; add carry\n (set_local $d (i64.add (i64.load (i32.sub (get_local $sp) (i32.const 8))) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $carry))))\n\n ;; use reg c\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $d (i64.add (get_local $c) (get_local $d)))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $d))\n ;; a\n (i64.store (get_local $sp) \n (i64.add ;; add a \n (get_local $a)\n (i64.add\n (i64.load (get_local $sp)) ;; load the operand\n (i64.or ;; carry \n (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $c))) \n (get_local $carry)))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::ADDMOD, { + .wast = ";; stack:\n;; 0: A\n;; -1: B\n;; -2: MOD\n(func $ADDMOD\n (local $sp i32)\n\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n (local $moda i64)\n (local $modb i64)\n (local $modc i64)\n (local $modd i64)\n\n (local $carry i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $moda (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $modb (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $modc (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $modd (i64.load (get_local $sp)))\n\n ;; a * 64^3 + b*64^2 + c*64 + d \n ;; d \n (set_local $d (i64.add (get_local $d1) (get_local $d)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $d1))))\n ;; c\n (set_local $c (i64.add (get_local $c) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $c) (get_local $carry))))\n (set_local $c (i64.add (get_local $c1) (get_local $c)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $c) (get_local $c1))) (get_local $carry)))\n ;; b\n (set_local $b (i64.add (get_local $b) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $b) (get_local $carry))))\n (set_local $b (i64.add (get_local $b1) (get_local $b)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $b) (get_local $b1))) (get_local $carry)))\n ;; a\n (set_local $a (i64.add (get_local $a) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $a) (get_local $carry))))\n (set_local $a (i64.add (get_local $a1) (get_local $a)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $a) (get_local $a1))) (get_local $carry)))\n\n (call $mod_320\n (get_local $carry) (get_local $a) (get_local $b) (get_local $c) (get_local $d)\n (i64.const 0) (get_local $moda) (get_local $modb) (get_local $modc) (get_local $modd) (get_local $sp))\n)\n", + .imports = "" + } +},{ + opcodeEnum::AND, { + .wast = "(func $AND\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (get_global $sp))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::BYTE, { + .wast = ";; stack:\n;; 0: offset\n;; -1: value\n(func $BYTE\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (set_local $sp (get_global $sp))\n\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (i64.store (get_local $sp)\n (if (result i64)\n (i32.and \n (i32.and \n (i32.and \n (i64.lt_u (get_local $a3) (i64.const 32))\n (i64.eqz (get_local $a2))) \n (i64.eqz (get_local $a1)))\n (i64.eqz (get_local $a0)))\n (i64.load8_u (i32.sub (i32.const 31)(i32.wrap/i64 (get_local $a3))))\n (i64.const 0)))\n\n ;; zero out the rest of the stack\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::DIV, { + .wast = "(func $DIV\n (local $sp i32)\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n (local $temp2 i64)\n\n (set_local $sp (get_global $sp))\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (br $main)\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if \n ;; check to make sure we are not overflowing\n (i32.or (i64.eqz (i64.clz (get_local $a1)))\n ;; divisor < dividend\n (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n\n ;; result = result + mask\n (set_local $dq (i64.add (get_local $maskd) (get_local $dq)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $dq) (get_local $maskd))))\n (set_local $cq (i64.add (get_local $cq) (get_local $temp)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $cq) (get_local $temp))))\n (set_local $cq (i64.add (get_local $maskc) (get_local $cq)))\n (set_local $temp (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $cq) (get_local $maskc))) (get_local $temp)))\n (set_local $bq (i64.add (get_local $bq) (get_local $temp)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $bq) (get_local $temp))))\n (set_local $bq (i64.add (get_local $maskb) (get_local $bq)))\n (set_local $aq (i64.add (get_local $maska) (i64.add (get_local $aq) (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $bq) (get_local $maskb))) (get_local $temp)))))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $aq))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $bq))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $cq))\n (i64.store (get_local $sp) (get_local $dq))\n)\n", + .imports = "" + } +},{ + opcodeEnum::DUP, { + .wast = "(func $DUP\n (param $a0 i32)\n (local $sp i32)\n\n (local $sp_ref i32)\n \n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n (set_local $sp_ref (i32.sub (i32.sub (get_local $sp) (i32.const 8)) (i32.mul (get_local $a0) (i32.const 32))))\n \n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.load (get_local $sp_ref)))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 8))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 16))))\n (i64.store (get_local $sp) (i64.load (i32.sub (get_local $sp_ref) (i32.const 24))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::EQ, { + .wast = "(func $EQ\n (local $sp i32)\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n (i64.store (get_local $sp)\n (i64.extend_u/i32\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 56))) (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 48))) (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 40))) (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 32))) (i64.load (get_local $sp))))))))\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::EXP, { + .wast = "(func $EXP\n (local $sp i32)\n\n ;; base\n (local $base0 i64)\n (local $base1 i64)\n (local $base2 i64)\n (local $base3 i64)\n\n ;; exp\n (local $exp0 i64)\n (local $exp1 i64)\n (local $exp2 i64)\n (local $exp3 i64)\n\n (local $r0 i64)\n (local $r1 i64)\n (local $r2 i64)\n (local $r3 i64)\n\n (local $gasCounter i32)\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $base0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $base1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $base2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $base3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $exp0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $exp1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $exp2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $exp3 (i64.load (get_local $sp)))\n\n ;; let result = new BN[1]\n (set_local $r3 (i64.const 1))\n\n (block $done\n (loop $loop\n ;; while [exp > 0] {\n (if (call $iszero_256 (get_local $exp0) (get_local $exp1) (get_local $exp2) (get_local $exp3))\n (br $done) \n )\n\n ;; if[exp.modn[2] === 1]\n ;; is odd?\n (if (i64.eqz (i64.ctz (get_local $exp3)))\n\n ;; result = result.mul[base].mod[TWO_POW256]\n ;; r = r * a\n (then\n (call $mul_256 (get_local $r0) (get_local $r1) (get_local $r2) (get_local $r3) (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (i32.add (get_local $sp) (i32.const 24)))\n (set_local $r0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $r1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $r2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $r3 (i64.load (get_local $sp)))\n )\n )\n ;; exp = exp.shrn 1\n (set_local $exp3 (i64.add (i64.shr_u (get_local $exp3) (i64.const 1)) (i64.shl (get_local $exp2) (i64.const 63))))\n (set_local $exp2 (i64.add (i64.shr_u (get_local $exp2) (i64.const 1)) (i64.shl (get_local $exp1) (i64.const 63))))\n (set_local $exp1 (i64.add (i64.shr_u (get_local $exp1) (i64.const 1)) (i64.shl (get_local $exp0) (i64.const 63))))\n (set_local $exp0 (i64.shr_u (get_local $exp0) (i64.const 1)))\n\n ;; base = base.mulr[baser].modr[TWO_POW256]\n (call $mul_256 (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (i32.add (get_local $sp) (i32.const 24)))\n (set_local $base0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $base1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $base2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $base3 (i64.load (get_local $sp)))\n\n (set_local $gasCounter (i32.add (get_local $gasCounter) (i32.const 1)))\n (br $loop)\n )\n ) \n\n ;; use gas\n ;; Log256[Exponent] * 10\n (call $useGas\n (i64.extend_u/i32\n (i32.mul\n (i32.const 10)\n (i32.div_u\n (i32.add (get_local $gasCounter) (i32.const 7))\n (i32.const 8)))))\n\n ;; decement the stack pointer\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $r0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $r1))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $r2))\n (i64.store (get_local $sp) (get_local $r3))\n)\n", + .imports = "" + } +},{ + opcodeEnum::GT, { + .wast = "(func $GT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == a1\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.gt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 > b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::ISZERO, { + .wast = "(func $ISZERO\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (i64.store (get_global $sp)\n (i64.extend_u/i32\n (call $iszero_256 (get_local $a0) (get_local $a1) (get_local $a2) (get_local $a3))\n )\n )\n\n ;; zero out the rest of memory\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::LT, { + .wast = "(func $LT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.lt_u (get_local $a0) (get_local $b0)) ;; a0 < b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == b0\n (i32.or (i64.lt_u (get_local $a1) (get_local $b1)) ;; a1 < b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.lt_u (get_local $a2) (get_local $b2)) ;; a2 < b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.lt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 < b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MLOAD, { + .wast = ";; stack:\n;; 0: offset\n(func $MLOAD\n (local $offset i32)\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n ;; subttract gas useage\n (call $memusegas (get_local $offset) (i32.const 32))\n\n ;; FIXME: how to deal with overflow?\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.load (i32.add (get_local $offset) (i32.const 24))))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.load (i32.add (get_local $offset) (i32.const 16))))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.load (i32.add (get_local $offset) (i32.const 8))))\n (i64.store (get_global $sp) (i64.load (get_local $offset)))\n\n ;; swap\n (drop (call $bswap_m256 (get_global $sp)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MOD, { + .wast = "(func $MOD\n (local $sp i32)\n\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n\n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSIZE, { + .wast = "(func $MSIZE\n (local $sp i32)\n\n ;; there's no input item for us to overwrite\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n\n (i64.store (i32.add (get_local $sp) (i32.const 0)) \n (i64.mul (get_global $wordCount) (i64.const 32)))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSTORE, { + .wast = ";; stack:\n;; 0: word\n;; -1: offset\n(func $MSTORE\n (local $sp i32)\n\n (local $offset i32)\n \n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n ;; subtrace gas useage\n (call $memusegas (get_local $offset) (i32.const 32))\n\n ;; pop itme from the stack\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n ;; swap top stack item\n (drop (call $bswap_m256 (get_local $sp)))\n\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n ;; store word to memory\n (i64.store (get_local $offset) (i64.load (get_local $sp)))\n (i64.store (i32.add (get_local $offset) (i32.const 8)) (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (i64.store (i32.add (get_local $offset) (i32.const 16)) (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (i64.store (i32.add (get_local $offset) (i32.const 24)) (i64.load (i32.add (get_local $sp) (i32.const 24))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSTORE8, { + .wast = ";; stack:\n;; 0: word\n;; -1: offset\n(func $MSTORE8\n (local $sp i32)\n\n (local $offset i32)\n\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n\n (call $memusegas (get_local $offset) (i32.const 1))\n\n ;; pop stack\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n (i32.store8 (i32.add (get_local $offset) (i32.const 0)) (i32.load (get_local $sp)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MUL, { + .wast = "(func $MUL\n (call $mul_256\n (i64.load (i32.add (get_global $sp) (i32.const 24)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (get_global $sp))\n (i64.load (i32.sub (get_global $sp) (i32.const 8)))\n (i64.load (i32.sub (get_global $sp) (i32.const 16)))\n (i64.load (i32.sub (get_global $sp) (i32.const 24)))\n (i64.load (i32.sub (get_global $sp) (i32.const 32)))\n (i32.sub (get_global $sp) (i32.const 8))\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::MULMOD, { + .wast = "(func $MULMOD\n (local $sp i32)\n\n (local $a i64)\n (local $c i64)\n (local $e i64)\n (local $g i64)\n (local $i i64)\n (local $k i64)\n (local $m i64)\n (local $o i64)\n (local $b i64)\n (local $d i64)\n (local $f i64)\n (local $h i64)\n (local $j i64)\n (local $l i64)\n (local $n i64)\n (local $p i64)\n (local $temp7 i64)\n (local $temp6 i64)\n (local $temp5 i64)\n (local $temp4 i64)\n (local $temp3 i64)\n (local $temp2 i64)\n (local $temp1 i64)\n (local $temp0 i64)\n (local $rowCarry i64)\n\n (local $moda i64)\n (local $modb i64)\n (local $modc i64)\n (local $modd i64)\n\n ;; pop two items of the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $e (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $g (i64.load (get_global $sp)))\n (set_local $i (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n (set_local $k (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $m (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $o (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 64)))\n\n ;; MUL\n ;; a b c d e f g h\n ;;* i j k l m n o p\n ;;----------------\n\n ;; split the ops\n (set_local $b (i64.and (get_local $a) (i64.const 4294967295)))\n (set_local $a (i64.shr_u (get_local $a) (i64.const 32))) \n\n (set_local $d (i64.and (get_local $c) (i64.const 4294967295)))\n (set_local $c (i64.shr_u (get_local $c) (i64.const 32))) \n\n (set_local $f (i64.and (get_local $e) (i64.const 4294967295)))\n (set_local $e (i64.shr_u (get_local $e) (i64.const 32)))\n\n (set_local $h (i64.and (get_local $g) (i64.const 4294967295)))\n (set_local $g (i64.shr_u (get_local $g) (i64.const 32)))\n\n (set_local $j (i64.and (get_local $i) (i64.const 4294967295)))\n (set_local $i (i64.shr_u (get_local $i) (i64.const 32))) \n\n (set_local $l (i64.and (get_local $k) (i64.const 4294967295)))\n (set_local $k (i64.shr_u (get_local $k) (i64.const 32))) \n\n (set_local $n (i64.and (get_local $m) (i64.const 4294967295)))\n (set_local $m (i64.shr_u (get_local $m) (i64.const 32)))\n\n (set_local $p (i64.and (get_local $o) (i64.const 4294967295)))\n (set_local $o (i64.shr_u (get_local $o) (i64.const 32)))\n\n ;; first row multiplication \n ;; p * h\n (set_local $temp0 (i64.mul (get_local $p) (get_local $h)))\n ;; p * g + carry\n (set_local $temp1 (i64.add (i64.mul (get_local $p) (get_local $g)) (i64.shr_u (get_local $temp0) (i64.const 32))))\n ;; p * f + carry\n (set_local $temp2 (i64.add (i64.mul (get_local $p) (get_local $f)) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; p * e + carry\n (set_local $temp3 (i64.add (i64.mul (get_local $p) (get_local $e)) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; p * d + carry\n (set_local $temp4 (i64.add (i64.mul (get_local $p) (get_local $d)) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; p * c + carry\n (set_local $temp5 (i64.add (i64.mul (get_local $p) (get_local $c)) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; p * b + carry\n (set_local $temp6 (i64.add (i64.mul (get_local $p) (get_local $b)) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; p * a + carry\n (set_local $temp7 (i64.add (i64.mul (get_local $p) (get_local $a)) (i64.shr_u (get_local $temp6) (i64.const 32))))\n (set_local $rowCarry (i64.shr_u (get_local $temp7) (i64.const 32)))\n\n ;; second row\n ;; o * h + $temp1 \n (set_local $temp1 (i64.add (i64.mul (get_local $o) (get_local $h)) (i64.and (get_local $temp1) (i64.const 4294967295))))\n ;; o * g + $temp2 + carry\n (set_local $temp2 (i64.add (i64.add (i64.mul (get_local $o) (get_local $g)) (i64.and (get_local $temp2) (i64.const 4294967295))) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; o * f + $temp3 + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $o) (get_local $f)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; o * e + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $o) (get_local $e)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; o * d + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $o) (get_local $d)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; o * c + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $o) (get_local $c)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; o * b + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $o) (get_local $b)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; o * a + carry + rowCarry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $o) (get_local $a)) (i64.shr_u (get_local $temp7) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $p) (i64.const 32)))\n\n ;; third row - n\n ;; n * h + $temp2 \n (set_local $temp2 (i64.add (i64.mul (get_local $n) (get_local $h)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n ;; n * g + $temp3 carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $n) (get_local $g)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; n * f + $temp4) + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $n) (get_local $f)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; n * e + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $n) (get_local $e)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; n * d + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $n) (get_local $d)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; n * c + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $n) (get_local $c)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; n * b + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $n) (get_local $b)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; n * a + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $n) (get_local $a)) (i64.shr_u (get_local $p) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $o) (i64.const 32)))\n\n ;; forth row \n ;; m * h + $temp3\n (set_local $temp3 (i64.add (i64.mul (get_local $m) (get_local $h)) (i64.and (get_local $temp3) (i64.const 4294967295))))\n ;; m * g + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $m) (get_local $g)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; m * f + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $m) (get_local $f)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; m * e + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $m) (get_local $e)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; m * d + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $m) (get_local $d)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; m * c + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $m) (get_local $c)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; m * b + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $m) (get_local $b)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; m * a + carry + rowCarry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $m) (get_local $a)) (i64.shr_u (get_local $o) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $n) (i64.const 32)))\n\n ;; fith row\n ;; l * h + $temp4\n (set_local $temp4 (i64.add (i64.mul (get_local $l) (get_local $h)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n ;; l * g + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $l) (get_local $g)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; l * f + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $l) (get_local $f)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; l * e + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $l) (get_local $e)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; l * d + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $l) (get_local $d)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; l * c + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $l) (get_local $c)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; l * b + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $l) (get_local $b)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; l * a + carry + rowCarry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $l) (get_local $a)) (i64.shr_u (get_local $n) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $m) (i64.const 32)))\n\n ;; sixth row \n ;; k * h + $temp5\n (set_local $temp5 (i64.add (i64.mul (get_local $k) (get_local $h)) (i64.and (get_local $temp5) (i64.const 4294967295))))\n ;; k * g + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $k) (get_local $g)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; k * f + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $k) (get_local $f)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; k * e + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $k) (get_local $e)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; k * d + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $k) (get_local $d)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; k * c + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $k) (get_local $c)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; k * b + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $k) (get_local $b)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; k * a + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $k) (get_local $a)) (i64.shr_u (get_local $m) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $l) (i64.const 32)))\n\n ;; seventh row\n ;; j * h + $temp6\n (set_local $temp6 (i64.add (i64.mul (get_local $j) (get_local $h)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n ;; j * g + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $j) (get_local $g)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; j * f + $p +carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $j) (get_local $f)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; j * e + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $j) (get_local $e)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; j * d + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $j) (get_local $d)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; j * c + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $j) (get_local $c)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; j * b + $l + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $j) (get_local $b)) (i64.and (get_local $l) (i64.const 4294967295))) (i64.shr_u (get_local $m) (i64.const 32))))\n ;; j * a + carry\n (set_local $k (i64.add (i64.add (i64.mul (get_local $j) (get_local $a)) (i64.shr_u (get_local $l) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $k) (i64.const 32)))\n\n ;; eigth row\n ;; i * h + $temp7 \n (set_local $temp7 (i64.add (i64.mul (get_local $i) (get_local $h)) (i64.and (get_local $temp7) (i64.const 4294967295))))\n ;; i * g + $p \n (set_local $p (i64.add (i64.add (i64.mul (get_local $i) (get_local $g)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; i * f + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $i) (get_local $f)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; i * e + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $i) (get_local $e)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; i * d + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $i) (get_local $d)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; i * c + $l + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $i) (get_local $c)) (i64.and (get_local $l) (i64.const 4294967295))) (i64.shr_u (get_local $m) (i64.const 32))))\n ;; i * b + $k + carry\n (set_local $k (i64.add (i64.add (i64.mul (get_local $i) (get_local $b)) (i64.and (get_local $k) (i64.const 4294967295))) (i64.shr_u (get_local $l) (i64.const 32))))\n ;; i * a + carry\n (set_local $j (i64.add (i64.add (i64.mul (get_local $i) (get_local $a)) (i64.shr_u (get_local $k) (i64.const 32))) (get_local $rowCarry)))\n\n ;; combine terms\n (set_local $a (get_local $j))\n (set_local $b (i64.or (i64.shl (get_local $k) (i64.const 32)) (i64.and (get_local $l) (i64.const 4294967295))))\n (set_local $c (i64.or (i64.shl (get_local $m) (i64.const 32)) (i64.and (get_local $n) (i64.const 4294967295))))\n (set_local $d (i64.or (i64.shl (get_local $o) (i64.const 32)) (i64.and (get_local $p) (i64.const 4294967295))))\n (set_local $e (i64.or (i64.shl (get_local $temp7) (i64.const 32)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n (set_local $f (i64.or (i64.shl (get_local $temp5) (i64.const 32)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n (set_local $g (i64.or (i64.shl (get_local $temp3) (i64.const 32)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n (set_local $h (i64.or (i64.shl (get_local $temp1) (i64.const 32)) (i64.and (get_local $temp0) (i64.const 4294967295))))\n\n ;; pop the MOD argmunet off the stack\n (set_local $moda (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $modb (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $modc (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $modd (i64.load (get_local $sp)))\n\n (call $mod_512\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h) \n (i64.const 0) (i64.const 0) (i64.const 0) (i64.const 0) (get_local $moda) (get_local $modb) (get_local $modc) (get_local $modd) (i32.add (get_local $sp) (i32.const 24))\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::NOT, { + .wast = "(func $NOT\n ;; FIXME: consider using 0xffffffffffffffff instead of -1?\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 24))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 16))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 8))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 0)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 0))) (i64.const -1)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::OR, { + .wast = "(func $OR\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (get_global $sp))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::PC, { + .wast = "(func $PC\n (param $pc i32)\n (local $sp i32)\n\n ;; add one to the stack\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n (i64.store (get_local $sp) (i64.extend_u/i32 (get_local $pc)))\n\n ;; zero out rest of stack\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::PUSH, { + .wast = "(func $PUSH\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (local $sp i32)\n\n ;; increament stack pointer\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n\n (i64.store (get_local $sp) (get_local $a3))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $a2))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $a1))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SDIV, { + .wast = "(func $SDIV\n (local $sp i32)\n\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n (local $temp2 i64)\n (local $sign i32)\n\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n ;; get the resulting sign\n (set_local $sign (i32.wrap/i64 (i64.shr_u (i64.xor (get_local $a1) (get_local $a)) (i64.const 63))))\n\n ;; convert to unsigned value\n (if (i64.eqz (i64.clz (get_local $a)))\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n ;; a = a + 1\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c)) (get_local $carry)))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b)) (get_local $carry)))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n (if (i64.eqz (i64.clz (get_local $a1)))\n (then\n (set_local $a1 (i64.xor (get_local $a1) (i64.const -1)))\n (set_local $b1 (i64.xor (get_local $b1) (i64.const -1)))\n (set_local $c1 (i64.xor (get_local $c1) (i64.const -1)))\n (set_local $d1 (i64.xor (get_local $d1) (i64.const -1)))\n\n (set_local $d1 (i64.add (get_local $d1) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d1)))\n (set_local $c1 (i64.add (get_local $c1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c1)) (get_local $carry)))\n (set_local $b1 (i64.add (get_local $b1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b1)) (get_local $carry)))\n (set_local $a1 (i64.add (get_local $a1) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n \n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (br $main)\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n\n ;; result = result + mask\n (set_local $dq (i64.add (get_local $maskd) (get_local $dq)))\n (set_local $carry (i64.lt_u (get_local $dq) (get_local $maskd)))\n (set_local $temp (i64.add (get_local $cq) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.lt_u (get_local $temp) (get_local $cq)))\n (set_local $cq (i64.add (get_local $maskc) (get_local $temp)))\n (set_local $carry (i32.or (i64.lt_u (get_local $cq) (get_local $maskc)) (get_local $carry)))\n (set_local $temp (i64.add (get_local $bq) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.lt_u (get_local $temp) (get_local $bq)))\n (set_local $bq (i64.add (get_local $maskb) (get_local $temp)))\n (set_local $carry (i32.or (i64.lt_u (get_local $bq) (get_local $maskb)) (get_local $carry)))\n (set_local $aq (i64.add (get_local $maska) (i64.add (get_local $aq) (i64.extend_u/i32 (get_local $carry)))))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n ;; convert to signed\n (if (get_local $sign)\n (then\n (set_local $aq (i64.xor (get_local $aq) (i64.const -1)))\n (set_local $bq (i64.xor (get_local $bq) (i64.const -1)))\n (set_local $cq (i64.xor (get_local $cq) (i64.const -1)))\n (set_local $dq (i64.xor (get_local $dq) (i64.const -1)))\n\n (set_local $dq (i64.add (get_local $dq) (i64.const 1)))\n (set_local $cq (i64.add (get_local $cq) (i64.extend_u/i32 (i64.eqz (get_local $dq)))))\n (set_local $bq (i64.add (get_local $bq) (i64.extend_u/i32 (i64.eqz (get_local $cq)))))\n (set_local $aq (i64.add (get_local $aq) (i64.extend_u/i32 (i64.eqz (get_local $bq)))))\n )\n )\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $aq))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $bq))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $cq))\n (i64.store (get_local $sp) (get_local $dq))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SGT, { + .wast = "(func $SGT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.gt_s (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == a1\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.gt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 > b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SHA3, { + .wast = "(func $SHA3\n (local $dataOffset i32)\n (local $dataOffset0 i64)\n (local $dataOffset1 i64)\n (local $dataOffset2 i64)\n (local $dataOffset3 i64)\n\n (local $length i32)\n (local $length0 i64)\n (local $length1 i64)\n (local $length2 i64)\n (local $length3 i64)\n\n (local $contextOffset i32)\n (local $outputOffset i32)\n\n (set_local $length0 (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n (set_local $length1 (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $length2 (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $length3 (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n\n (set_local $dataOffset0 (i64.load (i32.add (get_global $sp) (i32.const 0))))\n (set_local $dataOffset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $dataOffset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $dataOffset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $length \n (call $check_overflow (get_local $length0)\n (get_local $length1)\n (get_local $length2)\n (get_local $length3)))\n (set_local $dataOffset \n (call $check_overflow (get_local $dataOffset0)\n (get_local $dataOffset1)\n (get_local $dataOffset2)\n (get_local $dataOffset3)))\n\n ;; charge copy fee ceil(words/32) * 6 \n (call $useGas (i64.extend_u/i32 (i32.mul (i32.div_u (i32.add (get_local $length) (i32.const 31)) (i32.const 32)) (i32.const 6))))\n (call $memusegas (get_local $dataOffset) (get_local $length))\n\n (set_local $dataOffset (i32.add (get_global $memstart) (get_local $dataOffset)))\n\n (set_local $contextOffset (i32.const 32808))\n (set_local $outputOffset (i32.sub (get_global $sp) (i32.const 32)))\n\n (call $keccak (get_local $contextOffset) (get_local $dataOffset) (get_local $length) (get_local $outputOffset))\n\n (drop (call $bswap_m256 (get_local $outputOffset)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SIGNEXTEND, { + .wast = "(func $SIGNEXTEND\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n (local $sign i64)\n (local $t i32)\n (local $end i32)\n\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $end (get_global $sp))\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (if (i32.and \n (i32.and \n (i32.and \n (i64.lt_u (get_local $a3) (i64.const 32))\n (i64.eqz (get_local $a2))) \n (i64.eqz (get_local $a1)))\n (i64.eqz (get_local $a0)))\n (then\n (set_local $t (i32.add (i32.wrap/i64 (get_local $a3)) (get_local $sp))) \n (set_local $sign (i64.shr_s (i64.load8_s (get_local $t)) (i64.const 8)))\n (set_local $t (i32.add (get_local $t) (i32.const 1)))\n (block $done\n (loop $loop\n (if (i32.lt_u (get_local $end) (get_local $t))\n (br $done)\n )\n (i64.store (get_local $t) (get_local $sign))\n (set_local $t (i32.add (get_local $t) (i32.const 8)))\n (br $loop)\n )\n )\n )\n )\n)\n\n", + .imports = "" + } +},{ + opcodeEnum::SLT, { + .wast = "(func $SLT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.lt_s (get_local $a0) (get_local $b0)) ;; a0 < b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == b0\n (i32.or (i64.lt_u (get_local $a1) (get_local $b1)) ;; a1 < b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.lt_u (get_local $a2) (get_local $b2)) ;; a2 < b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.lt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 < b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SMOD, { + .wast = "(func $SMOD\n (local $sp i32)\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $sign i32)\n (local $temp i64)\n (local $temp2 i64)\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (set_local $maskd (i64.const 1))\n (set_local $sign (i32.wrap/i64 (i64.shr_u (get_local $d) (i64.const 63))))\n\n ;; convert to unsigned value\n (if (i64.eqz (i64.clz (get_local $a)))\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n ;; a = a + 1\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c)) (get_local $carry)))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b)) (get_local $carry)))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n\n (if (i64.eqz (i64.clz (get_local $a1)))\n (then\n (set_local $a1 (i64.xor (get_local $a1) (i64.const -1)))\n (set_local $b1 (i64.xor (get_local $b1) (i64.const -1)))\n (set_local $c1 (i64.xor (get_local $c1) (i64.const -1)))\n (set_local $d1 (i64.xor (get_local $d1) (i64.const -1)))\n\n (set_local $d1 (i64.add (get_local $d1) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d1)))\n (set_local $c1 (i64.add (get_local $c1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c1)) (get_local $carry)))\n (set_local $b1 (i64.add (get_local $b1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b1)) (get_local $carry)))\n (set_local $a1 (i64.add (get_local $a1) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n \n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n )\n\n ;; convert to signed\n (if (get_local $sign)\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (i64.eqz (get_local $d)))))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (i64.eqz (get_local $c)))))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (i64.eqz (get_local $b)))))\n )\n )\n\n ;; save the stack\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n) ;; end for SMOD\n", + .imports = "" + } +},{ + opcodeEnum::SUB, { + .wast = "(func $SUB\n (local $sp i32)\n\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n (local $carry i64)\n (local $temp i64)\n\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n ;; a * 64^3 + b*64^2 + c*64 + d \n ;; d\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $d1))))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n\n ;; c\n (set_local $temp (i64.sub (get_local $c) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.gt_u (get_local $temp) (get_local $c))))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.gt_u (get_local $c) (get_local $temp))) (get_local $carry)))\n\n ;; b\n (set_local $temp (i64.sub (get_local $b) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.gt_u (get_local $temp) (get_local $b))))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n\n ;; a\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.or (i64.extend_u/i32 (i64.gt_u (get_local $b) (get_local $temp))) (get_local $carry))) (get_local $a1)))\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SWAP, { + .wast = "(func $SWAP\n (param $a0 i32)\n (local $sp_ref i32)\n\n (local $topa i64)\n (local $topb i64)\n (local $topc i64)\n (local $topd i64)\n \n (set_local $sp_ref (i32.sub (i32.add (get_global $sp) (i32.const 24)) (i32.mul (i32.add (get_local $a0) (i32.const 1)) (i32.const 32))))\n\n (set_local $topa (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $topb (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $topc (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $topd (i64.load (get_global $sp)))\n \n ;; replace the top element\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.load (get_local $sp_ref)))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 8))))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 16))))\n (i64.store (get_global $sp) (i64.load (i32.sub (get_local $sp_ref) (i32.const 24))))\n\n ;; store the old top element\n (i64.store (get_local $sp_ref) (get_local $topa))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 8)) (get_local $topb))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 16)) (get_local $topc))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 24)) (get_local $topd))\n)\n", + .imports = "" + } +},{ + opcodeEnum::XOR, { + .wast = "(func $XOR\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (i32.add (get_global $sp) (i32.const 0)))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_i32, { + .wast = "(func $bswap_i32\n (param $int i32)\n (result i32)\n\n (i32.or\n (i32.or\n (i32.and (i32.shr_u (get_local $int) (i32.const 24)) (i32.const 0xff)) ;; 7 -> 0\n (i32.and (i32.shr_u (get_local $int) (i32.const 8)) (i32.const 0xff00))) ;; 6 -> 1\n (i32.or\n (i32.and (i32.shl (get_local $int) (i32.const 8)) (i32.const 0xff0000)) ;; 5 -> 2\n (i32.and (i32.shl (get_local $int) (i32.const 24)) (i32.const 0xff000000)))) ;; 4 -> 3\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_i64, { + .wast = "(func $bswap_i64\n (param $int i64)\n (result i64)\n\n (i64.or\n (i64.or\n (i64.or\n (i64.and (i64.shr_u (get_local $int) (i64.const 56)) (i64.const 0xff)) ;; 7 -> 0\n (i64.and (i64.shr_u (get_local $int) (i64.const 40)) (i64.const 0xff00))) ;; 6 -> 1\n (i64.or\n (i64.and (i64.shr_u (get_local $int) (i64.const 24)) (i64.const 0xff0000)) ;; 5 -> 2\n (i64.and (i64.shr_u (get_local $int) (i64.const 8)) (i64.const 0xff000000)))) ;; 4 -> 3\n (i64.or\n (i64.or\n (i64.and (i64.shl (get_local $int) (i64.const 8)) (i64.const 0xff00000000)) ;; 3 -> 4\n (i64.and (i64.shl (get_local $int) (i64.const 24)) (i64.const 0xff0000000000))) ;; 2 -> 5\n (i64.or\n (i64.and (i64.shl (get_local $int) (i64.const 40)) (i64.const 0xff000000000000)) ;; 1 -> 6\n (i64.and (i64.shl (get_local $int) (i64.const 56)) (i64.const 0xff00000000000000))))) ;; 0 -> 7\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m128, { + .wast = "(func $bswap_m128\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 8)))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $temp))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m160, { + .wast = "(func $bswap_m160\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 12)))))\n (i64.store (i32.add (get_local $sp) (i32.const 12)) (get_local $temp))\n\n (i32.store (i32.add (get_local $sp) (i32.const 8)) (call $bswap_i32 (i32.load (i32.add (get_local $sp) (i32.const 8)))))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m256, { + .wast = "(func $bswap_m256\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 24)))))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $temp))\n\n (set_local $temp (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 8)))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 16)))))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $temp))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback, { + .wast = "(func $callback\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_128, { + .wast = "(func $callback_128\n (param $result i32)\n\n (drop (call $bswap_m128 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_160, { + .wast = "(func $callback_160\n (param $result i32)\n\n (drop (call $bswap_m160 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_256, { + .wast = "(func $callback_256\n (param $result i32)\n\n (drop (call $bswap_m256 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_32, { + .wast = "(func $callback_32\n (param $result i32)\n\n (i64.store (get_global $sp) (i64.extend_u/i32 (get_local $result)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::check_overflow, { + .wast = "(func $check_overflow\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (result i32)\n\n (local $MAX_INT i32)\n (set_local $MAX_INT (i32.const -1))\n\n (if\n (i32.and \n (i32.and \n (i64.eqz (get_local $d))\n (i64.eqz (get_local $c)))\n (i32.and \n (i64.eqz (get_local $b))\n (i64.lt_u (get_local $a) (i64.extend_u/i32 (get_local $MAX_INT)))))\n (return (i32.wrap/i64 (get_local $a))))\n\n (return (get_local $MAX_INT))\n)\n", + .imports = "" + } +},{ + opcodeEnum::check_overflow_i64, { + .wast = "(func $check_overflow_i64\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (result i64)\n\n (if\n (i32.and \n (i32.and \n (i64.eqz (get_local $d))\n (i64.eqz (get_local $c)))\n (i64.eqz (get_local $b)))\n (return (get_local $a)))\n\n (return (i64.const 0xffffffffffffffff))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_256, { + .wast = ";; is a less than or equal to b // a >= b\n(func $gte_256\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i64.ge_u (get_local $a3) (get_local $b3))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_320, { + .wast = "(func $gte_320\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (param $a4 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n (param $b4 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i32.or (i64.gt_u (get_local $a3) (get_local $b3)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a3) (get_local $b3))\n (i64.ge_u (get_local $a4) (get_local $b4))))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_512, { + .wast = "(func $gte_512\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (param $a4 i64)\n (param $a5 i64)\n (param $a6 i64)\n (param $a7 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n (param $b4 i64)\n (param $b5 i64)\n (param $b6 i64)\n (param $b7 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i32.or (i64.gt_u (get_local $a3) (get_local $b3)) ;; a3 > b3\n (i32.and (i64.eq (get_local $a3) (get_local $b3))\n (i32.or (i64.gt_u (get_local $a4) (get_local $b4)) ;; a4 > b4\n (i32.and (i64.eq (get_local $a4) (get_local $b4))\n (i32.or (i64.gt_u (get_local $a5) (get_local $b5)) ;; a5 > b5\n (i32.and (i64.eq (get_local $a5) (get_local $b5))\n (i32.or (i64.gt_u (get_local $a6) (get_local $b6)) ;; a6 > b6\n (i32.and (i64.eq (get_local $a6) (get_local $b6))\n (i64.ge_u (get_local $a7) (get_local $b7))))))))))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_256, { + .wast = "(func $iszero_256\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n\n (i64.eqz (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3))) \n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_320, { + .wast = "(func $iszero_320\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n\n (i64.eqz (i64.or (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3)) (get_local 4)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_512, { + .wast = "(func $iszero_512\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n (i64.eqz (i64.or (i64.or (i64.or (i64.or (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3)) (get_local 4)) (get_local 5)) (get_local 6)) (get_local 7)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::keccak, { + .wast = ";;\n;; Copied from https://github.com/axic/keccak-wasm (has more comments)\n;;\n\n(func $keccak_theta\n (param $context_offset i32)\n\n (local $C0 i64)\n (local $C1 i64)\n (local $C2 i64)\n (local $C3 i64)\n (local $C4 i64)\n (local $D0 i64)\n (local $D1 i64)\n (local $D2 i64)\n (local $D3 i64)\n (local $D4 i64)\n\n ;; C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];\n (set_local $C0\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 160)))\n )\n )\n )\n )\n )\n\n (set_local $C1\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 168)))\n )\n )\n )\n )\n )\n\n (set_local $C2\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 136)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 176)))\n )\n )\n )\n )\n )\n\n (set_local $C3\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 144)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 184)))\n )\n )\n )\n )\n )\n\n (set_local $C4\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 152)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 192)))\n )\n )\n )\n )\n )\n\n ;; D[0] = ROTL64(C[1], 1) ^ C[4];\n (set_local $D0\n (i64.xor\n (get_local $C4)\n (i64.rotl\n (get_local $C1)\n (i64.const 1)\n )\n )\n )\n\n ;; D[1] = ROTL64(C[2], 1) ^ C[0];\n (set_local $D1\n (i64.xor\n (get_local $C0)\n (i64.rotl\n (get_local $C2)\n (i64.const 1)\n )\n )\n )\n\n ;; D[2] = ROTL64(C[3], 1) ^ C[1];\n (set_local $D2\n (i64.xor\n (get_local $C1)\n (i64.rotl\n (get_local $C3)\n (i64.const 1)\n )\n )\n )\n\n ;; D[3] = ROTL64(C[4], 1) ^ C[2];\n (set_local $D3\n (i64.xor\n (get_local $C2)\n (i64.rotl\n (get_local $C4)\n (i64.const 1)\n )\n )\n )\n\n ;; D[4] = ROTL64(C[0], 1) ^ C[3];\n (set_local $D4\n (i64.xor\n (get_local $C3)\n (i64.rotl\n (get_local $C0)\n (i64.const 1)\n )\n )\n )\n\n ;; A[x] ^= D[x];\n ;; A[x + 5] ^= D[x];\n ;; A[x + 10] ^= D[x];\n ;; A[x + 15] ^= D[x];\n ;; A[x + 20] ^= D[x];\n \n ;; x = 0\n (i64.store (i32.add (get_local $context_offset) (i32.const 0))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 40))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 80))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 120))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 160))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 160)))\n (get_local $D0)\n )\n )\n\n ;; x = 1\n (i64.store (i32.add (get_local $context_offset) (i32.const 8))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 48))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 88))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 128))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 168))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 168)))\n (get_local $D1)\n )\n )\n\n ;; x = 2\n (i64.store (i32.add (get_local $context_offset) (i32.const 16))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 56))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 96))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 136))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 136)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 176))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 176)))\n (get_local $D2)\n )\n )\n\n ;; x = 3\n (i64.store (i32.add (get_local $context_offset) (i32.const 24))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 64))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 104))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 144))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 144)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 184))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 184)))\n (get_local $D3)\n )\n )\n\n ;; x = 4\n (i64.store (i32.add (get_local $context_offset) (i32.const 32))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 72))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 112))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 152))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 152)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 192))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 192)))\n (get_local $D4)\n )\n )\n)\n\n(func $keccak_rho\n (param $context_offset i32)\n (param $rotation_consts i32)\n\n ;;(local $tmp i32)\n\n ;; state[ 1] = ROTL64(state[ 1], 1);\n ;;(set_local $tmp (i32.add (get_local $context_offset) (i32.const 1)))\n ;;(i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $context_offset)) (i64.const 1)))\n\n ;;(set_local $tmp (i32.add (get_local $context_offset) (i32.const 2)))\n ;;(i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $context_offset)) (i64.const 62)))\n\n (local $tmp i32)\n (local $i i32)\n\n ;; for (i = 0; i <= 24; i++)\n (set_local $i (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (i32.const 24))\n (br $done)\n )\n\n (set_local $tmp (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (i32.const 1) (get_local $i)))))\n\n (i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $tmp)) (i64.load8_u (i32.add (get_local $rotation_consts) (get_local $i)))))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n)\n\n(func $keccak_pi\n (param $context_offset i32)\n\n (local $A1 i64)\n (set_local $A1 (i64.load (i32.add (get_local $context_offset) (i32.const 8))))\n\n ;; Swap non-overlapping fields, i.e. $A1 = $A6, etc.\n ;; NOTE: $A0 is untouched\n (i64.store (i32.add (get_local $context_offset) (i32.const 8)) (i64.load (i32.add (get_local $context_offset) (i32.const 48))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 48)) (i64.load (i32.add (get_local $context_offset) (i32.const 72))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 72)) (i64.load (i32.add (get_local $context_offset) (i32.const 176))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 176)) (i64.load (i32.add (get_local $context_offset) (i32.const 112))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 112)) (i64.load (i32.add (get_local $context_offset) (i32.const 160))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 160)) (i64.load (i32.add (get_local $context_offset) (i32.const 16))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 16)) (i64.load (i32.add (get_local $context_offset) (i32.const 96))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 96)) (i64.load (i32.add (get_local $context_offset) (i32.const 104))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 104)) (i64.load (i32.add (get_local $context_offset) (i32.const 152))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 152)) (i64.load (i32.add (get_local $context_offset) (i32.const 184))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 184)) (i64.load (i32.add (get_local $context_offset) (i32.const 120))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 120)) (i64.load (i32.add (get_local $context_offset) (i32.const 32))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 32)) (i64.load (i32.add (get_local $context_offset) (i32.const 192))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 192)) (i64.load (i32.add (get_local $context_offset) (i32.const 168))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 168)) (i64.load (i32.add (get_local $context_offset) (i32.const 64))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 64)) (i64.load (i32.add (get_local $context_offset) (i32.const 128))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 128)) (i64.load (i32.add (get_local $context_offset) (i32.const 40))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 40)) (i64.load (i32.add (get_local $context_offset) (i32.const 24))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 24)) (i64.load (i32.add (get_local $context_offset) (i32.const 144))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 144)) (i64.load (i32.add (get_local $context_offset) (i32.const 136))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 136)) (i64.load (i32.add (get_local $context_offset) (i32.const 88))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 88)) (i64.load (i32.add (get_local $context_offset) (i32.const 56))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 56)) (i64.load (i32.add (get_local $context_offset) (i32.const 80))))\n\n ;; Place the previously saved overlapping field\n (i64.store (i32.add (get_local $context_offset) (i32.const 80)) (get_local $A1))\n)\n\n(func $keccak_chi\n (param $context_offset i32)\n\n (local $A0 i64)\n (local $A1 i64)\n (local $i i32)\n\n ;; for (round = 0; round < 25; i += 5)\n (set_local $i (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (i32.const 25))\n (br $done)\n )\n\n (set_local $A0 (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i)))))\n (set_local $A1 (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1))))))\n\n ;; A[0 + i] ^= ~A1 & A[2 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i))))\n (i64.and\n (i64.xor (get_local $A1) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2)))))\n )\n )\n )\n\n ;; A[1 + i] ^= ~A[2 + i] & A[3 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3)))))\n )\n )\n )\n\n ;; A[2 + i] ^= ~A[3 + i] & A[4 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4)))))\n )\n )\n )\n\n ;; A[3 + i] ^= ~A[4 + i] & A0;\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (get_local $A0)\n )\n )\n )\n\n ;; A[4 + i] ^= ~A0 & A1;\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4)))))\n (i64.and\n (i64.xor (get_local $A0) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (get_local $A1)\n )\n )\n )\n\n (set_local $i (i32.add (get_local $i) (i32.const 5)))\n (br $loop)\n )\n )\n)\n\n(func $keccak_permute\n (param $context_offset i32)\n\n (local $rotation_consts i32)\n (local $round_consts i32)\n (local $round i32)\n\n (set_local $round_consts (i32.add (get_local $context_offset) (i32.const 400)))\n (set_local $rotation_consts (i32.add (get_local $context_offset) (i32.const 592)))\n\n ;; for (round = 0; round < 24; round++)\n (set_local $round (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $round) (i32.const 24))\n (br $done)\n )\n\n ;; theta transform\n (call $keccak_theta (get_local $context_offset))\n\n ;; rho transform\n (call $keccak_rho (get_local $context_offset) (get_local $rotation_consts))\n\n ;; pi transform\n (call $keccak_pi (get_local $context_offset))\n\n ;; chi transform\n (call $keccak_chi (get_local $context_offset))\n\n ;; iota transform\n ;; context_offset[0] ^= KECCAK_ROUND_CONSTANTS[round];\n (i64.store (get_local $context_offset)\n (i64.xor\n (i64.load (get_local $context_offset))\n (i64.load (i32.add (get_local $round_consts) (i32.mul (i32.const 8) (get_local $round))))\n )\n )\n\n (set_local $round (i32.add (get_local $round) (i32.const 1)))\n (br $loop)\n ) \n ) \n)\n\n(func $keccak_block\n (param $input_offset i32)\n (param $input_length i32) ;; ignored, we expect keccak256\n (param $context_offset i32)\n\n ;; read blocks in little-endian order and XOR against context_offset\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 0))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 0)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 8))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 8)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 16))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 16)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 24))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 24)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 32))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 32)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 40))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 40)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 48))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 48)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 56))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 56)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 64))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 64)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 72))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 72)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 80))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 80)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 88))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 88)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 96))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 96)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 104))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 104)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 112))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 112)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 120))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 120)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 128))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 128)))\n )\n )\n \n (call $keccak_permute (get_local $context_offset))\n)\n\n;;\n;; Initialise the context\n;;\n(func $keccak_init\n (param $context_offset i32)\n (local $round_consts i32)\n (local $rotation_consts i32)\n\n (call $keccak_reset (get_local $context_offset))\n\n ;; insert the round constants (used by $KECCAK_IOTA)\n (set_local $round_consts (i32.add (get_local $context_offset) (i32.const 400)))\n (i64.store (i32.add (get_local $round_consts) (i32.const 0)) (i64.const 0x0000000000000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 8)) (i64.const 0x0000000000008082))\n (i64.store (i32.add (get_local $round_consts) (i32.const 16)) (i64.const 0x800000000000808A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 24)) (i64.const 0x8000000080008000))\n (i64.store (i32.add (get_local $round_consts) (i32.const 32)) (i64.const 0x000000000000808B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 40)) (i64.const 0x0000000080000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 48)) (i64.const 0x8000000080008081))\n (i64.store (i32.add (get_local $round_consts) (i32.const 56)) (i64.const 0x8000000000008009))\n (i64.store (i32.add (get_local $round_consts) (i32.const 64)) (i64.const 0x000000000000008A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 72)) (i64.const 0x0000000000000088))\n (i64.store (i32.add (get_local $round_consts) (i32.const 80)) (i64.const 0x0000000080008009))\n (i64.store (i32.add (get_local $round_consts) (i32.const 88)) (i64.const 0x000000008000000A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 96)) (i64.const 0x000000008000808B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 104)) (i64.const 0x800000000000008B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 112)) (i64.const 0x8000000000008089))\n (i64.store (i32.add (get_local $round_consts) (i32.const 120)) (i64.const 0x8000000000008003))\n (i64.store (i32.add (get_local $round_consts) (i32.const 128)) (i64.const 0x8000000000008002))\n (i64.store (i32.add (get_local $round_consts) (i32.const 136)) (i64.const 0x8000000000000080))\n (i64.store (i32.add (get_local $round_consts) (i32.const 144)) (i64.const 0x000000000000800A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 152)) (i64.const 0x800000008000000A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 160)) (i64.const 0x8000000080008081))\n (i64.store (i32.add (get_local $round_consts) (i32.const 168)) (i64.const 0x8000000000008080))\n (i64.store (i32.add (get_local $round_consts) (i32.const 176)) (i64.const 0x0000000080000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 184)) (i64.const 0x8000000080008008))\n\n ;; insert the rotation constants (used by $keccak_rho)\n (set_local $rotation_consts (i32.add (get_local $context_offset) (i32.const 592)))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 0)) (i32.const 1))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 1)) (i32.const 62))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 2)) (i32.const 28))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 3)) (i32.const 27))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 4)) (i32.const 36))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 5)) (i32.const 44))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 6)) (i32.const 6))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 7)) (i32.const 55))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 8)) (i32.const 20))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 9)) (i32.const 3))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 10)) (i32.const 10))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 11)) (i32.const 43))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 12)) (i32.const 25))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 13)) (i32.const 39))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 14)) (i32.const 41))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 15)) (i32.const 45))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 16)) (i32.const 15))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 17)) (i32.const 21))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 18)) (i32.const 8))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 19)) (i32.const 18))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 20)) (i32.const 2))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 21)) (i32.const 61))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 22)) (i32.const 56))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 23)) (i32.const 14))\n)\n\n;;\n;; Reset the context\n;;\n(func $keccak_reset\n (param $context_offset i32)\n\n ;; clear out the context memory\n (drop (call $memset (get_local $context_offset) (i32.const 0) (i32.const 400)))\n)\n\n;;\n;; Push input to the context\n;;\n(func $keccak_update\n (param $context_offset i32)\n (param $input_offset i32)\n (param $input_length i32)\n\n (local $residue_offset i32)\n (local $residue_buffer i32)\n (local $residue_index i32)\n (local $tmp i32)\n\n ;; this is where we store the pointer\n (set_local $residue_offset (i32.add (get_local $context_offset) (i32.const 200)))\n ;; this is where the buffer is\n (set_local $residue_buffer (i32.add (get_local $context_offset) (i32.const 208)))\n\n (set_local $residue_index (i32.load (get_local $residue_offset)))\n\n ;; process residue from last block\n (if (i32.ne (get_local $residue_index) (i32.const 0))\n (then\n ;; the space left in the residue buffer\n (set_local $tmp (i32.sub (i32.const 136) (get_local $residue_index)))\n\n ;; limit to what we have as an input\n (if (i32.lt_u (get_local $input_length) (get_local $tmp))\n (set_local $tmp (get_local $input_length))\n )\n\n ;; fill up the residue buffer\n (drop (call $memcpy\n (i32.add (get_local $residue_buffer) (get_local $residue_index))\n (get_local $input_offset)\n (get_local $tmp)\n ))\n\n (set_local $residue_index (i32.add (get_local $residue_index) (get_local $tmp)))\n\n ;; block complete\n (if (i32.eq (get_local $residue_index) (i32.const 136))\n (call $keccak_block (get_local $input_offset) (i32.const 136) (get_local $context_offset))\n\n (set_local $residue_index (i32.const 0))\n )\n\n (i32.store (get_local $residue_offset) (get_local $residue_index))\n\n (set_local $input_length (i32.sub (get_local $input_length) (get_local $tmp)))\n )\n )\n\n ;; while (input_length > block_size)\n (block $done\n (loop $loop\n (if (i32.lt_u (get_local $input_length) (i32.const 136))\n (br $done)\n )\n\n (call $keccak_block (get_local $input_offset) (i32.const 136) (get_local $context_offset))\n\n (set_local $input_offset (i32.add (get_local $input_offset) (i32.const 136)))\n (set_local $input_length (i32.sub (get_local $input_length) (i32.const 136)))\n (br $loop)\n )\n )\n\n ;; copy to the residue buffer\n (if (i32.gt_u (get_local $input_length) (i32.const 0))\n (then\n (drop (call $memcpy\n (i32.add (get_local $residue_buffer) (get_local $residue_index))\n (get_local $input_offset)\n (get_local $input_length)\n ))\n\n (set_local $residue_index (i32.add (get_local $residue_index) (get_local $input_length)))\n (i32.store (get_local $residue_offset) (get_local $residue_index))\n )\n )\n)\n\n;;\n;; Finalise and return the hash\n;;\n;; The 256 bit hash is returned at the output offset.\n;;\n(func $keccak_finish\n (param $context_offset i32)\n (param $output_offset i32)\n\n (local $residue_offset i32)\n (local $residue_buffer i32)\n (local $residue_index i32)\n (local $tmp i32)\n\n ;; this is where we store the pointer\n (set_local $residue_offset (i32.add (get_local $context_offset) (i32.const 200)))\n ;; this is where the buffer is\n (set_local $residue_buffer (i32.add (get_local $context_offset) (i32.const 208)))\n\n (set_local $residue_index (i32.load (get_local $residue_offset)))\n (set_local $tmp (get_local $residue_index))\n\n ;; clear the rest of the residue buffer\n (drop (call $memset (i32.add (get_local $residue_buffer) (get_local $tmp)) (i32.const 0) (i32.sub (i32.const 136) (get_local $tmp))))\n\n ;; ((char*)ctx->message)[ctx->rest] |= 0x01;\n (set_local $tmp (i32.add (get_local $residue_buffer) (get_local $residue_index)))\n (i32.store8 (get_local $tmp) (i32.or (i32.load8_u (get_local $tmp)) (i32.const 0x01)))\n\n ;; ((char*)ctx->message)[block_size - 1] |= 0x80;\n (set_local $tmp (i32.add (get_local $residue_buffer) (i32.const 135)))\n (i32.store8 (get_local $tmp) (i32.or (i32.load8_u (get_local $tmp)) (i32.const 0x80)))\n\n (call $keccak_block (get_local $residue_buffer) (i32.const 136) (get_local $context_offset))\n\n ;; the first 32 bytes pointed at by $output_offset is the final hash\n (i64.store (get_local $output_offset) (i64.load (get_local $context_offset)))\n (i64.store (i32.add (get_local $output_offset) (i32.const 8)) (i64.load (i32.add (get_local $context_offset) (i32.const 8))))\n (i64.store (i32.add (get_local $output_offset) (i32.const 16)) (i64.load (i32.add (get_local $context_offset) (i32.const 16))))\n (i64.store (i32.add (get_local $output_offset) (i32.const 24)) (i64.load (i32.add (get_local $context_offset) (i32.const 24))))\n)\n\n;;\n;; Calculate the hash. Helper method incorporating the above three.\n;;\n(func $keccak\n (param $context_offset i32)\n (param $input_offset i32)\n (param $input_length i32)\n (param $output_offset i32)\n\n (call $keccak_init (get_local $context_offset))\n (call $keccak_update (get_local $context_offset) (get_local $input_offset) (get_local $input_length))\n (call $keccak_finish (get_local $context_offset) (get_local $output_offset))\n)\n", + .imports = "" + } +},{ + opcodeEnum::memcpy, { + .wast = ";;\n;; memcpy from ewasm-libc/ewasm-cleanup\n;;\n(func $memcpy\n (param $dst i32)\n (param $src i32)\n (param $length i32)\n (result i32)\n\n (local $i i32)\n\n (set_local $i (i32.const 0))\n\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (get_local $length))\n (br $done)\n )\n\n (i32.store8 (i32.add (get_local $dst) (get_local $i)) (i32.load8_u (i32.add (get_local $src) (get_local $i))))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n\n (return (get_local $dst))\n)\n", + .imports = "" + } +},{ + opcodeEnum::memset, { + .wast = ";;\n;; memcpy from ewasm-libc/ewasm-cleanup\n;;\n(func $memset\n (param $ptr i32)\n (param $value i32)\n (param $length i32)\n (result i32)\n (local $i i32)\n\n (set_local $i (i32.const 0))\n\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (get_local $length))\n (br $done)\n )\n\n (i32.store8 (i32.add (get_local $ptr) (get_local $i)) (get_local $value))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n (get_local $ptr)\n)\n", + .imports = "" + } +},{ + opcodeEnum::memusegas, { + .wast = "(func $memusegas\n (param $offset i32)\n (param $length i32)\n\n (local $cost i64)\n ;; the number of new words being allocated\n (local $newWordCount i64)\n\n (if (i32.eqz (get_local $length))\n (then (return))\n )\n\n ;; const newMemoryWordCount = Math.ceil[[offset + length] / 32]\n (set_local $newWordCount \n (i64.div_u (i64.add (i64.const 31) (i64.add (i64.extend_u/i32 (get_local $offset)) (i64.extend_u/i32 (get_local $length))))\n (i64.const 32)))\n\n ;;if [runState.highestMem >= highestMem] return\n (if (i64.le_u (get_local $newWordCount) (get_global $wordCount))\n (then (return))\n )\n\n ;; words * 3 + words ^2 / 512\n (set_local $cost\n (i64.add\n (i64.mul (get_local $newWordCount) (i64.const 3))\n (i64.div_u\n (i64.mul (get_local $newWordCount)\n (get_local $newWordCount))\n (i64.const 512))))\n\n (call $useGas (i64.sub (get_local $cost) (get_global $prevMemCost)))\n (set_global $prevMemCost (get_local $cost))\n (set_global $wordCount (get_local $newWordCount))\n\n ;; grow actual memory\n ;; the first 31704 bytes are guaranteed to be available\n ;; adjust for 32 bytes - the maximal size of MSTORE write\n ;; TODO it should be current_memory * page_size\n (set_local $offset (i32.add (get_local $length) (i32.add (get_local $offset) (get_global $memstart))))\n (if (i32.gt_u (get_local $offset) (i32.mul (i32.const 65536) (current_memory)))\n (then\n (drop (grow_memory\n (i32.div_u (i32.add (i32.const 65535) (i32.sub (get_local $offset) (current_memory))) (i32.const 65536))))\n )\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::mod_320, { + .wast = "(func $mod_320\n ;; dividend\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (param $e i64)\n\n ;; divisor\n (param $a1 i64)\n (param $b1 i64)\n (param $c1 i64)\n (param $d1 i64)\n (param $e1 i64)\n\n ;; stack pointer\n (param $sp i32)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n (local $eq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $maske i64)\n\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maske (i64.const 1))\n (block $main\n ;; check div by 0\n (if (call $iszero_320 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1)) \n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (set_local $e (i64.const 0))\n (br $main)\n )\n )\n\n (block $done\n ;; align bits\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_320\n (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1)\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shl (get_local $d1) (i64.const 1)) (i64.shr_u (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.shl (get_local $e1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shl (get_local $maskd) (i64.const 1)) (i64.shr_u (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.shl (get_local $maske) (i64.const 1)))\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_320 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd) (get_local $maske))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_320 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $e) (get_local $e1)))\n (set_local $e (i64.sub (get_local $e) (get_local $e1)))\n\n (set_local $temp (i64.sub (get_local $d) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $d)))\n (set_local $d (i64.sub (get_local $temp) (get_local $d1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $d) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $e1 (i64.add (i64.shr_u (get_local $e1) (i64.const 1)) (i64.shl (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maske (i64.add (i64.shr_u (get_local $maske) (i64.const 1)) (i64.shl (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $c))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $d))\n (i64.store (get_local $sp) (get_local $e))\n)\n", + .imports = "" + } +},{ + opcodeEnum::mod_512, { + .wast = ";; Modulo 0x06\n(func $mod_512\n ;; dividend\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (param $e i64)\n (param $f i64)\n (param $g i64)\n (param $h i64)\n\n ;; divisor\n (param $a1 i64)\n (param $b1 i64)\n (param $c1 i64)\n (param $d1 i64)\n (param $e1 i64)\n (param $f1 i64)\n (param $g1 i64)\n (param $h1 i64)\n\n (param $sp i32)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $maske i64)\n (local $maskf i64)\n (local $maskg i64)\n (local $maskh i64)\n\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maskh (i64.const 1))\n\n (block $main\n ;; check div by 0\n (if (call $iszero_512 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1))\n (then\n (set_local $e (i64.const 0))\n (set_local $f (i64.const 0))\n (set_local $g (i64.const 0))\n (set_local $h (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1)))\n (call $gte_512 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1)\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shl (get_local $d1) (i64.const 1)) (i64.shr_u (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.add (i64.shl (get_local $e1) (i64.const 1)) (i64.shr_u (get_local $f1) (i64.const 63))))\n (set_local $f1 (i64.add (i64.shl (get_local $f1) (i64.const 1)) (i64.shr_u (get_local $g1) (i64.const 63))))\n (set_local $g1 (i64.add (i64.shl (get_local $g1) (i64.const 1)) (i64.shr_u (get_local $h1) (i64.const 63))))\n (set_local $h1 (i64.shl (get_local $h1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shl (get_local $maskd) (i64.const 1)) (i64.shr_u (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.add (i64.shl (get_local $maske) (i64.const 1)) (i64.shr_u (get_local $maskf) (i64.const 63))))\n (set_local $maskf (i64.add (i64.shl (get_local $maskf) (i64.const 1)) (i64.shr_u (get_local $maskg) (i64.const 63))))\n (set_local $maskg (i64.add (i64.shl (get_local $maskg) (i64.const 1)) (i64.shr_u (get_local $maskh) (i64.const 63))))\n (set_local $maskh (i64.shl (get_local $maskh) (i64.const 1)))\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_512 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd) (get_local $maske) (get_local $maskf) (get_local $maskg) (get_local $maskh))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_512 \n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h)\n (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $h) (get_local $h1)))\n (set_local $h (i64.sub (get_local $h) (get_local $h1)))\n\n (set_local $temp (i64.sub (get_local $g) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $g)))\n (set_local $g (i64.sub (get_local $temp) (get_local $g1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $g) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $f) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $f)))\n (set_local $f (i64.sub (get_local $temp) (get_local $f1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $f) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $e) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $e)))\n (set_local $e (i64.sub (get_local $temp) (get_local $e1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $e) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $d) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $d)))\n (set_local $d (i64.sub (get_local $temp) (get_local $d1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $d) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $h1 (i64.add (i64.shr_u (get_local $h1) (i64.const 1)) (i64.shl (get_local $g1) (i64.const 63))))\n (set_local $g1 (i64.add (i64.shr_u (get_local $g1) (i64.const 1)) (i64.shl (get_local $f1) (i64.const 63))))\n (set_local $f1 (i64.add (i64.shr_u (get_local $f1) (i64.const 1)) (i64.shl (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.add (i64.shr_u (get_local $e1) (i64.const 1)) (i64.shl (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskh (i64.add (i64.shr_u (get_local $maskh) (i64.const 1)) (i64.shl (get_local $maskg) (i64.const 63))))\n (set_local $maskg (i64.add (i64.shr_u (get_local $maskg) (i64.const 1)) (i64.shl (get_local $maskf) (i64.const 63))))\n (set_local $maskf (i64.add (i64.shr_u (get_local $maskf) (i64.const 1)) (i64.shl (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.add (i64.shr_u (get_local $maske) (i64.const 1)) (i64.shl (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (get_local $sp) (get_local $e))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $f))\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $g))\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $h))\n)\n", + .imports = "" + } +},{ + opcodeEnum::mul_256, { + .wast = "(func $mul_256\n ;; a b c d e f g h\n ;;* i j k l m n o p\n ;;----------------\n (param $a i64)\n (param $c i64)\n (param $e i64)\n (param $g i64)\n\n (param $i i64)\n (param $k i64)\n (param $m i64)\n (param $o i64)\n\n (param $sp i32)\n\n (local $b i64)\n (local $d i64)\n (local $f i64)\n (local $h i64)\n (local $j i64)\n (local $l i64)\n (local $n i64)\n (local $p i64)\n (local $temp6 i64)\n (local $temp5 i64)\n (local $temp4 i64)\n (local $temp3 i64)\n (local $temp2 i64)\n (local $temp1 i64)\n (local $temp0 i64)\n\n ;; split the ops\n (set_local $b (i64.and (get_local $a) (i64.const 4294967295)))\n (set_local $a (i64.shr_u (get_local $a) (i64.const 32))) \n\n (set_local $d (i64.and (get_local $c) (i64.const 4294967295)))\n (set_local $c (i64.shr_u (get_local $c) (i64.const 32))) \n\n (set_local $f (i64.and (get_local $e) (i64.const 4294967295)))\n (set_local $e (i64.shr_u (get_local $e) (i64.const 32)))\n\n (set_local $h (i64.and (get_local $g) (i64.const 4294967295)))\n (set_local $g (i64.shr_u (get_local $g) (i64.const 32)))\n\n (set_local $j (i64.and (get_local $i) (i64.const 4294967295)))\n (set_local $i (i64.shr_u (get_local $i) (i64.const 32))) \n\n (set_local $l (i64.and (get_local $k) (i64.const 4294967295)))\n (set_local $k (i64.shr_u (get_local $k) (i64.const 32))) \n\n (set_local $n (i64.and (get_local $m) (i64.const 4294967295)))\n (set_local $m (i64.shr_u (get_local $m) (i64.const 32)))\n\n (set_local $p (i64.and (get_local $o) (i64.const 4294967295)))\n (set_local $o (i64.shr_u (get_local $o) (i64.const 32)))\n ;; first row multiplication \n ;; p * h\n (set_local $temp0 (i64.mul (get_local $p) (get_local $h)))\n ;; p * g + carry\n (set_local $temp1 (i64.add (i64.mul (get_local $p) (get_local $g)) (i64.shr_u (get_local $temp0) (i64.const 32))))\n ;; p * f + carry\n (set_local $temp2 (i64.add (i64.mul (get_local $p) (get_local $f)) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; p * e + carry\n (set_local $temp3 (i64.add (i64.mul (get_local $p) (get_local $e)) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; p * d + carry\n (set_local $temp4 (i64.add (i64.mul (get_local $p) (get_local $d)) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; p * c + carry\n (set_local $temp5 (i64.add (i64.mul (get_local $p) (get_local $c)) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; p * b + carry\n (set_local $temp6 (i64.add (i64.mul (get_local $p) (get_local $b)) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; p * a + carry\n (set_local $a (i64.add (i64.mul (get_local $p) (get_local $a)) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; second row\n ;; o * h + $temp1 \"pg\"\n (set_local $temp1 (i64.add (i64.mul (get_local $o) (get_local $h)) (i64.and (get_local $temp1) (i64.const 4294967295))))\n ;; o * g + $temp2 \"pf\" + carry\n (set_local $temp2 (i64.add (i64.add (i64.mul (get_local $o) (get_local $g)) (i64.and (get_local $temp2) (i64.const 4294967295))) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; o * f + $temp3 \"pe\" + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $o) (get_local $f)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; o * e + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $o) (get_local $e)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; o * d + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $o) (get_local $d)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; o * c + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $o) (get_local $c)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; o * b + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $o) (get_local $b)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; third row - n\n ;; n * h + $temp2 \n (set_local $temp2 (i64.add (i64.mul (get_local $n) (get_local $h)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n ;; n * g + $temp3 + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $n) (get_local $g)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; n * f + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $n) (get_local $f)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; n * e + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $n) (get_local $e)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; n * d + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $n) (get_local $d)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; n * c + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $n) (get_local $c)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; forth row \n ;; m * h + $temp3\n (set_local $temp3 (i64.add (i64.mul (get_local $m) (get_local $h)) (i64.and (get_local $temp3) (i64.const 4294967295))))\n ;; m * g + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $m) (get_local $g)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; m * f + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $m) (get_local $f)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; m * e + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $m) (get_local $e)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; m * d + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $m) (get_local $d)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; fith row\n ;; l * h + $temp4\n (set_local $temp4 (i64.add (i64.mul (get_local $l) (get_local $h)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n ;; l * g + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $l) (get_local $g)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; l * f + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $l) (get_local $f)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; l * e + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $l) (get_local $e)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; sixth row \n ;; k * h + $temp5\n (set_local $temp5 (i64.add (i64.mul (get_local $k) (get_local $h)) (i64.and (get_local $temp5) (i64.const 4294967295))))\n ;; k * g + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $k) (get_local $g)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; k * f + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $k) (get_local $f)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; seventh row\n ;; j * h + $temp6\n (set_local $temp6 (i64.add (i64.mul (get_local $j) (get_local $h)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n ;; j * g + $a + carry\n\n ;; eigth row\n ;; i * h + $a\n (set_local $a (i64.add (i64.mul (get_local $i) (get_local $h)) (i64.and (i64.add (i64.add (i64.mul (get_local $j) (get_local $g)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))) (i64.const 4294967295))))\n\n ;; combine terms\n (set_local $a (i64.or (i64.shl (get_local $a) (i64.const 32)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n (set_local $c (i64.or (i64.shl (get_local $temp5) (i64.const 32)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n (set_local $e (i64.or (i64.shl (get_local $temp3) (i64.const 32)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n (set_local $g (i64.or (i64.shl (get_local $temp1) (i64.const 32)) (i64.and (get_local $temp0) (i64.const 4294967295))))\n\n ;; save stack \n (i64.store (get_local $sp) (get_local $a))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $e))\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $g))\n)\n", + .imports = "" + } +} + }; +} \ No newline at end of file diff --git a/include/wast.h b/include/wast.h new file mode 100644 index 00000000..e9c0f38c --- /dev/null +++ b/include/wast.h @@ -0,0 +1,438 @@ +#pragma once + +#include + +#include "evm2wasm.h" + +namespace evm2wasm +{ + static std::map wastSyncInterface = + { + { + opcodeEnum::LOG, { + .wast = "(func $LOG\n (param $number i32)\n\n (local $offset i32)\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n (local $length i32)\n (local $length0 i64)\n (local $length1 i64)\n (local $length2 i64)\n (local $length3 i64)\n\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $length0 (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n (set_local $length1 (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $length2 (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $length3 (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n\n (set_local $length\n (call $check_overflow (get_local $length0)\n (get_local $length1)\n (get_local $length2)\n (get_local $length3)))\n\n (call $memusegas (get_local $offset) (get_local $length))\n\n (call $log \n (get_local $offset)\n (get_local $length)\n (get_local $number)\n (i32.sub (get_global $sp) (i32.const 64))\n (i32.sub (get_global $sp) (i32.const 96))\n (i32.sub (get_global $sp) (i32.const 128))\n (i32.sub (get_global $sp) (i32.const 160)))\n)\n", + .imports = "(import \"ethereum\" \"log\" (func $log (param i32 i32 i32 i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::CALLDATALOAD, { + .wast = ";; stack:\n;; 0: dataOffset\n(func $CALLDATALOAD\n (local $writeOffset i32)\n (local $writeOffset0 i64)\n (local $writeOffset1 i64)\n (local $writeOffset2 i64)\n (local $writeOffset3 i64)\n\n (set_local $writeOffset0 (i64.load (i32.add (get_global $sp) (i32.const 0))))\n (set_local $writeOffset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $writeOffset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $writeOffset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (i64.store (i32.add (get_global $sp) (i32.const 0)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n\n (set_local $writeOffset\n (call $check_overflow (get_local $writeOffset0)\n (get_local $writeOffset1)\n (get_local $writeOffset2)\n (get_local $writeOffset3)))\n\n (call $callDataCopy (get_global $sp) (get_local $writeOffset) (i32.const 32))\n ;; swap top stack item\n (drop (call $bswap_m256 (get_global $sp)))\n)\n", + .imports = "(import \"ethereum\" \"callDataCopy\" (func $callDataCopy (param i32 i32 i32) ))" + } +},{ + opcodeEnum::GAS, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GAS (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getGasLeft))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getGasLeft\" (func $getGasLeft (result i64)))" + } +},{ + opcodeEnum::ADDRESS, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $ADDRESS (call $getAddress (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getAddress\" (func $getAddress (param i32) ))" + } +},{ + opcodeEnum::BALANCE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $BALANCE (call $getBalance(get_global $sp) (i32.add (get_global $sp) (i32.const 0)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBalance\" (func $getBalance (param i32 i32) ))" + } +},{ + opcodeEnum::ORIGIN, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $ORIGIN (call $getTxOrigin (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getTxOrigin\" (func $getTxOrigin (param i32) ))" + } +},{ + opcodeEnum::CALLER, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLER (call $getCaller (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getCaller\" (func $getCaller (param i32) ))" + } +},{ + opcodeEnum::CALLVALUE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLVALUE (call $getCallValue (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCallValue\" (func $getCallValue (param i32) ))" + } +},{ + opcodeEnum::CALLDATASIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLDATASIZE (i64.store\n (i32.add (get_global $sp) (i32.const 32))\n (i64.extend_u/i32\n (call $getCallDataSize)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCallDataSize\" (func $getCallDataSize (result i32)))" + } +},{ + opcodeEnum::CALLDATACOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLDATACOPY (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $callDataCopy(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8))))(get_local $length0)))", + .imports = "(import \"ethereum\" \"callDataCopy\" (func $callDataCopy (param i32 i32 i32) ))" + } +},{ + opcodeEnum::CODESIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CODESIZE (i64.store\n (i32.add (get_global $sp) (i32.const 32))\n (i64.extend_u/i32\n (call $getCodeSize)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getCodeSize\" (func $getCodeSize (result i32)))" + } +},{ + opcodeEnum::CODECOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CODECOPY (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $codeCopy(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8))))(get_local $length0)))", + .imports = "(import \"ethereum\" \"codeCopy\" (func $codeCopy (param i32 i32 i32) ))" + } +},{ + opcodeEnum::EXTCODESIZE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $EXTCODESIZE (i64.store\n (i32.add (get_global $sp) (i32.const 0))\n (i64.extend_u/i32\n (call $getExternalCodeSize(get_global $sp))))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getExternalCodeSize\" (func $getExternalCodeSize (param i32) (result i32)))" + } +},{ + opcodeEnum::EXTCODECOPY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $EXTCODECOPY (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $externalCodeCopy(get_global $sp)(get_local $offset0)(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40))))(get_local $length0)))", + .imports = "(import \"ethereum\" \"externalCodeCopy\" (func $externalCodeCopy (param i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::GASPRICE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GASPRICE (call $getTxGasPrice(i32.add (get_global $sp) (i32.const 32))))", + .imports = "(import \"ethereum\" \"getTxGasPrice\" (func $getTxGasPrice (param i32) ))" + } +},{ + opcodeEnum::BLOCKHASH, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $BLOCKHASH (call $getBlockHash(call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))) \n (i32.add (get_global $sp) \n (i32.const 0)))\n (drop (call $bswap_m256 (i32.add (i32.const 32) (get_global $sp))))\n )", + .imports = "(import \"ethereum\" \"getBlockHash\" (func $getBlockHash (param i32 i32) ))" + } +},{ + opcodeEnum::COINBASE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $COINBASE (call $getBlockCoinbase (i32.add (get_global $sp) (i32.const 32)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const 52)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"getBlockCoinbase\" (func $getBlockCoinbase (param i32) ))" + } +},{ + opcodeEnum::TIMESTAMP, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $TIMESTAMP (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockTimestamp))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockTimestamp\" (func $getBlockTimestamp (result i64)))" + } +},{ + opcodeEnum::NUMBER, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $NUMBER (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockNumber))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockNumber\" (func $getBlockNumber (result i64)))" + } +},{ + opcodeEnum::DIFFICULTY, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $DIFFICULTY (call $getBlockDifficulty(i32.add (get_global $sp) (i32.const 32))))", + .imports = "(import \"ethereum\" \"getBlockDifficulty\" (func $getBlockDifficulty (param i32) ))" + } +},{ + opcodeEnum::GASLIMIT, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $GASLIMIT (i64.store (i32.add (get_global $sp) (i32.const 32)) (call $getBlockGasLimit))\n\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 56)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 48)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 40)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"getBlockGasLimit\" (func $getBlockGasLimit (result i64)))" + } +},{ + opcodeEnum::CREATE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CREATE (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -64)))\n (i64.load (i32.add (get_global $sp) (i32.const -56)))\n (i64.load (i32.add (get_global $sp) (i32.const -48)))\n (i64.load (i32.add (get_global $sp) (i32.const -40)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $create(get_global $sp)(get_local $offset0)(get_local $length0) (i32.add (get_global $sp) (i32.const -64)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -40)) (i64.const 0))\n (i32.store (i32.add (get_global $sp) (i32.const -44)) (i32.const 0)))", + .imports = "(import \"ethereum\" \"create\" (func $create (param i32 i32 i32 i32) ))" + } +},{ + opcodeEnum::CALL, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALL (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $call(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"call\" (func $call (param i64 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::CALLCODE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $CALLCODE (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callCode(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"callCode\" (func $callCode (param i64 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::DELEGATECALL, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $DELEGATECALL (local $offset0 i32)(local $length0 i32)(local $offset1 i32)(local $length1 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -96)))\n (i64.load (i32.add (get_global $sp) (i32.const -88)))\n (i64.load (i32.add (get_global $sp) (i32.const -80)))\n (i64.load (i32.add (get_global $sp) (i32.const -72)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -128)))\n (i64.load (i32.add (get_global $sp) (i32.const -120)))\n (i64.load (i32.add (get_global $sp) (i32.const -112)))\n (i64.load (i32.add (get_global $sp) (i32.const -104)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0)))(set_local $offset1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -160)))\n (i64.load (i32.add (get_global $sp) (i32.const -152)))\n (i64.load (i32.add (get_global $sp) (i32.const -144)))\n (i64.load (i32.add (get_global $sp) (i32.const -136)))))(set_local $length1 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -192)))\n (i64.load (i32.add (get_global $sp) (i32.const -184)))\n (i64.load (i32.add (get_global $sp) (i32.const -176)))\n (i64.load (i32.add (get_global $sp) (i32.const -168)))))\n (call $memusegas (get_local $offset1) (get_local $length1))\n (set_local $offset1 (i32.add (get_global $memstart) (get_local $offset1))) (i64.store\n (i32.add (get_global $sp) (i32.const -192))\n (i64.extend_u/i32\n (i32.eqz (call $callDelegate(call $check_overflow_i64\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24))))(i32.add (get_global $sp) (i32.const -32))(i32.add (get_global $sp) (i32.const -64))(get_local $offset0)(get_local $length0)(get_local $offset1)(get_local $length1)) ;; flip CALL result from EEI to EVM convention (0 -> 1, 1,2,.. -> 1)\n )))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const -168)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -176)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const -184)) (i64.const 0)))", + .imports = "(import \"ethereum\" \"callDelegate\" (func $callDelegate (param i64 i32 i32 i32 i32 i32 i32) (result i32)))" + } +},{ + opcodeEnum::SSTORE, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SSTORE (call $storageStore(get_global $sp)(i32.add (get_global $sp) (i32.const -32))))", + .imports = "(import \"ethereum\" \"storageStore\" (func $storageStore (param i32 i32) ))" + } +},{ + opcodeEnum::SLOAD, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SLOAD (call $storageLoad(get_global $sp) \n (i32.add (get_global $sp) \n (i32.const 0)))\n (drop (call $bswap_m256 (i32.add (i32.const 32) (get_global $sp))))\n )", + .imports = "(import \"ethereum\" \"storageLoad\" (func $storageLoad (param i32 i32) ))" + } +},{ + opcodeEnum::SELFDESTRUCT, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $SELFDESTRUCT (call $selfDestruct(get_global $sp)))", + .imports = "(import \"ethereum\" \"selfDestruct\" (func $selfDestruct (param i32) ))" + } +},{ + opcodeEnum::RETURN, { + .wast = ";; generated by ./wasm/generateInterface.js\n(func $RETURN (local $offset0 i32)(local $length0 i32) (set_local $offset0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const 0)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 24)))))(set_local $length0 (call $check_overflow\n (i64.load (i32.add (get_global $sp) (i32.const -32)))\n (i64.load (i32.add (get_global $sp) (i32.const -24)))\n (i64.load (i32.add (get_global $sp) (i32.const -16)))\n (i64.load (i32.add (get_global $sp) (i32.const -8)))))\n (call $memusegas (get_local $offset0) (get_local $length0))\n (set_local $offset0 (i32.add (get_global $memstart) (get_local $offset0))) (call $return(get_local $offset0)(get_local $length0)))", + .imports = "(import \"ethereum\" \"return\" (func $return (param i32 i32) ))" + } +},{ + opcodeEnum::ADD, { + .wast = "(func $ADD\n (local $sp i32)\n\n (local $a i64)\n (local $c i64)\n (local $d i64)\n (local $carry i64)\n\n (set_local $sp (get_global $sp))\n \n ;; d c b a\n ;; pop the stack \n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_local $sp) (i32.const 8)))\n\n ;; d \n (set_local $carry (i64.add (get_local $d) (i64.load (i32.sub (get_local $sp) (i32.const 24)))))\n ;; save d to mem\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $carry))\n ;; check for overflow\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $carry) (get_local $d))))\n\n ;; c use $d as reg\n (set_local $d (i64.add (i64.load (i32.sub (get_local $sp) (i32.const 16))) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $carry))))\n (set_local $d (i64.add (get_local $c) (get_local $d)))\n ;; store the result\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $d))\n ;; check overflow\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $c))) (get_local $carry)))\n\n ;; b\n ;; add carry\n (set_local $d (i64.add (i64.load (i32.sub (get_local $sp) (i32.const 8))) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $carry))))\n\n ;; use reg c\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $d (i64.add (get_local $c) (get_local $d)))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $d))\n ;; a\n (i64.store (get_local $sp) \n (i64.add ;; add a \n (get_local $a)\n (i64.add\n (i64.load (get_local $sp)) ;; load the operand\n (i64.or ;; carry \n (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $c))) \n (get_local $carry)))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::ADDMOD, { + .wast = ";; stack:\n;; 0: A\n;; -1: B\n;; -2: MOD\n(func $ADDMOD\n (local $sp i32)\n\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n (local $moda i64)\n (local $modb i64)\n (local $modc i64)\n (local $modd i64)\n\n (local $carry i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $moda (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $modb (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $modc (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $modd (i64.load (get_local $sp)))\n\n ;; a * 64^3 + b*64^2 + c*64 + d \n ;; d \n (set_local $d (i64.add (get_local $d1) (get_local $d)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $d1))))\n ;; c\n (set_local $c (i64.add (get_local $c) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $c) (get_local $carry))))\n (set_local $c (i64.add (get_local $c1) (get_local $c)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $c) (get_local $c1))) (get_local $carry)))\n ;; b\n (set_local $b (i64.add (get_local $b) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $b) (get_local $carry))))\n (set_local $b (i64.add (get_local $b1) (get_local $b)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $b) (get_local $b1))) (get_local $carry)))\n ;; a\n (set_local $a (i64.add (get_local $a) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $a) (get_local $carry))))\n (set_local $a (i64.add (get_local $a1) (get_local $a)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $a) (get_local $a1))) (get_local $carry)))\n\n (call $mod_320\n (get_local $carry) (get_local $a) (get_local $b) (get_local $c) (get_local $d)\n (i64.const 0) (get_local $moda) (get_local $modb) (get_local $modc) (get_local $modd) (get_local $sp))\n)\n", + .imports = "" + } +},{ + opcodeEnum::AND, { + .wast = "(func $AND\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.and (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (get_global $sp))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::BYTE, { + .wast = ";; stack:\n;; 0: offset\n;; -1: value\n(func $BYTE\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (set_local $sp (get_global $sp))\n\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (i64.store (get_local $sp)\n (if (result i64)\n (i32.and \n (i32.and \n (i32.and \n (i64.lt_u (get_local $a3) (i64.const 32))\n (i64.eqz (get_local $a2))) \n (i64.eqz (get_local $a1)))\n (i64.eqz (get_local $a0)))\n (i64.load8_u (i32.sub (i32.const 31)(i32.wrap/i64 (get_local $a3))))\n (i64.const 0)))\n\n ;; zero out the rest of the stack\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::DIV, { + .wast = "(func $DIV\n (local $sp i32)\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n (local $temp2 i64)\n\n (set_local $sp (get_global $sp))\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (br $main)\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if \n ;; check to make sure we are not overflowing\n (i32.or (i64.eqz (i64.clz (get_local $a1)))\n ;; divisor < dividend\n (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n\n ;; result = result + mask\n (set_local $dq (i64.add (get_local $maskd) (get_local $dq)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $dq) (get_local $maskd))))\n (set_local $cq (i64.add (get_local $cq) (get_local $temp)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $cq) (get_local $temp))))\n (set_local $cq (i64.add (get_local $maskc) (get_local $cq)))\n (set_local $temp (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $cq) (get_local $maskc))) (get_local $temp)))\n (set_local $bq (i64.add (get_local $bq) (get_local $temp)))\n (set_local $temp (i64.extend_u/i32 (i64.lt_u (get_local $bq) (get_local $temp))))\n (set_local $bq (i64.add (get_local $maskb) (get_local $bq)))\n (set_local $aq (i64.add (get_local $maska) (i64.add (get_local $aq) (i64.or (i64.extend_u/i32 (i64.lt_u (get_local $bq) (get_local $maskb))) (get_local $temp)))))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $aq))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $bq))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $cq))\n (i64.store (get_local $sp) (get_local $dq))\n)\n", + .imports = "" + } +},{ + opcodeEnum::DUP, { + .wast = "(func $DUP\n (param $a0 i32)\n (local $sp i32)\n\n (local $sp_ref i32)\n \n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n (set_local $sp_ref (i32.sub (i32.sub (get_local $sp) (i32.const 8)) (i32.mul (get_local $a0) (i32.const 32))))\n \n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.load (get_local $sp_ref)))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 8))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 16))))\n (i64.store (get_local $sp) (i64.load (i32.sub (get_local $sp_ref) (i32.const 24))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::EQ, { + .wast = "(func $EQ\n (local $sp i32)\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n (i64.store (get_local $sp)\n (i64.extend_u/i32\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 56))) (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 48))) (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (i32.and (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 40))) (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (i64.eq (i64.load (i32.add (get_local $sp) (i32.const 32))) (i64.load (get_local $sp))))))))\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::EXP, { + .wast = "(func $EXP\n (local $sp i32)\n\n ;; base\n (local $base0 i64)\n (local $base1 i64)\n (local $base2 i64)\n (local $base3 i64)\n\n ;; exp\n (local $exp0 i64)\n (local $exp1 i64)\n (local $exp2 i64)\n (local $exp3 i64)\n\n (local $r0 i64)\n (local $r1 i64)\n (local $r2 i64)\n (local $r3 i64)\n\n (local $gasCounter i32)\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $base0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $base1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $base2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $base3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $exp0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $exp1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $exp2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $exp3 (i64.load (get_local $sp)))\n\n ;; let result = new BN[1]\n (set_local $r3 (i64.const 1))\n\n (block $done\n (loop $loop\n ;; while [exp > 0] {\n (if (call $iszero_256 (get_local $exp0) (get_local $exp1) (get_local $exp2) (get_local $exp3))\n (br $done) \n )\n\n ;; if[exp.modn[2] === 1]\n ;; is odd?\n (if (i64.eqz (i64.ctz (get_local $exp3)))\n\n ;; result = result.mul[base].mod[TWO_POW256]\n ;; r = r * a\n (then\n (call $mul_256 (get_local $r0) (get_local $r1) (get_local $r2) (get_local $r3) (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (i32.add (get_local $sp) (i32.const 24)))\n (set_local $r0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $r1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $r2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $r3 (i64.load (get_local $sp)))\n )\n )\n ;; exp = exp.shrn 1\n (set_local $exp3 (i64.add (i64.shr_u (get_local $exp3) (i64.const 1)) (i64.shl (get_local $exp2) (i64.const 63))))\n (set_local $exp2 (i64.add (i64.shr_u (get_local $exp2) (i64.const 1)) (i64.shl (get_local $exp1) (i64.const 63))))\n (set_local $exp1 (i64.add (i64.shr_u (get_local $exp1) (i64.const 1)) (i64.shl (get_local $exp0) (i64.const 63))))\n (set_local $exp0 (i64.shr_u (get_local $exp0) (i64.const 1)))\n\n ;; base = base.mulr[baser].modr[TWO_POW256]\n (call $mul_256 (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (get_local $base0) (get_local $base1) (get_local $base2) (get_local $base3) (i32.add (get_local $sp) (i32.const 24)))\n (set_local $base0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $base1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $base2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $base3 (i64.load (get_local $sp)))\n\n (set_local $gasCounter (i32.add (get_local $gasCounter) (i32.const 1)))\n (br $loop)\n )\n ) \n\n ;; use gas\n ;; Log256[Exponent] * 10\n (call $useGas\n (i64.extend_u/i32\n (i32.mul\n (i32.const 10)\n (i32.div_u\n (i32.add (get_local $gasCounter) (i32.const 7))\n (i32.const 8)))))\n\n ;; decement the stack pointer\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $r0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $r1))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $r2))\n (i64.store (get_local $sp) (get_local $r3))\n)\n", + .imports = "" + } +},{ + opcodeEnum::GT, { + .wast = "(func $GT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == a1\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.gt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 > b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::ISZERO, { + .wast = "(func $ISZERO\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (i64.store (get_global $sp)\n (i64.extend_u/i32\n (call $iszero_256 (get_local $a0) (get_local $a1) (get_local $a2) (get_local $a3))\n )\n )\n\n ;; zero out the rest of memory\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::LT, { + .wast = "(func $LT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n (set_local $sp (get_global $sp))\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_local $sp)))\n\n (set_local $sp (i32.sub (get_local $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.lt_u (get_local $a0) (get_local $b0)) ;; a0 < b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == b0\n (i32.or (i64.lt_u (get_local $a1) (get_local $b1)) ;; a1 < b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.lt_u (get_local $a2) (get_local $b2)) ;; a2 < b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.lt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 < b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MLOAD, { + .wast = ";; stack:\n;; 0: offset\n(func $MLOAD\n (local $offset i32)\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n ;; subttract gas useage\n (call $memusegas (get_local $offset) (i32.const 32))\n\n ;; FIXME: how to deal with overflow?\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.load (i32.add (get_local $offset) (i32.const 24))))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.load (i32.add (get_local $offset) (i32.const 16))))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.load (i32.add (get_local $offset) (i32.const 8))))\n (i64.store (get_global $sp) (i64.load (get_local $offset)))\n\n ;; swap\n (drop (call $bswap_m256 (get_global $sp)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MOD, { + .wast = "(func $MOD\n (local $sp i32)\n\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n\n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSIZE, { + .wast = "(func $MSIZE\n (local $sp i32)\n\n ;; there's no input item for us to overwrite\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n\n (i64.store (i32.add (get_local $sp) (i32.const 0)) \n (i64.mul (get_global $wordCount) (i64.const 32)))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSTORE, { + .wast = ";; stack:\n;; 0: word\n;; -1: offset\n(func $MSTORE\n (local $sp i32)\n\n (local $offset i32)\n \n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n ;; subtrace gas useage\n (call $memusegas (get_local $offset) (i32.const 32))\n\n ;; pop itme from the stack\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n ;; swap top stack item\n (drop (call $bswap_m256 (get_local $sp)))\n\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n ;; store word to memory\n (i64.store (get_local $offset) (i64.load (get_local $sp)))\n (i64.store (i32.add (get_local $offset) (i32.const 8)) (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (i64.store (i32.add (get_local $offset) (i32.const 16)) (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (i64.store (i32.add (get_local $offset) (i32.const 24)) (i64.load (i32.add (get_local $sp) (i32.const 24))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MSTORE8, { + .wast = ";; stack:\n;; 0: word\n;; -1: offset\n(func $MSTORE8\n (local $sp i32)\n\n (local $offset i32)\n\n (local $offset0 i64)\n (local $offset1 i64)\n (local $offset2 i64)\n (local $offset3 i64)\n\n ;; load args from the stack\n (set_local $offset0 (i64.load (get_global $sp)))\n (set_local $offset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $offset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $offset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $offset \n (call $check_overflow (get_local $offset0)\n (get_local $offset1)\n (get_local $offset2)\n (get_local $offset3)))\n\n (call $memusegas (get_local $offset) (i32.const 1))\n\n ;; pop stack\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n (set_local $offset (i32.add (get_local $offset) (get_global $memstart)))\n (i32.store8 (i32.add (get_local $offset) (i32.const 0)) (i32.load (get_local $sp)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::MUL, { + .wast = "(func $MUL\n (call $mul_256\n (i64.load (i32.add (get_global $sp) (i32.const 24)))\n (i64.load (i32.add (get_global $sp) (i32.const 16)))\n (i64.load (i32.add (get_global $sp) (i32.const 8)))\n (i64.load (get_global $sp))\n (i64.load (i32.sub (get_global $sp) (i32.const 8)))\n (i64.load (i32.sub (get_global $sp) (i32.const 16)))\n (i64.load (i32.sub (get_global $sp) (i32.const 24)))\n (i64.load (i32.sub (get_global $sp) (i32.const 32)))\n (i32.sub (get_global $sp) (i32.const 8))\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::MULMOD, { + .wast = "(func $MULMOD\n (local $sp i32)\n\n (local $a i64)\n (local $c i64)\n (local $e i64)\n (local $g i64)\n (local $i i64)\n (local $k i64)\n (local $m i64)\n (local $o i64)\n (local $b i64)\n (local $d i64)\n (local $f i64)\n (local $h i64)\n (local $j i64)\n (local $l i64)\n (local $n i64)\n (local $p i64)\n (local $temp7 i64)\n (local $temp6 i64)\n (local $temp5 i64)\n (local $temp4 i64)\n (local $temp3 i64)\n (local $temp2 i64)\n (local $temp1 i64)\n (local $temp0 i64)\n (local $rowCarry i64)\n\n (local $moda i64)\n (local $modb i64)\n (local $modc i64)\n (local $modd i64)\n\n ;; pop two items of the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $e (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $g (i64.load (get_global $sp)))\n (set_local $i (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n (set_local $k (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $m (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $o (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 64)))\n\n ;; MUL\n ;; a b c d e f g h\n ;;* i j k l m n o p\n ;;----------------\n\n ;; split the ops\n (set_local $b (i64.and (get_local $a) (i64.const 4294967295)))\n (set_local $a (i64.shr_u (get_local $a) (i64.const 32))) \n\n (set_local $d (i64.and (get_local $c) (i64.const 4294967295)))\n (set_local $c (i64.shr_u (get_local $c) (i64.const 32))) \n\n (set_local $f (i64.and (get_local $e) (i64.const 4294967295)))\n (set_local $e (i64.shr_u (get_local $e) (i64.const 32)))\n\n (set_local $h (i64.and (get_local $g) (i64.const 4294967295)))\n (set_local $g (i64.shr_u (get_local $g) (i64.const 32)))\n\n (set_local $j (i64.and (get_local $i) (i64.const 4294967295)))\n (set_local $i (i64.shr_u (get_local $i) (i64.const 32))) \n\n (set_local $l (i64.and (get_local $k) (i64.const 4294967295)))\n (set_local $k (i64.shr_u (get_local $k) (i64.const 32))) \n\n (set_local $n (i64.and (get_local $m) (i64.const 4294967295)))\n (set_local $m (i64.shr_u (get_local $m) (i64.const 32)))\n\n (set_local $p (i64.and (get_local $o) (i64.const 4294967295)))\n (set_local $o (i64.shr_u (get_local $o) (i64.const 32)))\n\n ;; first row multiplication \n ;; p * h\n (set_local $temp0 (i64.mul (get_local $p) (get_local $h)))\n ;; p * g + carry\n (set_local $temp1 (i64.add (i64.mul (get_local $p) (get_local $g)) (i64.shr_u (get_local $temp0) (i64.const 32))))\n ;; p * f + carry\n (set_local $temp2 (i64.add (i64.mul (get_local $p) (get_local $f)) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; p * e + carry\n (set_local $temp3 (i64.add (i64.mul (get_local $p) (get_local $e)) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; p * d + carry\n (set_local $temp4 (i64.add (i64.mul (get_local $p) (get_local $d)) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; p * c + carry\n (set_local $temp5 (i64.add (i64.mul (get_local $p) (get_local $c)) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; p * b + carry\n (set_local $temp6 (i64.add (i64.mul (get_local $p) (get_local $b)) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; p * a + carry\n (set_local $temp7 (i64.add (i64.mul (get_local $p) (get_local $a)) (i64.shr_u (get_local $temp6) (i64.const 32))))\n (set_local $rowCarry (i64.shr_u (get_local $temp7) (i64.const 32)))\n\n ;; second row\n ;; o * h + $temp1 \n (set_local $temp1 (i64.add (i64.mul (get_local $o) (get_local $h)) (i64.and (get_local $temp1) (i64.const 4294967295))))\n ;; o * g + $temp2 + carry\n (set_local $temp2 (i64.add (i64.add (i64.mul (get_local $o) (get_local $g)) (i64.and (get_local $temp2) (i64.const 4294967295))) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; o * f + $temp3 + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $o) (get_local $f)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; o * e + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $o) (get_local $e)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; o * d + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $o) (get_local $d)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; o * c + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $o) (get_local $c)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; o * b + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $o) (get_local $b)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; o * a + carry + rowCarry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $o) (get_local $a)) (i64.shr_u (get_local $temp7) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $p) (i64.const 32)))\n\n ;; third row - n\n ;; n * h + $temp2 \n (set_local $temp2 (i64.add (i64.mul (get_local $n) (get_local $h)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n ;; n * g + $temp3 carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $n) (get_local $g)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; n * f + $temp4) + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $n) (get_local $f)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; n * e + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $n) (get_local $e)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; n * d + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $n) (get_local $d)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; n * c + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $n) (get_local $c)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; n * b + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $n) (get_local $b)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; n * a + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $n) (get_local $a)) (i64.shr_u (get_local $p) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $o) (i64.const 32)))\n\n ;; forth row \n ;; m * h + $temp3\n (set_local $temp3 (i64.add (i64.mul (get_local $m) (get_local $h)) (i64.and (get_local $temp3) (i64.const 4294967295))))\n ;; m * g + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $m) (get_local $g)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; m * f + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $m) (get_local $f)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; m * e + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $m) (get_local $e)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; m * d + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $m) (get_local $d)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; m * c + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $m) (get_local $c)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; m * b + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $m) (get_local $b)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; m * a + carry + rowCarry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $m) (get_local $a)) (i64.shr_u (get_local $o) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $n) (i64.const 32)))\n\n ;; fith row\n ;; l * h + $temp4\n (set_local $temp4 (i64.add (i64.mul (get_local $l) (get_local $h)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n ;; l * g + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $l) (get_local $g)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; l * f + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $l) (get_local $f)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; l * e + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $l) (get_local $e)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; l * d + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $l) (get_local $d)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; l * c + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $l) (get_local $c)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; l * b + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $l) (get_local $b)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; l * a + carry + rowCarry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $l) (get_local $a)) (i64.shr_u (get_local $n) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $m) (i64.const 32)))\n\n ;; sixth row \n ;; k * h + $temp5\n (set_local $temp5 (i64.add (i64.mul (get_local $k) (get_local $h)) (i64.and (get_local $temp5) (i64.const 4294967295))))\n ;; k * g + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $k) (get_local $g)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; k * f + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $k) (get_local $f)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; k * e + $p + carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $k) (get_local $e)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; k * d + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $k) (get_local $d)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; k * c + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $k) (get_local $c)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; k * b + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $k) (get_local $b)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; k * a + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $k) (get_local $a)) (i64.shr_u (get_local $m) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $l) (i64.const 32)))\n\n ;; seventh row\n ;; j * h + $temp6\n (set_local $temp6 (i64.add (i64.mul (get_local $j) (get_local $h)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n ;; j * g + $temp7 + carry\n (set_local $temp7 (i64.add (i64.add (i64.mul (get_local $j) (get_local $g)) (i64.and (get_local $temp7) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; j * f + $p +carry\n (set_local $p (i64.add (i64.add (i64.mul (get_local $j) (get_local $f)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; j * e + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $j) (get_local $e)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; j * d + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $j) (get_local $d)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; j * c + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $j) (get_local $c)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; j * b + $l + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $j) (get_local $b)) (i64.and (get_local $l) (i64.const 4294967295))) (i64.shr_u (get_local $m) (i64.const 32))))\n ;; j * a + carry\n (set_local $k (i64.add (i64.add (i64.mul (get_local $j) (get_local $a)) (i64.shr_u (get_local $l) (i64.const 32))) (get_local $rowCarry)))\n (set_local $rowCarry (i64.shr_u (get_local $k) (i64.const 32)))\n\n ;; eigth row\n ;; i * h + $temp7 \n (set_local $temp7 (i64.add (i64.mul (get_local $i) (get_local $h)) (i64.and (get_local $temp7) (i64.const 4294967295))))\n ;; i * g + $p \n (set_local $p (i64.add (i64.add (i64.mul (get_local $i) (get_local $g)) (i64.and (get_local $p) (i64.const 4294967295))) (i64.shr_u (get_local $temp7) (i64.const 32))))\n ;; i * f + $o + carry\n (set_local $o (i64.add (i64.add (i64.mul (get_local $i) (get_local $f)) (i64.and (get_local $o) (i64.const 4294967295))) (i64.shr_u (get_local $p) (i64.const 32))))\n ;; i * e + $n + carry\n (set_local $n (i64.add (i64.add (i64.mul (get_local $i) (get_local $e)) (i64.and (get_local $n) (i64.const 4294967295))) (i64.shr_u (get_local $o) (i64.const 32))))\n ;; i * d + $m + carry\n (set_local $m (i64.add (i64.add (i64.mul (get_local $i) (get_local $d)) (i64.and (get_local $m) (i64.const 4294967295))) (i64.shr_u (get_local $n) (i64.const 32))))\n ;; i * c + $l + carry\n (set_local $l (i64.add (i64.add (i64.mul (get_local $i) (get_local $c)) (i64.and (get_local $l) (i64.const 4294967295))) (i64.shr_u (get_local $m) (i64.const 32))))\n ;; i * b + $k + carry\n (set_local $k (i64.add (i64.add (i64.mul (get_local $i) (get_local $b)) (i64.and (get_local $k) (i64.const 4294967295))) (i64.shr_u (get_local $l) (i64.const 32))))\n ;; i * a + carry\n (set_local $j (i64.add (i64.add (i64.mul (get_local $i) (get_local $a)) (i64.shr_u (get_local $k) (i64.const 32))) (get_local $rowCarry)))\n\n ;; combine terms\n (set_local $a (get_local $j))\n (set_local $b (i64.or (i64.shl (get_local $k) (i64.const 32)) (i64.and (get_local $l) (i64.const 4294967295))))\n (set_local $c (i64.or (i64.shl (get_local $m) (i64.const 32)) (i64.and (get_local $n) (i64.const 4294967295))))\n (set_local $d (i64.or (i64.shl (get_local $o) (i64.const 32)) (i64.and (get_local $p) (i64.const 4294967295))))\n (set_local $e (i64.or (i64.shl (get_local $temp7) (i64.const 32)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n (set_local $f (i64.or (i64.shl (get_local $temp5) (i64.const 32)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n (set_local $g (i64.or (i64.shl (get_local $temp3) (i64.const 32)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n (set_local $h (i64.or (i64.shl (get_local $temp1) (i64.const 32)) (i64.and (get_local $temp0) (i64.const 4294967295))))\n\n ;; pop the MOD argmunet off the stack\n (set_local $moda (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $modb (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $modc (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $modd (i64.load (get_local $sp)))\n\n (call $mod_512\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h) \n (i64.const 0) (i64.const 0) (i64.const 0) (i64.const 0) (get_local $moda) (get_local $modb) (get_local $modc) (get_local $modd) (i32.add (get_local $sp) (i32.const 24))\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::NOT, { + .wast = "(func $NOT\n ;; FIXME: consider using 0xffffffffffffffff instead of -1?\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 24))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 16))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 8))) (i64.const -1)))\n (i64.store (i32.add (get_global $sp) (i32.const 0)) (i64.xor (i64.load (i32.add (get_global $sp) (i32.const 0))) (i64.const -1)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::OR, { + .wast = "(func $OR\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.or (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (get_global $sp))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::PC, { + .wast = "(func $PC\n (param $pc i32)\n (local $sp i32)\n\n ;; add one to the stack\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n (i64.store (get_local $sp) (i64.extend_u/i32 (get_local $pc)))\n\n ;; zero out rest of stack\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::PUSH, { + .wast = "(func $PUSH\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (local $sp i32)\n\n ;; increament stack pointer\n (set_local $sp (i32.add (get_global $sp) (i32.const 32)))\n\n (i64.store (get_local $sp) (get_local $a3))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $a2))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $a1))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SDIV, { + .wast = "(func $SDIV\n (local $sp i32)\n\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $temp i64)\n (local $temp2 i64)\n (local $sign i32)\n\n (set_local $maskd (i64.const 1))\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n ;; get the resulting sign\n (set_local $sign (i32.wrap/i64 (i64.shr_u (i64.xor (get_local $a1) (get_local $a)) (i64.const 63))))\n\n ;; convert to unsigned value\n (if (i64.eqz (i64.clz (get_local $a)))\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n ;; a = a + 1\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c)) (get_local $carry)))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b)) (get_local $carry)))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n (if (i64.eqz (i64.clz (get_local $a1)))\n (then\n (set_local $a1 (i64.xor (get_local $a1) (i64.const -1)))\n (set_local $b1 (i64.xor (get_local $b1) (i64.const -1)))\n (set_local $c1 (i64.xor (get_local $c1) (i64.const -1)))\n (set_local $d1 (i64.xor (get_local $d1) (i64.const -1)))\n\n (set_local $d1 (i64.add (get_local $d1) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d1)))\n (set_local $c1 (i64.add (get_local $c1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c1)) (get_local $carry)))\n (set_local $b1 (i64.add (get_local $b1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b1)) (get_local $carry)))\n (set_local $a1 (i64.add (get_local $a1) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n \n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (br $main)\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n\n ;; result = result + mask\n (set_local $dq (i64.add (get_local $maskd) (get_local $dq)))\n (set_local $carry (i64.lt_u (get_local $dq) (get_local $maskd)))\n (set_local $temp (i64.add (get_local $cq) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.lt_u (get_local $temp) (get_local $cq)))\n (set_local $cq (i64.add (get_local $maskc) (get_local $temp)))\n (set_local $carry (i32.or (i64.lt_u (get_local $cq) (get_local $maskc)) (get_local $carry)))\n (set_local $temp (i64.add (get_local $bq) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.lt_u (get_local $temp) (get_local $bq)))\n (set_local $bq (i64.add (get_local $maskb) (get_local $temp)))\n (set_local $carry (i32.or (i64.lt_u (get_local $bq) (get_local $maskb)) (get_local $carry)))\n (set_local $aq (i64.add (get_local $maska) (i64.add (get_local $aq) (i64.extend_u/i32 (get_local $carry)))))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n ;; convert to signed\n (if (get_local $sign)\n (then\n (set_local $aq (i64.xor (get_local $aq) (i64.const -1)))\n (set_local $bq (i64.xor (get_local $bq) (i64.const -1)))\n (set_local $cq (i64.xor (get_local $cq) (i64.const -1)))\n (set_local $dq (i64.xor (get_local $dq) (i64.const -1)))\n\n (set_local $dq (i64.add (get_local $dq) (i64.const 1)))\n (set_local $cq (i64.add (get_local $cq) (i64.extend_u/i32 (i64.eqz (get_local $dq)))))\n (set_local $bq (i64.add (get_local $bq) (i64.extend_u/i32 (i64.eqz (get_local $cq)))))\n (set_local $aq (i64.add (get_local $aq) (i64.extend_u/i32 (i64.eqz (get_local $bq)))))\n )\n )\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $aq))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $bq))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $cq))\n (i64.store (get_local $sp) (get_local $dq))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SGT, { + .wast = "(func $SGT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.gt_s (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == a1\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.gt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 > b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SHA3, { + .wast = "(func $SHA3\n (local $dataOffset i32)\n (local $dataOffset0 i64)\n (local $dataOffset1 i64)\n (local $dataOffset2 i64)\n (local $dataOffset3 i64)\n\n (local $length i32)\n (local $length0 i64)\n (local $length1 i64)\n (local $length2 i64)\n (local $length3 i64)\n\n (local $contextOffset i32)\n (local $outputOffset i32)\n\n (set_local $length0 (i64.load (i32.sub (get_global $sp) (i32.const 32))))\n (set_local $length1 (i64.load (i32.sub (get_global $sp) (i32.const 24))))\n (set_local $length2 (i64.load (i32.sub (get_global $sp) (i32.const 16))))\n (set_local $length3 (i64.load (i32.sub (get_global $sp) (i32.const 8))))\n\n (set_local $dataOffset0 (i64.load (i32.add (get_global $sp) (i32.const 0))))\n (set_local $dataOffset1 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $dataOffset2 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $dataOffset3 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n\n (set_local $length \n (call $check_overflow (get_local $length0)\n (get_local $length1)\n (get_local $length2)\n (get_local $length3)))\n (set_local $dataOffset \n (call $check_overflow (get_local $dataOffset0)\n (get_local $dataOffset1)\n (get_local $dataOffset2)\n (get_local $dataOffset3)))\n\n ;; charge copy fee ceil(words/32) * 6 \n (call $useGas (i64.extend_u/i32 (i32.mul (i32.div_u (i32.add (get_local $length) (i32.const 31)) (i32.const 32)) (i32.const 6))))\n (call $memusegas (get_local $dataOffset) (get_local $length))\n\n (set_local $dataOffset (i32.add (get_global $memstart) (get_local $dataOffset)))\n\n (set_local $contextOffset (i32.const 32808))\n (set_local $outputOffset (i32.sub (get_global $sp) (i32.const 32)))\n\n (call $keccak (get_local $contextOffset) (get_local $dataOffset) (get_local $length) (get_local $outputOffset))\n\n (drop (call $bswap_m256 (get_local $outputOffset)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SIGNEXTEND, { + .wast = "(func $SIGNEXTEND\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n (local $sign i64)\n (local $t i32)\n (local $end i32)\n\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $end (get_global $sp))\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (if (i32.and \n (i32.and \n (i32.and \n (i64.lt_u (get_local $a3) (i64.const 32))\n (i64.eqz (get_local $a2))) \n (i64.eqz (get_local $a1)))\n (i64.eqz (get_local $a0)))\n (then\n (set_local $t (i32.add (i32.wrap/i64 (get_local $a3)) (get_local $sp))) \n (set_local $sign (i64.shr_s (i64.load8_s (get_local $t)) (i64.const 8)))\n (set_local $t (i32.add (get_local $t) (i32.const 1)))\n (block $done\n (loop $loop\n (if (i32.lt_u (get_local $end) (get_local $t))\n (br $done)\n )\n (i64.store (get_local $t) (get_local $sign))\n (set_local $t (i32.add (get_local $t) (i32.const 8)))\n (br $loop)\n )\n )\n )\n )\n)\n\n", + .imports = "" + } +},{ + opcodeEnum::SLT, { + .wast = "(func $SLT\n (local $sp i32)\n\n (local $a0 i64)\n (local $a1 i64)\n (local $a2 i64)\n (local $a3 i64)\n (local $b0 i64)\n (local $b1 i64)\n (local $b2 i64)\n (local $b3 i64)\n\n ;; load args from the stack\n (set_local $a0 (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $a1 (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $a2 (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $a3 (i64.load (get_global $sp)))\n\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $b0 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $b2 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $b3 (i64.load (get_local $sp)))\n\n (i64.store (get_local $sp) (i64.extend_u/i32 \n (i32.or (i64.lt_s (get_local $a0) (get_local $b0)) ;; a0 < b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0)) ;; a0 == b0\n (i32.or (i64.lt_u (get_local $a1) (get_local $b1)) ;; a1 < b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.lt_u (get_local $a2) (get_local $b2)) ;; a2 < b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2)) ;; a2 == b2\n (i64.lt_u (get_local $a3) (get_local $b3)))))))))) ;; a3 < b3\n\n ;; zero out the rest of the stack item\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (i64.const 0))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SMOD, { + .wast = "(func $SMOD\n (local $sp i32)\n ;; dividend\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n ;; divisor\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $carry i32)\n (local $sign i32)\n (local $temp i64)\n (local $temp2 i64)\n\n ;; load args from the stack\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n (set_local $maskd (i64.const 1))\n (set_local $sign (i32.wrap/i64 (i64.shr_u (get_local $d) (i64.const 63))))\n\n ;; convert to unsigned value\n (if (i64.eqz (i64.clz (get_local $a)))\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n ;; a = a + 1\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c)) (get_local $carry)))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b)) (get_local $carry)))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n\n (if (i64.eqz (i64.clz (get_local $a1)))\n (then\n (set_local $a1 (i64.xor (get_local $a1) (i64.const -1)))\n (set_local $b1 (i64.xor (get_local $b1) (i64.const -1)))\n (set_local $c1 (i64.xor (get_local $c1) (i64.const -1)))\n (set_local $d1 (i64.xor (get_local $d1) (i64.const -1)))\n\n (set_local $d1 (i64.add (get_local $d1) (i64.const 1)))\n (set_local $carry (i64.eqz (get_local $d1)))\n (set_local $c1 (i64.add (get_local $c1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $c1)) (get_local $carry)))\n (set_local $b1 (i64.add (get_local $b1) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i32.and (i64.eqz (get_local $b1)) (get_local $carry)))\n (set_local $a1 (i64.add (get_local $a1) (i64.extend_u/i32 (get_local $carry))))\n )\n )\n \n (block $main\n ;; check div by 0\n (if (call $iszero_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_256 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $a) (get_local $b) (get_local $c) (get_local $d)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.shl (get_local $d1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.shl (get_local $maskd) (i64.const 1)))\n\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_256 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_256 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $d) (get_local $d1)))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n )\n\n ;; convert to signed\n (if (get_local $sign)\n (then\n (set_local $a (i64.xor (get_local $a) (i64.const -1)))\n (set_local $b (i64.xor (get_local $b) (i64.const -1)))\n (set_local $c (i64.xor (get_local $c) (i64.const -1)))\n (set_local $d (i64.xor (get_local $d) (i64.const -1)))\n\n (set_local $d (i64.add (get_local $d) (i64.const 1)))\n (set_local $c (i64.add (get_local $c) (i64.extend_u/i32 (i64.eqz (get_local $d)))))\n (set_local $b (i64.add (get_local $b) (i64.extend_u/i32 (i64.eqz (get_local $c)))))\n (set_local $a (i64.add (get_local $a) (i64.extend_u/i32 (i64.eqz (get_local $b)))))\n )\n )\n\n ;; save the stack\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n) ;; end for SMOD\n", + .imports = "" + } +},{ + opcodeEnum::SUB, { + .wast = "(func $SUB\n (local $sp i32)\n\n (local $a i64)\n (local $b i64)\n (local $c i64)\n (local $d i64)\n\n (local $a1 i64)\n (local $b1 i64)\n (local $c1 i64)\n (local $d1 i64)\n\n (local $carry i64)\n (local $temp i64)\n\n (set_local $a (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $b (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $c (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $d (i64.load (get_global $sp)))\n ;; decement the stack pointer\n (set_local $sp (i32.sub (get_global $sp) (i32.const 32)))\n\n (set_local $a1 (i64.load (i32.add (get_local $sp) (i32.const 24))))\n (set_local $b1 (i64.load (i32.add (get_local $sp) (i32.const 16))))\n (set_local $c1 (i64.load (i32.add (get_local $sp) (i32.const 8))))\n (set_local $d1 (i64.load (get_local $sp)))\n\n ;; a * 64^3 + b*64^2 + c*64 + d \n ;; d\n (set_local $carry (i64.extend_u/i32 (i64.lt_u (get_local $d) (get_local $d1))))\n (set_local $d (i64.sub (get_local $d) (get_local $d1)))\n\n ;; c\n (set_local $temp (i64.sub (get_local $c) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.gt_u (get_local $temp) (get_local $c))))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i64.or (i64.extend_u/i32 (i64.gt_u (get_local $c) (get_local $temp))) (get_local $carry)))\n\n ;; b\n (set_local $temp (i64.sub (get_local $b) (get_local $carry)))\n (set_local $carry (i64.extend_u/i32 (i64.gt_u (get_local $temp) (get_local $b))))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n\n ;; a\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.or (i64.extend_u/i32 (i64.gt_u (get_local $b) (get_local $temp))) (get_local $carry))) (get_local $a1)))\n\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $a))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (get_local $sp) (get_local $d))\n)\n", + .imports = "" + } +},{ + opcodeEnum::SWAP, { + .wast = "(func $SWAP\n (param $a0 i32)\n (local $sp_ref i32)\n\n (local $topa i64)\n (local $topb i64)\n (local $topc i64)\n (local $topd i64)\n \n (set_local $sp_ref (i32.sub (i32.add (get_global $sp) (i32.const 24)) (i32.mul (i32.add (get_local $a0) (i32.const 1)) (i32.const 32))))\n\n (set_local $topa (i64.load (i32.add (get_global $sp) (i32.const 24))))\n (set_local $topb (i64.load (i32.add (get_global $sp) (i32.const 16))))\n (set_local $topc (i64.load (i32.add (get_global $sp) (i32.const 8))))\n (set_local $topd (i64.load (get_global $sp)))\n \n ;; replace the top element\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.load (get_local $sp_ref)))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 8))))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.load (i32.sub (get_local $sp_ref) (i32.const 16))))\n (i64.store (get_global $sp) (i64.load (i32.sub (get_local $sp_ref) (i32.const 24))))\n\n ;; store the old top element\n (i64.store (get_local $sp_ref) (get_local $topa))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 8)) (get_local $topb))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 16)) (get_local $topc))\n (i64.store (i32.sub (get_local $sp_ref) (i32.const 24)) (get_local $topd))\n)\n", + .imports = "" + } +},{ + opcodeEnum::XOR, { + .wast = "(func $XOR\n (i64.store (i32.sub (get_global $sp) (i32.const 8)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 8))) (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 16)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 16))) (i64.load (i32.add (get_global $sp) (i32.const 16)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 24)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 24))) (i64.load (i32.add (get_global $sp) (i32.const 8)))))\n (i64.store (i32.sub (get_global $sp) (i32.const 32)) (i64.xor (i64.load (i32.sub (get_global $sp) (i32.const 32))) (i64.load (i32.add (get_global $sp) (i32.const 0)))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_i32, { + .wast = "(func $bswap_i32\n (param $int i32)\n (result i32)\n\n (i32.or\n (i32.or\n (i32.and (i32.shr_u (get_local $int) (i32.const 24)) (i32.const 0xff)) ;; 7 -> 0\n (i32.and (i32.shr_u (get_local $int) (i32.const 8)) (i32.const 0xff00))) ;; 6 -> 1\n (i32.or\n (i32.and (i32.shl (get_local $int) (i32.const 8)) (i32.const 0xff0000)) ;; 5 -> 2\n (i32.and (i32.shl (get_local $int) (i32.const 24)) (i32.const 0xff000000)))) ;; 4 -> 3\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_i64, { + .wast = "(func $bswap_i64\n (param $int i64)\n (result i64)\n\n (i64.or\n (i64.or\n (i64.or\n (i64.and (i64.shr_u (get_local $int) (i64.const 56)) (i64.const 0xff)) ;; 7 -> 0\n (i64.and (i64.shr_u (get_local $int) (i64.const 40)) (i64.const 0xff00))) ;; 6 -> 1\n (i64.or\n (i64.and (i64.shr_u (get_local $int) (i64.const 24)) (i64.const 0xff0000)) ;; 5 -> 2\n (i64.and (i64.shr_u (get_local $int) (i64.const 8)) (i64.const 0xff000000)))) ;; 4 -> 3\n (i64.or\n (i64.or\n (i64.and (i64.shl (get_local $int) (i64.const 8)) (i64.const 0xff00000000)) ;; 3 -> 4\n (i64.and (i64.shl (get_local $int) (i64.const 24)) (i64.const 0xff0000000000))) ;; 2 -> 5\n (i64.or\n (i64.and (i64.shl (get_local $int) (i64.const 40)) (i64.const 0xff000000000000)) ;; 1 -> 6\n (i64.and (i64.shl (get_local $int) (i64.const 56)) (i64.const 0xff00000000000000))))) ;; 0 -> 7\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m128, { + .wast = "(func $bswap_m128\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 8)))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $temp))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m160, { + .wast = "(func $bswap_m160\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 12)))))\n (i64.store (i32.add (get_local $sp) (i32.const 12)) (get_local $temp))\n\n (i32.store (i32.add (get_local $sp) (i32.const 8)) (call $bswap_i32 (i32.load (i32.add (get_local $sp) (i32.const 8)))))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::bswap_m256, { + .wast = "(func $bswap_m256\n (param $sp i32)\n (result i32)\n (local $temp i64)\n\n (set_local $temp (call $bswap_i64 (i64.load (get_local $sp))))\n (i64.store (get_local $sp) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 24)))))\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $temp))\n\n (set_local $temp (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 8)))))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (call $bswap_i64 (i64.load (i32.add (get_local $sp) (i32.const 16)))))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $temp))\n (get_local $sp)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback, { + .wast = "(func $callback\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_128, { + .wast = "(func $callback_128\n (param $result i32)\n\n (drop (call $bswap_m128 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_160, { + .wast = "(func $callback_160\n (param $result i32)\n\n (drop (call $bswap_m160 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_256, { + .wast = "(func $callback_256\n (param $result i32)\n\n (drop (call $bswap_m256 (get_global $sp)))\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::callback_32, { + .wast = "(func $callback_32\n (param $result i32)\n\n (i64.store (get_global $sp) (i64.extend_u/i32 (get_local $result)))\n ;; zero out mem\n (i64.store (i32.add (get_global $sp) (i32.const 24)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 16)) (i64.const 0))\n (i64.store (i32.add (get_global $sp) (i32.const 8)) (i64.const 0))\n\n (call $main)\n)\n", + .imports = "" + } +},{ + opcodeEnum::check_overflow, { + .wast = "(func $check_overflow\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (result i32)\n\n (local $MAX_INT i32)\n (set_local $MAX_INT (i32.const -1))\n\n (if\n (i32.and \n (i32.and \n (i64.eqz (get_local $d))\n (i64.eqz (get_local $c)))\n (i32.and \n (i64.eqz (get_local $b))\n (i64.lt_u (get_local $a) (i64.extend_u/i32 (get_local $MAX_INT)))))\n (return (i32.wrap/i64 (get_local $a))))\n\n (return (get_local $MAX_INT))\n)\n", + .imports = "" + } +},{ + opcodeEnum::check_overflow_i64, { + .wast = "(func $check_overflow_i64\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (result i64)\n\n (if\n (i32.and \n (i32.and \n (i64.eqz (get_local $d))\n (i64.eqz (get_local $c)))\n (i64.eqz (get_local $b)))\n (return (get_local $a)))\n\n (return (i64.const 0xffffffffffffffff))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_256, { + .wast = ";; is a less than or equal to b // a >= b\n(func $gte_256\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i64.ge_u (get_local $a3) (get_local $b3))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_320, { + .wast = "(func $gte_320\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (param $a4 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n (param $b4 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i32.or (i64.gt_u (get_local $a3) (get_local $b3)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a3) (get_local $b3))\n (i64.ge_u (get_local $a4) (get_local $b4))))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::gte_512, { + .wast = "(func $gte_512\n (param $a0 i64)\n (param $a1 i64)\n (param $a2 i64)\n (param $a3 i64)\n (param $a4 i64)\n (param $a5 i64)\n (param $a6 i64)\n (param $a7 i64)\n\n (param $b0 i64)\n (param $b1 i64)\n (param $b2 i64)\n (param $b3 i64)\n (param $b4 i64)\n (param $b5 i64)\n (param $b6 i64)\n (param $b7 i64)\n\n (result i32)\n\n ;; a0 > b0 || [a0 == b0 && [a1 > b1 || [a1 == b1 && [a2 > b2 || [a2 == b2 && a3 >= b3 ]]]]\n (i32.or (i64.gt_u (get_local $a0) (get_local $b0)) ;; a0 > b0\n (i32.and (i64.eq (get_local $a0) (get_local $b0))\n (i32.or (i64.gt_u (get_local $a1) (get_local $b1)) ;; a1 > b1\n (i32.and (i64.eq (get_local $a1) (get_local $b1)) ;; a1 == b1\n (i32.or (i64.gt_u (get_local $a2) (get_local $b2)) ;; a2 > b2\n (i32.and (i64.eq (get_local $a2) (get_local $b2))\n (i32.or (i64.gt_u (get_local $a3) (get_local $b3)) ;; a3 > b3\n (i32.and (i64.eq (get_local $a3) (get_local $b3))\n (i32.or (i64.gt_u (get_local $a4) (get_local $b4)) ;; a4 > b4\n (i32.and (i64.eq (get_local $a4) (get_local $b4))\n (i32.or (i64.gt_u (get_local $a5) (get_local $b5)) ;; a5 > b5\n (i32.and (i64.eq (get_local $a5) (get_local $b5))\n (i32.or (i64.gt_u (get_local $a6) (get_local $b6)) ;; a6 > b6\n (i32.and (i64.eq (get_local $a6) (get_local $b6))\n (i64.ge_u (get_local $a7) (get_local $b7))))))))))))))))\n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_256, { + .wast = "(func $iszero_256\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n\n (i64.eqz (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3))) \n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_320, { + .wast = "(func $iszero_320\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n\n (i64.eqz (i64.or (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3)) (get_local 4)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::iszero_512, { + .wast = "(func $iszero_512\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (param i64)\n (result i32)\n (i64.eqz (i64.or (i64.or (i64.or (i64.or (i64.or (i64.or (i64.or (get_local 0) (get_local 1)) (get_local 2)) (get_local 3)) (get_local 4)) (get_local 5)) (get_local 6)) (get_local 7)))\n)\n", + .imports = "" + } +},{ + opcodeEnum::keccak, { + .wast = ";;\n;; Copied from https://github.com/axic/keccak-wasm (has more comments)\n;;\n\n(func $keccak_theta\n (param $context_offset i32)\n\n (local $C0 i64)\n (local $C1 i64)\n (local $C2 i64)\n (local $C3 i64)\n (local $C4 i64)\n (local $D0 i64)\n (local $D1 i64)\n (local $D2 i64)\n (local $D3 i64)\n (local $D4 i64)\n\n ;; C[x] = A[x] ^ A[x + 5] ^ A[x + 10] ^ A[x + 15] ^ A[x + 20];\n (set_local $C0\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 160)))\n )\n )\n )\n )\n )\n\n (set_local $C1\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 168)))\n )\n )\n )\n )\n )\n\n (set_local $C2\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 136)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 176)))\n )\n )\n )\n )\n )\n\n (set_local $C3\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 144)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 184)))\n )\n )\n )\n )\n )\n\n (set_local $C4\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 152)))\n (i64.load (i32.add (get_local $context_offset) (i32.const 192)))\n )\n )\n )\n )\n )\n\n ;; D[0] = ROTL64(C[1], 1) ^ C[4];\n (set_local $D0\n (i64.xor\n (get_local $C4)\n (i64.rotl\n (get_local $C1)\n (i64.const 1)\n )\n )\n )\n\n ;; D[1] = ROTL64(C[2], 1) ^ C[0];\n (set_local $D1\n (i64.xor\n (get_local $C0)\n (i64.rotl\n (get_local $C2)\n (i64.const 1)\n )\n )\n )\n\n ;; D[2] = ROTL64(C[3], 1) ^ C[1];\n (set_local $D2\n (i64.xor\n (get_local $C1)\n (i64.rotl\n (get_local $C3)\n (i64.const 1)\n )\n )\n )\n\n ;; D[3] = ROTL64(C[4], 1) ^ C[2];\n (set_local $D3\n (i64.xor\n (get_local $C2)\n (i64.rotl\n (get_local $C4)\n (i64.const 1)\n )\n )\n )\n\n ;; D[4] = ROTL64(C[0], 1) ^ C[3];\n (set_local $D4\n (i64.xor\n (get_local $C3)\n (i64.rotl\n (get_local $C0)\n (i64.const 1)\n )\n )\n )\n\n ;; A[x] ^= D[x];\n ;; A[x + 5] ^= D[x];\n ;; A[x + 10] ^= D[x];\n ;; A[x + 15] ^= D[x];\n ;; A[x + 20] ^= D[x];\n \n ;; x = 0\n (i64.store (i32.add (get_local $context_offset) (i32.const 0))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 40))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 80))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 120))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (get_local $D0)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 160))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 160)))\n (get_local $D0)\n )\n )\n\n ;; x = 1\n (i64.store (i32.add (get_local $context_offset) (i32.const 8))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 48))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 88))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 128))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (get_local $D1)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 168))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 168)))\n (get_local $D1)\n )\n )\n\n ;; x = 2\n (i64.store (i32.add (get_local $context_offset) (i32.const 16))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 56))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 96))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 136))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 136)))\n (get_local $D2)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 176))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 176)))\n (get_local $D2)\n )\n )\n\n ;; x = 3\n (i64.store (i32.add (get_local $context_offset) (i32.const 24))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 64))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 104))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 144))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 144)))\n (get_local $D3)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 184))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 184)))\n (get_local $D3)\n )\n )\n\n ;; x = 4\n (i64.store (i32.add (get_local $context_offset) (i32.const 32))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 72))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 112))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 152))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 152)))\n (get_local $D4)\n )\n )\n\n (i64.store (i32.add (get_local $context_offset) (i32.const 192))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 192)))\n (get_local $D4)\n )\n )\n)\n\n(func $keccak_rho\n (param $context_offset i32)\n (param $rotation_consts i32)\n\n ;;(local $tmp i32)\n\n ;; state[ 1] = ROTL64(state[ 1], 1);\n ;;(set_local $tmp (i32.add (get_local $context_offset) (i32.const 1)))\n ;;(i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $context_offset)) (i64.const 1)))\n\n ;;(set_local $tmp (i32.add (get_local $context_offset) (i32.const 2)))\n ;;(i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $context_offset)) (i64.const 62)))\n\n (local $tmp i32)\n (local $i i32)\n\n ;; for (i = 0; i <= 24; i++)\n (set_local $i (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (i32.const 24))\n (br $done)\n )\n\n (set_local $tmp (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (i32.const 1) (get_local $i)))))\n\n (i64.store (get_local $tmp) (i64.rotl (i64.load (get_local $tmp)) (i64.load8_u (i32.add (get_local $rotation_consts) (get_local $i)))))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n)\n\n(func $keccak_pi\n (param $context_offset i32)\n\n (local $A1 i64)\n (set_local $A1 (i64.load (i32.add (get_local $context_offset) (i32.const 8))))\n\n ;; Swap non-overlapping fields, i.e. $A1 = $A6, etc.\n ;; NOTE: $A0 is untouched\n (i64.store (i32.add (get_local $context_offset) (i32.const 8)) (i64.load (i32.add (get_local $context_offset) (i32.const 48))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 48)) (i64.load (i32.add (get_local $context_offset) (i32.const 72))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 72)) (i64.load (i32.add (get_local $context_offset) (i32.const 176))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 176)) (i64.load (i32.add (get_local $context_offset) (i32.const 112))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 112)) (i64.load (i32.add (get_local $context_offset) (i32.const 160))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 160)) (i64.load (i32.add (get_local $context_offset) (i32.const 16))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 16)) (i64.load (i32.add (get_local $context_offset) (i32.const 96))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 96)) (i64.load (i32.add (get_local $context_offset) (i32.const 104))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 104)) (i64.load (i32.add (get_local $context_offset) (i32.const 152))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 152)) (i64.load (i32.add (get_local $context_offset) (i32.const 184))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 184)) (i64.load (i32.add (get_local $context_offset) (i32.const 120))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 120)) (i64.load (i32.add (get_local $context_offset) (i32.const 32))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 32)) (i64.load (i32.add (get_local $context_offset) (i32.const 192))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 192)) (i64.load (i32.add (get_local $context_offset) (i32.const 168))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 168)) (i64.load (i32.add (get_local $context_offset) (i32.const 64))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 64)) (i64.load (i32.add (get_local $context_offset) (i32.const 128))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 128)) (i64.load (i32.add (get_local $context_offset) (i32.const 40))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 40)) (i64.load (i32.add (get_local $context_offset) (i32.const 24))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 24)) (i64.load (i32.add (get_local $context_offset) (i32.const 144))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 144)) (i64.load (i32.add (get_local $context_offset) (i32.const 136))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 136)) (i64.load (i32.add (get_local $context_offset) (i32.const 88))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 88)) (i64.load (i32.add (get_local $context_offset) (i32.const 56))))\n (i64.store (i32.add (get_local $context_offset) (i32.const 56)) (i64.load (i32.add (get_local $context_offset) (i32.const 80))))\n\n ;; Place the previously saved overlapping field\n (i64.store (i32.add (get_local $context_offset) (i32.const 80)) (get_local $A1))\n)\n\n(func $keccak_chi\n (param $context_offset i32)\n\n (local $A0 i64)\n (local $A1 i64)\n (local $i i32)\n\n ;; for (round = 0; round < 25; i += 5)\n (set_local $i (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (i32.const 25))\n (br $done)\n )\n\n (set_local $A0 (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i)))))\n (set_local $A1 (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1))))))\n\n ;; A[0 + i] ^= ~A1 & A[2 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i)))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (get_local $i))))\n (i64.and\n (i64.xor (get_local $A1) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2)))))\n )\n )\n )\n\n ;; A[1 + i] ^= ~A[2 + i] & A[3 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 1)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3)))))\n )\n )\n )\n\n ;; A[2 + i] ^= ~A[3 + i] & A[4 + i];\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 2)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4)))))\n )\n )\n )\n\n ;; A[3 + i] ^= ~A[4 + i] & A0;\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 3)))))\n (i64.and\n (i64.xor (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4))))) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (get_local $A0)\n )\n )\n )\n\n ;; A[4 + i] ^= ~A0 & A1;\n (i64.store (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4))))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.mul (i32.const 8) (i32.add (get_local $i) (i32.const 4)))))\n (i64.and\n (i64.xor (get_local $A0) (i64.const 0xFFFFFFFFFFFFFFFF)) ;; bitwise not\n (get_local $A1)\n )\n )\n )\n\n (set_local $i (i32.add (get_local $i) (i32.const 5)))\n (br $loop)\n )\n )\n)\n\n(func $keccak_permute\n (param $context_offset i32)\n\n (local $rotation_consts i32)\n (local $round_consts i32)\n (local $round i32)\n\n (set_local $round_consts (i32.add (get_local $context_offset) (i32.const 400)))\n (set_local $rotation_consts (i32.add (get_local $context_offset) (i32.const 592)))\n\n ;; for (round = 0; round < 24; round++)\n (set_local $round (i32.const 0))\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $round) (i32.const 24))\n (br $done)\n )\n\n ;; theta transform\n (call $keccak_theta (get_local $context_offset))\n\n ;; rho transform\n (call $keccak_rho (get_local $context_offset) (get_local $rotation_consts))\n\n ;; pi transform\n (call $keccak_pi (get_local $context_offset))\n\n ;; chi transform\n (call $keccak_chi (get_local $context_offset))\n\n ;; iota transform\n ;; context_offset[0] ^= KECCAK_ROUND_CONSTANTS[round];\n (i64.store (get_local $context_offset)\n (i64.xor\n (i64.load (get_local $context_offset))\n (i64.load (i32.add (get_local $round_consts) (i32.mul (i32.const 8) (get_local $round))))\n )\n )\n\n (set_local $round (i32.add (get_local $round) (i32.const 1)))\n (br $loop)\n ) \n ) \n)\n\n(func $keccak_block\n (param $input_offset i32)\n (param $input_length i32) ;; ignored, we expect keccak256\n (param $context_offset i32)\n\n ;; read blocks in little-endian order and XOR against context_offset\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 0))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 0)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 0)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 8))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 8)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 8)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 16))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 16)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 16)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 24))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 24)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 24)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 32))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 32)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 32)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 40))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 40)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 40)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 48))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 48)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 48)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 56))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 56)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 56)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 64))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 64)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 64)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 72))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 72)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 72)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 80))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 80)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 80)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 88))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 88)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 88)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 96))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 96)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 96)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 104))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 104)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 104)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 112))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 112)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 112)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 120))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 120)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 120)))\n )\n )\n\n (i64.store\n (i32.add (get_local $context_offset) (i32.const 128))\n (i64.xor\n (i64.load (i32.add (get_local $context_offset) (i32.const 128)))\n (i64.load (i32.add (get_local $input_offset) (i32.const 128)))\n )\n )\n \n (call $keccak_permute (get_local $context_offset))\n)\n\n;;\n;; Initialise the context\n;;\n(func $keccak_init\n (param $context_offset i32)\n (local $round_consts i32)\n (local $rotation_consts i32)\n\n (call $keccak_reset (get_local $context_offset))\n\n ;; insert the round constants (used by $KECCAK_IOTA)\n (set_local $round_consts (i32.add (get_local $context_offset) (i32.const 400)))\n (i64.store (i32.add (get_local $round_consts) (i32.const 0)) (i64.const 0x0000000000000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 8)) (i64.const 0x0000000000008082))\n (i64.store (i32.add (get_local $round_consts) (i32.const 16)) (i64.const 0x800000000000808A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 24)) (i64.const 0x8000000080008000))\n (i64.store (i32.add (get_local $round_consts) (i32.const 32)) (i64.const 0x000000000000808B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 40)) (i64.const 0x0000000080000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 48)) (i64.const 0x8000000080008081))\n (i64.store (i32.add (get_local $round_consts) (i32.const 56)) (i64.const 0x8000000000008009))\n (i64.store (i32.add (get_local $round_consts) (i32.const 64)) (i64.const 0x000000000000008A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 72)) (i64.const 0x0000000000000088))\n (i64.store (i32.add (get_local $round_consts) (i32.const 80)) (i64.const 0x0000000080008009))\n (i64.store (i32.add (get_local $round_consts) (i32.const 88)) (i64.const 0x000000008000000A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 96)) (i64.const 0x000000008000808B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 104)) (i64.const 0x800000000000008B))\n (i64.store (i32.add (get_local $round_consts) (i32.const 112)) (i64.const 0x8000000000008089))\n (i64.store (i32.add (get_local $round_consts) (i32.const 120)) (i64.const 0x8000000000008003))\n (i64.store (i32.add (get_local $round_consts) (i32.const 128)) (i64.const 0x8000000000008002))\n (i64.store (i32.add (get_local $round_consts) (i32.const 136)) (i64.const 0x8000000000000080))\n (i64.store (i32.add (get_local $round_consts) (i32.const 144)) (i64.const 0x000000000000800A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 152)) (i64.const 0x800000008000000A))\n (i64.store (i32.add (get_local $round_consts) (i32.const 160)) (i64.const 0x8000000080008081))\n (i64.store (i32.add (get_local $round_consts) (i32.const 168)) (i64.const 0x8000000000008080))\n (i64.store (i32.add (get_local $round_consts) (i32.const 176)) (i64.const 0x0000000080000001))\n (i64.store (i32.add (get_local $round_consts) (i32.const 184)) (i64.const 0x8000000080008008))\n\n ;; insert the rotation constants (used by $keccak_rho)\n (set_local $rotation_consts (i32.add (get_local $context_offset) (i32.const 592)))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 0)) (i32.const 1))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 1)) (i32.const 62))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 2)) (i32.const 28))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 3)) (i32.const 27))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 4)) (i32.const 36))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 5)) (i32.const 44))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 6)) (i32.const 6))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 7)) (i32.const 55))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 8)) (i32.const 20))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 9)) (i32.const 3))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 10)) (i32.const 10))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 11)) (i32.const 43))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 12)) (i32.const 25))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 13)) (i32.const 39))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 14)) (i32.const 41))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 15)) (i32.const 45))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 16)) (i32.const 15))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 17)) (i32.const 21))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 18)) (i32.const 8))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 19)) (i32.const 18))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 20)) (i32.const 2))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 21)) (i32.const 61))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 22)) (i32.const 56))\n (i32.store8 (i32.add (get_local $rotation_consts) (i32.const 23)) (i32.const 14))\n)\n\n;;\n;; Reset the context\n;;\n(func $keccak_reset\n (param $context_offset i32)\n\n ;; clear out the context memory\n (drop (call $memset (get_local $context_offset) (i32.const 0) (i32.const 400)))\n)\n\n;;\n;; Push input to the context\n;;\n(func $keccak_update\n (param $context_offset i32)\n (param $input_offset i32)\n (param $input_length i32)\n\n (local $residue_offset i32)\n (local $residue_buffer i32)\n (local $residue_index i32)\n (local $tmp i32)\n\n ;; this is where we store the pointer\n (set_local $residue_offset (i32.add (get_local $context_offset) (i32.const 200)))\n ;; this is where the buffer is\n (set_local $residue_buffer (i32.add (get_local $context_offset) (i32.const 208)))\n\n (set_local $residue_index (i32.load (get_local $residue_offset)))\n\n ;; process residue from last block\n (if (i32.ne (get_local $residue_index) (i32.const 0))\n (then\n ;; the space left in the residue buffer\n (set_local $tmp (i32.sub (i32.const 136) (get_local $residue_index)))\n\n ;; limit to what we have as an input\n (if (i32.lt_u (get_local $input_length) (get_local $tmp))\n (set_local $tmp (get_local $input_length))\n )\n\n ;; fill up the residue buffer\n (drop (call $memcpy\n (i32.add (get_local $residue_buffer) (get_local $residue_index))\n (get_local $input_offset)\n (get_local $tmp)\n ))\n\n (set_local $residue_index (i32.add (get_local $residue_index) (get_local $tmp)))\n\n ;; block complete\n (if (i32.eq (get_local $residue_index) (i32.const 136))\n (call $keccak_block (get_local $input_offset) (i32.const 136) (get_local $context_offset))\n\n (set_local $residue_index (i32.const 0))\n )\n\n (i32.store (get_local $residue_offset) (get_local $residue_index))\n\n (set_local $input_length (i32.sub (get_local $input_length) (get_local $tmp)))\n )\n )\n\n ;; while (input_length > block_size)\n (block $done\n (loop $loop\n (if (i32.lt_u (get_local $input_length) (i32.const 136))\n (br $done)\n )\n\n (call $keccak_block (get_local $input_offset) (i32.const 136) (get_local $context_offset))\n\n (set_local $input_offset (i32.add (get_local $input_offset) (i32.const 136)))\n (set_local $input_length (i32.sub (get_local $input_length) (i32.const 136)))\n (br $loop)\n )\n )\n\n ;; copy to the residue buffer\n (if (i32.gt_u (get_local $input_length) (i32.const 0))\n (then\n (drop (call $memcpy\n (i32.add (get_local $residue_buffer) (get_local $residue_index))\n (get_local $input_offset)\n (get_local $input_length)\n ))\n\n (set_local $residue_index (i32.add (get_local $residue_index) (get_local $input_length)))\n (i32.store (get_local $residue_offset) (get_local $residue_index))\n )\n )\n)\n\n;;\n;; Finalise and return the hash\n;;\n;; The 256 bit hash is returned at the output offset.\n;;\n(func $keccak_finish\n (param $context_offset i32)\n (param $output_offset i32)\n\n (local $residue_offset i32)\n (local $residue_buffer i32)\n (local $residue_index i32)\n (local $tmp i32)\n\n ;; this is where we store the pointer\n (set_local $residue_offset (i32.add (get_local $context_offset) (i32.const 200)))\n ;; this is where the buffer is\n (set_local $residue_buffer (i32.add (get_local $context_offset) (i32.const 208)))\n\n (set_local $residue_index (i32.load (get_local $residue_offset)))\n (set_local $tmp (get_local $residue_index))\n\n ;; clear the rest of the residue buffer\n (drop (call $memset (i32.add (get_local $residue_buffer) (get_local $tmp)) (i32.const 0) (i32.sub (i32.const 136) (get_local $tmp))))\n\n ;; ((char*)ctx->message)[ctx->rest] |= 0x01;\n (set_local $tmp (i32.add (get_local $residue_buffer) (get_local $residue_index)))\n (i32.store8 (get_local $tmp) (i32.or (i32.load8_u (get_local $tmp)) (i32.const 0x01)))\n\n ;; ((char*)ctx->message)[block_size - 1] |= 0x80;\n (set_local $tmp (i32.add (get_local $residue_buffer) (i32.const 135)))\n (i32.store8 (get_local $tmp) (i32.or (i32.load8_u (get_local $tmp)) (i32.const 0x80)))\n\n (call $keccak_block (get_local $residue_buffer) (i32.const 136) (get_local $context_offset))\n\n ;; the first 32 bytes pointed at by $output_offset is the final hash\n (i64.store (get_local $output_offset) (i64.load (get_local $context_offset)))\n (i64.store (i32.add (get_local $output_offset) (i32.const 8)) (i64.load (i32.add (get_local $context_offset) (i32.const 8))))\n (i64.store (i32.add (get_local $output_offset) (i32.const 16)) (i64.load (i32.add (get_local $context_offset) (i32.const 16))))\n (i64.store (i32.add (get_local $output_offset) (i32.const 24)) (i64.load (i32.add (get_local $context_offset) (i32.const 24))))\n)\n\n;;\n;; Calculate the hash. Helper method incorporating the above three.\n;;\n(func $keccak\n (param $context_offset i32)\n (param $input_offset i32)\n (param $input_length i32)\n (param $output_offset i32)\n\n (call $keccak_init (get_local $context_offset))\n (call $keccak_update (get_local $context_offset) (get_local $input_offset) (get_local $input_length))\n (call $keccak_finish (get_local $context_offset) (get_local $output_offset))\n)\n", + .imports = "" + } +},{ + opcodeEnum::memcpy, { + .wast = ";;\n;; memcpy from ewasm-libc/ewasm-cleanup\n;;\n(func $memcpy\n (param $dst i32)\n (param $src i32)\n (param $length i32)\n (result i32)\n\n (local $i i32)\n\n (set_local $i (i32.const 0))\n\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (get_local $length))\n (br $done)\n )\n\n (i32.store8 (i32.add (get_local $dst) (get_local $i)) (i32.load8_u (i32.add (get_local $src) (get_local $i))))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n\n (return (get_local $dst))\n)\n", + .imports = "" + } +},{ + opcodeEnum::memset, { + .wast = ";;\n;; memcpy from ewasm-libc/ewasm-cleanup\n;;\n(func $memset\n (param $ptr i32)\n (param $value i32)\n (param $length i32)\n (result i32)\n (local $i i32)\n\n (set_local $i (i32.const 0))\n\n (block $done\n (loop $loop\n (if (i32.ge_u (get_local $i) (get_local $length))\n (br $done)\n )\n\n (i32.store8 (i32.add (get_local $ptr) (get_local $i)) (get_local $value))\n\n (set_local $i (i32.add (get_local $i) (i32.const 1)))\n (br $loop)\n )\n )\n (get_local $ptr)\n)\n", + .imports = "" + } +},{ + opcodeEnum::memusegas, { + .wast = "(func $memusegas\n (param $offset i32)\n (param $length i32)\n\n (local $cost i64)\n ;; the number of new words being allocated\n (local $newWordCount i64)\n\n (if (i32.eqz (get_local $length))\n (then (return))\n )\n\n ;; const newMemoryWordCount = Math.ceil[[offset + length] / 32]\n (set_local $newWordCount \n (i64.div_u (i64.add (i64.const 31) (i64.add (i64.extend_u/i32 (get_local $offset)) (i64.extend_u/i32 (get_local $length))))\n (i64.const 32)))\n\n ;;if [runState.highestMem >= highestMem] return\n (if (i64.le_u (get_local $newWordCount) (get_global $wordCount))\n (then (return))\n )\n\n ;; words * 3 + words ^2 / 512\n (set_local $cost\n (i64.add\n (i64.mul (get_local $newWordCount) (i64.const 3))\n (i64.div_u\n (i64.mul (get_local $newWordCount)\n (get_local $newWordCount))\n (i64.const 512))))\n\n (call $useGas (i64.sub (get_local $cost) (get_global $prevMemCost)))\n (set_global $prevMemCost (get_local $cost))\n (set_global $wordCount (get_local $newWordCount))\n\n ;; grow actual memory\n ;; the first 31704 bytes are guaranteed to be available\n ;; adjust for 32 bytes - the maximal size of MSTORE write\n ;; TODO it should be current_memory * page_size\n (set_local $offset (i32.add (get_local $length) (i32.add (get_local $offset) (get_global $memstart))))\n (if (i32.gt_u (get_local $offset) (i32.mul (i32.const 65536) (current_memory)))\n (then\n (drop (grow_memory\n (i32.div_u (i32.add (i32.const 65535) (i32.sub (get_local $offset) (current_memory))) (i32.const 65536))))\n )\n )\n)\n", + .imports = "" + } +},{ + opcodeEnum::mod_320, { + .wast = "(func $mod_320\n ;; dividend\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (param $e i64)\n\n ;; divisor\n (param $a1 i64)\n (param $b1 i64)\n (param $c1 i64)\n (param $d1 i64)\n (param $e1 i64)\n\n ;; stack pointer\n (param $sp i32)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n (local $eq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $maske i64)\n\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maske (i64.const 1))\n (block $main\n ;; check div by 0\n (if (call $iszero_320 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1)) \n (then\n (set_local $a (i64.const 0))\n (set_local $b (i64.const 0))\n (set_local $c (i64.const 0))\n (set_local $d (i64.const 0))\n (set_local $e (i64.const 0))\n (br $main)\n )\n )\n\n (block $done\n ;; align bits\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1))) (call $gte_320\n (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1)\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shl (get_local $d1) (i64.const 1)) (i64.shr_u (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.shl (get_local $e1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shl (get_local $maskd) (i64.const 1)) (i64.shr_u (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.shl (get_local $maske) (i64.const 1)))\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_320 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd) (get_local $maske))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_320 (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $e) (get_local $e1)))\n (set_local $e (i64.sub (get_local $e) (get_local $e1)))\n\n (set_local $temp (i64.sub (get_local $d) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $d)))\n (set_local $d (i64.sub (get_local $temp) (get_local $d1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $d) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $e1 (i64.add (i64.shr_u (get_local $e1) (i64.const 1)) (i64.shl (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maske (i64.add (i64.shr_u (get_local $maske) (i64.const 1)) (i64.shl (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n (i64.store (i32.add (get_local $sp) (i32.const 24)) (get_local $b))\n (i64.store (i32.add (get_local $sp) (i32.const 16)) (get_local $c))\n (i64.store (i32.add (get_local $sp) (i32.const 8)) (get_local $d))\n (i64.store (get_local $sp) (get_local $e))\n)\n", + .imports = "" + } +},{ + opcodeEnum::mod_512, { + .wast = ";; Modulo 0x06\n(func $mod_512\n ;; dividend\n (param $a i64)\n (param $b i64)\n (param $c i64)\n (param $d i64)\n (param $e i64)\n (param $f i64)\n (param $g i64)\n (param $h i64)\n\n ;; divisor\n (param $a1 i64)\n (param $b1 i64)\n (param $c1 i64)\n (param $d1 i64)\n (param $e1 i64)\n (param $f1 i64)\n (param $g1 i64)\n (param $h1 i64)\n\n (param $sp i32)\n\n ;; quotient\n (local $aq i64)\n (local $bq i64)\n (local $cq i64)\n (local $dq i64)\n\n ;; mask\n (local $maska i64)\n (local $maskb i64)\n (local $maskc i64)\n (local $maskd i64)\n (local $maske i64)\n (local $maskf i64)\n (local $maskg i64)\n (local $maskh i64)\n\n (local $carry i32)\n (local $temp i64)\n\n (set_local $maskh (i64.const 1))\n\n (block $main\n ;; check div by 0\n (if (call $iszero_512 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1))\n (then\n (set_local $e (i64.const 0))\n (set_local $f (i64.const 0))\n (set_local $g (i64.const 0))\n (set_local $h (i64.const 0))\n (br $main)\n )\n )\n\n ;; align bits\n (block $done\n (loop $loop\n ;; align bits;\n (if (i32.or (i64.eqz (i64.clz (get_local $a1)))\n (call $gte_512 (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1)\n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h)))\n (br $done)\n )\n\n ;; divisor = divisor << 1\n (set_local $a1 (i64.add (i64.shl (get_local $a1) (i64.const 1)) (i64.shr_u (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shl (get_local $b1) (i64.const 1)) (i64.shr_u (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shl (get_local $c1) (i64.const 1)) (i64.shr_u (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shl (get_local $d1) (i64.const 1)) (i64.shr_u (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.add (i64.shl (get_local $e1) (i64.const 1)) (i64.shr_u (get_local $f1) (i64.const 63))))\n (set_local $f1 (i64.add (i64.shl (get_local $f1) (i64.const 1)) (i64.shr_u (get_local $g1) (i64.const 63))))\n (set_local $g1 (i64.add (i64.shl (get_local $g1) (i64.const 1)) (i64.shr_u (get_local $h1) (i64.const 63))))\n (set_local $h1 (i64.shl (get_local $h1) (i64.const 1)))\n\n ;; mask = mask << 1\n (set_local $maska (i64.add (i64.shl (get_local $maska) (i64.const 1)) (i64.shr_u (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shl (get_local $maskb) (i64.const 1)) (i64.shr_u (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shl (get_local $maskc) (i64.const 1)) (i64.shr_u (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shl (get_local $maskd) (i64.const 1)) (i64.shr_u (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.add (i64.shl (get_local $maske) (i64.const 1)) (i64.shr_u (get_local $maskf) (i64.const 63))))\n (set_local $maskf (i64.add (i64.shl (get_local $maskf) (i64.const 1)) (i64.shr_u (get_local $maskg) (i64.const 63))))\n (set_local $maskg (i64.add (i64.shl (get_local $maskg) (i64.const 1)) (i64.shr_u (get_local $maskh) (i64.const 63))))\n (set_local $maskh (i64.shl (get_local $maskh) (i64.const 1)))\n (br $loop)\n )\n )\n\n (block $done\n (loop $loop\n ;; loop while mask != 0\n (if (call $iszero_512 (get_local $maska) (get_local $maskb) (get_local $maskc) (get_local $maskd) (get_local $maske) (get_local $maskf) (get_local $maskg) (get_local $maskh))\n (br $done)\n )\n ;; if dividend >= divisor\n (if (call $gte_512 \n (get_local $a) (get_local $b) (get_local $c) (get_local $d) (get_local $e) (get_local $f) (get_local $g) (get_local $h)\n (get_local $a1) (get_local $b1) (get_local $c1) (get_local $d1) (get_local $e1) (get_local $f1) (get_local $g1) (get_local $h1))\n (then\n ;; dividend = dividend - divisor\n (set_local $carry (i64.lt_u (get_local $h) (get_local $h1)))\n (set_local $h (i64.sub (get_local $h) (get_local $h1)))\n\n (set_local $temp (i64.sub (get_local $g) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $g)))\n (set_local $g (i64.sub (get_local $temp) (get_local $g1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $g) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $f) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $f)))\n (set_local $f (i64.sub (get_local $temp) (get_local $f1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $f) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $e) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $e)))\n (set_local $e (i64.sub (get_local $temp) (get_local $e1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $e) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $d) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $d)))\n (set_local $d (i64.sub (get_local $temp) (get_local $d1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $d) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $c) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $c)))\n (set_local $c (i64.sub (get_local $temp) (get_local $c1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $c) (get_local $temp)) (get_local $carry)))\n\n (set_local $temp (i64.sub (get_local $b) (i64.extend_u/i32 (get_local $carry))))\n (set_local $carry (i64.gt_u (get_local $temp) (get_local $b)))\n (set_local $b (i64.sub (get_local $temp) (get_local $b1)))\n (set_local $carry (i32.or (i64.gt_u (get_local $b) (get_local $temp)) (get_local $carry)))\n (set_local $a (i64.sub (i64.sub (get_local $a) (i64.extend_u/i32 (get_local $carry))) (get_local $a1)))\n )\n )\n ;; divisor = divisor >> 1\n (set_local $h1 (i64.add (i64.shr_u (get_local $h1) (i64.const 1)) (i64.shl (get_local $g1) (i64.const 63))))\n (set_local $g1 (i64.add (i64.shr_u (get_local $g1) (i64.const 1)) (i64.shl (get_local $f1) (i64.const 63))))\n (set_local $f1 (i64.add (i64.shr_u (get_local $f1) (i64.const 1)) (i64.shl (get_local $e1) (i64.const 63))))\n (set_local $e1 (i64.add (i64.shr_u (get_local $e1) (i64.const 1)) (i64.shl (get_local $d1) (i64.const 63))))\n (set_local $d1 (i64.add (i64.shr_u (get_local $d1) (i64.const 1)) (i64.shl (get_local $c1) (i64.const 63))))\n (set_local $c1 (i64.add (i64.shr_u (get_local $c1) (i64.const 1)) (i64.shl (get_local $b1) (i64.const 63))))\n (set_local $b1 (i64.add (i64.shr_u (get_local $b1) (i64.const 1)) (i64.shl (get_local $a1) (i64.const 63))))\n (set_local $a1 (i64.shr_u (get_local $a1) (i64.const 1)))\n\n ;; mask = mask >> 1\n (set_local $maskh (i64.add (i64.shr_u (get_local $maskh) (i64.const 1)) (i64.shl (get_local $maskg) (i64.const 63))))\n (set_local $maskg (i64.add (i64.shr_u (get_local $maskg) (i64.const 1)) (i64.shl (get_local $maskf) (i64.const 63))))\n (set_local $maskf (i64.add (i64.shr_u (get_local $maskf) (i64.const 1)) (i64.shl (get_local $maske) (i64.const 63))))\n (set_local $maske (i64.add (i64.shr_u (get_local $maske) (i64.const 1)) (i64.shl (get_local $maskd) (i64.const 63))))\n (set_local $maskd (i64.add (i64.shr_u (get_local $maskd) (i64.const 1)) (i64.shl (get_local $maskc) (i64.const 63))))\n (set_local $maskc (i64.add (i64.shr_u (get_local $maskc) (i64.const 1)) (i64.shl (get_local $maskb) (i64.const 63))))\n (set_local $maskb (i64.add (i64.shr_u (get_local $maskb) (i64.const 1)) (i64.shl (get_local $maska) (i64.const 63))))\n (set_local $maska (i64.shr_u (get_local $maska) (i64.const 1)))\n (br $loop)\n )\n )\n );; end of main\n\n (i64.store (get_local $sp) (get_local $e))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $f))\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $g))\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $h))\n)\n", + .imports = "" + } +},{ + opcodeEnum::mul_256, { + .wast = "(func $mul_256\n ;; a b c d e f g h\n ;;* i j k l m n o p\n ;;----------------\n (param $a i64)\n (param $c i64)\n (param $e i64)\n (param $g i64)\n\n (param $i i64)\n (param $k i64)\n (param $m i64)\n (param $o i64)\n\n (param $sp i32)\n\n (local $b i64)\n (local $d i64)\n (local $f i64)\n (local $h i64)\n (local $j i64)\n (local $l i64)\n (local $n i64)\n (local $p i64)\n (local $temp6 i64)\n (local $temp5 i64)\n (local $temp4 i64)\n (local $temp3 i64)\n (local $temp2 i64)\n (local $temp1 i64)\n (local $temp0 i64)\n\n ;; split the ops\n (set_local $b (i64.and (get_local $a) (i64.const 4294967295)))\n (set_local $a (i64.shr_u (get_local $a) (i64.const 32))) \n\n (set_local $d (i64.and (get_local $c) (i64.const 4294967295)))\n (set_local $c (i64.shr_u (get_local $c) (i64.const 32))) \n\n (set_local $f (i64.and (get_local $e) (i64.const 4294967295)))\n (set_local $e (i64.shr_u (get_local $e) (i64.const 32)))\n\n (set_local $h (i64.and (get_local $g) (i64.const 4294967295)))\n (set_local $g (i64.shr_u (get_local $g) (i64.const 32)))\n\n (set_local $j (i64.and (get_local $i) (i64.const 4294967295)))\n (set_local $i (i64.shr_u (get_local $i) (i64.const 32))) \n\n (set_local $l (i64.and (get_local $k) (i64.const 4294967295)))\n (set_local $k (i64.shr_u (get_local $k) (i64.const 32))) \n\n (set_local $n (i64.and (get_local $m) (i64.const 4294967295)))\n (set_local $m (i64.shr_u (get_local $m) (i64.const 32)))\n\n (set_local $p (i64.and (get_local $o) (i64.const 4294967295)))\n (set_local $o (i64.shr_u (get_local $o) (i64.const 32)))\n ;; first row multiplication \n ;; p * h\n (set_local $temp0 (i64.mul (get_local $p) (get_local $h)))\n ;; p * g + carry\n (set_local $temp1 (i64.add (i64.mul (get_local $p) (get_local $g)) (i64.shr_u (get_local $temp0) (i64.const 32))))\n ;; p * f + carry\n (set_local $temp2 (i64.add (i64.mul (get_local $p) (get_local $f)) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; p * e + carry\n (set_local $temp3 (i64.add (i64.mul (get_local $p) (get_local $e)) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; p * d + carry\n (set_local $temp4 (i64.add (i64.mul (get_local $p) (get_local $d)) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; p * c + carry\n (set_local $temp5 (i64.add (i64.mul (get_local $p) (get_local $c)) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; p * b + carry\n (set_local $temp6 (i64.add (i64.mul (get_local $p) (get_local $b)) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; p * a + carry\n (set_local $a (i64.add (i64.mul (get_local $p) (get_local $a)) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; second row\n ;; o * h + $temp1 \"pg\"\n (set_local $temp1 (i64.add (i64.mul (get_local $o) (get_local $h)) (i64.and (get_local $temp1) (i64.const 4294967295))))\n ;; o * g + $temp2 \"pf\" + carry\n (set_local $temp2 (i64.add (i64.add (i64.mul (get_local $o) (get_local $g)) (i64.and (get_local $temp2) (i64.const 4294967295))) (i64.shr_u (get_local $temp1) (i64.const 32))))\n ;; o * f + $temp3 \"pe\" + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $o) (get_local $f)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; o * e + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $o) (get_local $e)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; o * d + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $o) (get_local $d)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; o * c + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $o) (get_local $c)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; o * b + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $o) (get_local $b)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n ;; third row - n\n ;; n * h + $temp2 \n (set_local $temp2 (i64.add (i64.mul (get_local $n) (get_local $h)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n ;; n * g + $temp3 + carry\n (set_local $temp3 (i64.add (i64.add (i64.mul (get_local $n) (get_local $g)) (i64.and (get_local $temp3) (i64.const 4294967295))) (i64.shr_u (get_local $temp2) (i64.const 32))))\n ;; n * f + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $n) (get_local $f)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; n * e + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $n) (get_local $e)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; n * d + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $n) (get_local $d)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; n * c + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $n) (get_local $c)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; forth row \n ;; m * h + $temp3\n (set_local $temp3 (i64.add (i64.mul (get_local $m) (get_local $h)) (i64.and (get_local $temp3) (i64.const 4294967295))))\n ;; m * g + $temp4 + carry\n (set_local $temp4 (i64.add (i64.add (i64.mul (get_local $m) (get_local $g)) (i64.and (get_local $temp4) (i64.const 4294967295))) (i64.shr_u (get_local $temp3) (i64.const 32))))\n ;; m * f + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $m) (get_local $f)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; m * e + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $m) (get_local $e)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; m * d + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $m) (get_local $d)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; fith row\n ;; l * h + $temp4\n (set_local $temp4 (i64.add (i64.mul (get_local $l) (get_local $h)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n ;; l * g + $temp5 + carry\n (set_local $temp5 (i64.add (i64.add (i64.mul (get_local $l) (get_local $g)) (i64.and (get_local $temp5) (i64.const 4294967295))) (i64.shr_u (get_local $temp4) (i64.const 32))))\n ;; l * f + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $l) (get_local $f)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; l * e + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $l) (get_local $e)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; sixth row \n ;; k * h + $temp5\n (set_local $temp5 (i64.add (i64.mul (get_local $k) (get_local $h)) (i64.and (get_local $temp5) (i64.const 4294967295))))\n ;; k * g + $temp6 + carry\n (set_local $temp6 (i64.add (i64.add (i64.mul (get_local $k) (get_local $g)) (i64.and (get_local $temp6) (i64.const 4294967295))) (i64.shr_u (get_local $temp5) (i64.const 32))))\n ;; k * f + $a + carry\n (set_local $a (i64.add (i64.add (i64.mul (get_local $k) (get_local $f)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))))\n\n ;; seventh row\n ;; j * h + $temp6\n (set_local $temp6 (i64.add (i64.mul (get_local $j) (get_local $h)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n ;; j * g + $a + carry\n\n ;; eigth row\n ;; i * h + $a\n (set_local $a (i64.add (i64.mul (get_local $i) (get_local $h)) (i64.and (i64.add (i64.add (i64.mul (get_local $j) (get_local $g)) (i64.and (get_local $a) (i64.const 4294967295))) (i64.shr_u (get_local $temp6) (i64.const 32))) (i64.const 4294967295))))\n\n ;; combine terms\n (set_local $a (i64.or (i64.shl (get_local $a) (i64.const 32)) (i64.and (get_local $temp6) (i64.const 4294967295))))\n (set_local $c (i64.or (i64.shl (get_local $temp5) (i64.const 32)) (i64.and (get_local $temp4) (i64.const 4294967295))))\n (set_local $e (i64.or (i64.shl (get_local $temp3) (i64.const 32)) (i64.and (get_local $temp2) (i64.const 4294967295))))\n (set_local $g (i64.or (i64.shl (get_local $temp1) (i64.const 32)) (i64.and (get_local $temp0) (i64.const 4294967295))))\n\n ;; save stack \n (i64.store (get_local $sp) (get_local $a))\n (i64.store (i32.sub (get_local $sp) (i32.const 8)) (get_local $c))\n (i64.store (i32.sub (get_local $sp) (i32.const 16)) (get_local $e))\n (i64.store (i32.sub (get_local $sp) (i32.const 24)) (get_local $g))\n)\n", + .imports = "" + } +} + }; +} \ No newline at end of file diff --git a/libs/evm2wasm/CMakeLists.txt b/libs/evm2wasm/CMakeLists.txt index 1d452d73..22778482 100644 --- a/libs/evm2wasm/CMakeLists.txt +++ b/libs/evm2wasm/CMakeLists.txt @@ -2,6 +2,10 @@ set(include_dir ${PROJECT_SOURCE_DIR}/include) find_package(Threads REQUIRED) +hunter_add_package(fmt) + +find_package(fmt CONFIG REQUIRED) + add_library(libevm2wasm STATIC evm2wasm.cpp ${include_dir}/evm2wasm.h ) @@ -12,4 +16,4 @@ if(BUILD_SHARED_LIBS) endif() target_include_directories(libevm2wasm PUBLIC ${include_dir}) -target_link_libraries(libevm2wasm PRIVATE binaryen::binaryen Threads::Threads) \ No newline at end of file +target_link_libraries(libevm2wasm PRIVATE binaryen::binaryen Threads::Threads fmt::fmt) \ No newline at end of file diff --git a/libs/evm2wasm/evm2wasm.cpp b/libs/evm2wasm/evm2wasm.cpp index 3936f5bf..8aa79820 100644 --- a/libs/evm2wasm/evm2wasm.cpp +++ b/libs/evm2wasm/evm2wasm.cpp @@ -1,13 +1,24 @@ -#include +#include + +#include +#include +#include +#include + +#include #include #include #include -#include +#include "evm2wasm.h" +#include "wast-async.h" +#include "wast.h" using namespace std; +using namespace fmt::literals; + namespace { bool nibble2value(char input, unsigned& output) { @@ -89,11 +100,319 @@ string wast2wasm(const string& input, bool debug) { return output.str(); } -string evm2wast(const vector& input, bool tracing) { - (void)input; - (void)tracing; - // FIXME: do evm magic here - return "(module (export \"main\" (func $main)) (func $main))"; +string evm2wast(const vector& evmCode, bool stackTrace, bool useAsyncAPI, bool inlineOps, bool chargePerOp) +{ + // this keep track of the opcode we have found so far. This will be used to + // to figure out what .wast files to include + std::set opcodesUsed; + std::set ignoredOps = {opcodeEnum::JUMP, opcodeEnum::JUMPI, opcodeEnum::JUMPDEST, + opcodeEnum::POP, opcodeEnum::STOP, opcodeEnum::INVALID}; + std::vector callbackTable; + + // an array of found segments + std::vector jumpSegments; + + // the transcompiled EVM code + fmt::MemoryWriter wast; + fmt::MemoryWriter segment; + // + // keeps track of the gas that each section uses + int gasCount = 0; + + // used for pruning dead code + bool jumpFound = false; + + // the accumulative stack difference for the current segment + int segmentStackDelta = 0; + int segmentStackHigh = 0; + int segmentStackLow = 0; + + // adds stack height checks to the beginning of a segment + auto addStackCheck = [&segment, &segmentStackHigh, &segmentStackLow, &segmentStackDelta]() { + fmt::MemoryWriter check; + if (segmentStackHigh != 0) + { + check << "(if (i32.gt_s (get_global $sp) (i32.const {check}))\n\ + (then (unreachable)))"_format("check"_a = ((1023 - segmentStackHigh) * 32)); + } + + if (segmentStackLow != 0) + { + check << "(if (i32.lt_s (get_global $sp) (i32.const {check}))\n\ + (then (unreachable)))"_format("check"_a = (-segmentStackLow * 32 - 32)); + } + + check << segment.str(); + segment = std::move(check); + segmentStackHigh = 0; + segmentStackLow = 0; + segmentStackDelta = 0; + }; + + // add a metering statment at the beginning of a segment + auto addMetering = [&segment, &wast, &gasCount, &chargePerOp]() { + if (!chargePerOp) { + wast << "(call $useGas (i64.const {gasCount}))"_format("gasCount"_a = gasCount); + } + wast << segment.str(); + segment.clear(); + gasCount = 0; + }; + + // finishes off a segment + auto endSegment = [&segment, &addStackCheck, &addMetering]() { + segment << ")"; + addStackCheck(); + addMetering(); + }; + + for (size_t pc = 0; pc < evmCode.size(); pc++) + { + auto opint = evmCode[pc]; + auto op = opcodes(opint); + + // creates a stack trace + if (stackTrace) + { + segment << "(call $stackTrace (i32.const {pc}) (i32.const {opint}) \ + (i32.const {gasCount}) (get_global $sp))\n"_format( + "pc"_a = pc, "opint"_a = opint, "gasCount"_a = op.fee); + } + + if (chargePerOp) { + segment << "(call $useGas (i64.const {fee}))"_format("fee"_a = op.fee); + } + + // do not charge gas for interface methods + // TODO: implement proper gas charging and enable this here + if (opint < 0x30 || (opint > 0x45 && opint < 0xa0)) { + gasCount += op.fee; + } + + segmentStackDelta += op.on; + if (segmentStackDelta > segmentStackHigh) + { + segmentStackHigh = segmentStackDelta; + } + + segmentStackDelta -= op.off; + if (segmentStackDelta < segmentStackLow) + { + segmentStackLow = segmentStackDelta; + } + + switch (op.name) + { + case opcodeEnum::JUMP: + jumpFound = true; + segment << "\ + ;; jump\n\ + (set_local $jump_dest (call $check_overflow \n\ + (i64.load (get_global $sp))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 8)))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 16)))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n\ + (set_global $sp (i32.sub (get_global $sp) (i32.const 32)))\n\ + (br $loop)"; + opcodesUsed.insert(opcodeEnum::check_overflow); + pc = findNextJumpDest(evmCode, pc); + break; + case opcodeEnum::JUMPI: + jumpFound = true; + segment << "set_local $jump_dest (call $check_overflow \n\ + (i64.load (get_global $sp))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 8)))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 16)))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 24)))))\n\n\ + (set_global $sp (i32.sub (get_global $sp) (i32.const 64)))\n\ + (br_if $loop (i32.eqz (i64.eqz (i64.or\n\ + (i64.load (i32.add (get_global $sp) (i32.const 32)))\n\ + (i64.or\n\ + (i64.load (i32.add (get_global $sp) (i32.const 40)))\n\ + (i64.or\n\ + (i64.load (i32.add (get_global $sp) (i32.const 48)))\n\ + (i64.load (i32.add (get_global $sp) (i32.const 56)))\n\ + )\ + )\ + ))))\n"; + opcodesUsed.insert(opcodeEnum::check_overflow); + addStackCheck(); + addMetering(); + break; + case opcodeEnum::JUMPDEST: + endSegment(); + jumpSegments.push_back({.number = pc, .type = "jump_dest"}); + gasCount = 1; + break; + case opcodeEnum::GAS: + segment << "(call $GAS)\n"; + //addMetering(); // this causes an unreachable error in stackOverflowM1 -d 14 + break; + case opcodeEnum::LOG: + segment << "(call $LOG (i32.const " << op.number << "))\n"; + break; + case opcodeEnum::DUP: + case opcodeEnum::SWAP: + // adds the number on the stack to SWAP + segment << "(call ${opname} (i32.const {opnumber}))\n"_format( + "opname"_a = opcodeToString(op.name), "opnumber"_a = (op.number - 1)); + break; + case opcodeEnum::PC: + segment << "(call $PC (i32.const {pc}))\n"_format("pc"_a = pc); + break; + case opcodeEnum::PUSH: + { + pc++; + size_t sliceSize = std::min(op.number, 32ul); + std::vector bytes = std::vector(evmCode.begin() + pc, evmCode.begin() + pc + sliceSize); + + pc += op.number; + if (op.number < 32) + { + bytes.insert(bytes.begin(), 32 - op.number, 0); + } + + auto bytesRounded = ceil((double)op.number / 8.0); + fmt::MemoryWriter push; + int q = 0; + + // pad the remaining of the word with 0 + for (; q < 4 - bytesRounded; q++) + { + fmt::MemoryWriter pad; + pad << "(i64.const 0)"; + pad << push.str(); + push = std::move(pad); + } + + for (; q < 4; q++) + { + //TODO clean this disgusting mess up + + std::reverse(bytes.begin()+q*8, bytes.begin()+q*8+8); + + int64_t int64 = 0; + memcpy(&int64, &bytes[q*8], 8); + + push << "(i64.const {int64})"_format("int64"_a = int64); + } + + segment << fmt::format("(call $PUSH {push})", "push"_a = push.str()); + pc--; + break; + } + case opcodeEnum::POP: + // do nothing + break; + case opcodeEnum::STOP: + segment << "(br $done)"; + if (jumpFound) + { + pc = findNextJumpDest(evmCode, pc); + } + else + { + // the rest is dead code; + pc = evmCode.size(); + } + break; + case opcodeEnum::SELFDESTRUCT: + case opcodeEnum::RETURN: + segment << "(call $" << opcodeToString(op.name) << ") (br $done)\n"; + if (jumpFound) + { + pc = findNextJumpDest(evmCode, pc); + } + else + { + // the rest is dead code + pc = evmCode.size(); + } + break; + case opcodeEnum::INVALID: + segment.clear(); + segment << "(unreachable)"; + pc = findNextJumpDest(evmCode, pc); + break; + + default: + if (useAsyncAPI && callbackFuncs.find(op.name) != callbackFuncs.end()) + { + std::string cbFunc = (*callbackFuncs.find(op.name)).second; + auto result = std::find(std::begin(callbackTable), std::end(callbackTable), cbFunc); + size_t index = result - std::begin(callbackTable); + if (result == std::end(callbackTable)) + { + callbackTable.push_back(cbFunc); + index = callbackFuncs.size(); + } + segment << "(call ${opname} (i32.const {index}))\n"_format("opname"_a = opcodeToString(op.name), "index"_a = index); + } + else + { + // use synchronous API + segment << "(call ${opname})\n"_format("opname"_a = opcodeToString(op.name)); + } + break; + } + + if (ignoredOps.find(op.name) == std::end(ignoredOps)) + { + opcodesUsed.insert(op.name); + } + + auto stackDelta = op.on - op.off; + // update the stack pointer + if (stackDelta != 0) + { + segment << "(set_global $sp (i32.add (get_global $sp) (i32.const {stackDelta})))\n"_format( + "stackDelta"_a = stackDelta * 32); + } + + // adds the logic to save the stack pointer before exiting to wiat to for a callback + // note, this must be done before the sp is updated above^ + if (useAsyncAPI && callbackFuncs.find(op.name) != std::end(callbackFuncs)) + { + segment << "(set_global $cb_dest (i32.const {jumpSegmentsLength})) \ + (br $done))"_format("jumpSegmentsLength"_a = jumpSegments.size() + 1); + jumpSegments.push_back({.number = 0, .type = "cb_dest"}); + } + } + + endSegment(); + + std::string wastStr = wast.str(); + wast.clear(); + wast << assembleSegments(jumpSegments) << wastStr << "))"; + + auto wastFiles = wastSyncInterface; // default to synchronous interface + if (useAsyncAPI) + { + wastFiles = wastAsyncInterface; + } + + std::vector imports; + std::vector funcs; + // inline EVM opcode implemention + if (inlineOps) + { + std::tie(funcs, imports) = resolveFunctions(opcodesUsed, wastFiles); + } + + // import stack trace function + if (stackTrace) + { + imports.push_back("(import \"debug\" \"printMemHex\" (func $printMem (param i32 i32)))"); + imports.push_back("(import \"debug\" \"print\" (func $print (param i32)))"); + imports.push_back( + "(import \"debug\" \"evmTrace\" (func $stackTrace (param i32 i32 i32 i32)))"); + } + imports.push_back("(import \"ethereum\" \"useGas\" (func $useGas (param i64)))"); + + wastStr = wast.str(); + funcs.push_back(wastStr); + wastStr = buildModule(funcs, imports, callbackTable); + return wastStr; } string evmhex2wast(const string& input, bool tracing) { @@ -114,4 +433,387 @@ string evmhex2wasm(const string& input, bool tracing) { return evm2wasm(tmp, tracing); } +// given an array for segments builds a wasm module from those segments +// @param {Array} segments +// @return {String} +std::string assembleSegments(const std::vector& segments) +{ + auto wasm = buildJumpMap(segments); + + for (size_t index = 0; index < segments.size(); ++index) + { + wasm = "(block ${index} {wasm}"_format("index"_a = index + 1, "wasm"_a = wasm); + } + + std::string result = + "\ + (func $main\ + (export \"main\")\ + (local $jump_dest i32) (local $jump_map_switch i32)\ + (set_local $jump_dest (i32.const -1))\ +\ + (block $done\ + (loop $loop\ + {wasm}"_format("wasm"_a = wasm); + return result; +} + +std::string opcodeToString(opcodeEnum opcode) +{ + switch (opcode) + { + case opcodeEnum::STOP: + return "STOP"; + case opcodeEnum::ADD: + return "ADD"; + case opcodeEnum::MUL: + return "MUL"; + case opcodeEnum::SUB: + return "SUB"; + case opcodeEnum::DIV: + return "DIV"; + case opcodeEnum::SDIV: + return "SDIV"; + case opcodeEnum::MOD: + return "MOD"; + case opcodeEnum::SMOD: + return "SMOD"; + case opcodeEnum::ADDMOD: + return "ADDMOD"; + case opcodeEnum::MULMOD: + return "MULMOD"; + case opcodeEnum::EXP: + return "EXP"; + case opcodeEnum::SIGNEXTEND: + return "SIGNEXTEND"; + case opcodeEnum::LT: + return "LT"; + case opcodeEnum::GT: + return "GT"; + case opcodeEnum::SLT: + return "SLT"; + case opcodeEnum::SGT: + return "SGT"; + case opcodeEnum::EQ: + return "EQ"; + case opcodeEnum::ISZERO: + return "ISZERO"; + case opcodeEnum::AND: + return "AND"; + case opcodeEnum::OR: + return "OR"; + case opcodeEnum::XOR: + return "XOR"; + case opcodeEnum::NOT: + return "NOT"; + case opcodeEnum::BYTE: + return "BYTE"; + case opcodeEnum::SHA3: + return "SHA3"; + case opcodeEnum::ADDRESS: + return "ADDRESS"; + case opcodeEnum::BALANCE: + return "BALANCE"; + case opcodeEnum::ORIGIN: + return "ORIGIN"; + case opcodeEnum::CALLER: + return "CALLER"; + case opcodeEnum::CALLVALUE: + return "CALLVALUE"; + case opcodeEnum::CALLDATALOAD: + return "CALLDATALOAD"; + case opcodeEnum::CALLDATASIZE: + return "CALLDATASIZE"; + case opcodeEnum::CALLDATACOPY: + return "CALLDATACOPY"; + case opcodeEnum::CODESIZE: + return "CODESIZE"; + case opcodeEnum::CODECOPY: + return "CODECOPY"; + case opcodeEnum::GASPRICE: + return "GASPRICE"; + case opcodeEnum::EXTCODESIZE: + return "EXTCODESIZE"; + case opcodeEnum::EXTCODECOPY: + return "EXTCODECOPY"; + case opcodeEnum::BLOCKHASH: + return "BLOCKHASH"; + case opcodeEnum::COINBASE: + return "COINBASE"; + case opcodeEnum::TIMESTAMP: + return "TIMESTAMP"; + case opcodeEnum::NUMBER: + return "NUMBER"; + case opcodeEnum::DIFFICULTY: + return "DIFFICULTY"; + case opcodeEnum::GASLIMIT: + return "GASLIMIT"; + case opcodeEnum::POP: + return "POP"; + case opcodeEnum::MLOAD: + return "MLOAD"; + case opcodeEnum::MSTORE: + return "MSTORE"; + case opcodeEnum::MSTORE8: + return "MSTORE8"; + case opcodeEnum::SLOAD: + return "SLOAD"; + case opcodeEnum::SSTORE: + return "SSTORE"; + case opcodeEnum::JUMP: + return "JUMP"; + case opcodeEnum::JUMPI: + return "JUMPI"; + case opcodeEnum::PC: + return "PC"; + case opcodeEnum::MSIZE: + return "MSIZE"; + case opcodeEnum::GAS: + return "GAS"; + case opcodeEnum::JUMPDEST: + return "JUMPDEST"; + case opcodeEnum::PUSH: + return "PUSH"; + case opcodeEnum::DUP: + return "DUP"; + case opcodeEnum::SWAP: + return "SWAP"; + case opcodeEnum::LOG: + return "LOG"; + case opcodeEnum::CREATE: + return "CREATE"; + case opcodeEnum::CALL: + return "CALL"; + case opcodeEnum::CALLCODE: + return "CALLCODE"; + case opcodeEnum::RETURN: + return "RETURN"; + case opcodeEnum::DELEGATECALL: + return "DELEGATECALL"; + case opcodeEnum::SELFDESTRUCT: + return "SELFDESTRUCT"; + default: + abort(); + } +} + +Op opcodes(int op) +{ + auto result = codes.find(op); + std::tuple code; + if (result == std::end(codes)) + { + code = std::make_tuple(opcodeEnum::INVALID, 0, 0, 0); + } + else + { + code = (*result).second; + }; + auto opcode = std::get<0>(code); + unsigned int number; + + switch (opcode) + { + case opcodeEnum::LOG: + number = op - 0xa0; + break; + + case opcodeEnum::PUSH: + number = op - 0x5f; + break; + + case opcodeEnum::DUP: + number = op - 0x7f; + break; + + case opcodeEnum::SWAP: + number = op - 0x8f; + break; + + default: + number = -1; + } + + return {opcode, std::get<1>(code), std::get<2>(code), std::get<3>(code), number}; +} + +// returns the index of the next jump destination opcode in given EVM code in an +// array and a starting index +// @param {Array} evmCode +// @param {Integer} index +// @return {Integer} +size_t findNextJumpDest(const std::vector& evmCode, size_t i) +{ + for (; i < evmCode.size(); i++) + { + auto opint = evmCode[i]; + auto op = opcodes(opint); + switch (op.name) + { + case opcodeEnum::PUSH: + // skip add how many bytes where pushed + i += op.number; + break; + case opcodeEnum::JUMPDEST: + return --i; + default: + break; + } + } + return --i; +} + +// Ensure that dependencies are only imported once (use the Set) +// @param {Set} funcSet a set of wasm function that need to be linked to their dependencies +// @return {Set} +std::set resolveFunctionDeps(const std::set& funcSet) +{ + std::set funcs = funcSet; + for (auto&& func : funcs) + { + auto deps = depMap.find(func); + if (deps != depMap.end()) + { + for (auto&& dep : (*deps).second) + { + funcs.insert(dep); + } + } + } + return funcs; +} + +/** + * given a Set of wasm function this return an array for wasm equivalents + * @param {Set} funcSet + * @return {Array} + */ +std::tuple, std::vector> resolveFunctions( + const std::set& funcSet, std::map wastFiles) +{ + std::vector funcs; + std::vector imports; + for (auto&& func : resolveFunctionDeps(funcSet)) + { + funcs.push_back(wastFiles[func].wast); + imports.push_back(wastFiles[func].imports); + } + return std::tuple, std::vector>{funcs, imports}; +} + +/** + * builds a wasm module + * @param {Array} funcs the function to include in the module + * @param {Array} imports the imports for the module's import table + * @return {string} + */ +std::string buildModule(const std::vector& funcs, + const std::vector& imports, const std::vector& callbacks) +{ + fmt::MemoryWriter funcBuf; + for (auto&& func : funcs) + { + funcBuf << func; + } + + fmt::MemoryWriter callbackTableBuf; + if (callbacks.size() > 0) + { + fmt::MemoryWriter callbacksBuf; + callbacksBuf.write(callbacks[0]); + for (size_t i = 1; i < callbacks.size(); ++i) + { + callbacksBuf << " " << callbacks[i]; + } + callbackTableBuf << "\ + (table\n\ + (export \"callback\") ;; name of table\n\ + anyfunc\n\ + (elem {callbacksStr}) ;; elements will have indexes in order\n\ + )"_format("callbacksStr"_a = callbacksBuf.str()); + } + + fmt::MemoryWriter importsBuf; + if (imports.size() > 0) + { + importsBuf << imports[0]; + for (size_t i = 1; i < imports.size(); ++i) + { + importsBuf << "\n" << imports[i]; + } + } + + return "\ +(module\n\ + {importsStr}\n\ + (global $cb_dest (mut i32) (i32.const 0))\n\ + (global $sp (mut i32) (i32.const -32))\n\ + (global $init (mut i32) (i32.const 0))\n\ +\n\ + ;; memory related global\n\ + (global $memstart i32 (i32.const 33832))\n\ + ;; the number of 256 words stored in memory\n\ + (global $wordCount (mut i64) (i64.const 0))\n\ + ;; what was charged for the last memory allocation\n\ + (global $prevMemCost (mut i64) (i64.const 0))\n\ +\n\ + ;; TODO: memory should only be 1, but can\'t resize right now\n\ + (memory 500)\n\ + (export \"memory\" (memory 0))\n\ +\n\ + {callbackTableStr}\n\ +\n\ + {funcStr}\n\ +)"_format("importsStr"_a = importsBuf.str(), "callbackTableStr"_a = callbackTableBuf.str(), + "funcStr"_a = funcBuf.str()); +} + +// Builds the Jump map, which maps EVM jump location to a block label +// @param {Array} segments +// @return {String} +std::string buildJumpMap(const std::vector& segments) +{ + fmt::MemoryWriter wasmBuf; + wasmBuf << "(unreachable)"; + + fmt::MemoryWriter brTableBuf; + for (size_t index = 0; index < segments.size(); ++index) + { + auto&& seg = segments[index]; + brTableBuf << " $" << (index + 1); + if (seg.type == "jump_dest") + { + std::string wasmStr = wasmBuf.str(); + wasmBuf.clear(); + wasmBuf << "(if (i32.eq (get_local $jump_dest) (i32.const {segnumber}))\ + (then (br {index}))\ + (else {wasm}))"_format( + "segnumber"_a = seg.number, "index"_a = index + 1, "wasm"_a = wasmBuf.str()); + } + } + + std::string wasmStr = wasmBuf.str(); + wasmBuf.clear(); + wasmBuf << "\ + (block $0\n\ + (if\n\ + (i32.eqz (get_global $init))\n\ + (then\n\ + (set_global $init (i32.const 1))\n\ + (br $0))\n\ + (else\n\ + ;; the callback dest can never be in the first block\n\ + (if (i32.eq (get_global $cb_dest) (i32.const 0)) \n\ + (then\n\ + {wasm}\n\ + )\n\ + (else \n\ + ;; return callback destination and zero out $cb_dest \n\ + (set_local $jump_map_switch (get_global $cb_dest)) \n\ + (set_global $cb_dest (i32.const 0))\n\ + (br_table $0 {brTable} (get_local $jump_map_switch))\n\ + )))))"_format("wasm"_a = wasmStr, "brTable"_a = brTableBuf.str()); + + return wasmBuf.str(); } +}; diff --git a/tools/evm2wasm/main.cpp b/tools/evm2wasm/main.cpp index 8dc55bfe..011ffdfd 100644 --- a/tools/evm2wasm/main.cpp +++ b/tools/evm2wasm/main.cpp @@ -8,6 +8,7 @@ using namespace std; + int main(int argc, char **argv) { if (argc < 2) { cerr << "Usage: " << argv[0] << " [--wast]" << endl; diff --git a/wasm/generateInterface.js b/wasm/generateInterface.js index 70196360..a6532b41 100644 --- a/wasm/generateInterface.js +++ b/wasm/generateInterface.js @@ -427,6 +427,47 @@ function generateManifest (interfaceManifest, opts) { return json } +function generateCPPHeader(interfaceManifest, opts) { + function quoteString(str) { + // from https://stackoverflow.com/questions/770523/escaping-strings-in-javascript + return JSON.stringify(str).slice(1, -1); + } + + function escapeNewlines(str) { + return str.replace(/\n/gi, '\n') + } + + let entries = [] + + for (let opcode in interfaceManifest) { + const wast = quoteString(escapeNewlines(interfaceManifest[opcode].wast)) + const imports = quoteString(escapeNewlines(interfaceManifest[opcode].imports || "")) + + entries.push(`{ + opcodeEnum::${opcode}, { + .wast = "${wast}", + .imports = "${imports}" + } +}`) + } + + const interfaceName = opts.useAsyncAPI ? 'wastAsyncInterface' : 'wastSyncInterface' + + return `#pragma once + +#include + +#include "evm2wasm.h" + +namespace evm2wasm +{ + static std::map ${interfaceName} = + { + ${entries.join()} + }; +}` +} + // generateManifest mutates the input, so use a copy const interfaceManifestCopy = JSON.parse(JSON.stringify(interfaceManifest)) @@ -435,3 +476,7 @@ let asyncInterfaceJson = generateManifest(interfaceManifestCopy, {'useAsyncAPI': fs.writeFileSync(path.join(__dirname, 'wast.json'), JSON.stringify(syncJson, null, 2)) fs.writeFileSync(path.join(__dirname, 'wast-async.json'), JSON.stringify(asyncInterfaceJson, null, 2)) + +// generate C++ header +fs.writeFileSync(path.join(__dirname, '../include/wast.h'), generateCPPHeader(syncJson, {'useAsyncAPI': false})) +fs.writeFileSync(path.join(__dirname, '../include/wast-async.h'), generateCPPHeader(asyncInterfaceJson, {'useAsyncAPI': true}))