diff --git a/.clang-format b/.clang-format index 2fa1f67a..12d0e405 100644 --- a/.clang-format +++ b/.clang-format @@ -4,22 +4,19 @@ AlignConsecutiveAssignments: 'true' AlignConsecutiveDeclarations: 'false' AlignEscapedNewlines: Right AlignOperands: 'false' -AlignTrailingComments: 'true' +AlignTrailingComments: 'false' AllowAllParametersOfDeclarationOnNextLine: 'false' AllowShortBlocksOnASingleLine: 'false' AllowShortCaseLabelsOnASingleLine: 'true' AllowShortFunctionsOnASingleLine: None -AllowShortIfStatementsOnASingleLine: 'true' AllowShortLoopsOnASingleLine: 'false' AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: 'false' -AlwaysBreakTemplateDeclarations: 'true' BinPackArguments: 'true' BinPackParameters: 'true' BreakAfterJavaFieldAnnotations: 'true' BreakBeforeBinaryOperators: None -BreakBeforeBraces: Stroustrup -BreakBeforeInheritanceComma: 'false' +BreakBeforeBraces: Allman BreakBeforeTernaryOperators: 'false' BreakConstructorInitializers: BeforeColon BreakStringLiterals: 'false' @@ -56,4 +53,4 @@ SpacesInParentheses: 'false' SpacesInSquareBrackets: 'false' Standard: Cpp11 TabWidth: '2' -UseTab: Never \ No newline at end of file +UseTab: Never diff --git a/.gitignore b/.gitignore index 04985b7f..7518f4e9 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ ._.DS_Store Thumbs.db ._* -.idea \ No newline at end of file +.idea +.vs/* \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 3f183c8e..a151f1ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,17 +1,21 @@ -cmake_minimum_required(VERSION 2.8.6) +cmake_minimum_required(VERSION 3.5) PROJECT(Zano) set(VERSION "1.0") -# if(POLICY CMP0043) -# cmake_policy(SET CMP0043 OLD) -# endif() +if(POLICY CMP0043) + cmake_policy(SET CMP0043 NEW) +endif() +if(POLICY CMP0043) + cmake_policy(SET CMP0074 NEW) +endif() + + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -# if(POLICY CMP0020) -# cmake_policy(SET CMP0020 OLD) -# endif() if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android") add_definitions(-DMOBILE_WALLET_BUILD) @@ -50,9 +54,12 @@ message("Generated with config types: ${CMAKE_CONFIGURATION_TYPES}, and built ty enable_testing() +set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically +find_package(OpenSSL REQUIRED) + if(APPLE) - set(CMAKE_OSX_DEPLOYMENT_TARGET 10.10.5) + set(CMAKE_OSX_DEPLOYMENT_TARGET 10.12) endif() set(USE_PCH FALSE CACHE BOOL "Use shared precompiled headers") @@ -60,7 +67,7 @@ set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect su set(TESTNET FALSE CACHE BOOL "Compile for testnet") set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon") -include_directories(src contrib/eos_portable_archive contrib contrib/epee/include "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") +include_directories(src contrib/eos_portable_archive contrib contrib/epee/include ${OPENSSL_INCLUDE_DIR} "${CMAKE_BINARY_DIR}/version" "${CMAKE_BINARY_DIR}/contrib/zlib") add_definitions(-DSTATICLIB) @@ -69,6 +76,11 @@ if(TESTNET) add_definitions(-DTESTNET) endif() +if(CAKEWALLET) + message("NOTICE: Building libraries for CAKEWALLET") + add_definitions(-DCAKEWALLET) +endif() + set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically find_package(OpenSSL REQUIRED) @@ -90,9 +102,9 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") endif() if(MSVC) - add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0 /D__SSE4_1__") + add_definitions("/D_CRT_SECURE_NO_WARNINGS /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN /DGTEST_HAS_TR1_TUPLE=0") add_compile_options(/bigobj /Zm1000 /Z7 /MP2 /W3 /GS- /wd4996 /wd4503 /wd4345 /wd4091 /FIinline_c.h) - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:10485760 /DEBUG dbghelp.lib crypt32.lib") if(STATIC) foreach(VAR CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE) string(REPLACE "/MD" "/MT" ${VAR} "${${VAR}}") @@ -106,7 +118,7 @@ else() else() set(ARCH_FLAG "-march=${ARCH}") endif() - set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return") + set(WARNINGS "-Wall -Wextra -Wpointer-arith -Wvla -Wwrite-strings -Wno-error=extra -Wno-error=deprecated-declarations -Wno-error=sign-compare -Wno-error=strict-aliasing -Wno-error=type-limits -Wno-unused-parameter -Wno-error=unused-variable -Wno-aggregate-return -Wno-comment -Wno-unknown-pragmas -Wno-pragmas") # if(NOT APPLE) # set(WARNINGS "${WARNINGS} -Werror") # endif() @@ -138,16 +150,16 @@ else() else() set(APPLE_FLAG "") endif() - set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes") + set(C_WARNINGS "-Waggregate-return -Wnested-externs -Wstrict-prototypes -Wno-comment") set(CXX_WARNINGS "-Wno-reorder -Wno-missing-field-initializers") - try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c11") + try_compile(STATIC_ASSERT_RES "${CMAKE_CURRENT_BINARY_DIR}/static-assert" "${CMAKE_CURRENT_SOURCE_DIR}/utils/test-static-assert.c" COMPILE_DEFINITIONS "-std=c++14") if(STATIC_ASSERT_RES) set(STATIC_ASSERT_FLAG "") else() set(STATIC_ASSERT_FLAG "-Dstatic_assert=_Static_assert") endif() set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 -D_GNU_SOURCE ${MINGW_FLAG} ${STATIC_ASSERT_FLAG} ${WARNINGS} ${C_WARNINGS} ${ARCH_FLAG}") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++11 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fpermissive -ftemplate-depth-1024 -std=c++14 -D_GNU_SOURCE ${APPLE_FLAG} ${MINGW_FLAG} ${WARNINGS} ${CXX_WARNINGS} ${ARCH_FLAG}") if (NOT APPLE AND NOT MSVC) if (CLANG) set(LLVM_USE_LINKER "gold") @@ -182,6 +194,11 @@ else() endif() +# always use local Boost installation rather than the system-wide (unless ZANO_USE_SYSTEM_BOOST is defined for some reason, which is not recommended) +if(NOT DEFINED ENV{ZANO_USE_SYSTEM_BOOST}) + set(Boost_NO_SYSTEM_PATHS ON) +endif() + if(MSVC) set(Boost_USE_STATIC_LIBS ON) endif() @@ -204,8 +221,10 @@ if(CMAKE_SYSTEM_NAME STREQUAL "iOS") elseif(CMAKE_SYSTEM_NAME STREQUAL "Android") set(Boost_LIBRARY_DIRS "${Boost_LIBRARY_DIRS}/${CMAKE_ANDROID_ARCH_ABI}/") set(Boost_LIBRARIES "${Boost_LIBRARY_DIRS}libboost_system.a;${Boost_LIBRARY_DIRS}libboost_filesystem.a;${Boost_LIBRARY_DIRS}libboost_thread.a;${Boost_LIBRARY_DIRS}libboost_timer.a;${Boost_LIBRARY_DIRS}libboost_date_time.a;${Boost_LIBRARY_DIRS}libboost_chrono.a;${Boost_LIBRARY_DIRS}libboost_regex.a;${Boost_LIBRARY_DIRS}libboost_serialization.a;${Boost_LIBRARY_DIRS}libboost_atomic.a;${Boost_LIBRARY_DIRS}libboost_program_options.a") +elseif(APPLE) + find_package(Boost 1.71 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) else() - find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale) + find_package(Boost 1.70 REQUIRED COMPONENTS system filesystem thread timer date_time chrono regex serialization atomic program_options locale log) endif() @@ -227,7 +246,7 @@ elseif(NOT MSVC) endif() if(BUILD_GUI) - cmake_minimum_required(VERSION 2.8.11) + cmake_minimum_required(VERSION 3.1) find_package(Qt5Widgets REQUIRED) endif() diff --git a/README.md b/README.md index 13558e5f..1b661e0a 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,13 @@ Be sure to clone the repository properly:\ ### Dependencies | component / version | minimum
(not recommended but may work) | recommended | most recent of what we have ever tested | |--|--|--|--| -| gcc (Linux) | 5.4.0 | 7.5.0 | 8.3.0 | +| gcc (Linux) | 5.4.0 | 9.4.0 | 12.3.0 | | llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 | -| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2017 (15.9.0) | 2022 (17.4.2) | -| [XCode](https://developer.apple.com/downloads/) (macOS) | 9.2 | 12.3 | 12.3 | -| [CMake](https://cmake.org/download/) | 2.8.6 | 3.15.5 | 3.26.3 | +| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2017 (15.9.30) | 2017 (15.9.30) | 2022 (17.7.5) | +| [XCode](https://developer.apple.com/downloads/) (macOS) | 12.3 | 14.3 | 14.3 | +| [CMake](https://cmake.org/download/) | 3.15.5 | 3.22.1 | 3.26.3 | | [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.76 | -| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | - | 1.1.1n | 1.1.1n | +| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | 1.1.1n | 1.1.1w | 1.1.1w | | [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 | Note:\ @@ -30,27 +30,37 @@ Note:\ ### Linux -Recommended OS version: Ubuntu 18.04 LTS. +Recommended OS versions: Ubuntu 20.04, 22.04 LTS. 1. Prerequisites [*server version*] - sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev + sudo apt-get install -y build-essential g++ curl autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev [*GUI version*] sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen checkinstall zlib1g-dev mesa-common-dev libglu1-mesa-dev -2. Download and build Boost +2. Clone Zano into a local folder\ + (If for some reason you need to use alternative Zano branch, change 'master' to the required branch name.) + + git clone --recursive https://github.com/hyle-team/zano.git -b master + + In the following steps we assume that you cloned Zano into '~/zano' folder in your home directory. + +3. Download and build Boost\ + (Assuming you have cloned Zano into the 'zano' folder. If you used a different location for Zano, **edit line 4** accordingly.) curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2 echo "430ae8354789de4fd19ee52f3b1f739e1fba576f0aded0897c3c2bc00fb38778 boost_1_70_0.tar.bz2" | shasum -c && tar -xjf boost_1_70_0.tar.bz2 - cd boost_1_70_0 + rm boost_1_70_0.tar.bz2 && cd boost_1_70_0 + patch -p0 < ../zano/utils/boost_1.70_gcc_8.patch || cd .. ./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log - ./b2 + ./b2 && cd .. + Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end. -3. Install Qt\ +4. Install Qt\ (*GUI version only, skip this step if you're building server version*) [*GUI version*] @@ -61,20 +71,19 @@ Recommended OS version: Ubuntu 18.04 LTS. Then follow the instructions in Wizard. Don't forget to tick the WebEngine module checkbox! -4. Install OpenSSL +5. Install OpenSSL - We recommend installing OpenSSL v1.1.1n locally unless you would like to use the same version system-wide. Adjust the local path `/home/user/openssl` in the commands below according to your needs. + We recommend installing OpenSSL v1.1.1w locally unless you would like to use the same version system-wide.\ + (Assuming that `$HOME` environment variable is set to your home directory. Otherwise, edit line 4 accordingly.) - curl -OL https://www.openssl.org/source/openssl-1.1.1n.tar.gz - echo "40dceb51a4f6a5275bde0e6bf20ef4b91bfc32ed57c0552e2e8e15463372b17a openssl-1.1.1n.tar.gz" | shasum -c && tar xaf openssl-1.1.1n.tar.gz - cd openssl-1.1.1n/ - ./config --prefix=/home/user/openssl --openssldir=/home/user/openssl shared zlib - make - make test - make install + curl -OL https://www.openssl.org/source/openssl-1.1.1w.tar.gz + echo "cf3098950cb4d853ad95c0841f1f9c6d3dc102dccfcacd521d93925208b76ac8 openssl-1.1.1w.tar.gz" | shasum -c && tar xaf openssl-1.1.1w.tar.gz + cd openssl-1.1.1w/ + ./config --prefix=$HOME/openssl --openssldir=$HOME/openssl shared zlib + make && make test && make install && cd .. -5. Set environment variables properly\ +6. [*OPTIONAL*] Set global environment variables for convenient use\ For instance, by adding the following lines to `~/.bashrc` [*server version*] @@ -89,18 +98,27 @@ For instance, by adding the following lines to `~/.bashrc` export OPENSSL_ROOT_DIR=/home/user/openssl export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64 - - -6. Build the binaries - 1. Build daemon and simplewallet: - - cd zano/ && make -j1 - or + **NOTICE: Please edit the lines above according to your actual paths.** + **NOTICE 2:** Make sure you've restarted your terminal session (by reopening the terminal window or reconnecting the server) to apply these changes. + +8. Build the binaries + 1. If you skipped step 6 and did not set the environment variables: + + cd zano && mkdir build && cd build + BOOST_ROOT=$HOME/boost_1_70_0 OPENSSL_ROOT_DIR=$HOME/openssl cmake .. + make -j1 daemon simplewallet + + 2. If you set the variables in step 6: + cd zano && mkdir build && cd build cmake .. make -j1 daemon simplewallet + or simply: + + cd zano && make -j1 + **NOTICE**: If you are building on a machine with a relatively high amount of RAM or with the proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution. **NOTICE 2**: If you'd like to build binaries for the testnet, use `cmake -D TESTNET=TRUE ..` instead of `cmake ..` . @@ -110,12 +128,12 @@ For instance, by adding the following lines to `~/.bashrc` cd zano utils/build_script_linux.sh -7. Look for the binaries in `build` folder + Look for the binaries in `build` folder
### Windows -Recommended OS version: Windows 7 x64. +Recommended OS version: Windows 7 x64, Windows 11 x64. 1. Install required prerequisites (Boost, Qt, CMake, OpenSSL). 2. Edit paths in `utils/configure_local_paths.cmd`. 3. Run one of `utils/configure_win64_msvsNNNN_gui.cmd` according to your MSVC version. diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt index 601672d5..a3220829 100644 --- a/contrib/CMakeLists.txt +++ b/contrib/CMakeLists.txt @@ -28,7 +28,7 @@ endif() set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTY FOLDER "unused") if(MSVC) - set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused") + #set_property(TARGET ntdll_extra_target PROPERTY FOLDER "unused") endif() diff --git a/contrib/db/libmdbx/src/CMakeLists.txt b/contrib/db/libmdbx/src/CMakeLists.txt index 04aead5f..7dfc94aa 100644 --- a/contrib/db/libmdbx/src/CMakeLists.txt +++ b/contrib/db/libmdbx/src/CMakeLists.txt @@ -45,61 +45,6 @@ if(CC_HAS_VISIBILITY AND (LTO_ENABLED OR INTERPROCEDURAL_OPTIMIZATION)) set_target_properties(mdbx PROPERTIES LINK_FLAGS "-fvisibility=hidden") endif() -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - if(MSVC) - if(NOT MSVC_LIB_EXE) - # Find lib.exe - get_filename_component(CL_NAME ${CMAKE_C_COMPILER} NAME) - string(REPLACE cl.exe lib.exe MSVC_LIB_EXE ${CL_NAME}) - find_program(MSVC_LIB_EXE ${MSVC_LIB_EXE}) - endif() - if(MSVC_LIB_EXE) - message(STATUS "Found MSVC's lib tool: ${MSVC_LIB_EXE}") - set(MDBX_NTDLL_EXTRA_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.lib) - add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB} - COMMENT "Create extra-import-library for ntdll.dll" - MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" - COMMAND ${MSVC_LIB_EXE} /def:"${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" /out:"${MDBX_NTDLL_EXTRA_IMPLIB}" ${INITIAL_CMAKE_STATIC_LINKER_FLAGS}) - else() - message(SEND_ERROR "MSVC's lib tool not found") - endif() - elseif(MINGW OR MINGW64) - if(NOT DLLTOOL) - # Find dlltool - get_filename_component(GCC_NAME ${CMAKE_C_COMPILER} NAME) - string(REPLACE gcc dlltool DLLTOOL_NAME ${GCC_NAME}) - find_program(DLLTOOL NAMES ${DLLTOOL_NAME}) - endif() - if(DLLTOOL) - message(STATUS "Found dlltool: ${DLLTOOL}") - set(MDBX_NTDLL_EXTRA_IMPLIB "${CMAKE_CURRENT_BINARY_DIR}/mdbx_ntdll_extra.a") - add_custom_command(OUTPUT ${MDBX_NTDLL_EXTRA_IMPLIB} - COMMENT "Create extra-import-library for ntdll.dll" - MAIN_DEPENDENCY "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" - COMMAND ${DLLTOOL} -d "${CMAKE_CURRENT_SOURCE_DIR}/elements/ntdll.def" -l "${MDBX_NTDLL_EXTRA_IMPLIB}") - else() - message(SEND_ERROR "dlltool not found") - endif() - endif() -endif() - -target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ${CMAKE_THREAD_LIBS_INIT}) -if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") - target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll.lib) - if(MDBX_NTDLL_EXTRA_IMPLIB) - # LY: Sometimes Cmake requires a nightmarish magic for simple things. - # 1) create a target out of the library compilation result - add_custom_target(ntdll_extra_target DEPENDS ${MDBX_NTDLL_EXTRA_IMPLIB}) - # 2) create an library target out of the library compilation result - add_library(ntdll_extra STATIC IMPORTED GLOBAL) - add_dependencies(ntdll_extra ntdll_extra_target) - # 3) specify where the library is (and where to find the headers) - set_target_properties(ntdll_extra - PROPERTIES - IMPORTED_LOCATION ${MDBX_NTDLL_EXTRA_IMPLIB}) - target_link_libraries(mdbx ${MDBX_LIBDEP_MODE} ntdll_extra) - endif() -endif() set_target_properties(mdbx PROPERTIES INTERPROCEDURAL_OPTIMIZATION $ diff --git a/contrib/db/libmdbx/src/elements/internals.h b/contrib/db/libmdbx/src/elements/internals.h index 6aba3740..48ac8f41 100644 --- a/contrib/db/libmdbx/src/elements/internals.h +++ b/contrib/db/libmdbx/src/elements/internals.h @@ -54,7 +54,7 @@ #endif #if MDBX_DISABLE_GNU_SOURCE #undef _GNU_SOURCE -#elif defined(__linux__) || defined(__gnu_linux__) +#elif ( defined(__linux__) || defined(__gnu_linux__) ) && !defined(_GNU_SOURCE) #define _GNU_SOURCE #endif diff --git a/contrib/epee/include/misc_helpers.h b/contrib/epee/include/misc_helpers.h index dd3067c8..58ddc3cd 100644 --- a/contrib/epee/include/misc_helpers.h +++ b/contrib/epee/include/misc_helpers.h @@ -54,18 +54,19 @@ catch(const std::exception& ex) \ { \ (void)(ex); \ - LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \ custom_code; \ + LOG_ERROR("Exception at [" << location << "], what=" << ex.what()); \ return return_val; \ } \ catch(...) \ { \ - LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \ custom_code; \ + LOG_ERROR("Exception at [" << location << "], generic exception \"...\""); \ return return_val; \ } #define CATCH_ENTRY(location, return_val) CATCH_ENTRY_CUSTOM(location, (void)0, return_val) #define CATCH_ENTRY2(return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, (void)0, return_val) +#define CATCH_ENTRY_CUSTOM2(custom_code, return_val) CATCH_ENTRY_CUSTOM(LOCATION_SS, custom_code, return_val) #define CATCH_ENTRY_L0(location, return_val) CATCH_ENTRY(location, return_val) #define CATCH_ENTRY_L1(location, return_val) CATCH_ENTRY(location, return_val) diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h index 1389ba03..5855d977 100644 --- a/contrib/epee/include/misc_language.h +++ b/contrib/epee/include/misc_language.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "include_base_utils.h" #include "auto_val_init.h" @@ -273,6 +274,21 @@ namespace misc_utils } } + uint64_t get_avg() const + { + CRITICAL_REGION_LOCAL(m_lock); + if (!queued_items.size()) + return 0; + + uint64_t summ = 0; + for (const auto& item : queued_items) + { + summ += *item.first; + } + + return summ / queued_items.size(); + } + template friend std::ostream & operator<< (std::ostream &out, median_helper const &mh); }; // class median_helper @@ -291,26 +307,25 @@ namespace misc_utils /************************************************************************/ /* */ /************************************************************************/ - template - type_vec_type median(std::vector &v) + template + typename container_t::value_type median(container_t &v) { - //CRITICAL_REGION_LOCAL(m_lock); + typename container_t::value_type median{}; if(v.empty()) - return boost::value_initialized(); + return median; if(v.size() == 1) return v[0]; - size_t n = (v.size()) / 2; - std::sort(v.begin(), v.end()); - //nth_element(v.begin(), v.begin()+n-1, v.end()); - if(v.size()%2) - {//1, 3, 5... - return v[n]; - }else - {//2, 4, 6... - return (v[n-1] + v[n])/2; + auto median_it = v.begin() + v.size() / 2; + std::nth_element(v.begin(), median_it, v.end()); + median = *median_it; + if (v.size() % 2 == 0) + { + auto max_it = std::max_element(v.begin(), median_it); // it's garanteed that after nth_element() the necessary element is in this interval + median = (median + *max_it) / 2; // average of [size/2-1] and [size/2] elements } + return median; } /************************************************************************/ @@ -372,6 +387,11 @@ namespace misc_utils virtual void do_call(){}; }; + template + struct call_basic_param + { + virtual void do_call(param_t& p) {}; + }; template struct call_specific: public call_basic @@ -386,12 +406,34 @@ namespace misc_utils t_callback m_cb; }; + template + struct call_specific_param : public call_basic_param + { + call_specific_param(t_callback cb) :m_cb(cb) + {} + virtual void do_call(const param_t& p) + { + m_cb(p); + } + private: + t_callback m_cb; + }; + + + template auto build_abstract_callback(t_callback cb) -> std::shared_ptr { return std::shared_ptr(new call_specific(cb)); } + + template + auto build_abstract_callback_param(t_callback cb) -> std::shared_ptr> + { + return std::shared_ptr>(new call_specific_param(cb)); + } + template @@ -427,6 +469,71 @@ namespace misc_utils return res.first; } + + class events_dispatcher + { + + public: + + template + struct callback_entry + { + std::shared_ptr > m_cb; + }; + + std::map m_callbacks; + + template + void SUBSCIRBE_DEBUG_EVENT(callback_t cb) + { + std::type_index ti = typeid(param_t); + auto it = m_callbacks.find(ti); + if (it != m_callbacks.end()) + { + throw std::runtime_error("Handler for this type already registered"); + } + + callback_entry cb_entry = { epee::misc_utils::build_abstract_callback_param(cb) }; + + m_callbacks[ti] = cb_entry; + } + + template + void UNSUBSCRIBE_DEBUG_EVENT() + { + std::type_index ti = typeid(param_t); + auto it = m_callbacks.find(ti); + if (it != m_callbacks.end()) + { + m_callbacks.erase(it); + } + } + + void UNSUBSCRIBE_ALL() + { + m_callbacks.clear(); + } + + template + void RAISE_DEBUG_EVENT(const param_t& p) + { + std::type_index ti = typeid(param_t); + auto it = m_callbacks.find(ti); + if (it != m_callbacks.end()) + { + callback_entry* pcallback_entry = boost::any_cast>(&it->second); + if (!pcallback_entry) + { + throw std::runtime_error("Unexpected error: registered tipe holding something else in boost::eny"); + } + pcallback_entry->m_cb->do_call(p); + } + } + + }; + + + } // namespace misc_utils } // namespace epee diff --git a/contrib/epee/include/misc_log_ex.h b/contrib/epee/include/misc_log_ex.h index 0b957a5f..318237c9 100644 --- a/contrib/epee/include/misc_log_ex.h +++ b/contrib/epee/include/misc_log_ex.h @@ -116,29 +116,29 @@ DISABLE_VS_WARNINGS(4100) #define ENABLE_CHANNEL_BY_DEFAULT(ch_name) \ static bool COMBINE(init_channel, __LINE__) UNUSED_ATTRIBUTE = epee::misc_utils::static_initializer([](){ \ - epee::log_space::log_singletone::enable_channel(ch_name); return true; \ + epee::log_space::log_singletone::enable_channel(ch_name, false); return true; \ }); #if defined(ENABLE_LOGGING_INTERNAL) -#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_PREFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x << std::endl; epee::log_space::log_singletone::do_log_message(ss________.str() , y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_PREFIX_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_NO_POSTFIX2(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x; epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL2_CB(log_channel, log_name, x, y, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, false, log_name);cb(ss________.str());CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_COLOR2_CB(log_channel, log_name, x, y, color, cb) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, color, false, log_name); cb(ss________.str());CATCH_ALL_DO_NOTHING();}} -#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( y <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ +#define LOG_PRINT_CHANNEL_2_JORNAL(log_channel, log_name, x, y) {if ( (y) <= epee::log_space::log_singletone::get_log_detalisation_level() && epee::log_space::log_singletone::channel_enabled(log_channel))\ {TRY_ENTRY();std::stringstream ss________; ss________ << epee::log_space::log_singletone::get_prefix_entry() << x << std::endl;epee::log_space::log_singletone::do_log_message(ss________.str(), y, epee::log_space::console_color_default, true, log_name);CATCH_ALL_DO_NOTHING();}} #define LOG_ERROR2_CB(log_name, x, cb) { \ @@ -556,8 +556,11 @@ namespace log_space else m_have_to_kill_console = false; - ::AllocConsole(); - freopen("CONOUT$", "w", stdout); + if (m_have_to_kill_console) + { + ::AllocConsole(); + freopen("CONOUT$", "w", stdout); + } std::cout.clear(); #endif } @@ -1236,21 +1239,24 @@ namespace log_space return genabled_channels.find(ch_name) != genabled_channels.end(); } - static void enable_channels(const std::string& channels_set) + static void enable_channels(const std::string& channels_set, bool verbose = true) { std::set& genabled_channels = get_enabled_channels(); std::list list_of_channels; boost::split(list_of_channels, channels_set, boost::is_any_of(",;: "), boost::token_compress_on); - std::cout << "log channels: "; + if (verbose) + std::cout << "log channels: "; for (const auto& ch : list_of_channels) { genabled_channels.insert(ch); - std::cout << ch << " "; + if (verbose) + std::cout << ch << " "; } - std::cout << " enabled" << std::endl; + if (verbose) + std::cout << " enabled" << std::endl; } - static void enable_channel(const std::string& ch_name) + static void enable_channel(const std::string& ch_name, bool verbose = true) { std::set& genabled_channels = get_enabled_channels(); //lazy synchronization: just replace with modified copy of whole set @@ -1258,7 +1264,8 @@ namespace log_space enabled_channels_local.insert(ch_name); genabled_channels.swap(enabled_channels_local); #ifndef ANDROID_BUILD - std::cout << "log channel '" << ch_name << "' enabled" << std::endl; + if (verbose) + std::cout << "log channel '" << ch_name << "' enabled" << std::endl; #endif } diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h index c0b57596..b0c8838a 100644 --- a/contrib/epee/include/net/http_client.h +++ b/contrib/epee/include/net/http_client.h @@ -57,987 +57,1048 @@ extern epee::critical_section gregexp_lock; namespace epee { -namespace net_utils -{ - -using namespace std; - - /*struct url - { - public: - void parse(const std::string& url_s) - { - const string prot_end("://"); - string::const_iterator prot_i = search(url_s.begin(), url_s.end(), - prot_end.begin(), prot_end.end()); - protocol_.reserve(distance(url_s.begin(), prot_i)); - transform(url_s.begin(), prot_i, - back_inserter(protocol_), - ptr_fun(tolower)); // protocol is icase - if( prot_i == url_s.end() ) - return; - advance(prot_i, prot_end.length()); - string::const_iterator path_i = find(prot_i, url_s.end(), '/'); - host_.reserve(distance(prot_i, path_i)); - transform(prot_i, path_i, - back_inserter(host_), - ptr_fun(tolower)); // host is icase - string::const_iterator query_i = find(path_i, url_s.end(), '?'); - path_.assign(path_i, query_i); - if( query_i != url_s.end() ) - ++query_i; - query_.assign(query_i, url_s.end()); - } - - std::string protocol_; - std::string host_; - std::string path_; - std::string query_; - };*/ - - - - - //--------------------------------------------------------------------------- - static inline const char* get_hex_vals() - { - static char hexVals[16] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - return hexVals; - } - - static inline const char* get_unsave_chars() - { - //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&"; - static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&"; - return unsave_chars; - } - - static inline bool is_unsafe(unsigned char compare_char) - { - if(compare_char <= 32 || compare_char >= 123) - return true; - - const char* punsave = get_unsave_chars(); - - for(int ichar_pos = 0; 0!=punsave[ichar_pos] ;ichar_pos++) - if(compare_char == punsave[ichar_pos]) - return true; - - return false; - } - - static inline - std::string dec_to_hex(char num, int radix) - { - int temp=0; - std::string csTmp; - int num_char; - - num_char = (int) num; - if (num_char < 0) - num_char = 256 + num_char; - - while (num_char >= radix) - { - temp = num_char % radix; - num_char = (int)floor((float)num_char / (float)radix); - csTmp = get_hex_vals()[temp]; - } - - csTmp += get_hex_vals()[num_char]; - - if(csTmp.size() < 2) - { - csTmp += '0'; - } - - std::reverse(csTmp.begin(), csTmp.end()); - //_mbsrev((unsigned char*)csTmp.data()); - - return csTmp; - } - - static inline std::string convert(char val) - { - std::string csRet; - csRet += "%"; - csRet += dec_to_hex(val, 16); - return csRet; - } - static inline std::string conver_to_url_format(const std::string& uri) - { - - std::string result; - - for(size_t i = 0; i!= uri.size(); i++) - { - if(is_unsafe(uri[i])) - result += convert(uri[i]); - else - result += uri[i]; - - } - - return result; - } - - static inline std::string convert_to_url_format_force_all(const std::string& uri) + namespace net_utils { - std::string result; + using namespace std; - for(size_t i = 0; i!= uri.size(); i++) + /*struct url { - result += convert(uri[i]); + public: + void parse(const std::string& url_s) + { + const string prot_end("://"); + string::const_iterator prot_i = search(url_s.begin(), url_s.end(), + prot_end.begin(), prot_end.end()); + protocol_.reserve(distance(url_s.begin(), prot_i)); + transform(url_s.begin(), prot_i, + back_inserter(protocol_), + ptr_fun(tolower)); // protocol is icase + if( prot_i == url_s.end() ) + return; + advance(prot_i, prot_end.length()); + string::const_iterator path_i = find(prot_i, url_s.end(), '/'); + host_.reserve(distance(prot_i, path_i)); + transform(prot_i, path_i, + back_inserter(host_), + ptr_fun(tolower)); // host is icase + string::const_iterator query_i = find(path_i, url_s.end(), '?'); + path_.assign(path_i, query_i); + if( query_i != url_s.end() ) + ++query_i; + query_.assign(query_i, url_s.end()); } - return result; - } + std::string protocol_; + std::string host_; + std::string path_; + std::string query_; + };*/ + //--------------------------------------------------------------------------- + static inline const char* get_hex_vals() + { + static char hexVals[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + return hexVals; + } - namespace http - { + static inline const char* get_unsave_chars() + { + //static char unsave_chars[] = "\"<>%\\^[]`+$,@:;/!#?=&"; + static char unsave_chars[] = "\"<>%\\^[]`+$,@:;!#&"; + return unsave_chars; + } - class http_simple_client: public i_target_handler - { - public: - - - private: - enum reciev_machine_state - { - reciev_machine_state_header, - reciev_machine_state_body_content_len, - reciev_machine_state_body_connection_close, - reciev_machine_state_body_chunked, - reciev_machine_state_done, - reciev_machine_state_error - }; - - - - enum chunked_state{ - http_chunked_state_chunk_head, - http_chunked_state_chunk_body, - http_chunked_state_done, - http_chunked_state_undefined - }; - - - blocked_mode_client m_net_client; - std::string m_host_buff; - std::string m_port; - //unsigned int m_timeout; - unsigned int m_connection_timeout; - unsigned int m_recv_timeout; - std::string m_header_cache; - http_response_info m_response_info; - //std::string* m_ptarget_buffer; - boost::shared_ptr m_pcontent_encoding_handler; - reciev_machine_state m_state; - chunked_state m_chunked_state; - std::string m_chunked_cache; - critical_section m_lock; - - protected: - uint64_t m_len_in_summary; - uint64_t m_len_in_remain; - - public: - void set_host_name(const std::string& name) - { - CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = name; - } - - boost::asio::ip::tcp::socket& get_socket() - { - return m_net_client.get_socket(); - } - - - bool connect(const std::string& host, int port, unsigned int timeout) - { - return connect(host, std::to_string(port), timeout); - } - - bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) - { - m_connection_timeout = connection_timeout; - m_recv_timeout = recv_timeout; + static inline bool is_unsafe(unsigned char compare_char) + { + if (compare_char <= 32 || compare_char >= 123) return true; - } - bool connect(const std::string& host, std::string port) + const char* punsave = get_unsave_chars(); + + for (int ichar_pos = 0; 0 != punsave[ichar_pos]; ichar_pos++) + if (compare_char == punsave[ichar_pos]) + return true; + + return false; + } + + static inline + std::string dec_to_hex(char num, int radix) + { + int temp = 0; + std::string csTmp; + int num_char; + + num_char = (int)num; + if (num_char < 0) + num_char = 256 + num_char; + + while (num_char >= radix) { - CRITICAL_REGION_LOCAL(m_lock); - m_host_buff = host; - m_port = port; - - return m_net_client.connect(host, port, m_connection_timeout, m_recv_timeout); + temp = num_char % radix; + num_char = (int)floor((float)num_char / (float)radix); + csTmp = get_hex_vals()[temp]; } - bool connect(const std::string& host, const std::string& port, unsigned int timeout) + csTmp += get_hex_vals()[num_char]; + + if (csTmp.size() < 2) { - m_connection_timeout = m_recv_timeout = timeout; - return connect(host, port); + csTmp += '0'; } - //--------------------------------------------------------------------------- - bool disconnect() - { - CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.disconnect(); - } - //--------------------------------------------------------------------------- - bool is_connected() - { - CRITICAL_REGION_LOCAL(m_lock); - return m_net_client.is_connected(); - } - //--------------------------------------------------------------------------- - virtual bool handle_target_data(std::string& piece_of_transfer) - { - CRITICAL_REGION_LOCAL(m_lock); - m_response_info.m_body += piece_of_transfer; - piece_of_transfer.clear(); - return true; - } - //--------------------------------------------------------------------------- - inline - bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "GET", body, ppresponse_info, additional_params); - } - //--------------------------------------------------------------------------- - inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!is_connected()) - { - LOG_PRINT("Reconnecting...", LOG_LEVEL_3); - if(!connect(m_host_buff, m_port)) - { - LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); - return false; - } - } - m_response_info.clear(); - std::string req_buff = method + " "; - req_buff += uri + " HTTP/1.1\r\n" + - "Host: "+ m_host_buff +"\r\n" + "Content-Length: " + boost::lexical_cast(body.size()) + "\r\n"; + std::reverse(csTmp.begin(), csTmp.end()); + //_mbsrev((unsigned char*)csTmp.data()); + + return csTmp; + } + + static inline std::string convert(char val) + { + std::string csRet; + csRet += "%"; + csRet += dec_to_hex(val, 16); + return csRet; + } + static inline std::string conver_to_url_format(const std::string& uri) + { + + std::string result; + + for (size_t i = 0; i != uri.size(); i++) + { + if (is_unsafe(uri[i])) + result += convert(uri[i]); + else + result += uri[i]; + + } + + return result; + } + + static inline std::string convert_to_url_format_force_all(const std::string& uri) + { + + std::string result; + + for (size_t i = 0; i != uri.size(); i++) + { + result += convert(uri[i]); + } + + return result; + } - //handle "additional_params" - for(fields_list::const_iterator it = additional_params.begin(); it!=additional_params.end(); it++) - req_buff += it->first + ": " + it->second + "\r\n"; - req_buff += "\r\n"; - //-- - bool res = m_net_client.send(req_buff); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - if(body.size()) - res = m_net_client.send(body); - CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); - if(ppresponse_info) - *ppresponse_info = &m_response_info; - m_state = reciev_machine_state_header; - return handle_reciev(); - } - //--------------------------------------------------------------------------- - inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) - { - CRITICAL_REGION_LOCAL(m_lock); - return invoke(uri, "POST", body, ppresponse_info, additional_params); - } - private: - //--------------------------------------------------------------------------- - inline bool handle_reciev() - { - CRITICAL_REGION_LOCAL(m_lock); - bool keep_handling = true; - bool need_more_data = true; - std::string recv_buffer; - while(keep_handling) - { - if(need_more_data) - { - if(!m_net_client.recv(recv_buffer)) - { - LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3); - m_state = reciev_machine_state_error; - } - if(!recv_buffer.size()) + namespace http + { + template + class http_simple_client_t : public i_target_handler + { + public: + + + private: + enum reciev_machine_state + { + reciev_machine_state_header, + reciev_machine_state_body_content_len, + reciev_machine_state_body_connection_close, + reciev_machine_state_body_chunked, + reciev_machine_state_done, + reciev_machine_state_error + }; + + + + enum chunked_state { + http_chunked_state_chunk_head, + http_chunked_state_chunk_body, + http_chunked_state_done, + http_chunked_state_undefined + }; + + + blocked_mode_client_t m_net_client; + std::string m_host_buff; + std::string m_port; + //unsigned int m_timeout; + unsigned int m_connection_timeout; + unsigned int m_recv_timeout; + std::string m_header_cache; + http_response_info m_response_info; + //std::string* m_ptarget_buffer; + boost::shared_ptr m_pcontent_encoding_handler; + reciev_machine_state m_state; + chunked_state m_chunked_state; + std::string m_chunked_cache; + critical_section m_lock; + + protected: + uint64_t m_len_in_summary; + uint64_t m_len_in_remain; + + public: + void set_host_name(const std::string& name) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = name; + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_net_client.get_socket(); + } + + + bool connect(const std::string& host, int port, unsigned int timeout) + { + return connect(host, std::to_string(port), timeout); + } + + bool set_timeouts(unsigned int connection_timeout, unsigned int recv_timeout) + { + m_connection_timeout = connection_timeout; + m_recv_timeout = recv_timeout; + return true; + } + + bool connect(const std::string& host, std::string port) + { + CRITICAL_REGION_LOCAL(m_lock); + m_host_buff = host; + m_port = port; + + return m_net_client.connect(host, port, m_connection_timeout, m_recv_timeout); + } + + bool connect(const std::string& host, const std::string& port, unsigned int timeout) + { + m_connection_timeout = m_recv_timeout = timeout; + return connect(host, port); + } + //--------------------------------------------------------------------------- + bool disconnect() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.disconnect(); + } + //--------------------------------------------------------------------------- + bool is_connected() + { + CRITICAL_REGION_LOCAL(m_lock); + return m_net_client.is_connected(); + } + //--------------------------------------------------------------------------- + virtual bool handle_target_data(std::string& piece_of_transfer) + { + CRITICAL_REGION_LOCAL(m_lock); + m_response_info.m_body += piece_of_transfer; + piece_of_transfer.clear(); + return true; + } + //--------------------------------------------------------------------------- + inline + bool invoke_get(const std::string& uri, const std::string& body = std::string(), const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "GET", body, ppresponse_info, additional_params); + } + + //--------------------------------------------------------------------------- + inline bool invoke(const std::string& uri, const std::string& method, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!is_connected()) + { + LOG_PRINT("Reconnecting...", LOG_LEVEL_3); + if (!connect(m_host_buff, m_port)) { - //connection is going to be closed - if(reciev_machine_state_body_connection_close != m_state) + LOG_PRINT("Failed to connect to " << m_host_buff << ":" << m_port, LOG_LEVEL_3); + return false; + } + } + m_response_info.clear(); + std::string req_buff = method + " "; + req_buff += uri + " HTTP/1.1\r\n" + + "Host: " + m_host_buff + "\r\n" + "Content-Length: " + boost::lexical_cast(body.size()) + "\r\n"; + + + //handle "additional_params" + for (fields_list::const_iterator it = additional_params.begin(); it != additional_params.end(); it++) + req_buff += it->first + ": " + it->second + "\r\n"; + req_buff += "\r\n"; + //-- + + bool res = m_net_client.send(req_buff); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + if (body.size()) + res = m_net_client.send(body); + CHECK_AND_ASSERT_MES(res, false, "HTTP_CLIENT: Failed to SEND"); + + if (ppresponse_info) + *ppresponse_info = &m_response_info; + + m_state = reciev_machine_state_header; + return handle_reciev(); + } + //--------------------------------------------------------------------------- + inline bool invoke_post(const std::string& uri, const std::string& body, const http_response_info** ppresponse_info = NULL, const fields_list& additional_params = fields_list()) + { + CRITICAL_REGION_LOCAL(m_lock); + return invoke(uri, "POST", body, ppresponse_info, additional_params); + } + private: + //--------------------------------------------------------------------------- + inline bool handle_reciev() + { + CRITICAL_REGION_LOCAL(m_lock); + bool keep_handling = true; + bool need_more_data = true; + std::string recv_buffer; + while (keep_handling) + { + if (need_more_data) + { + if (!m_net_client.recv(recv_buffer)) { + LOG_PRINT("Unexpected reciec fail", LOG_LEVEL_3); m_state = reciev_machine_state_error; } - } - need_more_data = false; - } - switch(m_state) - { - case reciev_machine_state_header: - keep_handling = handle_header(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_content_len: - keep_handling = handle_body_content_len(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_connection_close: - keep_handling = handle_body_connection_close(recv_buffer, need_more_data); - break; - case reciev_machine_state_body_chunked: - keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); - break; - case reciev_machine_state_done: - keep_handling = false; - break; - case reciev_machine_state_error: - keep_handling = false; - break; - } - - } - m_header_cache.clear(); - if(m_state != reciev_machine_state_error) - { - if(m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) - disconnect(); - - return true; - } - else + if (!recv_buffer.size()) + { + //connection is going to be closed + if (reciev_machine_state_body_connection_close != m_state) { - LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); - return false; + m_state = reciev_machine_state_error; } - } - //--------------------------------------------------------------------------- - inline - bool handle_header(std::string& recv_buff, bool& need_more_data) - { - - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - LOG_ERROR("Connection closed at handle_header"); - m_state = reciev_machine_state_error; - return false; - } + } + need_more_data = false; + } + switch (m_state) + { + case reciev_machine_state_header: + keep_handling = handle_header(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_content_len: + keep_handling = handle_body_content_len(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_connection_close: + keep_handling = handle_body_connection_close(recv_buffer, need_more_data); + break; + case reciev_machine_state_body_chunked: + keep_handling = handle_body_body_chunked(recv_buffer, need_more_data); + break; + case reciev_machine_state_done: + keep_handling = false; + break; + case reciev_machine_state_error: + keep_handling = false; + break; + } - m_header_cache += recv_buff; - recv_buff.clear(); - std::string::size_type pos = m_header_cache.find("\r\n\r\n"); - if(pos != std::string::npos) - { - recv_buff.assign(m_header_cache.begin()+pos+4, m_header_cache.end()); - m_header_cache.erase(m_header_cache.begin()+pos+4, m_header_cache.end()); - - analize_cached_header_and_invoke_state(); - m_header_cache.clear(); - if(!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) - need_more_data = true; - - return true; - }else - need_more_data = true; - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3); - m_state = reciev_machine_state_done; - return true; - } - CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); - m_len_in_remain -= recv_buff.size(); - bool r = m_pcontent_encoding_handler->update_in(recv_buff); - //CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_pcontent_encoding_handler->update_in returned false"); - if (!r) - { - m_state = reciev_machine_state_error; - disconnect(); - return false; - } - - if(m_len_in_remain == 0) - m_state = reciev_machine_state_done; - else - need_more_data = true; - - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - m_state = reciev_machine_state_done; - return true; - } - need_more_data = true; - m_pcontent_encoding_handler->update_in(recv_buff); - - - return true; - } - //--------------------------------------------------------------------------- - inline bool is_hex_symbol(char ch) - { - - if( (ch >= '0' && ch <='9')||(ch >= 'A' && ch <='F')||(ch >= 'a' && ch <='f')) - return true; - else - return false; - } - //--------------------------------------------------------------------------- - inline - bool get_len_from_chunk_head(const std::string &chunk_head, uint64_t& result_size) - { - std::stringstream str_stream; - str_stream << std::hex; - if(!(str_stream << chunk_head && str_stream >> result_size)) - return false; - - return true; - } - //--------------------------------------------------------------------------- - inline - bool get_chunk_head(std::string& buff, uint64_t& chunk_size, bool& is_matched) - { - is_matched = false; - size_t offset = 0; - for(std::string::iterator it = buff.begin(); it!= buff.end(); it++, offset++) - { - if(!is_hex_symbol(*it)) - { - if(*it == '\r' || *it == ' ' ) - { - offset--; - continue; - } - else if(*it == '\n') - { - std::string chunk_head = buff.substr(0, offset); - if(!get_len_from_chunk_head(chunk_head, chunk_size)) - return false; - - if(0 == chunk_size) - { - //Here is a small confusion - //In breif - if the chunk is the last one we need to get terminating sequence - //along with the cipher, generally in the "ddd\r\n\r\n" form - - for(it++;it != buff.end(); it++) - { - if('\r' == *it) - continue; - else if('\n' == *it) - break; - else - { - LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); - return false; - } - } - - if(it == buff.end()) - return true; - } - - buff.erase(buff.begin(), ++it); - - is_matched = true; - return true; - } - else - return false; - } - } - - return true; - } - //--------------------------------------------------------------------------- - inline - bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) - { - CRITICAL_REGION_LOCAL(m_lock); - if(!recv_buff.size()) - { - LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3); - m_state = reciev_machine_state_done; - return true; - } - m_chunked_cache += recv_buff; - recv_buff.clear(); - bool is_matched = false; - - while(true) - { - if(!m_chunked_cache.size()) - { - need_more_data = true; - break; - } - - switch(m_chunked_state) - { - case http_chunked_state_chunk_head: - if(m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') - { - //optimize a bit - if(m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') - m_chunked_cache.erase(0, 2); - else - m_chunked_cache.erase(0, 1); - break; - } - if(!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) - { - LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); - m_state = reciev_machine_state_error; - return false; - } - - if(!is_matched) - { - need_more_data = true; - return true; - }else - { - m_chunked_state = http_chunked_state_chunk_body; - if(m_len_in_remain == 0) - {//last chunk, let stop the stream and fix the chunk queue. - m_state = reciev_machine_state_done; - return true; - } - m_chunked_state = http_chunked_state_chunk_body; - break; - } - break; - case http_chunked_state_chunk_body: - { - std::string chunk_body; - if(m_len_in_remain >= m_chunked_cache.size()) - { - m_len_in_remain -= m_chunked_cache.size(); - chunk_body.swap(m_chunked_cache); - }else - { - chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); - m_chunked_cache.erase(0, m_len_in_remain); - m_len_in_remain = 0; - } - - m_pcontent_encoding_handler->update_in(chunk_body); - - if(!m_len_in_remain) - m_chunked_state = http_chunked_state_chunk_head; - } - break; - case http_chunked_state_done: - m_state = reciev_machine_state_done; - return true; - case http_chunked_state_undefined: - default: - LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); - return false; - } - } - - return true; - } - //--------------------------------------------------------------------------- - inline - bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process) - { - LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4); - - STATIC_REGEXP_EXPR_1(rexp_mach_field, - "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" - // 12 3 4 5 6 7 8 9 - "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", - //10 1112 13 - boost::regex::icase | boost::regex::normal); - - boost::smatch result; - std::string::const_iterator it_current_bound = m_cache_to_process.begin(); - std::string::const_iterator it_end_bound = m_cache_to_process.end(); - - - - //lookup all fields and fill well-known fields - while( boost::regex_search( it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) - { - const size_t field_val = 12; - //const size_t field_etc_name = 10; - - int i = 2; //start position = 2 - if(result[i++].matched)//"Connection" - body_info.m_connection = result[field_val]; - else if(result[i++].matched)//"Referrer" - body_info.m_referer = result[field_val]; - else if(result[i++].matched)//"Content-Length" - body_info.m_content_length = result[field_val]; - else if(result[i++].matched)//"Content-Type" - body_info.m_content_type = result[field_val]; - else if(result[i++].matched)//"Transfer-Encoding" - body_info.m_transfer_encoding = result[field_val]; - else if(result[i++].matched)//"Content-Encoding" - body_info.m_content_encoding = result[field_val]; - else if(result[i++].matched)//"Host" - { body_info.m_host = result[field_val]; - string_tools::trim(body_info.m_host); - } - else if(result[i++].matched)//"Cookie" - body_info.m_cookie = result[field_val]; - else if(result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) - {;} - else - {CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:"<(result[1]); - m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); - m_response_info.m_response_code = boost::lexical_cast(result[3]); - - m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); - return true; - }else - { - LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); - return false; - } - - } - inline - bool set_reply_content_encoder() - { - STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); - boost::smatch result; // 12 3 - if(boost::regex_search( m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) - { -#ifdef HTTP_ENABLE_GZIP - m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched)); -#else - m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); - LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); - return false; -#endif - } - else - { - m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); - } - - return true; - } - inline - bool analize_cached_header_and_invoke_state() - { - m_response_info.clear(); - analize_first_response_line(); - std::string fake_str; //gcc error workaround - - bool res = parse_header(m_response_info.m_header_info, m_header_cache); - CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); - - set_reply_content_encoder(); - - m_len_in_summary = 0; - bool content_len_valid = false; - if(m_response_info.m_header_info.m_content_length.size()) - content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); - - - - if(!m_len_in_summary && ((m_response_info.m_response_code>=100&&m_response_info.m_response_code<200) - || 204 == m_response_info.m_response_code - || 304 == m_response_info.m_response_code) ) - {//There will be no response body, server will display the local page with error - m_state = reciev_machine_state_done; - return true; - }else if(m_response_info.m_header_info.m_transfer_encoding.size()) - { - string_tools::trim(m_response_info.m_header_info.m_transfer_encoding); - if(string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked")) - { - LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding); - m_state = reciev_machine_state_error; - return false; - } - m_state = reciev_machine_state_body_chunked; - m_chunked_state = http_chunked_state_chunk_head; - return true; - } - else if(!m_response_info.m_header_info.m_content_length.empty()) - { - //In the response header the length was specified - if(!content_len_valid) - { - LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length="<(u_c.port), timeout)) - { - LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); - return false; - } - } - - return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); - } - - struct idle_handler_base - { - virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) = 0; - virtual ~idle_handler_base() {} - }; - - template - struct idle_handler : public idle_handler_base - { - callback_t m_cb; - - idle_handler(callback_t cb) : m_cb(cb) {} - virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - return m_cb(piece_of_data, total_bytes, received_bytes); - } - }; - - class interruptible_http_client : public http_simple_client - { - std::shared_ptr m_pcb; - bool m_permanent_error = false; - - virtual bool handle_target_data(std::string& piece_of_transfer) - { - bool r = m_pcb->do_call(piece_of_transfer, m_len_in_summary, m_len_in_summary - m_len_in_remain); - piece_of_transfer.clear(); - return r; - } - - public: - template - bool invoke_cb(callback_t cb, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) - { - m_pcb.reset(new idle_handler(cb)); - const http_response_info* p_hri = nullptr; - bool r = invoke_request(url, *this, timeout, &p_hri, method, body, additional_params); - if (p_hri && !(p_hri->m_response_code >= 200 && p_hri->m_response_code < 300)) - { - LOG_PRINT_L0("HTTP request to " << url << " failed with code: " << p_hri->m_response_code); - m_permanent_error = true; - return false; - } - return r; - } - - template - bool download(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) - { - std::ofstream fs; - fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); - if (!fs.is_open()) - { - LOG_ERROR("Fsiled to open " << path_for_file); - return false; - } - auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - fs.write(piece_of_data.data(), piece_of_data.size()); - return cb(total_bytes, received_bytes); - }; - bool r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params); - fs.close(); - return r; - } - - // - template - bool download_and_unzip(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), uint64_t fails_count = 1000, const fields_list& additional_params = fields_list()) - { - std::ofstream fs; - fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); - if (!fs.is_open()) - { - LOG_ERROR("Fsiled to open " << path_for_file); - return false; - } - std::string buff; - gzip_decoder_lambda zip_decoder; - uint64_t state_total_bytes = 0; - uint64_t state_received_bytes_base = 0; - uint64_t state_received_bytes_current = 0; - bool stopped = false; - auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) - { - //remember total_bytes only for first attempt, where fetched full lenght of the file - if (!state_total_bytes) - state_total_bytes = total_bytes; - - buff += piece_of_data; - return zip_decoder.update_in(buff, [&](const std::string& unpacked_buff) + } + m_header_cache.clear(); + if (m_state != reciev_machine_state_error) { - state_received_bytes_current = received_bytes; - fs.write(unpacked_buff.data(), unpacked_buff.size()); - stopped = !cb(unpacked_buff, state_total_bytes, state_received_bytes_base + received_bytes); - return !stopped; - }); - }; - uint64_t current_err_count = 0; - bool r = false; - m_permanent_error = false; - while (!r && current_err_count < fails_count) + if (m_response_info.m_header_info.m_connection.size() && !string_tools::compare_no_case("close", m_response_info.m_header_info.m_connection)) + disconnect(); + + return true; + } + else + { + LOG_PRINT_L3("Returning false because of wrong state machine. state: " << m_state); + return false; + } + } + //--------------------------------------------------------------------------- + inline + bool handle_header(std::string& recv_buff, bool& need_more_data) { - LOG_PRINT_L0("Attempt " << current_err_count + 1 << "/" << fails_count << " to get " << url << " (offset:" << state_received_bytes_base << ")"); - fields_list additional_params_local = additional_params; - additional_params_local.push_back(std::make_pair("Range", std::string("bytes=") + std::to_string(state_received_bytes_base) + "-")); - r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params_local); + + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_ERROR("Connection closed at handle_header"); + m_state = reciev_machine_state_error; + return false; + } + + m_header_cache += recv_buff; + recv_buff.clear(); + std::string::size_type pos = m_header_cache.find("\r\n\r\n"); + if (pos != std::string::npos) + { + recv_buff.assign(m_header_cache.begin() + pos + 4, m_header_cache.end()); + m_header_cache.erase(m_header_cache.begin() + pos + 4, m_header_cache.end()); + + analize_cached_header_and_invoke_state(); + m_header_cache.clear(); + if (!recv_buff.size() && (m_state != reciev_machine_state_error && m_state != reciev_machine_state_done)) + need_more_data = true; + + return true; + } + else + need_more_data = true; + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_content_len(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_PRINT("Warning: Content-Len mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_len_in_remain >= recv_buff.size()"); + m_len_in_remain -= recv_buff.size(); + bool r = m_pcontent_encoding_handler->update_in(recv_buff); + //CHECK_AND_ASSERT_MES(m_len_in_remain >= recv_buff.size(), false, "m_pcontent_encoding_handler->update_in returned false"); if (!r) { - if (stopped || m_permanent_error) + m_state = reciev_machine_state_error; + disconnect(); + return false; + } + + if (m_len_in_remain == 0) + m_state = reciev_machine_state_done; + else + need_more_data = true; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_connection_close(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + m_state = reciev_machine_state_done; + return true; + } + need_more_data = true; + m_pcontent_encoding_handler->update_in(recv_buff); + + + return true; + } + //--------------------------------------------------------------------------- + inline bool is_hex_symbol(char ch) + { + + if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) + return true; + else + return false; + } + //--------------------------------------------------------------------------- + inline + bool get_len_from_chunk_head(const std::string &chunk_head, uint64_t& result_size) + { + std::stringstream str_stream; + str_stream << std::hex; + if (!(str_stream << chunk_head && str_stream >> result_size)) + return false; + + return true; + } + //--------------------------------------------------------------------------- + inline + bool get_chunk_head(std::string& buff, uint64_t& chunk_size, bool& is_matched) + { + is_matched = false; + size_t offset = 0; + for (std::string::iterator it = buff.begin(); it != buff.end(); it++, offset++) + { + if (!is_hex_symbol(*it)) + { + if (*it == '\r' || *it == ' ') + { + offset--; + continue; + } + else if (*it == '\n') + { + std::string chunk_head = buff.substr(0, offset); + if (!get_len_from_chunk_head(chunk_head, chunk_size)) + return false; + + if (0 == chunk_size) + { + //Here is a small confusion + //In breif - if the chunk is the last one we need to get terminating sequence + //along with the cipher, generally in the "ddd\r\n\r\n" form + + for (it++; it != buff.end(); it++) + { + if ('\r' == *it) + continue; + else if ('\n' == *it) + break; + else + { + LOG_ERROR("http_stream_filter: Wrong last chunk terminator"); + return false; + } + } + + if (it == buff.end()) + return true; + } + + buff.erase(buff.begin(), ++it); + + is_matched = true; + return true; + } + else + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool handle_body_body_chunked(std::string& recv_buff, bool& need_more_data) + { + CRITICAL_REGION_LOCAL(m_lock); + if (!recv_buff.size()) + { + LOG_PRINT("Warning: CHUNKED mode, but connection unexpectedly closed", LOG_LEVEL_3); + m_state = reciev_machine_state_done; + return true; + } + m_chunked_cache += recv_buff; + recv_buff.clear(); + bool is_matched = false; + + while (true) + { + if (!m_chunked_cache.size()) + { + need_more_data = true; break; - current_err_count++; - state_received_bytes_base += state_received_bytes_current; - state_received_bytes_current = 0; - boost::this_thread::sleep_for(boost::chrono::milliseconds(2000)); + } + + switch (m_chunked_state) + { + case http_chunked_state_chunk_head: + if (m_chunked_cache[0] == '\n' || m_chunked_cache[0] == '\r') + { + //optimize a bit + if (m_chunked_cache[0] == '\r' && m_chunked_cache.size()>1 && m_chunked_cache[1] == '\n') + m_chunked_cache.erase(0, 2); + else + m_chunked_cache.erase(0, 1); + break; + } + if (!get_chunk_head(m_chunked_cache, m_len_in_remain, is_matched)) + { + LOG_ERROR("http_stream_filter::handle_chunked(*) Failed to get length from chunked head:" << m_chunked_cache); + m_state = reciev_machine_state_error; + return false; + } + + if (!is_matched) + { + need_more_data = true; + return true; + } + else + { + m_chunked_state = http_chunked_state_chunk_body; + if (m_len_in_remain == 0) + {//last chunk, let stop the stream and fix the chunk queue. + m_state = reciev_machine_state_done; + return true; + } + m_chunked_state = http_chunked_state_chunk_body; + break; + } + break; + case http_chunked_state_chunk_body: + { + std::string chunk_body; + if (m_len_in_remain >= m_chunked_cache.size()) + { + m_len_in_remain -= m_chunked_cache.size(); + chunk_body.swap(m_chunked_cache); + } + else + { + chunk_body.assign(m_chunked_cache, 0, m_len_in_remain); + m_chunked_cache.erase(0, m_len_in_remain); + m_len_in_remain = 0; + } + + m_pcontent_encoding_handler->update_in(chunk_body); + + if (!m_len_in_remain) + m_chunked_state = http_chunked_state_chunk_head; + } + break; + case http_chunked_state_done: + m_state = reciev_machine_state_done; + return true; + case http_chunked_state_undefined: + default: + LOG_ERROR("http_stream_filter::handle_chunked(): Wrong state" << m_chunked_state); + return false; + } + } + + return true; + } + //--------------------------------------------------------------------------- + inline + bool parse_header(http_header_info& body_info, const std::string& m_cache_to_process) + { + LOG_FRAME("http_stream_filter::parse_cached_header(*)", LOG_LEVEL_4); + + STATIC_REGEXP_EXPR_1(rexp_mach_field, + "\n?((Connection)|(Referer)|(Content-Length)|(Content-Type)|(Transfer-Encoding)|(Content-Encoding)|(Host)|(Cookie)" + // 12 3 4 5 6 7 8 9 + "|([\\w-]+?)) ?: ?((.*?)(\r?\n))[^\t ]", + //10 1112 13 + boost::regex::icase | boost::regex::normal); + + boost::smatch result; + std::string::const_iterator it_current_bound = m_cache_to_process.begin(); + std::string::const_iterator it_end_bound = m_cache_to_process.end(); + + + + //lookup all fields and fill well-known fields + while (boost::regex_search(it_current_bound, it_end_bound, result, rexp_mach_field, boost::match_default) && result[0].matched) + { + const size_t field_val = 12; + //const size_t field_etc_name = 10; + + int i = 2; //start position = 2 + if (result[i++].matched)//"Connection" + body_info.m_connection = result[field_val]; + else if (result[i++].matched)//"Referrer" + body_info.m_referer = result[field_val]; + else if (result[i++].matched)//"Content-Length" + body_info.m_content_length = result[field_val]; + else if (result[i++].matched)//"Content-Type" + body_info.m_content_type = result[field_val]; + else if (result[i++].matched)//"Transfer-Encoding" + body_info.m_transfer_encoding = result[field_val]; + else if (result[i++].matched)//"Content-Encoding" + body_info.m_content_encoding = result[field_val]; + else if (result[i++].matched)//"Host" + { + body_info.m_host = result[field_val]; + string_tools::trim(body_info.m_host); + } + else if (result[i++].matched)//"Cookie" + body_info.m_cookie = result[field_val]; + else if (result[i++].matched)//e.t.c (HAVE TO BE MATCHED!) + { + ; + } + else + { + CHECK_AND_ASSERT_MES(false, false, "http_stream_filter::parse_cached_header() not matched last entry in:" << m_cache_to_process); + } + + it_current_bound = result[(int)result.size() - 1].first; + } + return true; + + } + inline + bool analize_first_response_line() + { + + //First line response, look like this: "HTTP/1.1 200 OK" + STATIC_REGEXP_EXPR_1(rexp_match_first_response_line, "^HTTP/(\\d+).(\\d+) ((\\d)\\d{2})( [^\n]*)?\r?\n", boost::regex::icase | boost::regex::normal); + // 1 2 34 5 + //size_t match_len = 0; + boost::smatch result; + if (boost::regex_search(m_header_cache, result, rexp_match_first_response_line, boost::match_default) && result[0].matched) + { + CHECK_AND_ASSERT_MES(result[1].matched&&result[2].matched, false, "http_stream_filter::handle_invoke_reply_line() assert failed..."); + m_response_info.m_http_ver_hi = boost::lexical_cast(result[1]); + m_response_info.m_http_ver_lo = boost::lexical_cast(result[2]); + m_response_info.m_response_code = boost::lexical_cast(result[3]); + + m_header_cache.erase(to_nonsonst_iterator(m_header_cache, result[0].first), to_nonsonst_iterator(m_header_cache, result[0].second)); + return true; + } + else + { + LOG_ERROR("http_stream_filter::handle_invoke_reply_line(): Failed to match first response line:" << m_header_cache); + return false; + } + + } + inline + bool set_reply_content_encoder() + { + STATIC_REGEXP_EXPR_1(rexp_match_gzip, "^.*?((gzip)|(deflate))", boost::regex::icase | boost::regex::normal); + boost::smatch result; // 12 3 + if (boost::regex_search(m_response_info.m_header_info.m_content_encoding, result, rexp_match_gzip, boost::match_default) && result[0].matched) + { +#ifdef HTTP_ENABLE_GZIP + m_pcontent_encoding_handler.reset(new content_encoding_gzip(this, result[3].matched)); +#else + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + LOG_ERROR("GZIP encoding not supported in this build, please add zlib to your project and define HTTP_ENABLE_GZIP"); + return false; +#endif + } + else + { + m_pcontent_encoding_handler.reset(new do_nothing_sub_handler(this)); + } + + return true; + } + inline + bool analize_cached_header_and_invoke_state() + { + m_response_info.clear(); + analize_first_response_line(); + std::string fake_str; //gcc error workaround + + bool res = parse_header(m_response_info.m_header_info, m_header_cache); + CHECK_AND_ASSERT_MES(res, false, "http_stream_filter::analize_cached_reply_header_and_invoke_state(): failed to anilize reply header: " << m_header_cache); + + set_reply_content_encoder(); + + m_len_in_summary = 0; + bool content_len_valid = false; + if (m_response_info.m_header_info.m_content_length.size()) + content_len_valid = string_tools::get_xtype_from_string(m_len_in_summary, m_response_info.m_header_info.m_content_length); + + + + if (!m_len_in_summary && ((m_response_info.m_response_code >= 100 && m_response_info.m_response_code<200) + || 204 == m_response_info.m_response_code + || 304 == m_response_info.m_response_code)) + {//There will be no response body, server will display the local page with error + m_state = reciev_machine_state_done; + return true; + } + else if (m_response_info.m_header_info.m_transfer_encoding.size()) + { + string_tools::trim(m_response_info.m_header_info.m_transfer_encoding); + if (string_tools::compare_no_case(m_response_info.m_header_info.m_transfer_encoding, "chunked")) + { + LOG_ERROR("Wrong Transfer-Encoding:" << m_response_info.m_header_info.m_transfer_encoding); + m_state = reciev_machine_state_error; + return false; + } + m_state = reciev_machine_state_body_chunked; + m_chunked_state = http_chunked_state_chunk_head; + return true; + } + else if (!m_response_info.m_header_info.m_content_length.empty()) + { + //In the response header the length was specified + if (!content_len_valid) + { + LOG_ERROR("http_stream_filter::analize_cached_reply_header_and_invoke_state(): Failed to get_len_from_content_lenght();, m_query_info.m_content_length=" << m_response_info.m_header_info.m_content_length); + m_state = reciev_machine_state_error; + return false; + } + if (!m_len_in_summary) + { + m_state = reciev_machine_state_done; + return true; + } + else + { + m_len_in_remain = m_len_in_summary; + m_state = reciev_machine_state_body_content_len; + return true; + } + } + else if (!m_response_info.m_header_info.m_connection.empty() && is_connection_close_field(m_response_info.m_header_info.m_connection)) + { //By indirect signs we suspect that data transfer will end with a connection break + m_state = reciev_machine_state_body_connection_close; + } + else if (is_multipart_body(m_response_info.m_header_info, fake_str)) + { + m_state = reciev_machine_state_error; + LOG_ERROR("Unsupported MULTIPART BODY."); + return false; + } + else + { //Apparently there are no signs of the form of transfer, will receive data until the connection is closed + m_state = reciev_machine_state_body_connection_close; + LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache, LOG_LEVEL_2); + return false; + } + return false; + } + inline + bool is_connection_close_field(const std::string& str) + { + STATIC_REGEXP_EXPR_1(rexp_match_close, "^\\s*close", boost::regex::icase | boost::regex::normal); + boost::smatch result; + if (boost::regex_search(str, result, rexp_match_close, boost::match_default) && result[0].matched) + return true; + else + return false; + } + inline + bool is_multipart_body(const http_header_info& head_info, OUT std::string& boundary) + { + //Check whether this is multi part - if yes, capture boundary immediately + STATIC_REGEXP_EXPR_1(rexp_match_multipart_type, "^\\s*multipart/([\\w\\-]+); boundary=((\"(.*?)\")|(\\\\\"(.*?)\\\\\")|([^\\s;]*))", boost::regex::icase | boost::regex::normal); + boost::smatch result; + if (boost::regex_search(head_info.m_content_type, result, rexp_match_multipart_type, boost::match_default) && result[0].matched) + { + if (result[4].matched) + boundary = result[4]; + else if (result[6].matched) + boundary = result[6]; + else if (result[7].matched) + boundary = result[7]; + else + { + LOG_ERROR("Failed to match boundary in content-type=" << head_info.m_content_type); + return false; + } + return true; + } + else + return false; + + return true; + } + }; + // class http_simple_client + + typedef http_simple_client_t http_simple_client; + typedef http_simple_client_t https_simple_client; + + + /************************************************************************/ + /* */ + /************************************************************************/ + template + bool invoke_request(const std::string& url, t_transport& tr, unsigned int timeout, const http_response_info** ppresponse_info, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { + http::url_content u_c; + bool res = parse_url(url, u_c); + + if (!tr.is_connected() && !u_c.host.empty()) + { + CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); + + if (!u_c.port) + u_c.port = 80;//default for http + + if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) + { + LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); + return false; } } - if (current_err_count >= fails_count) - { - LOG_PRINT_YELLOW("Downloading from " << url << " FAILED as it's reached maximum (" << fails_count << ") number of attempts. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); - } - else if (m_permanent_error) - { - LOG_PRINT_YELLOW("Downloading from " << url << " FAILED due to permanent HTTP error. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); - } - - fs.close(); - return r; + return tr.invoke(u_c.uri, method, body, ppresponse_info, additional_params); } - }; + struct idle_handler_base + { + virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) = 0; + virtual ~idle_handler_base() {} + }; - } // namespace http + template + struct idle_handler : public idle_handler_base + { + callback_t m_cb; -} // namespace net_utils -} // namespace epee + idle_handler(callback_t cb) : m_cb(cb) {} + virtual bool do_call(const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + return m_cb(piece_of_data, total_bytes, received_bytes); + } + }; + + class interruptible_http_client : public http_simple_client + { + std::shared_ptr m_pcb; + bool m_permanent_error = false; + + virtual bool handle_target_data(std::string& piece_of_transfer) + { + bool r = m_pcb->do_call(piece_of_transfer, m_len_in_summary, m_len_in_summary - m_len_in_remain); + piece_of_transfer.clear(); + return r; + } + + public: + template + bool invoke_cb(callback_t cb, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { + m_pcb.reset(new idle_handler(cb)); + const http_response_info* p_hri = nullptr; + bool r = invoke_request(url, *this, timeout, &p_hri, method, body, additional_params); + if (p_hri && !(p_hri->m_response_code >= 200 && p_hri->m_response_code < 300)) + { + LOG_PRINT_L0("HTTP request to " << url << " failed with code: " << p_hri->m_response_code); + m_permanent_error = true; + return false; + } + return r; + } + + template + bool download(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), const fields_list& additional_params = fields_list()) + { + std::ofstream fs; + fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); + if (!fs.is_open()) + { + LOG_ERROR("Fsiled to open " << path_for_file); + return false; + } + auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + fs.write(piece_of_data.data(), piece_of_data.size()); + return cb(total_bytes, received_bytes); + }; + bool r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params); + fs.close(); + return r; + } + + // + template + bool download_and_unzip(callback_t cb, const std::string& path_for_file, const std::string& url, uint64_t timeout, const std::string& method = "GET", const std::string& body = std::string(), uint64_t fails_count = 1000, const fields_list& additional_params = fields_list()) + { + std::ofstream fs; + fs.open(path_for_file, std::ios::binary | std::ios::out | std::ios::trunc); + if (!fs.is_open()) + { + LOG_ERROR("Fsiled to open " << path_for_file); + return false; + } + std::string buff; + gzip_decoder_lambda zip_decoder; + uint64_t state_total_bytes = 0; + uint64_t state_received_bytes_base = 0; + uint64_t state_received_bytes_current = 0; + bool stopped = false; + auto local_cb = [&](const std::string& piece_of_data, uint64_t total_bytes, uint64_t received_bytes) + { + //remember total_bytes only for first attempt, where fetched full lenght of the file + if (!state_total_bytes) + state_total_bytes = total_bytes; + + buff += piece_of_data; + return zip_decoder.update_in(buff, [&](const std::string& unpacked_buff) + { + state_received_bytes_current = received_bytes; + fs.write(unpacked_buff.data(), unpacked_buff.size()); + stopped = !cb(unpacked_buff, state_total_bytes, state_received_bytes_base + received_bytes); + return !stopped; + }); + }; + uint64_t current_err_count = 0; + bool r = false; + m_permanent_error = false; + while (!r && current_err_count < fails_count) + { + LOG_PRINT_L0("Attempt " << current_err_count + 1 << "/" << fails_count << " to get " << url << " (offset:" << state_received_bytes_base << ")"); + fields_list additional_params_local = additional_params; + additional_params_local.push_back(std::make_pair("Range", std::string("bytes=") + std::to_string(state_received_bytes_base) + "-")); + r = this->invoke_cb(local_cb, url, timeout, method, body, additional_params_local); + if (!r) + { + if (stopped || m_permanent_error) + break; + current_err_count++; + state_received_bytes_base += state_received_bytes_current; + state_received_bytes_current = 0; + boost::this_thread::sleep_for(boost::chrono::milliseconds(2000)); + } + } + + if (current_err_count >= fails_count) + { + LOG_PRINT_YELLOW("Downloading from " << url << " FAILED as it's reached maximum (" << fails_count << ") number of attempts. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); + } + else if (m_permanent_error) + { + LOG_PRINT_YELLOW("Downloading from " << url << " FAILED due to permanent HTTP error. Downloaded " << state_received_bytes_base << " bytes.", LOG_LEVEL_0); + } + + fs.close(); + return r; + } + }; + + template + bool fetch_url_t(transport_t& tr, const url_content& u_c, std::string& response_body, const std::string& method = "GET", const std::string& request_body = "", unsigned int timeout = 1000) + { + fields_list additional_params; + if (!tr.is_connected() && !u_c.host.empty()) + { + if (!tr.connect(u_c.host, static_cast(u_c.port), timeout)) + { + LOG_PRINT_L2("invoke_request: cannot connect to " << u_c.host << ":" << u_c.port); + return false; + } + } + const http_response_info* ppresponse_info = nullptr; + if (tr.invoke(u_c.uri, "GET", request_body, &ppresponse_info, additional_params) && ppresponse_info) + { + response_body = ppresponse_info->m_body; + return true; + } + return false; + } + + inline + bool fetch_url(const std::string& url, std::string& response_body, const std::string& method = "GET", const std::string& request_body = "", unsigned int timeout = 1000) + { + try + { + url_content u_c = AUTO_VAL_INIT(u_c); + bool res = epee::net_utils::parse_url(url, u_c); + CHECK_AND_ASSERT_MES(res, false, "failed to parse url: " << url); + if (u_c.schema == "https") + { + https_simple_client tr; + return fetch_url_t(tr, u_c, response_body, method, request_body, timeout); + } + else + { + http_simple_client tr; + return fetch_url_t(tr, u_c, response_body, method, request_body, timeout); + } + } + catch (...) + { + return false; + } + + } + + } // namespace http + + } // namespace net_utils +} // namespace epee \ No newline at end of file diff --git a/contrib/epee/include/net/http_server_handlers_map2.h b/contrib/epee/include/net/http_server_handlers_map2.h index 6b45950a..3102cb2d 100644 --- a/contrib/epee/include/net/http_server_handlers_map2.h +++ b/contrib/epee/include/net/http_server_handlers_map2.h @@ -29,13 +29,22 @@ #include "serialization/keyvalue_serialization.h" #include "storages/portable_storage_template_helper.h" #include "http_base.h" +#include "net/net_utils_base.h" + + + +template +typename_t get_documentation_json_struct() +{ + return AUTO_VAL_INIT_T(typename_t); +} template bool auto_doc_t(const std::string& prefix_name, std::string& generate_reference) { if (!generate_reference.size()) return true; - request_t req = AUTO_VAL_INIT(req); - response_t res = AUTO_VAL_INIT(res); + request_t req = get_documentation_json_struct(); + response_t res = get_documentation_json_struct(); std::stringstream ss; ss << prefix_name << ENDL << "REQUEST: " << ENDL << epee::serialization::store_t_to_json(req) << ENDL << "--------------------------------" << ENDL @@ -51,6 +60,20 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference) return auto_doc_t(prefix_name, generate_reference); } +namespace epee { + namespace net_utils { + namespace http { + struct i_chain_handler + { + virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, epee::net_utils::http::http_response_info& response_info, + epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) = 0; + }; + } + } +} + + + #define CHAIN_HTTP_TO_MAP2(context_type) bool handle_http_request(const epee::net_utils::http::http_request_info& query_info, \ epee::net_utils::http::http_response_info& response, \ @@ -73,6 +96,13 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference) call_found = false; \ if(false) return true; //just a stub to have "else if" +#define BEGIN_URI_MAP2_VIRTUAL() virtual bool handle_http_request_map(const epee::net_utils::http::http_request_info& query_info, \ + epee::net_utils::http::http_response_info& response_info, \ + epee::net_utils::connection_context_base& m_conn_context, bool& call_found, std::string& generate_reference) { \ + call_found = false; \ + if(false) return true; //just a stub to have "else if" + + #define MAP_URI2(pattern, callback) else if(std::string::npos != query_info.m_URI.find(pattern)) return callback(query_info, response_info, m_conn_context); #define MAP_URI_AUTO_XML2(s_pattern, callback_f, command_type) //TODO: don't think i ever again will use xml - ambiguous and "overtagged" format @@ -117,6 +147,8 @@ bool auto_doc(const std::string& prefix_name, std::string& generate_reference) LOG_PRINT( "[HTTP/BIN][" << epee::string_tools::get_ip_string_from_int32(m_conn_context.m_remote_ip ) << "][" << query_info.m_URI << "] processed with " << ticks1-ticks << "/"<< ticks2-ticks1 << "/" << ticks3-ticks2 << "ms", LOG_LEVEL_2); \ } +#define CHAIN_TO_PHANDLER(pi_chain_handler) else if (pi_chain_handler && pi_chain_handler->handle_http_request_map(query_info, response_info, m_conn_context, call_found, generate_reference) && call_found) { return true;} + #define CHAIN_URI_MAP2(callback) else {callback(query_info, response_info, m_conn_context);call_found = true;} #define END_URI_MAP2() return true;} @@ -287,6 +319,7 @@ struct json_command_type_t #define MAP_JON_RPC_WE(method_name, callback_f, command_type) \ else if(auto_doc>("[" method_name "]", generate_reference) && callback_name == method_name) \ { \ + call_found = true; \ PREPARE_OBJECTS_FROM_JSON(command_type) \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ fail_resp.jsonrpc = "2.0"; \ @@ -304,6 +337,7 @@ struct json_command_type_t #define MAP_JON_RPC_WERI(method_name, callback_f, command_type) \ else if(auto_doc>("[" method_name "]", generate_reference) && callback_name == method_name) \ { \ + call_found = true; \ PREPARE_OBJECTS_FROM_JSON(command_type) \ epee::json_rpc::error_response fail_resp = AUTO_VAL_INIT(fail_resp); \ fail_resp.jsonrpc = "2.0"; \ @@ -321,6 +355,7 @@ struct json_command_type_t #define MAP_JON_RPC(method_name, callback_f, command_type) \ else if(auto_doc>(std::string("[") + method_name + "]", generate_reference) && callback_name == method_name) \ { \ + call_found = true; \ PREPARE_OBJECTS_FROM_JSON(command_type) \ if(!callback_f(req.params, resp.result, m_conn_context)) \ { \ diff --git a/contrib/epee/include/net/http_server_impl_base.h b/contrib/epee/include/net/http_server_impl_base.h index c02475c3..4b083804 100644 --- a/contrib/epee/include/net/http_server_impl_base.h +++ b/contrib/epee/include/net/http_server_impl_base.h @@ -31,7 +31,7 @@ #include -#include +#include #include "net/http_server_cp2.h" #include "net/http_server_handlers_map2.h" @@ -65,7 +65,7 @@ namespace epee bool res = m_net_server.init_server(bind_port, bind_ip); if(!res) { - LOG_ERROR("Failed to bind server"); + LOG_ERROR("Failed to bind to " << bind_ip << ":" << bind_port); return false; } return true; @@ -74,14 +74,14 @@ namespace epee bool run(size_t threads_count, bool wait = true) { //go to loop - LOG_PRINT("Run net_service loop( " << threads_count << " threads)...", LOG_LEVEL_0); + LOG_PRINT("Run net_service loop (" << threads_count << " threads)...", LOG_LEVEL_1); if(!m_net_server.run_server(threads_count, wait)) { LOG_ERROR("Failed to run net tcp server!"); } if(wait) - LOG_PRINT("net_service loop stopped.", LOG_LEVEL_0); + LOG_PRINT("net_service loop stopped.", LOG_LEVEL_1); return true; } diff --git a/contrib/epee/include/net/net_helper.h b/contrib/epee/include/net/net_helper.h index 72ff4e75..4a42e679 100644 --- a/contrib/epee/include/net/net_helper.h +++ b/contrib/epee/include/net/net_helper.h @@ -38,12 +38,14 @@ #include #include #include +#include #include #include #include #include #include "net/net_utils_base.h" #include "misc_language.h" +#include "misc_helpers.h" //#include "profile_tools.h" #include "../string_tools.h" @@ -54,637 +56,744 @@ namespace epee { -namespace net_utils -{ + namespace net_utils + { - class blocked_mode_client - { - - - struct handler_obj - { - handler_obj(boost::system::error_code& error, size_t& bytes_transferred):ref_error(error), ref_bytes_transferred(bytes_transferred) - {} - handler_obj(const handler_obj& other_obj):ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred) - {} - - boost::system::error_code& ref_error; - size_t& ref_bytes_transferred; - - void operator()(const boost::system::error_code& error, // Result of operation. - std::size_t bytes_transferred // Number of bytes read. - ) - { - ref_error = error; - ref_bytes_transferred = bytes_transferred; - } - }; - - public: - inline - blocked_mode_client():m_socket(m_io_service), - m_initialized(false), - m_connected(false), - m_deadline(m_io_service), - m_shutdowned(0), - m_connect_timeout{}, - m_reciev_timeout{} - { - - - m_initialized = true; + template + struct socket_backend; - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); - - // Start the persistent actor that checks for deadline expiry. - check_deadline(); - - } - inline - ~blocked_mode_client() - { - NESTED_TRY_ENTRY(); - - //profile_tools::local_coast lc("~blocked_mode_client()", 3); - shutdown(); - - NESTED_CATCH_ENTRY(__func__); - } - - inline void set_recv_timeout(int reciev_timeout) - { - m_reciev_timeout = reciev_timeout; - } - - inline - bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + template<> + struct socket_backend { - return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); - } + socket_backend(boost::asio::io_service& _io_service): m_ssl_context(boost::asio::ssl::context::sslv23), m_socket(_io_service, m_ssl_context) + { + // Create a context that uses the default paths for + // finding CA certificates. + m_ssl_context.set_default_verify_paths(); + /*m_socket.set_verify_mode(boost::asio::ssl::verify_peer); + m_socket.set_verify_callback( + boost::bind(&socket_backend::verify_certificate, this, _1, _2));*/ - inline - bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") - { - m_connect_timeout = connect_timeout; - m_reciev_timeout = reciev_timeout; - m_connected = false; - if(!m_reciev_timeout) - m_reciev_timeout = m_connect_timeout; + } - try - { - m_socket.close(); - // Get a list of endpoints corresponding to the server name. - + /* + bool verify_certificate(bool preverified, + boost::asio::ssl::verify_context& ctx) + { + std::cout << "verify_certificate (preverified " << preverified << " ) ...\n"; + // The verify callback can be used to check whether the certificate that is + // being presented is valid for the peer. For example, RFC 2818 describes + // the steps involved in doing this for HTTPS. Consult the OpenSSL + // documentation for more details. Note that the callback is called once + // for each certificate in the certificate chain, starting from the root + // certificate authority. - ////////////////////////////////////////////////////////////////////////// + // In this example we will simply print the certificate's subject name. + char subject_name[256]; + X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle()); + X509_NAME_oneline(X509_get_subject_name(cert), subject_name, 256); + std::cout << "Verifying " << subject_name << "\n"; - boost::asio::ip::tcp::resolver resolver(m_io_service); - boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port); - boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); - boost::asio::ip::tcp::resolver::iterator end; - if(iterator == end) - { - LOG_ERROR("Failed to resolve " << addr); - return false; - } + // dummy verification + return true; + }*/ - ////////////////////////////////////////////////////////////////////////// + void set_domain(const std::string& domain_name) + { + SSL_set_tlsext_host_name(m_socket.native_handle(), domain_name.c_str()); + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_socket.next_layer(); + } + + auto& get_stream() + { + return m_socket; + } + + void on_after_connect() + { + m_socket.handshake(boost::asio::ssl::stream_base::client); + } + + private: + boost::asio::ssl::context m_ssl_context; + boost::asio::ssl::stream m_socket; + }; + + template<> + struct socket_backend + { + socket_backend(boost::asio::io_service& _io_service): m_socket(_io_service) + {} + + boost::asio::ip::tcp::socket& get_socket() + { + return m_socket; + } + + void set_domain(const std::string& domain_name) + { + + } + + boost::asio::ip::tcp::socket& get_stream() + { + return m_socket; + } + + void on_after_connect() + { + + } + private: + boost::asio::ip::tcp::socket m_socket; + }; - //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); - boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - m_socket.open(remote_endpoint.protocol()); - if(bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "" ) - { - boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); - m_socket.bind(local_endpoint); - } + template + class blocked_mode_client_t + { + struct handler_obj + { + handler_obj(boost::system::error_code& error, size_t& bytes_transferred) :ref_error(error), ref_bytes_transferred(bytes_transferred) + {} + handler_obj(const handler_obj& other_obj) :ref_error(other_obj.ref_error), ref_bytes_transferred(other_obj.ref_bytes_transferred) + {} - - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + boost::system::error_code& ref_error; + size_t& ref_bytes_transferred; + + void operator()(const boost::system::error_code& error, // Result of operation. + std::size_t bytes_transferred // Number of bytes read. + ) + { + ref_error = error; + ref_bytes_transferred = bytes_transferred; + } + }; + + public: + inline + blocked_mode_client_t() :m_sct_back(m_io_service), + m_initialized(false), + m_connected(false), + m_deadline(m_io_service), + m_shutdowned(0), + m_connect_timeout{}, + m_reciev_timeout{} + { - boost::system::error_code ec = boost::asio::error::would_block; - - //m_socket.connect(remote_endpoint); - m_socket.async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - - if (!ec && m_socket.is_open()) - { - m_connected = true; - m_deadline.expires_at(boost::posix_time::pos_infin); - return true; - }else - { - LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); - return false; - } - - } - catch(const boost::system::system_error& er) - { - LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4); - return false; - } - catch(...) - { - LOG_PRINT("Some fatal problems.", LOG_LEVEL_4); - return false; - } - - return true; - } + m_initialized = true; - inline - bool disconnect() - { - try - { - if(m_connected) - { - m_connected = false; - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both); - - } - } - - catch(const boost::system::system_error& /*er*/) - { - //LOG_ERROR("Some problems at disconnect, message: " << er.what()); - return false; - } - catch(...) - { - //LOG_ERROR("Some fatal problems."); - return false; - } - return true; - } + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + + // Start the persistent actor that checks for deadline expiry. + check_deadline(); + + } + inline + ~blocked_mode_client_t() + { + NESTED_TRY_ENTRY(); + + //profile_tools::local_coast lc("~blocked_mode_client()", 3); + shutdown(); + + NESTED_CATCH_ENTRY(__func__); + } + + inline void set_recv_timeout(int reciev_timeout) + { + m_reciev_timeout = reciev_timeout; + } + + inline + bool connect(const std::string& addr, int port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + return connect(addr, std::to_string(port), connect_timeout, reciev_timeout, bind_ip); + } + + inline + bool connect(const std::string& addr, const std::string& port, unsigned int connect_timeout, unsigned int reciev_timeout, const std::string& bind_ip = "0.0.0.0") + { + m_connect_timeout = connect_timeout; + m_reciev_timeout = reciev_timeout; + m_connected = false; + if (!m_reciev_timeout) + m_reciev_timeout = m_connect_timeout; + + try + { + m_sct_back.get_socket().close(); + // Get a list of endpoints corresponding to the server name. - inline - bool send(const std::string& buff) - { + ////////////////////////////////////////////////////////////////////////// - try - { - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + boost::asio::ip::tcp::resolver resolver(m_io_service); + boost::asio::ip::tcp::resolver::query query(boost::asio::ip::tcp::v4(), addr, port); + boost::asio::ip::tcp::resolver::iterator iterator = resolver.resolve(query); + boost::asio::ip::tcp::resolver::iterator end; + if (iterator == end) + { + LOG_ERROR("Failed to resolve " << addr); + return false; + } - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + ////////////////////////////////////////////////////////////////////////// + m_sct_back.set_domain(addr); - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1); + //boost::asio::ip::tcp::endpoint remote_endpoint(boost::asio::ip::address::from_string(addr.c_str()), port); + boost::asio::ip::tcp::endpoint remote_endpoint(*iterator); - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - if (ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); + m_sct_back.get_socket().open(remote_endpoint.protocol()); + if (bind_ip != "0.0.0.0" && bind_ip != "0" && bind_ip != "") + { + boost::asio::ip::tcp::endpoint local_endpoint(boost::asio::ip::address::from_string(addr.c_str()), 0); + m_sct_back.get_socket().bind(local_endpoint); + } + + + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_connect_timeout)); + + + boost::system::error_code ec = boost::asio::error::would_block; + + //m_sct_back.get_socket().connect(remote_endpoint); + m_sct_back.get_socket().async_connect(remote_endpoint, boost::lambda::var(ec) = boost::lambda::_1); + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (!ec && m_sct_back.get_socket().is_open()) + { + m_sct_back.on_after_connect(); + m_connected = true; + m_deadline.expires_at(boost::posix_time::pos_infin); + return true; + } + else + { + LOG_PRINT("Some problems at connect, message: " << ec.message(), LOG_LEVEL_3); + return false; + } + + } + catch (const boost::system::system_error& er) + { + LOG_PRINT("Some problems at connect, message: " << er.what(), LOG_LEVEL_4); + return false; + } + catch (...) + { + LOG_PRINT("Some fatal problems.", LOG_LEVEL_4); + return false; + } + + return true; + } + + + inline + bool disconnect() + { + try + { + if (m_connected) + { + m_connected = false; + m_sct_back.get_socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both); + + } + } + + catch (const boost::system::system_error& /*er*/) + { + //LOG_ERROR("Some problems at disconnect, message: " << er.what()); + return false; + } + catch (...) + { + //LOG_ERROR("Some fatal problems."); + return false; + } + return true; + } + + + inline + bool send(const std::string& buff) + { + + try + { + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_sct_back.get_stream(), boost::asio::buffer(buff), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } + + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; + + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_sct_back.get_socket(), boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + } + */ + boost::system::error_code ec; + + size_t writen = m_sct_back.get_stream().write_some(boost::asio::buffer(data, sz), ec); + + + + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at send, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at connect, message: " << er.what()); - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } + return true; + } - return true; - } + bool is_connected() + { + return m_connected && m_sct_back.get_socket().is_open(); + //TRY_ENTRY() + //return m_socket.is_open(); + //CATCH_ENTRY_L0("is_connected", false) + } - inline - bool send(const void* data, size_t sz) - { - try - { - /* - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + inline + bool recv(std::string& buff) + { - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - } - */ - boost::system::error_code ec; + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. - size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); - + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; + + handler_obj hndlr(ec, bytes_transfered); + + char local_buff[10000] = { 0 }; + //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr); + boost::asio::async_read(m_sct_back.get_stream(), boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr); + + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } - if (!writen || ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); + if (ec) + { + LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value()); + if (ec == boost::asio::error::eof) + { + LOG_PRINT_L4("Connection err_code eof."); + //connection closed there, empty + return true; + } + + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + } + else + { + LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered); + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + /*if(!bytes_transfered) + return false;*/ + + buff.assign(local_buff, bytes_transfered); + return true; + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } - } - - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at send, message: " << er.what()); - m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } - - return true; - } - - bool is_connected() - { - return m_connected && m_socket.is_open(); - //TRY_ENTRY() - //return m_socket.is_open(); - //CATCH_ENTRY_L0("is_connected", false) - } - - inline - bool recv(std::string& buff) - { - - try - { - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_read_until), the deadline applies to the - // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - //boost::system::error_code ec = boost::asio::error::would_block; - - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - - boost::system::error_code ec = boost::asio::error::would_block; - size_t bytes_transfered = 0; - - handler_obj hndlr(ec, bytes_transfered); - - char local_buff[10000] = {0}; - //m_socket.async_read_some(boost::asio::buffer(local_buff, sizeof(local_buff)), hndlr); - boost::asio::async_read(m_socket, boost::asio::buffer(local_buff, sizeof(local_buff)), boost::asio::transfer_at_least(1), hndlr); - - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) - { - m_io_service.run_one(); - } - - - if (ec) - { - LOG_PRINT_L4("READ ENDS: Connection err_code " << ec.value()); - if(ec == boost::asio::error::eof) - { - LOG_PRINT_L4("Connection err_code eof."); - //connection closed there, empty - return true; - } - - LOG_PRINT_L3("Problems at read: " << ec.message()); - m_connected = false; - return false; - }else - { - LOG_PRINT_L4("READ ENDS: Success. bytes_tr: " << bytes_transfered); - m_deadline.expires_at(boost::posix_time::pos_infin); - } - - /*if(!bytes_transfered) - return false;*/ - - buff.assign(local_buff, bytes_transfered); - return true; - } - - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at read, message: " << er.what()); - m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems at read."); - return false; - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } - return false; + return false; - } + } - inline bool recv_n(std::string& buff, int64_t sz) - { + inline bool recv_n(std::string& buff, int64_t sz) + { - try - { - // Set a deadline for the asynchronous operation. Since this function uses - // a composed operation (async_read_until), the deadline applies to the - // entire operation, rather than individual reads from the socket. - m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + try + { + // Set a deadline for the asynchronous operation. Since this function uses + // a composed operation (async_read_until), the deadline applies to the + // entire operation, rather than individual reads from the socket. + m_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - //boost::system::error_code ec = boost::asio::error::would_block; + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + //boost::system::error_code ec = boost::asio::error::would_block; - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. - buff.resize(static_cast(sz)); - boost::system::error_code ec = boost::asio::error::would_block; - size_t bytes_transfered = 0; + buff.resize(static_cast(sz)); + boost::system::error_code ec = boost::asio::error::would_block; + size_t bytes_transfered = 0; - - handler_obj hndlr(ec, bytes_transfered); - //char local_buff[10000] = {0}; - boost::asio::async_read(m_socket, boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr); + handler_obj hndlr(ec, bytes_transfered); - // Block until the asynchronous operation has completed. - while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) - { - m_io_service.run_one(); - } + //char local_buff[10000] = {0}; + boost::asio::async_read(m_sct_back.get_stream(), boost::asio::buffer((char*)buff.data(), buff.size()), boost::asio::transfer_at_least(buff.size()), hndlr); - if (ec) - { - LOG_PRINT_L3("Problems at read: " << ec.message()); + // Block until the asynchronous operation has completed. + while (ec == boost::asio::error::would_block && !boost::interprocess::ipcdetail::atomic_read32(&m_shutdowned)) + { + m_io_service.run_one(); + } + + if (ec) + { + LOG_PRINT_L3("Problems at read: " << ec.message()); + m_connected = false; + return false; + } + else + { + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + if (bytes_transfered != buff.size()) + { + LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size()); + return false; + } + + return true; + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at read, message: " << er.what()); m_connected = false; - return false; - }else - { - m_deadline.expires_at(boost::posix_time::pos_infin); - } + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems at read."); + return false; + } - if(bytes_transfered != buff.size()) - { - LOG_ERROR("Transferred missmatch with transfer_at_least value: m_bytes_transferred=" << bytes_transfered << " at_least value=" << buff.size()); - return false; - } - return true; - } - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at read, message: " << er.what()); + return false; + } + + bool shutdown() + { + m_deadline.cancel(); + boost::system::error_code ignored_ec; + m_sct_back.get_socket().cancel(ignored_ec); + m_sct_back.get_socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); + m_sct_back.get_socket().close(ignored_ec); + boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); m_connected = false; - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems at read."); - return false; - } + return true; + } + + void set_connected(bool connected) + { + m_connected = connected; + } + boost::asio::io_service& get_io_service() + { + return m_io_service; + } + + boost::asio::ip::tcp::socket& get_socket() + { + return m_sct_back.get_socket(); + } + + private: + + void check_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + m_connected = false; + m_sct_back.get_socket().close(); + + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_deadline.expires_at(boost::posix_time::pos_infin); + } + + // Put the actor back to sleep. + m_deadline.async_wait(boost::bind(&blocked_mode_client_t::check_deadline, this)); + } - return false; - } - - bool shutdown() - { - m_deadline.cancel(); - boost::system::error_code ignored_ec; - m_socket.cancel(ignored_ec); - m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ignored_ec); - m_socket.close(ignored_ec); - boost::interprocess::ipcdetail::atomic_write32(&m_shutdowned, 1); - m_connected = false; - return true; - } - - void set_connected(bool connected) - { - m_connected = connected; - } - boost::asio::io_service& get_io_service() - { - return m_io_service; - } - - boost::asio::ip::tcp::socket& get_socket() - { - return m_socket; - } - - private: - - void check_deadline() - { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (m_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) - { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - LOG_PRINT_L3("Timed out socket"); - m_connected = false; - m_socket.close(); - - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - m_deadline.expires_at(boost::posix_time::pos_infin); - } - - // Put the actor back to sleep. - m_deadline.async_wait(boost::bind(&blocked_mode_client::check_deadline, this)); - } - - - - protected: - boost::asio::io_service m_io_service; - boost::asio::ip::tcp::socket m_socket; - int m_connect_timeout; - int m_reciev_timeout; - bool m_initialized; - bool m_connected; - boost::asio::deadline_timer m_deadline; - volatile uint32_t m_shutdowned; - }; + protected: + boost::asio::io_service m_io_service; + socket_backend m_sct_back; + int m_connect_timeout; + int m_reciev_timeout; + bool m_initialized; + bool m_connected; + boost::asio::deadline_timer m_deadline; + volatile uint32_t m_shutdowned; + }; - /************************************************************************/ - /* */ - /************************************************************************/ - class async_blocked_mode_client: public blocked_mode_client - { - public: - async_blocked_mode_client():m_send_deadline(blocked_mode_client::m_io_service) - { + /************************************************************************/ + /* */ + /************************************************************************/ + template + class async_blocked_mode_client_t : public blocked_mode_client_t + { + public: + async_blocked_mode_client_t() :m_send_deadline(blocked_mode_client_t::m_io_service) + { - // No deadline is required until the first socket operation is started. We - // set the deadline to positive infinity so that the actor takes no action - // until a specific deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); + // No deadline is required until the first socket operation is started. We + // set the deadline to positive infinity so that the actor takes no action + // until a specific deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); - // Start the persistent actor that checks for deadline expiry. - check_send_deadline(); - } - ~async_blocked_mode_client() - { - m_send_deadline.cancel(); - } - - bool shutdown() - { - blocked_mode_client::shutdown(); - m_send_deadline.cancel(); - return true; - } + // Start the persistent actor that checks for deadline expiry. + check_send_deadline(); + } + ~async_blocked_mode_client_t() + { + m_send_deadline.cancel(); + } - inline - bool send(const void* data, size_t sz) - { - try - { - /* - m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); + bool shutdown() + { + blocked_mode_client_t::shutdown(); + m_send_deadline.cancel(); + return true; + } - // Set up the variable that receives the result of the asynchronous - // operation. The error code is set to would_block to signal that the - // operation is incomplete. Asio guarantees that its asynchronous - // operations will never fail with would_block, so any other value in - // ec indicates completion. - boost::system::error_code ec = boost::asio::error::would_block; + inline + bool send(const void* data, size_t sz) + { + try + { + /* + m_send_deadline.expires_from_now(boost::posix_time::milliseconds(m_reciev_timeout)); - // Start the asynchronous operation itself. The boost::lambda function - // object is used as a callback and will update the ec variable when the - // operation completes. The blocking_udp_client.cpp example shows how you - // can use boost::bind rather than boost::lambda. - boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); + // Set up the variable that receives the result of the asynchronous + // operation. The error code is set to would_block to signal that the + // operation is incomplete. Asio guarantees that its asynchronous + // operations will never fail with would_block, so any other value in + // ec indicates completion. + boost::system::error_code ec = boost::asio::error::would_block; - // Block until the asynchronous operation has completed. - while(ec == boost::asio::error::would_block) - { - m_io_service.run_one(); - }*/ - - boost::system::error_code ec; + // Start the asynchronous operation itself. The boost::lambda function + // object is used as a callback and will update the ec variable when the + // operation completes. The blocking_udp_client.cpp example shows how you + // can use boost::bind rather than boost::lambda. + boost::asio::async_write(m_socket, boost::asio::buffer(data, sz), boost::lambda::var(ec) = boost::lambda::_1); - size_t writen = m_socket.write_some(boost::asio::buffer(data, sz), ec); + // Block until the asynchronous operation has completed. + while(ec == boost::asio::error::would_block) + { + m_io_service.run_one(); + }*/ - if (!writen || ec) - { - LOG_PRINT_L3("Problems at write: " << ec.message()); - return false; - }else - { - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } - } + boost::system::error_code ec; - catch(const boost::system::system_error& er) - { - LOG_ERROR("Some problems at connect, message: " << er.what()); - return false; - } - catch(...) - { - LOG_ERROR("Some fatal problems."); - return false; - } + size_t writen = blocked_mode_client_t::m_sct_back.get_socket().write_some(boost::asio::buffer(data, sz), ec); - return true; - } + if (!writen || ec) + { + LOG_PRINT_L3("Problems at write: " << ec.message()); + return false; + } + else + { + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } + } + + catch (const boost::system::system_error& er) + { + LOG_ERROR("Some problems at connect, message: " << er.what()); + return false; + } + catch (...) + { + LOG_ERROR("Some fatal problems."); + return false; + } + + return true; + } - private: + private: - boost::asio::deadline_timer m_send_deadline; + boost::asio::deadline_timer m_send_deadline; - void check_send_deadline() - { - // Check whether the deadline has passed. We compare the deadline against - // the current time since a new asynchronous operation may have moved the - // deadline before this actor had a chance to run. - if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) - { - // The deadline has passed. The socket is closed so that any outstanding - // asynchronous operations are cancelled. This allows the blocked - // connect(), read_line() or write_line() functions to return. - LOG_PRINT_L3("Timed out socket"); - m_socket.close(); + void check_send_deadline() + { + // Check whether the deadline has passed. We compare the deadline against + // the current time since a new asynchronous operation may have moved the + // deadline before this actor had a chance to run. + if (m_send_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now()) + { + // The deadline has passed. The socket is closed so that any outstanding + // asynchronous operations are cancelled. This allows the blocked + // connect(), read_line() or write_line() functions to return. + LOG_PRINT_L3("Timed out socket"); + blocked_mode_client_t::m_sct_back.get_socket().close(); - // There is no longer an active deadline. The expiry is set to positive - // infinity so that the actor takes no action until a new deadline is set. - m_send_deadline.expires_at(boost::posix_time::pos_infin); - } + // There is no longer an active deadline. The expiry is set to positive + // infinity so that the actor takes no action until a new deadline is set. + m_send_deadline.expires_at(boost::posix_time::pos_infin); + } - // Put the actor back to sleep. - m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client::check_send_deadline, this)); - } - }; -} + // Put the actor back to sleep. + m_send_deadline.async_wait(boost::bind(&async_blocked_mode_client_t::check_send_deadline, this)); + } + }; + + typedef blocked_mode_client_t blocked_mode_client; + typedef async_blocked_mode_client_t async_blocked_mode_client; + } } diff --git a/contrib/epee/include/net/net_parse_helpers.h b/contrib/epee/include/net/net_parse_helpers.h index 586dac98..57f10753 100644 --- a/contrib/epee/include/net/net_parse_helpers.h +++ b/contrib/epee/include/net/net_parse_helpers.h @@ -155,6 +155,13 @@ namespace net_utils { content.port = boost::lexical_cast(result[6]); } + else + { + if (content.schema == "http") + content.port = 80; + else if (content.schema == "https") + content.port = 443; + } if(result[7].matched) { content.uri = result[7]; diff --git a/contrib/epee/include/net/net_utils_base.h b/contrib/epee/include/net/net_utils_base.h index 1ef06777..8b474516 100644 --- a/contrib/epee/include/net/net_utils_base.h +++ b/contrib/epee/include/net/net_utils_base.h @@ -79,6 +79,8 @@ namespace net_utils m_started(time(NULL)) {} + connection_context_base(const connection_context_base& a) = default; + connection_context_base& operator=(const connection_context_base& a) { set_details(a.m_connection_id, a.m_remote_ip, a.m_remote_port, a.m_is_income); diff --git a/contrib/epee/include/serialization/keyvalue_enable_POD_serialize_as_string.h b/contrib/epee/include/serialization/keyvalue_enable_POD_serialize_as_string.h new file mode 100644 index 00000000..9ae9b7f4 --- /dev/null +++ b/contrib/epee/include/serialization/keyvalue_enable_POD_serialize_as_string.h @@ -0,0 +1,55 @@ +// Copyright (c) 2006-2022, Andrey N. Sabelnikov, www.sabelnikov.net +// 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. +// * Neither the name of the Andrey N. Sabelnikov nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// 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 OWNER 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. +// + +#pragma once +#include "keyvalue_helpers.h" + + +//should be done in global namespace +#define KV_ENABLE_POD_SERIALIZATION_AS_HEX(type_name) \ +namespace epee \ +{ \ + namespace serialization \ + { \ + template \ + bool kv_serialize(const type_name& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) \ + { \ + std::string s = epee::transform_t_pod_to_str(d); \ + return kv_serialize(s, stg, hparent_section, pname); \ + } \ + template \ + bool kv_unserialize(type_name& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) \ + { \ + std::string s; \ + bool r = kv_unserialize(s, stg, hparent_section, pname); \ + if (r) \ + { \ + d = epee::transform_str_to_t_pod(s); \ + } \ + return r; \ + } \ + } \ +} diff --git a/contrib/epee/include/serialization/keyvalue_helpers.h b/contrib/epee/include/serialization/keyvalue_helpers.h index 0ae911b0..79a4886b 100644 --- a/contrib/epee/include/serialization/keyvalue_helpers.h +++ b/contrib/epee/include/serialization/keyvalue_helpers.h @@ -62,6 +62,8 @@ namespace epee t_pod_type transform_str_to_t_pod(const std::string& a) { t_pod_type res = AUTO_VAL_INIT(res); + if (a.empty()) + return res; if (!epee::string_tools::hex_to_pod(a, res)) throw std::runtime_error(std::string("Unable to transform \"") + a + "\" to pod type " + typeid(t_pod_type).name()); return res; diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h index d33d5ad1..c0d46af3 100644 --- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h +++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h @@ -429,6 +429,55 @@ namespace epee bool kv_unserialize(std::deque& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) { return kv_serialization_overloads_impl_is_base_serializable_types, typename std::remove_const::type>::value>::kv_unserialize(d, stg, hparent_section, pname); - } + } + //------------------------------------------------------------------------------------------------------------------- + //boost::optional + template + bool kv_serialize(const boost::optional& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if(d != boost::none) + { + return kv_serialize(*d, stg, hparent_section, pname); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(boost::optional& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + d = t_type(); + bool r = kv_unserialize(*d, stg, hparent_section, pname); + if (!r) + { + d = boost::none; + } + return r; + } + //------------------------------------------------------------------------------------------------------------------- + //boost::shared_ptr + template + bool kv_serialize(const boost::shared_ptr& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + if (d.get()) + { + return kv_serialize(*d, stg, hparent_section, pname); + } + return true; + } + //------------------------------------------------------------------------------------------------------------------- + template + bool kv_unserialize(boost::shared_ptr& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname) + { + d.reset(); + t_type* ptr = new t_type(); + bool r = kv_unserialize(*ptr, stg, hparent_section, pname); + if (!r) + { + d.reset(ptr); + } + return r; + } + + } } \ No newline at end of file diff --git a/contrib/epee/include/storages/http_abstract_invoke.h b/contrib/epee/include/storages/http_abstract_invoke.h index 0b6ef8e3..aa0af3d8 100644 --- a/contrib/epee/include/storages/http_abstract_invoke.h +++ b/contrib/epee/include/storages/http_abstract_invoke.h @@ -29,11 +29,25 @@ #include "portable_storage_template_helper.h" #include "net/http_base.h" #include "net/http_server_handlers_map2.h" +#include "net/http_client.h" namespace epee { namespace net_utils { + + template + bool get_http_json_t(const std::string& url, t_response& result_struct, unsigned int timeout = 5000, const std::string& method = "GET") + { + std::string body; + if (!http::fetch_url(url, body, method, "", timeout)) + { + return false; + } + return serialization::load_t_from_json(result_struct, body); + } + + template bool invoke_http_json_remote_command2(const std::string& url, t_request& out_struct, t_response& result_struct, t_transport& transport, unsigned int timeout = 5000, const std::string& method = "GET") { @@ -72,6 +86,8 @@ namespace epee if(!serialization::store_t_to_binary(out_struct, req_param)) return false; + LOG_PRINT_L3("[HTTP_BIN] ---> " << "[" << &req_param << "][" << method << "][" << url << "] REQUEST BODY BASE64: " << ENDL << epee::string_encoding::base64_encode(req_param)); + const http::http_response_info* pri = NULL; if(!invoke_request(url, transport, timeout, &pri, method, req_param)) { @@ -85,6 +101,8 @@ namespace epee return false; } + LOG_PRINT_L3("[HTTP_BIN] <--- " << "[" << &req_param << "][" << method << "][" << url << "] RESPONSE(" << pri->m_response_code << ") BODY BASE64: " << ENDL << epee::string_encoding::base64_encode(pri->m_body)); + if(pri->m_response_code != 200) { LOG_PRINT_L1("Failed to invoke http request to " << url << ", wrong response code: " << pri->m_response_code); diff --git a/contrib/epee/include/storages/portable_storage.h b/contrib/epee/include/storages/portable_storage.h index 4d36cc03..a5d46e19 100644 --- a/contrib/epee/include/storages/portable_storage.h +++ b/contrib/epee/include/storages/portable_storage.h @@ -77,8 +77,7 @@ namespace epee bool insert_next_section(harray hSecArray, hsection& hinserted_childsection); //------------------------------------------------------------------------ //delete entry (section, value or array) - bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); - + bool delete_entry(const std::string& pentry_name, hsection hparent_section = nullptr); //------------------------------------------------------------------------------- bool store_to_binary(binarybuffer& target); bool load_from_binary(const binarybuffer& target); @@ -87,6 +86,8 @@ namespace epee bool dump_as_json(std::string& targetObj, size_t indent = 0, end_of_line_t eol = eol_crlf); bool load_from_json(const std::string& source); + template + bool enum_entries(hsection hparent_section, cb_t cb); private: section m_root; hsection get_root_section() {return &m_root;} @@ -384,6 +385,20 @@ namespace epee CATCH_ENTRY("portable_storage::insert_first_value", nullptr); } //--------------------------------------------------------------------------------------------------------------- + template + bool portable_storage::enum_entries(hsection hparent_section, cb_t cb) + { + TRY_ENTRY(); + if (!hparent_section) hparent_section = &m_root; + for (const auto& e : hparent_section->m_entries) + { + if (!cb(e.first, e.second)) + break; + } + return true; + CATCH_ENTRY("portable_storage::enum_entries", false); + } + template bool portable_storage::insert_next_value(harray hval_array, const t_value& target) { diff --git a/contrib/epee/include/storages/portable_storage_from_json.h b/contrib/epee/include/storages/portable_storage_from_json.h index 4e74fb7a..fa76cc9b 100644 --- a/contrib/epee/include/storages/portable_storage_from_json.h +++ b/contrib/epee/include/storages/portable_storage_from_json.h @@ -30,7 +30,6 @@ namespace epee { - using namespace misc_utils::parse; namespace serialization { namespace json @@ -86,7 +85,7 @@ namespace epee switch(*it) { case '"': - match_string2(it, buf_end, name); + misc_utils::parse::match_string2(it, buf_end, name); state = match_state_waiting_separator; break; case '}': @@ -107,7 +106,7 @@ namespace epee if(*it == '"') {//just a named string value started std::string val; - match_string2(it, buf_end, val); + misc_utils::parse::match_string2(it, buf_end, val); //insert text value stg.set_value(name, val, current_section); state = match_state_wonder_after_value; @@ -115,7 +114,7 @@ namespace epee {//just a named number value started std::string val; bool is_v_float = false;bool is_signed = false; - match_number2(it, buf_end, val, is_v_float, is_signed); + misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed); if(!is_v_float) { if(is_signed) @@ -136,7 +135,7 @@ namespace epee }else if(isalpha(*it) ) {// could be null, true or false std::string word; - match_word2(it, buf_end, word); + misc_utils::parse::match_word2(it, buf_end, word); if(boost::iequals(word, "null")) { state = match_state_wonder_after_value; @@ -191,7 +190,7 @@ namespace epee { //mean array of strings std::string val; - match_string2(it, buf_end, val); + misc_utils::parse::match_string2(it, buf_end, val); h_array = stg.insert_first_value(name, val, current_section); CHECK_AND_ASSERT_THROW_MES(h_array, " failed to insert values entry"); state = match_state_array_after_value; @@ -200,7 +199,7 @@ namespace epee {//array of numbers value started std::string val; bool is_v_float = false;bool is_signed_val = false; - match_number2(it, buf_end, val, is_v_float, is_signed_val); + misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed_val); if(!is_v_float) { int64_t nval = boost::lexical_cast(val);//bool res = string_tools::string_to_num_fast(val, nval); @@ -222,7 +221,7 @@ namespace epee }else if(isalpha(*it) ) {// array of booleans std::string word; - match_word2(it, buf_end, word); + misc_utils::parse::match_word2(it, buf_end, word); if(boost::iequals(word, "true")) { h_array = stg.insert_first_value(name, true, current_section); @@ -266,7 +265,7 @@ namespace epee if(*it == '"') { std::string val; - match_string2(it, buf_end, val); + misc_utils::parse::match_string2(it, buf_end, val); bool res = stg.insert_next_value(h_array, val); CHECK_AND_ASSERT_THROW_MES(res, "failed to insert values"); state = match_state_array_after_value; @@ -277,7 +276,7 @@ namespace epee {//array of numbers value started std::string val; bool is_v_float = false;bool is_signed_val = false; - match_number2(it, buf_end, val, is_v_float, is_signed_val); + misc_utils::parse::match_number2(it, buf_end, val, is_v_float, is_signed_val); bool insert_res = false; if(!is_v_float) { @@ -299,7 +298,7 @@ namespace epee if(isalpha(*it) ) {// array of booleans std::string word; - match_word2(it, buf_end, word); + misc_utils::parse::match_word2(it, buf_end, word); if(boost::iequals(word, "true")) { bool r = stg.insert_next_value(h_array, true); diff --git a/contrib/epee/include/storages/portable_storage_val_converters.h b/contrib/epee/include/storages/portable_storage_val_converters.h index caf7a322..8e38beeb 100644 --- a/contrib/epee/include/storages/portable_storage_val_converters.h +++ b/contrib/epee/include/storages/portable_storage_val_converters.h @@ -129,7 +129,20 @@ POP_VS_WARNINGS template struct convert_to_integral { - static void convert(const from_type& from, to_type& to) + static void convert(const std::string& from, uint64_t& to) + { + //attempt to convert string to unsigned int + try + { + to = std::stoull(from); + }catch(...) + { + ASSERT_AND_THROW_WRONG_CONVERSION(); + } + } + + template + static void convert(const from_type_t& from, to_type_t& to) { ASSERT_AND_THROW_WRONG_CONVERSION(); } diff --git a/contrib/epee/include/string_coding.h b/contrib/epee/include/string_coding.h index 0b125bbd..a034dec9 100644 --- a/contrib/epee/include/string_coding.h +++ b/contrib/epee/include/string_coding.h @@ -37,6 +37,7 @@ #endif #include #endif +#include #include "warnings.h" @@ -310,7 +311,14 @@ namespace string_encoding return get_md5_as_hexstring(src.data(), src.size()); } #endif - + inline + std::string toupper(std::string s) + { + std::transform(s.begin(), s.end(), s.begin(), + [](unsigned char c) { return std::toupper(c); } // correct + ); + return s; + } } } diff --git a/contrib/epee/include/string_tools.h b/contrib/epee/include/string_tools.h index 95a5d88e..24dbffee 100644 --- a/contrib/epee/include/string_tools.h +++ b/contrib/epee/include/string_tools.h @@ -23,16 +23,12 @@ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // - - - #ifndef _STRING_TOOLS_H_ #define _STRING_TOOLS_H_ -//#include #include #include -//#include +#include #include #include #include @@ -212,7 +208,7 @@ namespace string_tools t_pod_type parse_tpod_from_hex_string(const std::string& str_hash) { t_pod_type t_pod = AUTO_VAL_INIT(t_pod); - parse_tpod_from_hex_string(str_hash, t_pod); + epee::string_tools::parse_tpod_from_hex_string(str_hash, t_pod); // using fully qualified name to avoid Argument-Dependent Lookup issues return t_pod; } //---------------------------------------------------------------------------- @@ -322,13 +318,6 @@ POP_GCC_WARNINGS return true; } -/* template - bool get_xparam_from_command_line(const std::map& res, const std::basic_string & key, t_type& val) - { - - } - */ - template bool get_xparam_from_command_line(const std::map& res, const t_string & key, t_type& val) { @@ -803,6 +792,9 @@ POP_GCC_WARNINGS return buff; } #endif -} -} +} // namespace stringtools +} // namwspace epee + +namespace epst = epee::string_tools; // EPshort alias for convenience + #endif //_STRING_TOOLS_H_ diff --git a/contrib/epee/include/sync_locked_object.h b/contrib/epee/include/sync_locked_object.h index 2980bbb7..aa01e110 100644 --- a/contrib/epee/include/sync_locked_object.h +++ b/contrib/epee/include/sync_locked_object.h @@ -84,6 +84,8 @@ namespace epee template friend class locked_object_proxy; public: + typedef std::shared_ptr> lock_shared_ptr; + std::shared_ptr> lock() { std::shared_ptr> res; diff --git a/contrib/epee/include/syncobj.h b/contrib/epee/include/syncobj.h index 07c0a484..9971ef12 100644 --- a/contrib/epee/include/syncobj.h +++ b/contrib/epee/include/syncobj.h @@ -711,4 +711,4 @@ namespace epee #define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { EXCLUSIVE_CRITICAL_REGION_LOCAL(x) #define EXCLUSIVE_CRITICAL_REGION_END() } -} +} // namespace epee diff --git a/contrib/epee/include/warnings.h b/contrib/epee/include/warnings.h index bbdcd9fe..433372fc 100644 --- a/contrib/epee/include/warnings.h +++ b/contrib/epee/include/warnings.h @@ -12,9 +12,13 @@ #define DISABLE_GCC_WARNING(w) #define DISABLE_CLANG_WARNING(w) #define DISABLE_GCC_AND_CLANG_WARNING(w) +#define ATTRIBUTE_UNUSED #else + +#define ATTRIBUTE_UNUSED __attribute__((unused)) + #include #define PUSH_VS_WARNINGS diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da31da22..6b5ff732 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -124,7 +124,7 @@ ENABLE_SHARED_PCH(currency_core CURRENCY_CORE) add_library(wallet ${WALLET}) if(CMAKE_SYSTEM_NAME STREQUAL "Android" ) add_dependencies(wallet version ${PCH_LIB_NAME}) - target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log) + target_link_libraries(wallet currency_core crypto common zlibstatic ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} android log OpenSSL::SSL OpenSSL::Crypto) else() add_dependencies(wallet version ${PCH_LIB_NAME}) ENABLE_SHARED_PCH(wallet WALLET) @@ -162,19 +162,19 @@ target_link_libraries(currency_core lmdb mdbx) add_executable(daemon ${DAEMON} ${P2P} ${CURRENCY_PROTOCOL}) add_dependencies(daemon version) -target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(daemon rpc stratum currency_core crypto common libminiupnpc-static zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(daemon DAEMON) ENABLE_SHARED_PCH_EXECUTABLE(daemon) add_executable(connectivity_tool ${CONN_TOOL}) add_dependencies(connectivity_tool version) -target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(connectivity_tool currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(connectivity_tool CONN_TOOL) ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool) add_executable(simplewallet ${SIMPLEWALLET}) add_dependencies(simplewallet version) -target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) +target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET) ENABLE_SHARED_PCH_EXECUTABLE(simplewallet) @@ -199,7 +199,7 @@ if(BUILD_GUI) QT5_USE_MODULES(Zano WebEngineWidgets WebChannel) find_package(Qt5PrintSupport REQUIRED) - target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES}) + target_link_libraries(Zano wallet rpc currency_core crypto common zlibstatic ethash Qt5::WebEngineWidgets Qt5::PrintSupport ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES} OpenSSL::SSL OpenSSL::Crypto) if (UNIX AND NOT APPLE) target_link_libraries(Zano rt) endif() diff --git a/src/common/boost_serialization_helper.h b/src/common/boost_serialization_helper.h index 5ad68a05..1f2297a4 100644 --- a/src/common/boost_serialization_helper.h +++ b/src/common/boost_serialization_helper.h @@ -16,6 +16,7 @@ #define CHECK_PROJECT_NAME() std::string project_name = CURRENCY_NAME; ar & project_name; if(!(project_name == CURRENCY_NAME) ) {throw std::runtime_error(std::string("wrong storage file: project name in file: ") + project_name + ", expected: " + CURRENCY_NAME );} + namespace tools { template diff --git a/src/common/boost_serialization_maps.h b/src/common/boost_serialization_maps.h new file mode 100644 index 00000000..7f44e4d2 --- /dev/null +++ b/src/common/boost_serialization_maps.h @@ -0,0 +1,47 @@ +// Copyright (c) 2014-2022 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#define BEGIN_BOOST_SERIALIZATION() template inline void serialize(t_archive &_arch, const unsigned int ver) { + +template struct TAssertEquality { + static_assert(A == B, "Serialization map is not updated, sizeof() missmatch"); + static constexpr bool _cResult = (A == B); +}; + +//experemental feature: self-validated serialization map, needed to not forget add new members to serialization maps +#define BEGIN_BOOST_SERIALIZATION_SV(sz) BEGIN_BOOST_SERIALIZATION() \ + static constexpr bool _cIsEqual = TAssertEquality::_cResult; + + + +#define BOOST_SERIALIZE(x) _arch & x; +#define BOOST_SERIALIZE_BASE_CLASS(class_type) _arch & static_cast(*this); + +#define BOOST_END_VERSION_UNDER(x) \ + if(ver < x ) {return;} + +#define END_BOOST_SERIALIZATION() } + + +/* + example of use: + + struct tx_extra_info + { + crypto::public_key m_tx_pub_key; + extra_alias_entry m_alias; + std::string m_user_data_blob; + extra_attachment_info m_attachment_info; + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(m_tx_pub_key) + BOOST_SERIALIZE(m_alias) + if(ver < xxx) return; + BOOST_SERIALIZE(m_user_data_blob) + BOOST_SERIALIZE(m_attachment_info) + END_BOOST_SERIALIZATION() + }; +*/ diff --git a/src/common/callstack_helper.cpp b/src/common/callstack_helper.cpp index 74bcc557..b84fe5a8 100644 --- a/src/common/callstack_helper.cpp +++ b/src/common/callstack_helper.cpp @@ -137,11 +137,17 @@ namespace tools STACKFRAME64 frame; memset(&frame, 0, sizeof frame); +#ifndef _M_ARM64 frame.AddrPC.Offset = context.Rip; +#endif frame.AddrPC.Mode = AddrModeFlat; +#ifndef _M_ARM64 frame.AddrStack.Offset = context.Rsp; +#endif frame.AddrStack.Mode = AddrModeFlat; +#ifndef _M_ARM64 frame.AddrFrame.Offset = context.Rbp; +#endif frame.AddrFrame.Mode = AddrModeFlat; IMAGEHLP_LINE64 line = { 0 }; diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp index 0474f9cd..a7b9a5ff 100644 --- a/src/common/command_line.cpp +++ b/src/common/command_line.cpp @@ -37,6 +37,7 @@ namespace command_line const arg_descriptor arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database"); const arg_descriptor arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status"); + const arg_descriptor arg_process_predownload_from_path("predownload-from-local-path", "Instead of downloading file use downloaded local file"); const arg_descriptor arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database"); const arg_descriptor arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading"); diff --git a/src/common/command_line.h b/src/common/command_line.h index 2c147d20..905b1067 100644 --- a/src/common/command_line.h +++ b/src/common/command_line.h @@ -229,6 +229,7 @@ namespace command_line extern const arg_descriptor arg_db_engine; extern const arg_descriptor arg_no_predownload; extern const arg_descriptor arg_force_predownload; + extern const arg_descriptor arg_process_predownload_from_path; extern const arg_descriptor arg_validate_predownload; extern const arg_descriptor arg_predownload_link; extern const arg_descriptor arg_deeplink; diff --git a/src/common/crypto_boost_serialization.h b/src/common/crypto_boost_serialization.h deleted file mode 100644 index 310c8e92..00000000 --- a/src/common/crypto_boost_serialization.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2014-2018 Zano Project -// Copyright (c) 2014-2018 The Louisdor Project -// Copyright (c) 2012-2013 The Cryptonote developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "crypto/crypto.h" - -namespace boost -{ - namespace serialization - { - //--------------------------------------------------- - template - inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - template - inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - template - inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - template - inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - - template - inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - template - inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver) - { - a & reinterpret_cast(x); - } - } -} - -//} diff --git a/src/common/crypto_serialization.h b/src/common/crypto_serialization.h new file mode 100644 index 00000000..dd988a68 --- /dev/null +++ b/src/common/crypto_serialization.h @@ -0,0 +1,300 @@ +// Copyright (c) 2014-2024 Zano Project +// Copyright (c) 2014-2018 The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once +#include +#include +#include +#include +#include +#include +#include + +#include "serialization/serialization.h" +#include "serialization/debug_archive.h" +#include "crypto/chacha8.h" +#include "crypto/crypto.h" +#include "crypto/hash.h" +#include "crypto/range_proofs.h" +#include "crypto/clsag.h" +#include "crypto/zarcanum.h" +#include "crypto/one_out_of_many_proofs.h" +#include "boost_serialization_maps.h" +#include "serialization/keyvalue_enable_POD_serialize_as_string.h" +// +// binary serialization +// + +namespace crypto +{ + struct bpp_signature_serialized : public bpp_signature + { + BEGIN_SERIALIZE_OBJECT() + FIELD(L) + FIELD(R) + FIELD(A0) + FIELD(A) + FIELD(B) + FIELD(r) + FIELD(s) + FIELD(delta) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(L) + BOOST_SERIALIZE(R) + BOOST_SERIALIZE(A0) + BOOST_SERIALIZE(A) + BOOST_SERIALIZE(B) + BOOST_SERIALIZE(r) + BOOST_SERIALIZE(s) + BOOST_SERIALIZE(delta) + END_BOOST_SERIALIZATION() + }; + + struct bppe_signature_serialized : public bppe_signature + { + BEGIN_SERIALIZE_OBJECT() + FIELD(L) + FIELD(R) + FIELD(A0) + FIELD(A) + FIELD(B) + FIELD(r) + FIELD(s) + FIELD(delta_1) + FIELD(delta_2) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(L) + BOOST_SERIALIZE(R) + BOOST_SERIALIZE(A0) + BOOST_SERIALIZE(A) + BOOST_SERIALIZE(B) + BOOST_SERIALIZE(r) + BOOST_SERIALIZE(s) + BOOST_SERIALIZE(delta_1) + BOOST_SERIALIZE(delta_2) + END_BOOST_SERIALIZATION() + }; + + struct CLSAG_GG_signature_serialized : public CLSAG_GG_signature + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD((std::vector&)(r)) + FIELD(K1) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE((std::vector&)(r)) + BOOST_SERIALIZE(K1) + END_BOOST_SERIALIZATION() + }; + + struct CLSAG_GGX_signature_serialized : public CLSAG_GGX_signature + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD((std::vector&)(r_g)) + FIELD((std::vector&)(r_x)) + FIELD(K1) + FIELD(K2) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE((std::vector&)(r_g)) + BOOST_SERIALIZE((std::vector&)(r_x)) + BOOST_SERIALIZE(K1) + BOOST_SERIALIZE(K2) + END_BOOST_SERIALIZATION() + }; + + struct CLSAG_GGXXG_signature_serialized : public CLSAG_GGXXG_signature + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD_N("r_g", (std::vector&)(r_g)) + FIELD_N("r_x", (std::vector&)(r_x)) + FIELD(K1) + FIELD(K2) + FIELD(K3) + FIELD(K4) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE((std::vector&)(r_g)) + BOOST_SERIALIZE((std::vector&)(r_x)) + BOOST_SERIALIZE(K1) + BOOST_SERIALIZE(K2) + BOOST_SERIALIZE(K3) + BOOST_SERIALIZE(K4) + END_BOOST_SERIALIZATION() + }; + + struct vector_UG_aggregation_proof_serialized : public vector_UG_aggregation_proof + { + BEGIN_SERIALIZE_OBJECT() + FIELD(amount_commitments_for_rp_aggregation) + FIELD((std::vector&)(y0s)) + FIELD((std::vector&)(y1s)) + FIELD(c) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(amount_commitments_for_rp_aggregation) + BOOST_SERIALIZE((std::vector&)(y0s)) + BOOST_SERIALIZE((std::vector&)(y1s)) + BOOST_SERIALIZE(c) + END_BOOST_SERIALIZATION() + }; + + struct linear_composition_proof_s : public linear_composition_proof + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD(y0) + FIELD(y1) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE(y0) + BOOST_SERIALIZE(y1) + END_BOOST_SERIALIZATION() + }; + + struct generic_schnorr_sig_s : public generic_schnorr_sig + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD(y) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE(y) + END_BOOST_SERIALIZATION() + }; + + struct generic_double_schnorr_sig_s : public generic_double_schnorr_sig + { + BEGIN_SERIALIZE_OBJECT() + FIELD(c) + FIELD(y0) + FIELD(y1) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(c) + BOOST_SERIALIZE(y0) + BOOST_SERIALIZE(y1) + END_BOOST_SERIALIZATION() + }; + + struct BGE_proof_s : public BGE_proof + { + BEGIN_SERIALIZE_OBJECT() + FIELD(A) + FIELD(B) + FIELD(Pk) + FIELD_N("f", (std::vector&)(f)) + FIELD(y) + FIELD(z) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(A) + BOOST_SERIALIZE(B) + BOOST_SERIALIZE(Pk) + BOOST_SERIALIZE(f) + BOOST_SERIALIZE(y) + BOOST_SERIALIZE(z) + END_BOOST_SERIALIZATION() + }; + +} // namespace crypto + +BLOB_SERIALIZER(crypto::chacha8_iv); +BLOB_SERIALIZER(crypto::hash); +BLOB_SERIALIZER(crypto::public_key); +BLOB_SERIALIZER(crypto::secret_key); +BLOB_SERIALIZER(crypto::key_derivation); +BLOB_SERIALIZER(crypto::key_image); +BLOB_SERIALIZER(crypto::signature); +BLOB_SERIALIZER(crypto::scalar_t); +BLOB_SERIALIZER(crypto::point_t); + +VARIANT_TAG(debug_archive, crypto::hash, "hash"); +VARIANT_TAG(debug_archive, crypto::public_key, "public_key"); +VARIANT_TAG(debug_archive, crypto::secret_key, "secret_key"); +VARIANT_TAG(debug_archive, crypto::key_derivation, "key_derivation"); +VARIANT_TAG(debug_archive, crypto::key_image, "key_image"); +VARIANT_TAG(debug_archive, crypto::signature, "signature"); + + +// +// Key-value serialization +// + +KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::scalar_t); +KV_ENABLE_POD_SERIALIZATION_AS_HEX(crypto::hash); + +// +// Boost serialization +// + +namespace boost +{ + namespace serialization + { + //--------------------------------------------------- + template + inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + + template + inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::scalar_t &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + template + inline void serialize(Archive &a, crypto::point_t &x, const boost::serialization::version_type ver) + { + a & reinterpret_cast(x); + } + } // namespace serialization +} // namespace boost diff --git a/src/common/db_backend_lmdb.cpp b/src/common/db_backend_lmdb.cpp index 6dfb1eea..75e60ce4 100644 --- a/src/common/db_backend_lmdb.cpp +++ b/src/common/db_backend_lmdb.cpp @@ -291,6 +291,10 @@ namespace tools if (res == MDB_NOTFOUND) return false; + if (res != MDB_SUCCESS) + { + return false; + } CHECK_AND_ASSERT_MESS_LMDB_DB(res, false, "Unable to mdb_get, h: " << h << ", ks: " << ks); res_buff.assign((const char*)data.mv_data, data.mv_size); diff --git a/src/common/error_codes.h b/src/common/error_codes.h index 7b77fec3..a1278d4b 100644 --- a/src/common/error_codes.h +++ b/src/common/error_codes.h @@ -4,6 +4,7 @@ #pragma once +#include "../currency_core/basic_api_response_codes.h" #define API_RETURN_CODE_OK BASIC_RESPONSE_STATUS_OK #define API_RETURN_CODE_FAIL BASIC_RESPONSE_STATUS_FAILED @@ -23,6 +24,7 @@ #define API_RETURN_CODE_WALLET_WRONG_ID "WALLET_WRONG_ID" #define API_RETURN_CODE_WALLET_WATCH_ONLY_NOT_SUPPORTED "WALLET_WATCH_ONLY_NOT_SUPPORTED" #define API_RETURN_CODE_WALLET_AUDITABLE_NOT_SUPPORTED "WALLET_AUDITABLE_NOT_SUPPORTED" +#define API_RETURN_CODE_WALLET_FEE_TOO_LOW "API_RETURN_CODE_WALLET_FEE_TOO_LOW" #define API_RETURN_CODE_FILE_NOT_FOUND "FILE_NOT_FOUND" #define API_RETURN_CODE_ALREADY_EXISTS "ALREADY_EXISTS" #define API_RETURN_CODE_CANCELED "CANCELED" @@ -40,4 +42,5 @@ #define API_RETURN_CODE_TX_IS_TOO_BIG "TX_IS_TOO_BIG" #define API_RETURN_CODE_TX_REJECTED "TX_REJECTED" #define API_RETURN_CODE_HTLC_ORIGIN_HASH_MISSMATCHED "HTLC_ORIGIN_HASH_MISSMATCHED" -#define API_RETURN_CODE_WRAP "WRAP" \ No newline at end of file +#define API_RETURN_CODE_WRAP "WRAP" +#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS" diff --git a/src/common/ntp.cpp b/src/common/ntp.cpp index db55610a..0b50e9be 100644 --- a/src/common/ntp.cpp +++ b/src/common/ntp.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019 Zano Project +// Copyright (c) 2019-2022 Zano Project // Note: class udp_blocking_client is a slightly modified version of an example // taken from https://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/example/timeouts/blocking_udp_client.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/src/common/pre_download.h b/src/common/pre_download.h index 373c0bd4..ec12df55 100644 --- a/src/common/pre_download.h +++ b/src/common/pre_download.h @@ -21,8 +21,8 @@ namespace tools }; #ifndef TESTNET - static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2200000.pak", "c3bd64c62495c3f266759750952519f13f32fc161b59547beaa8202b6e26d516", 2628767033, 5100195840 }; - static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2200000.pak", "fcbf0ab3b23836e1a51fa675e719900fb94110cfb74790b3323cebce7fb9f5bd", 3426025872, 4954472448 }; + static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2500000.pak", "8ffa2cb4213f4f96f97033c65a9e52bc350f683237808597784e79b24d5bfee7", 3242348793, 5905489920 }; + static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2500000.pak", "5509650e12c8f901e6731a2bfaf3abfd64409e3e1366d3d94cd11db8beddb0c3", 4239505801, 5893566464 }; #else static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 }; static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 }; @@ -50,6 +50,7 @@ namespace tools boost::system::error_code ec; uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec); + if (ec) sz = 0; bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload); if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) ) { @@ -59,53 +60,59 @@ namespace tools // okay, let's download - std::string downloading_file_path = db_main_file_path + ".download"; - - LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0); - epee::net_utils::http::interruptible_http_client cl; - - crypto::stream_cn_hash hash_stream; - auto last_update = std::chrono::system_clock::now(); - - auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes) + if (!command_line::has_arg(vm, command_line::arg_process_predownload_from_path)) { - if (cb_should_stop(total_bytes, received_bytes)) + + LOG_PRINT_MAGENTA("Trying to download blockchain database from " << url << " ...", LOG_LEVEL_0); + epee::net_utils::http::interruptible_http_client cl; + + crypto::stream_cn_hash hash_stream; + auto last_update = std::chrono::system_clock::now(); + + auto cb = [&hash_stream, &last_update, &cb_should_stop](const std::string& buff, uint64_t total_bytes, uint64_t received_bytes) { - LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0); - return false; + if (cb_should_stop(total_bytes, received_bytes)) + { + LOG_PRINT_MAGENTA(ENDL << "Interrupting download", LOG_LEVEL_0); + return false; + } + + hash_stream.update(buff.data(), buff.size()); + + auto dif = std::chrono::system_clock::now() - last_update; + if (dif >= std::chrono::milliseconds(300)) + { + boost::io::ios_flags_saver ifs(std::cout); + std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r"; + last_update = std::chrono::system_clock::now(); + } + + return true; + }; + + tools::create_directories_if_necessary(working_folder); + r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */); + if (!r) + { + LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0); + return !flag_force_predownload; // fatal error only if force-predownload } - hash_stream.update(buff.data(), buff.size()); - - auto dif = std::chrono::system_clock::now() - last_update; - if (dif >= std::chrono::milliseconds(300)) + crypto::hash data_hash = hash_stream.calculate_hash(); + if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash) { - boost::io::ios_flags_saver ifs(std::cout); - std::cout << "Received " << received_bytes / 1048576 << " of " << total_bytes / 1048576 << " MiB ( " << std::fixed << std::setprecision(1) << 100.0 * received_bytes / total_bytes << " %)\r"; - last_update = std::chrono::system_clock::now(); + LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash); + return !flag_force_predownload; // fatal error only if force-predownload } - return true; - }; - - tools::create_directories_if_necessary(working_folder); - r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */); - if (!r) - { - LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0); - return !flag_force_predownload; // fatal error only if force-predownload + LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct", LOG_LEVEL_0); } - - crypto::hash data_hash = hash_stream.calculate_hash(); - if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash) + else { - LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash); - return !flag_force_predownload; // fatal error only if force-predownload + downloading_file_path = command_line::get_arg(vm, command_line::arg_process_predownload_from_path); } - LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0); - if (!command_line::has_arg(vm, command_line::arg_validate_predownload)) { boost::filesystem::remove(db_main_file_path, ec); @@ -138,11 +145,14 @@ namespace tools std::string path_to_temp_blockchain_file = path_to_temp_blockchain + "/" + dbbs.get_db_main_file_name(); tools::create_directories_if_necessary(path_to_temp_blockchain); - boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec); - if (ec) + if (downloading_file_path != path_to_temp_blockchain_file) { - LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file); - return false; + boost::filesystem::rename(downloading_file_path, path_to_temp_blockchain_file, ec); + if (ec) + { + LOG_ERROR("Rename failed: " << downloading_file_path << " -> " << path_to_temp_blockchain_file); + return false; + } } // remove old blockchain database from disk @@ -180,6 +190,28 @@ namespace tools r = target_core.init(target_core_vm); CHECK_AND_ASSERT_MES(r, false, "Failed to init target core"); + if (true/*TODO: copnfigure with command line option*/) + { + //set checkpoints + { + currency::checkpoints checkpoints; + bool res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + res = source_core.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + } + { + currency::checkpoints checkpoints; + bool res = currency::create_checkpoints(checkpoints); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize checkpoints"); + res = target_core.set_checkpoints(std::move(checkpoints)); + CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core"); + } + } + + + + CHECK_AND_ASSERT_MES(target_core.get_top_block_height() == 0, false, "Target blockchain initialized not empty"); uint64_t total_blocks = source_core.get_current_blockchain_size(); diff --git a/src/common/variant_helper.h b/src/common/variant_helper.h new file mode 100644 index 00000000..7fcf996b --- /dev/null +++ b/src/common/variant_helper.h @@ -0,0 +1,58 @@ +// Copyright (c) 2014-2018 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#define VARIANT_SWITCH_BEGIN(v_type_obj) {auto & local_reference_eokcmeokmeokcm ATTRIBUTE_UNUSED = v_type_obj; if(false) {; +#define VARIANT_CASE_CONST(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { const v_type& typed_name ATTRIBUTE_UNUSED = boost::get(local_reference_eokcmeokmeokcm); +#define VARIANT_CASE(v_type, typed_name) } else if(local_reference_eokcmeokmeokcm.type() == typeid(v_type)) { v_type& typed_name ATTRIBUTE_UNUSED = boost::get(local_reference_eokcmeokmeokcm); +#define VARIANT_CASE_TV(v_type) VARIANT_CASE(v_type, tv) +#define VARIANT_CASE_OTHER() } else { +#define VARIANT_CASE_THROW_ON_OTHER() } else { ASSERT_MES_AND_THROW("Unknown type in switch statemet: " << local_reference_eokcmeokmeokcm.type().name()); +#define VARIANT_CASE_THROW_ON_OTHER_MSG(err_msg) } else { ASSERT_MES_AND_THROW(err_msg << local_reference_eokcmeokmeokcm.type().name()); + +#define VARIANT_SWITCH_END() } } + + +/* + +usage: + + + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE(tx_out_bare, o); + + VARIANT_CASE_TV(tx_out_zarcanum); + //@#@ + VARIANT_SWITCH_END(); + + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE_CONST(txout_to_key, o); + VARIANT_CASE_CONST(txout_multisig, ms); + VARIANT_CASE_CONST(txout_htlc, htlc); + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + + + + VARIANT_SWITCH_BEGIN(s); + VARIANT_CASE(void_sig, v); + VARIANT_CASE(NLSAG_sig, signatures); + VARIANT_CASE(zarcanum_sig, s); + //@#@ + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + + + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE(tx_out_bare, o) + + VARIANT_CASE_TV(tx_out_zarcanum) + //@#@ + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + + +*/ + diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp index 1ee022b3..07528c56 100644 --- a/src/connectivity_tool/conn_tool.cpp +++ b/src/connectivity_tool/conn_tool.cpp @@ -407,8 +407,12 @@ bool generate_genesis(const std::string& path_config, uint64_t premine_split_amo ss.str(""); ss.clear(); + const account_public_address dummy_address = AUTO_VAL_INIT(dummy_address); + std::cout << ENDL << "PROOF PHRASE: " << gcp.proof_string << ENDL; - construct_miner_tx(0, 0, 0, 0, 0, destinations, bl.miner_tx, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS); + uint64_t block_reward_without_fee = 0; + uint64_t block_reward = 0; + construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, block_reward, TRANSACTION_VERSION_PRE_HF4, gcp.proof_string, CURRENCY_MINER_TX_MAX_OUTS, false, pos_entry(), nullptr, nullptr, destinations); currency::blobdata txb = tx_to_blob(bl.miner_tx); //self validate block diff --git a/src/crypto/RIPEMD160_helper.cpp b/src/crypto/RIPEMD160_helper.cpp index 1386540a..9962802f 100644 --- a/src/crypto/RIPEMD160_helper.cpp +++ b/src/crypto/RIPEMD160_helper.cpp @@ -1,9 +1,6 @@ // Copyright (c) 2020 The Zano developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once - #include "RIPEMD160_helper.h" #include "auto_val_init.h" extern "C" { @@ -18,7 +15,7 @@ namespace crypto { { dword MDbuf[RMDsize / 32] = {0}; /* contains (A, B, C, D(, E)) */ - byte* hashcode = (byte*)&h; /* hashcode[RMDsize / 8]; /* for final hash-value */ + byte* hashcode = (byte*)&h; /* hashcode[RMDsize / 8]; for final hash-value */ dword X[16] = {0}; /* current 16-word chunk */ unsigned int i = 0; /* counter */ dword length = static_cast(length_size_t); /* length in bytes of message */ diff --git a/src/crypto/bitcoin/sha256.cpp b/src/crypto/bitcoin/sha256.cpp index 56266951..20c994f3 100644 --- a/src/crypto/bitcoin/sha256.cpp +++ b/src/crypto/bitcoin/sha256.cpp @@ -7,7 +7,7 @@ #include #include - +#include "warnings.h" //#include #if defined(__x86_64__) || defined(__amd64__) || defined(__i386__) @@ -462,6 +462,9 @@ namespace TransformD64Type TransformD64_4way = nullptr; TransformD64Type TransformD64_8way = nullptr; + PUSH_GCC_WARNINGS + DISABLE_GCC_AND_CLANG_WARNING(unused-function) + bool SelfTest() { // Input state (equal to the initial SHA256 state) static const uint32_t init[8] = { @@ -626,7 +629,7 @@ std::string SHA256AutoDetect() assert(SelfTest()); return ret; } - +POP_GCC_WARNINGS ////// SHA-256 CSHA256::CSHA256() : bytes(0) diff --git a/src/crypto/clsag.cpp b/src/crypto/clsag.cpp new file mode 100644 index 00000000..26be2c59 --- /dev/null +++ b/src/crypto/clsag.cpp @@ -0,0 +1,1132 @@ +// Copyright (c) 2022-2024 Zano Project +// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +// This file contains implementation of the original d-CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el) +// and the extended d/v-CLSAG version (s.a. https://github.com/hyle-team/docs/blob/master/zano/dv-CLSAG-extension/ by sowle) +// +#include "clsag.h" +//#include "misc_log_ex.h" +#include "../currency_core/crypto_config.h" + +DISABLE_GCC_AND_CLANG_WARNING(unused-function) + +namespace crypto +{ +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + + static std::ostream &operator <<(std::ostream &o, const crypto::hash &v) { return o << pod_to_hex(v); } + static std::ostream &operator <<(std::ostream &o, const crypto::public_key &v) { return o << pod_to_hex(v); } + + bool generate_CLSAG_GG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki, + const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig) + { + DBG_PRINT("generate_CLSAG_GG"); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range"); + + // calculate key images + point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address); + point_t key_image = secret_x * ki_base; + CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch"); + point_t K1_div8 = (c_scalar_1div8 * secret_f) * ki_base; + K1_div8.to_public_key(sig.K1); + point_t K1 = K1_div8; + K1.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(3 + 2 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + } + hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hash input_hash = hsc.calc_hash_no_reduce(); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // calculate aggregate pub keys + std::vector W_pub_keys; + W_pub_keys.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys.emplace_back(agg_coeff_0 * point_t(ring[i].stealth_address) + agg_coeff_1 * (point_t(ring[i].amount_commitment).modify_mul8() - pseudo_out_amount_commitment)); + DBG_VAL_PRINT(W_pub_keys[i]); + } + + // aggregate secret key + scalar_t w_sec_key = agg_coeff_0 * secret_x + agg_coeff_1 * secret_f; + + // calculate aggregate key image + point_t W_key_image = agg_coeff_0 * key_image + agg_coeff_1 * K1; + DBG_VAL_PRINT(W_key_image); + + // initial commitment + scalar_t alpha = scalar_t::random(); + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(alpha * c_point_G); + hsc.add_point(alpha * ki_base); + scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1} + + sig.r.resize_and_make_random(ring_size); + + for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size) + { + if (i == 0) + sig.c = c_prev; // c_0 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r[i] * c_point_G + c_prev * W_pub_keys[i]); + hsc.add_point(sig.r[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image); + c_prev = hsc.calc_hash(); // c_{i + 1} + } + + if (secret_index == 0) + sig.c = c_prev; + + sig.r[secret_index] = alpha - c_prev * w_sec_key; + + return true; + } + + + + bool verify_CLSAG_GG(const hash& m, const std::vector& ring, const crypto::public_key& pseudo_out_amount_commitment, const key_image& ki, + const CLSAG_GG_signature& sig) + { + DBG_PRINT("verify_CLSAG_GG"); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r.size(), "ring size != r size"); + + point_t key_image(ki); + CRYPTO_CHECK_AND_THROW_MES(key_image.is_in_main_subgroup(), "key image 0 does not belong to the main subgroup"); + + point_t pseudo_out_amount_commitment_pt(pseudo_out_amount_commitment); + pseudo_out_amount_commitment_pt.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(3 + 2 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + } + hsc.add_pub_key(pseudo_out_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hash input_hash = hsc.calc_hash_no_reduce(); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + + // calculate aggregate pub keys + std::vector W_pub_keys; + W_pub_keys.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys.emplace_back(agg_coeff_0 * point_t(ring[i].stealth_address) + agg_coeff_1 * (point_t(ring[i].amount_commitment).modify_mul8() - pseudo_out_amount_commitment_pt)); + DBG_VAL_PRINT(W_pub_keys[i]); + } + + // calculate aggregate key image + point_t W_key_image = agg_coeff_0 * key_image + agg_coeff_1 * point_t(sig.K1).modify_mul8(); + DBG_VAL_PRINT(W_key_image); + + scalar_t c_prev = sig.c; + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r[i] * c_point_G + c_prev * W_pub_keys[i]); + hsc.add_point(sig.r[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image); + c_prev = hsc.calc_hash(); // c_{i + 1} + } + + return c_prev == sig.c; + } + + + //--------------------------------------------------------------- + + // + // Disclaimer: extensions to the CLSAG implemented below are non-standard and are in proof-of-concept state. + // They shouldn't be used in production code until formal security proofs are done and (ideally) the code is peer-reviewed. + // -- sowle + // + + + bool generate_CLSAG_GGX(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_blinded_asset_id, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_t, uint64_t secret_index, CLSAG_GGX_signature& sig) + { + DBG_PRINT("== generate_CLSAG_GGX =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range"); + + // calculate key images + point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address); + point_t key_image = secret_0_xp * ki_base; + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch"); + CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch"); + CRYPTO_CHECK_AND_THROW_MES( secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch"); + CRYPTO_CHECK_AND_THROW_MES( secret_2_t * c_point_X == 8 * point_t(ring[secret_index].blinded_asset_id) - pseudo_out_blinded_asset_id, "secret_2_t mismatch"); +#endif + + point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base; + K1_div8.to_public_key(sig.K1); + point_t K1 = K1_div8; + K1.modify_mul8(); + + point_t K2_div8 = (c_scalar_1div8 * secret_2_t) * ki_base; + K2_div8.to_public_key(sig.K2); + point_t K2 = K2_div8; + K2.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(4 + 3 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].blinded_asset_id); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id); + } + hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment); + hsc.add_point(c_scalar_1div8 * pseudo_out_blinded_asset_id); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + // prepare A_i, Q_i + std::vector A_i, Q_i; + A_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].blinded_asset_id); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment) + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layer 2; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (Q_i[i] - pseudo_out_blinded_asset_id) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + // aggregate secret key (layers 0, 1; G component) + scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f; + DBG_VAL_PRINT(w_sec_key_g * c_point_G); + + // aggregate secret key (layer 2; X component) + scalar_t w_sec_key_x = agg_coeff_2 * secret_2_t; + DBG_VAL_PRINT(w_sec_key_x * c_point_X); + + // calculate aggregate key image (layers 0, 1; G component) + point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1; + DBG_VAL_PRINT(key_image); + DBG_VAL_PRINT(K1); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2; X component) + point_t W_key_image_x = agg_coeff_2 * K2; + DBG_VAL_PRINT(K2); + DBG_VAL_PRINT(W_key_image_x); + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * c_point_G == W_pub_keys_g[secret_index], "aggregated secret G and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_g, "aggregated secret G and key image mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * c_point_X == W_pub_keys_x[secret_index], "aggregated secret X and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_x, "aggregated secret X and key image mismatch"); +#endif + + // initial commitment + scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1 + scalar_t alpha_x = scalar_t::random(); // randomness for layer 2 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(alpha_g * c_point_G); + hsc.add_point(alpha_g * ki_base); + hsc.add_point(alpha_x * c_point_X); + hsc.add_point(alpha_x * ki_base); + //DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")"); + scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1} + + sig.r_g.resize_and_make_random(ring_size); + sig.r_x.resize_and_make_random(ring_size); + + for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size) + { + DBG_PRINT("c[" << i << "] = " << c_prev); + if (i == 0) + sig.c = c_prev; // c_0 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + } + DBG_PRINT("c[" << secret_index << "] = " << c_prev); + + if (secret_index == 0) + sig.c = c_prev; + + sig.r_g[secret_index] = alpha_g - c_prev * w_sec_key_g; + sig.r_x[secret_index] = alpha_x - c_prev * w_sec_key_x; + + return true; + } + + bool verify_CLSAG_GGX(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, + const public_key& pseudo_out_blinded_asset_id, const key_image& ki, const CLSAG_GGX_signature& sig) + { + DBG_PRINT("== verify_CLSAG_GGX =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_g.size(), "ring size != r_g size"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_x.size(), "ring size != r_x size"); + + point_t key_image(ki); + CRYPTO_CHECK_AND_THROW_MES(key_image.is_in_main_subgroup(), "key image 0 does not belong to the main subgroup"); + + point_t pseudo_out_amount_commitment_pt(pseudo_out_amount_commitment); + pseudo_out_amount_commitment_pt.modify_mul8(); + + point_t pseudo_out_blinded_asset_id_pt(pseudo_out_blinded_asset_id); + pseudo_out_blinded_asset_id_pt.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(4 + 3 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].blinded_asset_id); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id); + } + hsc.add_pub_key(pseudo_out_amount_commitment); + hsc.add_pub_key(pseudo_out_blinded_asset_id); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + // prepare A_i, Q_i + std::vector A_i, Q_i; + A_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].blinded_asset_id); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment_pt) + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layer 2; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (Q_i[i] - pseudo_out_blinded_asset_id_pt) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + // calculate aggregate key image (layers 0, 1; G components) + point_t W_key_image_g = + agg_coeff_0 * key_image + + agg_coeff_1 * point_t(sig.K1).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K1).modify_mul8()); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2; X component) + point_t W_key_image_x = + agg_coeff_2 * point_t(sig.K2).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K2).modify_mul8()); + DBG_VAL_PRINT(W_key_image_x); + + + scalar_t c_prev = sig.c; + DBG_PRINT("c[0] = " << c_prev); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGX_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + DBG_PRINT("c[" << i + 1 << "] = " << c_prev); + //DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); + } + + return c_prev == sig.c; + } + + + //--------------------------------------------------------------- + /* + + bool generate_CLSAG_GGXG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig) + { + DBG_PRINT("== generate_CLSAG_GGXG =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range"); + + // calculate key images + point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address); + point_t key_image = secret_0_xp * ki_base; + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch"); + CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch"); + CRYPTO_CHECK_AND_THROW_MES(secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch"); + CRYPTO_CHECK_AND_THROW_MES(secret_3_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch"); + CRYPTO_CHECK_AND_THROW_MES(secret_2_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), "secret_2_x mismatch"); +#endif + + point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base; + K1_div8.to_public_key(sig.K1); + point_t K1 = K1_div8; + K1.modify_mul8(); + + point_t K2_div8 = (c_scalar_1div8 * secret_2_x) * ki_base; + K2_div8.to_public_key(sig.K2); + point_t K2 = K2_div8; + K2.modify_mul8(); + + point_t K3_div8 = (c_scalar_1div8 * secret_3_q) * ki_base; + K3_div8.to_public_key(sig.K3); + point_t K3 = K3_div8; + K3.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(4 + 3 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].concealing_point); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", cp:" << ring[i].concealing_point); + } + hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment); + hsc.add_point(c_scalar_1div8 * extended_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hsc.add_pub_key(sig.K3); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_3); + hsc.add_hash(input_hash); + scalar_t agg_coeff_3 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_3); + + // prepare A_i, Q_i + std::vector A_i, Q_i; + A_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].concealing_point); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1, 3; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment) + + agg_coeff_3 * Q_i[i] + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layer 2; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (extended_amount_commitment - A_i[i] - Q_i[i]) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + // aggregate secret key (layers 0, 1, 3; G component) + scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f + agg_coeff_3 * secret_3_q; + DBG_VAL_PRINT(w_sec_key_g * c_point_G); + + // aggregate secret key (layer 2; X component) + scalar_t w_sec_key_x = agg_coeff_2 * secret_2_x; + DBG_VAL_PRINT(w_sec_key_x * c_point_X); + + // calculate aggregate key image (layers 0, 1, 3; G component) + point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + agg_coeff_3 * K3; + DBG_VAL_PRINT(key_image); + DBG_VAL_PRINT(K1); + DBG_VAL_PRINT(K3); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2; X component) + point_t W_key_image_x = agg_coeff_2 * K2; + DBG_VAL_PRINT(K2); + DBG_VAL_PRINT(W_key_image_x); + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * c_point_G == W_pub_keys_g[secret_index], "aggregated secret G and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_g, "aggregated secret G and key image mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * c_point_X == W_pub_keys_x[secret_index], "aggregated secret X and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_x, "aggregated secret X and key image mismatch"); +#endif + + // initial commitment + scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1,3 + scalar_t alpha_x = scalar_t::random(); // randomness for layer 2 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(alpha_g * c_point_G); + hsc.add_point(alpha_g * ki_base); + hsc.add_point(alpha_x * c_point_X); + hsc.add_point(alpha_x * ki_base); + //DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")"); + scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1} + + sig.r_g.resize_and_make_random(ring_size); + sig.r_x.resize_and_make_random(ring_size); + + for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size) + { + DBG_PRINT("c[" << i << "] = " << c_prev); + if (i == 0) + sig.c = c_prev; // c_0 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + } + DBG_PRINT("c[" << secret_index << "] = " << c_prev); + + if (secret_index == 0) + sig.c = c_prev; + + sig.r_g[secret_index] = alpha_g - c_prev * w_sec_key_g; + sig.r_x[secret_index] = alpha_x - c_prev * w_sec_key_x; + + return true; + } + + + bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, + const key_image& ki, const CLSAG_GGXG_signature& sig) + { + DBG_PRINT("== verify_CLSAG_GGXG =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_g.size(), "ring size != r_g size"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_x.size(), "ring size != r_x size"); + + point_t key_image(ki); + CRYPTO_CHECK_AND_THROW_MES(key_image.is_in_main_subgroup(), "key image 0 does not belong to the main subgroup"); + + point_t pseudo_out_amount_commitment_pt(pseudo_out_amount_commitment); + pseudo_out_amount_commitment_pt.modify_mul8(); + + point_t extended_amount_commitment_pt(extended_amount_commitment); + extended_amount_commitment_pt.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(4 + 3 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].concealing_point); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", cp:" << ring[i].concealing_point); + } + hsc.add_pub_key(pseudo_out_amount_commitment); + hsc.add_pub_key(extended_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hsc.add_pub_key(sig.K3); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_LAYER_3); + hsc.add_hash(input_hash); + scalar_t agg_coeff_3 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_3); + + // prepare A_i, Q_i + std::vector A_i, Q_i; + A_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].concealing_point); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1, 3; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment_pt) + + agg_coeff_3 * Q_i[i] + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layer 2; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (extended_amount_commitment_pt - A_i[i] - Q_i[i]) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + // calculate aggregate key image (layers 0, 1, 3; G components) + point_t W_key_image_g = + agg_coeff_0 * key_image + + agg_coeff_1 * point_t(sig.K1).modify_mul8() + + agg_coeff_3 * point_t(sig.K3).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K1).modify_mul8()); + DBG_VAL_PRINT(point_t(sig.K3).modify_mul8()); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2; X component) + point_t W_key_image_x = + agg_coeff_2 * point_t(sig.K2).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K2).modify_mul8()); + DBG_VAL_PRINT(W_key_image_x); + + + scalar_t c_prev = sig.c; + DBG_PRINT("c[0] = " << c_prev); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + DBG_PRINT("c[" << i + 1 << "] = " << c_prev); + //DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); + } + + return c_prev == sig.c; + } + + */ + //--------------------------------------------------------------- + + + bool generate_CLSAG_GGXXG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_blinded_asset_id, const point_t& extended_amount_commitment, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_t, const scalar_t& secret_3_x, const scalar_t& secret_4_q, uint64_t secret_index, + CLSAG_GGXXG_signature& sig) + { + DBG_PRINT("== generate_CLSAG_GGXXG =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(secret_index < ring_size, "secret_index is out of range"); + + // calculate key images + point_t ki_base = hash_helper_t::hp(ring[secret_index].stealth_address); + point_t key_image = secret_0_xp * ki_base; + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(key_image == point_t(ki), "key image 0 mismatch"); + CRYPTO_CHECK_AND_THROW_MES((secret_0_xp * c_point_G).to_public_key() == ring[secret_index].stealth_address, "secret_0_xp mismatch"); + CRYPTO_CHECK_AND_THROW_MES( secret_1_f * c_point_G == 8 * point_t(ring[secret_index].amount_commitment) - pseudo_out_amount_commitment, "secret_1_f mismatch"); + CRYPTO_CHECK_AND_THROW_MES( secret_2_t * c_point_X == 8 * point_t(ring[secret_index].blinded_asset_id) - pseudo_out_blinded_asset_id, "secret_2_t mismatch"); + CRYPTO_CHECK_AND_THROW_MES( secret_3_x * c_point_X == extended_amount_commitment - 8 * point_t(ring[secret_index].amount_commitment) - 8 * point_t(ring[secret_index].concealing_point), ""); + CRYPTO_CHECK_AND_THROW_MES( secret_4_q * c_point_G == 8 * point_t(ring[secret_index].concealing_point), "secret_3_q mismatch"); +#endif + + point_t K1_div8 = (c_scalar_1div8 * secret_1_f) * ki_base; + K1_div8.to_public_key(sig.K1); + point_t K1 = K1_div8; + K1.modify_mul8(); + + point_t K2_div8 = (c_scalar_1div8 * secret_2_t) * ki_base; + K2_div8.to_public_key(sig.K2); + point_t K2 = K2_div8; + K2.modify_mul8(); + + point_t K3_div8 = (c_scalar_1div8 * secret_3_x) * ki_base; + K3_div8.to_public_key(sig.K3); + point_t K3 = K3_div8; + K3.modify_mul8(); + + point_t K4_div8 = (c_scalar_1div8 * secret_4_q) * ki_base; + K4_div8.to_public_key(sig.K4); + point_t K4 = K4_div8; + K4.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(5 + 4 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].blinded_asset_id); + hsc.add_pub_key(ring[i].concealing_point); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id << ", cp:" << ring[i].concealing_point); + } + hsc.add_point(c_scalar_1div8 * pseudo_out_amount_commitment); + hsc.add_point(c_scalar_1div8 * pseudo_out_blinded_asset_id); + hsc.add_point(c_scalar_1div8 * extended_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hsc.add_pub_key(sig.K3); + hsc.add_pub_key(sig.K4); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_3); + hsc.add_hash(input_hash); + scalar_t agg_coeff_3 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_3); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_4); + hsc.add_hash(input_hash); + scalar_t agg_coeff_4 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_4); + + // prepare A_i, Q_i + std::vector A_i, P_i, Q_i; + A_i.reserve(ring_size), P_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + P_i.emplace_back(ring[i].blinded_asset_id); + P_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].concealing_point); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " P_i[" << i << "] = " << P_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1, 4; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment) + + agg_coeff_4 * Q_i[i] + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layerx 2, 3; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (P_i[i] - pseudo_out_blinded_asset_id) + + agg_coeff_3 * (extended_amount_commitment - A_i[i] - Q_i[i]) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + // aggregate secret key (layers 0, 1, 4; G component) + scalar_t w_sec_key_g = agg_coeff_0 * secret_0_xp + agg_coeff_1 * secret_1_f + agg_coeff_4 * secret_4_q; + DBG_VAL_PRINT(w_sec_key_g * c_point_G); + + // aggregate secret key (layer 2, 3; X component) + scalar_t w_sec_key_x = agg_coeff_2 * secret_2_t + agg_coeff_3 * secret_3_x; + DBG_VAL_PRINT(w_sec_key_x * c_point_X); + + // calculate aggregate key image (layers 0, 1, 4; G component) + point_t W_key_image_g = agg_coeff_0 * key_image + agg_coeff_1 * K1 + agg_coeff_4 * K4; + DBG_VAL_PRINT(key_image); + DBG_VAL_PRINT(K1); + DBG_VAL_PRINT(K4); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2, 3; X component) + point_t W_key_image_x = agg_coeff_2 * K2 + agg_coeff_3 * K3; + DBG_VAL_PRINT(K2); + DBG_VAL_PRINT(K3); + DBG_VAL_PRINT(W_key_image_x); + +#ifndef NDEBUG + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * c_point_G == W_pub_keys_g[secret_index], "aggregated secret G and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_g * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_g, "aggregated secret G and key image mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * c_point_X == W_pub_keys_x[secret_index], "aggregated secret X and pub key mismatch"); + CRYPTO_CHECK_AND_THROW_MES(w_sec_key_x * hash_helper_t::hp(ring[secret_index].stealth_address) == W_key_image_x, "aggregated secret X and key image mismatch"); +#endif + + // initial commitment + scalar_t alpha_g = scalar_t::random(); // randomness for layers 0,1,4 + scalar_t alpha_x = scalar_t::random(); // randomness for layer 2,3 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(alpha_g * c_point_G); + hsc.add_point(alpha_g * ki_base); + hsc.add_point(alpha_x * c_point_X); + hsc.add_point(alpha_x * ki_base); + //DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")"); + scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1} + + sig.r_g.resize_and_make_random(ring_size); + sig.r_x.resize_and_make_random(ring_size); + + for(size_t j = 0, i = (secret_index + 1) % ring_size; j < ring_size - 1; ++j, i = (i + 1) % ring_size) + { + DBG_PRINT("c[" << i << "] = " << c_prev); + if (i == 0) + sig.c = c_prev; // c_0 + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + //DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); + } + DBG_PRINT("c[" << secret_index << "] = " << c_prev); + + + if (secret_index == 0) + sig.c = c_prev; + + sig.r_g[secret_index] = alpha_g - c_prev * w_sec_key_g; + sig.r_x[secret_index] = alpha_x - c_prev * w_sec_key_x; + + return true; + } + + bool verify_CLSAG_GGXXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& pseudo_out_blinded_asset_id, const public_key& extended_amount_commitment, const key_image& ki, + const CLSAG_GGXXG_signature& sig) + { + DBG_PRINT("== verify_CLSAG_GGXXG =="); + size_t ring_size = ring.size(); + CRYPTO_CHECK_AND_THROW_MES(ring_size > 0, "ring size is zero"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_g.size(), "ring size != r_g size"); + CRYPTO_CHECK_AND_THROW_MES(ring_size == sig.r_x.size(), "ring size != r_x size"); + + point_t key_image(ki); + CRYPTO_CHECK_AND_THROW_MES(key_image.is_in_main_subgroup(), "key image 0 does not belong to the main subgroup"); + + point_t pseudo_out_amount_commitment_pt(pseudo_out_amount_commitment); + pseudo_out_amount_commitment_pt.modify_mul8(); + + point_t pseudo_out_blinded_asset_id_pt(pseudo_out_blinded_asset_id); + pseudo_out_blinded_asset_id_pt.modify_mul8(); + + point_t extended_amount_commitment_pt(extended_amount_commitment); + extended_amount_commitment_pt.modify_mul8(); + + // calculate aggregation coefficients + hash_helper_t::hs_t hsc(5 + 4 * ring_size); + hsc.add_scalar(m); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_pub_key(ring[i].stealth_address); + hsc.add_pub_key(ring[i].amount_commitment); + hsc.add_pub_key(ring[i].blinded_asset_id); + hsc.add_pub_key(ring[i].concealing_point); + DBG_PRINT("ring[" << i << "]: sa:" << ring[i].stealth_address << ", ac:" << ring[i].amount_commitment << ", baid:" << ring[i].blinded_asset_id << ", cp:" << ring[i].concealing_point); + } + hsc.add_pub_key(pseudo_out_amount_commitment); + hsc.add_pub_key(pseudo_out_blinded_asset_id); + hsc.add_pub_key(extended_amount_commitment); + hsc.add_key_image(ki); + hsc.add_pub_key(sig.K1); + hsc.add_pub_key(sig.K2); + hsc.add_pub_key(sig.K3); + hsc.add_pub_key(sig.K4); + hash input_hash = hsc.calc_hash_no_reduce(); + DBG_VAL_PRINT(input_hash); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_0); + hsc.add_hash(input_hash); + scalar_t agg_coeff_0 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_0); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_1); + hsc.add_hash(input_hash); + scalar_t agg_coeff_1 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_1); + + // may we get rid of it? + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_2); + hsc.add_hash(input_hash); + scalar_t agg_coeff_2 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_2); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_3); + hsc.add_hash(input_hash); + scalar_t agg_coeff_3 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_3); + + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_LAYER_4); + hsc.add_hash(input_hash); + scalar_t agg_coeff_4 = hsc.calc_hash(); + DBG_VAL_PRINT(agg_coeff_4); + + // prepare A_i, Q_i + std::vector A_i, P_i, Q_i; + A_i.reserve(ring_size), P_i.reserve(ring_size), Q_i.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + A_i.emplace_back(ring[i].amount_commitment); + A_i.back().modify_mul8(); + P_i.emplace_back(ring[i].blinded_asset_id); + P_i.back().modify_mul8(); + Q_i.emplace_back(ring[i].concealing_point); + Q_i.back().modify_mul8(); + DBG_PRINT("A_i[" << i << "] = " << A_i[i] << " P_i[" << i << "] = " << P_i[i] << " Q_i[" << i << "] = " << Q_i[i]); + } + + // calculate aggregate pub keys (layers 0, 1, 4; G components) + std::vector W_pub_keys_g; + W_pub_keys_g.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_g.emplace_back( + agg_coeff_0 * point_t(ring[i].stealth_address) + + agg_coeff_1 * (A_i[i] - pseudo_out_amount_commitment_pt) + + agg_coeff_4 * Q_i[i] + ); + DBG_VAL_PRINT(W_pub_keys_g[i]); + } + + // calculate aggregate pub keys (layer 2, 3; X component) + std::vector W_pub_keys_x; + W_pub_keys_x.reserve(ring_size); + for(size_t i = 0; i < ring_size; ++i) + { + W_pub_keys_x.emplace_back( + agg_coeff_2 * (P_i[i] - pseudo_out_blinded_asset_id_pt) + + agg_coeff_3 * (extended_amount_commitment_pt - A_i[i] - Q_i[i]) + ); + DBG_VAL_PRINT(W_pub_keys_x[i]); + } + + DBG_VAL_PRINT(point_t(ki)); + + // calculate aggregate key image (layers 0, 1, 4; G components) + DBG_VAL_PRINT(point_t(sig.K1).modify_mul8()); + point_t W_key_image_g = + agg_coeff_0 * key_image + + agg_coeff_1 * point_t(sig.K1).modify_mul8() + + agg_coeff_4 * point_t(sig.K4).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K1).modify_mul8()); + DBG_VAL_PRINT(point_t(sig.K4).modify_mul8()); + DBG_VAL_PRINT(W_key_image_g); + + // calculate aggregate key image (layer 2, 3; X component) + point_t W_key_image_x = + agg_coeff_2 * point_t(sig.K2).modify_mul8() + + agg_coeff_3 * point_t(sig.K3).modify_mul8(); + DBG_VAL_PRINT(point_t(sig.K2).modify_mul8()); + DBG_VAL_PRINT(point_t(sig.K3).modify_mul8()); + DBG_VAL_PRINT(W_key_image_x); + + + scalar_t c_prev = sig.c; + DBG_PRINT("c[0] = " << c_prev); + for(size_t i = 0; i < ring_size; ++i) + { + hsc.add_32_chars(CRYPTO_HDS_CLSAG_GGXXG_CHALLENGE); + hsc.add_hash(input_hash); + hsc.add_point(sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i]); + hsc.add_point(sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g); + hsc.add_point(sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i]); + hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); + c_prev = hsc.calc_hash(); // c_{i + 1} + DBG_PRINT("c[" << i + 1 << "] = " << c_prev); + //DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); + } + + return c_prev == sig.c; + } + + + +} // namespace crypto diff --git a/src/crypto/clsag.h b/src/crypto/clsag.h new file mode 100644 index 00000000..da969d8a --- /dev/null +++ b/src/crypto/clsag.h @@ -0,0 +1,178 @@ +// Copyright (c) 2022-2024 Zano Project +// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +// This file contains implementation of the original d-CLSAG (s.a. https://eprint.iacr.org/2019/654.pdf by Goodel at el) +// and the extended d/v-CLSAG version (s.a. https://github.com/hyle-team/docs/blob/master/zano/dv-CLSAG-extension/ by sowle) +// +#pragma once +#include "crypto-sugar.h" + +namespace crypto +{ + // 2-CLSAG signature where both dimensions are with respect to the group element G (that's why 'GG') + struct CLSAG_GG_signature + { + scalar_t c; + scalar_vec_t r; // size = size of the ring + public_key K1; // auxiliary key image for layer 1 + }; + + + inline bool operator==(const CLSAG_GG_signature& lhs, const CLSAG_GG_signature& rhs) + { + return + lhs.c == rhs.c && + lhs.r == rhs.r && + lhs.K1 == rhs.K1; + } + + inline bool operator!=(const CLSAG_GG_signature& lhs, const CLSAG_GG_signature& rhs) { return !(lhs == rhs); } + + struct CLSAG_GG_input_ref_t + { + CLSAG_GG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment) + : stealth_address(stealth_address), amount_commitment(amount_commitment) + {} + + const public_key& stealth_address; // P, not premultiplied by 1/8, TODO @#@#: make sure it's okay + const public_key& amount_commitment; // A, premultiplied by 1/8 + }; + + // pseudo_out_amount_commitment -- not premultiplied by 1/8 + bool generate_CLSAG_GG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki, + const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig); + + // pseudo_out_amount_commitment -- premultiplied by 1/8 + bool verify_CLSAG_GG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const key_image& ki, + const CLSAG_GG_signature& sig); + + + // + // Disclaimer: extensions to the CLSAG implemented below are non-standard and are in proof-of-concept state. + // They shouldn't be used in production code until formal security proofs are done and (ideally) the code is peer-reviewed. + // -- sowle + // + + + + // + // 3/2-CLSAG + // + + + // 3/2-CLSAG signature (with respect to the group element G, G, X -- that's why 'GGX') + struct CLSAG_GGX_signature + { + scalar_t c; + scalar_vec_t r_g; // for G-components (layers 0, 1), size = size of the ring + scalar_vec_t r_x; // for X-component (layer 2), size = size of the ring + public_key K1; // auxiliary key image for layer 1 (G) + public_key K2; // auxiliary key image for layer 2 (X) + }; + + struct CLSAG_GGX_input_ref_t : public CLSAG_GG_input_ref_t + { + CLSAG_GGX_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& blinded_asset_id) + : CLSAG_GG_input_ref_t(stealth_address, amount_commitment) + , blinded_asset_id(blinded_asset_id) + {} + + const public_key& blinded_asset_id; // T, premultiplied by 1/8 + }; + + // pseudo_out_amount_commitment -- not premultiplied by 1/8 + // pseudo_out_asset_id -- not premultiplied by 1/8 + bool generate_CLSAG_GGX(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_asset_id, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_t, uint64_t secret_index, CLSAG_GGX_signature& sig); + + // pseudo_out_amount_commitment -- premultiplied by 1/8 + // pseudo_out_asset_id -- premultiplied by 1/8 + // may throw an exception TODO @#@# make sure it's okay + bool verify_CLSAG_GGX(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, + const public_key& pseudo_out_asset_id, const key_image& ki, const CLSAG_GGX_signature& sig); + + + /* + // + // 4/2-CLSAG (eventually, it's not used in Zano) + // + + + // 4/2-CLSAG signature (with respect to the group element G, G, X, G -- that's why 'GGXG') + struct CLSAG_GGXG_signature + { + scalar_t c; + scalar_vec_t r_g; // for G-components (layers 0, 1, 3), size = size of the ring + scalar_vec_t r_x; // for X-component (layer 2), size = size of the ring + public_key K1; // auxiliary key image for layer 1 (G) + public_key K2; // auxiliary key image for layer 2 (X) + public_key K3; // auxiliary key image for layer 3 (G) + }; + + struct CLSAG_GGXG_input_ref_t : public CLSAG_GG_input_ref_t + { + CLSAG_GGXG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& concealing_point) + : CLSAG_GG_input_ref_t(stealth_address, amount_commitment) + , concealing_point(concealing_point) + {} + + const public_key& concealing_point; // Q, premultiplied by 1/8 + }; + + // pseudo_out_amount_commitment -- not premultiplied by 1/8 + // extended_amount_commitment -- not premultiplied by 1/8 + bool generate_CLSAG_GGXG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig); + + // pseudo_out_amount_commitment -- premultiplied by 1/8 + // extended_amount_commitment -- premultiplied by 1/8 + // may throw an exception TODO @#@# make sure it's okay + bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, + const public_key& extended_amount_commitment, const key_image& ki, const CLSAG_GGXG_signature& sig); + + */ + + // + // 5/2-CLSAG + // + + + // 5/2-CLSAG signature (with respect to the group element G, G, X, X, G -- that's why 'GGXXG') + struct CLSAG_GGXXG_signature + { + scalar_t c; + scalar_vec_t r_g; // for G-components (layers 0, 1, 4), size = size of the ring + scalar_vec_t r_x; // for X-component (layers 2, 3), size = size of the ring + public_key K1; // auxiliary key image for layer 1 (G) + public_key K2; // auxiliary key image for layer 2 (X) + public_key K3; // auxiliary key image for layer 2 (X) + public_key K4; // auxiliary key image for layer 3 (G) + }; + + struct CLSAG_GGXXG_input_ref_t : public CLSAG_GGX_input_ref_t + { + CLSAG_GGXXG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment, const public_key& blinded_asset_id, const public_key& concealing_point) + : CLSAG_GGX_input_ref_t(stealth_address, amount_commitment, blinded_asset_id) + , concealing_point(concealing_point) + {} + + const public_key& concealing_point; // Q, premultiplied by 1/8 + }; + + // pseudo_out_amount_commitment -- not premultiplied by 1/8 + // pseudo_out_asset_id -- not premultiplied by 1/8 + // extended_amount_commitment -- not premultiplied by 1/8 + bool generate_CLSAG_GGXXG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& pseudo_out_blinded_asset_id, const point_t& extended_amount_commitment, const key_image& ki, + const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_r, const scalar_t& secret_3_x, const scalar_t& secret_4_q, uint64_t secret_index, CLSAG_GGXXG_signature& sig); + + // pseudo_out_amount_commitment -- premultiplied by 1/8 + // pseudo_out_asset_id -- premultiplied by 1/8 + // extended_amount_commitment -- premultiplied by 1/8 + // may throw an exception TODO @#@# make sure it's okay + bool verify_CLSAG_GGXXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& pseudo_out_blinded_asset_id, const public_key& extended_amount_commitment, const key_image& ki, + const CLSAG_GGXXG_signature& sig); + + +} // namespace crypto diff --git a/src/crypto/crypto-ops.c b/src/crypto/crypto-ops.c index 1233da47..852c5f1f 100644 --- a/src/crypto/crypto-ops.c +++ b/src/crypto/crypto-ops.c @@ -40,7 +40,6 @@ DISABLE_VS_WARNINGS(4146 4244) void fe_mul(fe, const fe, const fe); void fe_sq(fe, const fe); void fe_tobytes(unsigned char *, const fe); -static void ge_madd(ge_p1p1 *, const ge_p3 *, const ge_precomp *); static void ge_msub(ge_p1p1 *, const ge_p3 *, const ge_precomp *); static void ge_p2_0(ge_p2 *); static void ge_p3_dbl(ge_p1p1 *, const ge_p3 *); @@ -119,7 +118,7 @@ Postconditions: |h| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc. */ -static void fe_add(fe h, const fe f, const fe g) { +void fe_add(fe h, const fe f, const fe g) { int32_t f0 = f[0]; int32_t f1 = f[1]; int32_t f2 = f[2]; @@ -1425,7 +1424,7 @@ int ge_frombytes_vartime(ge_p3 *h, const unsigned char *s) { r = p + q */ -static void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { +void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q) { fe t0; fe_add(r->X, p->Y, p->X); fe_sub(r->Y, p->Y, p->X); @@ -4314,3 +4313,171 @@ void ge_cached_to_p2(ge_p2 *r, const ge_cached *c) fe_copy(r->Z, c->Z); } + + +/////////////////////////// +// EXPERIMENTAL +// + +// With these select_vartime/ge_scalarmult_base_vartime I got ~25% speed up comparing to the select/ge_scalarmult_base -- sowle +static void select_vartime(ge_precomp *t, int pos, signed char b) +{ + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + const ge_precomp* base; + + if (babs == 0) + { + ge_precomp_0(t); + } + else if (bnegative == 0) + { + base = &ge_base[pos][babs - 1]; + fe_copy(t->yplusx, base->yplusx); + fe_copy(t->yminusx, base->yminusx); + fe_copy(t->xy2d, base->xy2d); + } + else + { + base = &ge_base[pos][babs - 1]; + fe_copy(t->yplusx, base->yminusx); + fe_copy(t->yminusx, base->yplusx); + fe_neg(t->xy2d, base->xy2d); + } +} + +void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a) +{ + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(h); + for (i = 1; i < 64; i += 2) { + select_vartime(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + select_vartime(&t, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } +} + + +static void select_custom_precomp_vartime(ge_precomp *t, const precomp_data_t base_precomp, int pos, signed char b) +{ + unsigned char bnegative = negative(b); + unsigned char babs = b - (((-bnegative) & b) << 1); + const ge_precomp* base; + + if (babs == 0) + { + ge_precomp_0(t); + } + else if (bnegative == 0) + { + base = &base_precomp[pos][babs - 1]; + fe_copy(t->yplusx, base->yplusx); + fe_copy(t->yminusx, base->yminusx); + fe_copy(t->xy2d, base->xy2d); + } + else + { + base = &base_precomp[pos][babs - 1]; + fe_copy(t->yplusx, base->yminusx); + fe_copy(t->yminusx, base->yplusx); + fe_neg(t->xy2d, base->xy2d); + } +} + + +void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a) +{ + signed char e[64]; + signed char carry; + ge_p1p1 r; + ge_p2 s; + ge_precomp t; + int i; + + for (i = 0; i < 32; ++i) { + e[2 * i + 0] = (a[i] >> 0) & 15; + e[2 * i + 1] = (a[i] >> 4) & 15; + } + /* each e[i] is between 0 and 15 */ + /* e[63] is between 0 and 7 */ + + carry = 0; + for (i = 0; i < 63; ++i) { + e[i] += carry; + carry = e[i] + 8; + carry >>= 4; + e[i] -= carry << 4; + } + e[63] += carry; + /* each e[i] is between -8 and 8 */ + + ge_p3_0(h); + for (i = 1; i < 64; i += 2) { + select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } + + ge_p3_dbl(&r, h); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p2(&s, &r); + ge_p2_dbl(&r, &s); ge_p1p1_to_p3(h, &r); + + for (i = 0; i < 64; i += 2) { + select_custom_precomp_vartime(&t, base_precomp, i / 2, e[i]); + ge_madd(&r, h, &t); ge_p1p1_to_p3(h, &r); + } +} + +void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p) +{ + fe recip; + fe x; + fe y; + //unsigned char s[32]; + + fe_invert(recip, p->Z); + fe_mul(x, p->X, recip); + fe_mul(y, p->Y, recip); + fe_sub(r->yminusx, y, x); + fe_add(r->yplusx, y, x); + fe_mul(r->xy2d, x, y); + fe_mul(r->xy2d, r->xy2d, fe_d2); + + // to get canonical representation and obtain the very same beautiful numbers for ge_base in crypto-ops-data.c (maybe unnecessary, TODO -- sowle) + //fe_tobytes(s, r->yminusx); fe_frombytes(r->yminusx, s); + //fe_tobytes(s, r->yplusx); fe_frombytes(r->yplusx, s); + //fe_tobytes(s, r->xy2d); fe_frombytes(r->xy2d, s); +} + diff --git a/src/crypto/crypto-ops.h b/src/crypto/crypto-ops.h index 318af2a2..8ed42fcd 100644 --- a/src/crypto/crypto-ops.h +++ b/src/crypto/crypto-ops.h @@ -60,6 +60,7 @@ void ge_double_scalarmult_base_vartime(ge_p2 *, const unsigned char *, const ge_ extern const fe fe_sqrtm1; extern const fe fe_d; +extern const fe fe_d2; int ge_frombytes_vartime(ge_p3 *, const unsigned char *); /* From ge_p1p1_to_p2.c */ @@ -112,12 +113,19 @@ void ge_p2_to_p3(ge_p3 *r, const ge_p2 *t); void ge_bytes_hash_to_ec(ge_p3 *, const void *, size_t); void ge_bytes_hash_to_ec_32(ge_p3 *, const unsigned char *); void ge_cached_to_p2(ge_p2 *r, const ge_cached *c); +void ge_madd(ge_p1p1 *r, const ge_p3 *p, const ge_precomp *q); void ge_p3_0(ge_p3 *h); void ge_sub(ge_p1p1 *, const ge_p3 *, const ge_cached *); void ge_double_scalarmult_base_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A, const unsigned char *b); void ge_scalarmult_vartime_p3(ge_p3 *r, const unsigned char *a, const ge_p3 *A); void ge_scalarmult_vartime_p3_v2(ge_p3 *r, const unsigned char *a, const ge_p3 *A); +void ge_scalarmult_base_vartime(ge_p3 *h, const unsigned char *a); + +/* precomp_data[i][j] = (j + 1) * 256^i * G */ +typedef ge_precomp (precomp_data_t)[32][8]; +void ge_scalarmult_precomp_vartime(ge_p3 *h, const precomp_data_t base_precomp, const unsigned char *a); +void ge_p3_to_precomp(ge_precomp *r, const ge_p3* p); extern const fe fe_ma2; extern const fe fe_ma; @@ -139,6 +147,7 @@ void sc_invert(unsigned char*, const unsigned char*); void fe_sq(fe h, const fe f); int fe_isnonzero(const fe f); +void fe_add(fe h, const fe f, const fe g); void fe_sub(fe h, const fe f, const fe g); void fe_mul(fe, const fe, const fe); void fe_frombytes(fe h, const unsigned char *s); diff --git a/src/crypto/crypto-sugar.cpp b/src/crypto/crypto-sugar.cpp index 8b8779ae..dfc4dcc6 100644 --- a/src/crypto/crypto-sugar.cpp +++ b/src/crypto/crypto-sugar.cpp @@ -1,5 +1,5 @@ -// Copyright (c) 2020-2021 Zano Project -// Copyright (c) 2020-2021 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2020-2023 Zano Project +// Copyright (c) 2020-2023 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -10,18 +10,1968 @@ namespace crypto { - const point_g_t c_point_G; + void construct_precomp_data(precomp_data_t precomp_data, const point_t& point) + { + point_t A = point; + for(size_t i = 0; i < 32; ++i) + { + point_t B = A; + ge_p3_to_precomp(&precomp_data[i][0], &B.m_p3); + for(size_t j = 1; j < 8; ++j) + { + B += A; // B = (j+1) * 256^i * point + ge_p3_to_precomp(&precomp_data[i][j], &B.m_p3); + } - const scalar_t c_scalar_1 = { 1 }; - const scalar_t c_scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; - const scalar_t c_scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; - const scalar_t c_scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; - const scalar_t c_scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; - const scalar_t c_scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff }; - const scalar_t c_scalar_1div8 = { 0x6106e529e2dc2f79, 0x07d39db37d1cdad0, 0x0, 0x0600000000000000 }; + if (i != 31) + A.modify_mul_pow_2(8); // *= 256 + } + } - const point_t c_point_H = { 0x05087c1f5b9b32d6, 0x00547595f445c3b5, 0x764df64578552f2a, 0x8a49a651e0e0da45 }; // == Hp(G), this is being checked in bpp_basics - const point_t c_point_H2 = { 0x70c8d1ab9dbf1cc0, 0xc561bb12639a8516, 0x3cfff1def9e5b268, 0xe0936386f3bcce1a }; // == Hp("h2_generator"), cheched in bpp_basics - const point_t c_point_0 = point_t(point_t::tag_zero()); + + + namespace xdetails + { + // correctness of the data below is checked in crypto_generators_precomp + const precomp_data_t c_point_H_precomp_data = { + { + {{-25839914, 157462, -1791824, 10231988, 22558850, 19431640, 1713390, -20343323, 20342775, 1666609}, {12627670, 3909784, 17340562, 12788648, -22385878, -8266372, -35905398, -3684433, 17151013, 3727105}, {-28348363, -14228846, -10343840, -8899709, -10188216, 6790737, 28668879, 2065510, 25295296, -16739572}}, + {{12123870, 4350399, 31368205, -22615939, 989700, -1440444, 15590912, -7885237, 44322961, -33221404}, {-28041004, 10461293, -8953557, -1384985, -14277550, -18504792, 49472974, 1396059, -658645, 75728}, {13727829, 11677165, 26433470, 12146275, 32407426, -2423122, 27136530, -10656245, -3753335, 16230956}}, + {{51118090, 23785065, 39026994, 2444219, -30603395, -10804617, 38098061, 2907744, -11829286, 22814379}, {15342100, -9010597, -4035044, 20632301, 24850527, -5195793, 3876595, -11041592, -6587238, 8562267}, {26743467, -11422186, -13358731, 5744188, 4533953, -16135507, 30744883, 9806359, 14389811, 8975338}}, + {{56115520, -18546359, -19913338, 25001369, -44259974, -14499756, 16792302, 24258992, -13788063, -3143064}, {2585728, 5642651, 3745158, 7694735, -3406330, -1325930, 49431660, -8643236, 36098755, -5309184}, {13514064, 9335126, -16596225, -10753192, -30689993, -13556891, -24905790, 13661483, 18360127, -5012662}}, + {{40257206, 5111877, -1861784, 16048642, 43576417, -4669748, 19711942, -13265373, 55653581, 5997509}, {-7985782, -24758881, -22389642, -13273734, -20216997, 4479316, -31781518, 12429299, -6234603, 11644217}, {8308870, 7279307, 2148143, 6729248, 13588178, 6069241, -7335771, -3739510, -20848443, -4679153}}, + {{-20737583, 27643402, 2873210, -18261180, -18291839, -6268028, -44531715, -26015787, 30895024, -19385598}, {20881151, 508072, -43245146, -13149954, 22807711, -10594262, -2548441, 6997175, -26672556, 8968670}, {-3147785, 4292662, 9423734, 1742649, -19533160, 13807977, -31176939, -12874821, 15603023, 8351508}}, + {{37413813, -1313394, 23553487, 8302956, 12352081, -3174611, -6777671, 1421792, 20288577, -3464110}, {28674127, -30915570, -9713975, -901872, -1830099, 15958287, -42359115, -25372112, 41343195, -18340440}, {-29145482, 8990939, 31593182, -6148974, 32107442, 14618056, -18645181, -2212088, 18396641, -10005536}}, + {{35535538, 25794127, 43515704, 7451164, 30438366, -13113112, -35782574, -341097, 17819789, -11389240}, {-16377682, -2898071, -14119008, 17585196, 28897698, 18946252, 12492268, 1927079, 839259, 20827124}, {18576950, -7897849, 5919315, -9586273, 9031580, -5030272, -27116638, -3256204, -26195311, 10194521}} + }, + { + {{-36262283, -8280932, -16610732, -2898617, 54211337, -1517172, 21906950, 28435490, 43210590, 1218117}, {-1682705, 21957008, -43519870, -21918475, 8453905, 8719882, 41295776, 1553544, -1661538, 21673717}, {-9313596, 3378603, 30865986, 4384431, 16516598, -12721875, 19781157, -3772318, 948918, 2360171}}, + {{11810118, 5302376, -53718285, -31290081, 13990972, 1666459, 6304131, -1281229, -7153374, 13608666}, {-29575724, -1961816, -9798595, 1984375, -19036358, -10172507, 59208415, -31173633, -4781370, 16988722}, {-6095994, 133097, 24224235, 15247983, -4182301, -14756634, 21587507, 15178946, 20553208, 139840}}, + {{2291056, -9094995, -18537175, 13841361, -9273433, 11351059, -39031822, -14003027, -30576624, -5092422}, {-38783152, 2494507, -5017801, -17472967, -30855757, -6211997, -21681524, -9899335, -30822138, 15804444}, {-4183462, 5813348, 29610200, -9958924, 25900635, 1141273, -33371288, 15312502, 23382985, -15625255}}, + {{-1724561, 19851118, 3919214, -2434649, 4130055, 20191732, 2517693, 13459913, -23620343, -25742142}, {-17758693, -10804838, 6776962, 15458523, 32038261, 7791842, -406949, -4282451, 2266571, 153584}, {-23310663, -9743136, 698945, 958768, 5459145, 6080624, -21941743, -3333725, -15816139, -8876490}}, + {{28128915, 23717069, -14254111, 2468716, -1635116, 18789860, -47465541, -22684584, 22941926, 3043558}, {-31309425, -5190323, -40715825, -24164380, 26692650, 7205330, 9697223, 5927456, -23103520, -17034232}, {14136931, -16019746, -30971127, 10213637, -18320195, -15932654, -29761632, -10025284, 17978682, -4780093}}, + {{-16194700, 14443627, -457615, 3365937, -25122175, 4893010, -8305342, 4674804, 26476643, -2742423}, {2041920, 18261487, -9367817, 15814617, 28453069, -5976986, -27177734, -5350136, 7076635, 22120243}, {-20867270, -16604482, 10073765, 11011343, -10881223, -16058169, -6868310, 4582827, 26986633, 13221031}}, + {{19072366, 403182, 21379737, 8772482, 16514929, -1966122, -9491088, -2999541, -44055881, -1946664}, {-28972312, -26192360, 1124223, -17812394, -32715399, 14219630, 54954794, 28715165, 7867853, 9844806}, {-7630275, -14547412, -33539487, -10085666, 21792472, -16652098, -32937274, -7466694, 8795856, -1457197}}, + {{9731789, 3178613, -7600042, 5767160, -8969708, -15253601, -20961771, -16367485, -20006727, -26056008}, {-41832827, -1543225, 41196390, 18278104, 5428010, 1099055, 24798383, 14642177, 5003627, -1244530}, {-2128966, -6957926, 27996724, 11491959, 3338739, -9092543, -15839431, 11002022, -5046122, -1189604}} + }, + { + {{-2755970, -17615939, 31275222, 7003405, 26870823, 17119318, 8784719, 16951735, 23823587, 22420775}, {3795378, 417741, 4513574, 16119343, 10251751, 15662672, -47304547, -7686413, 8368547, 397985}, {-8607656, 8976384, 23477053, -11277011, -16031733, -2258893, -5744423, -12596121, -1025983, 8903149}}, + {{46492022, 19075568, -7280406, 21312445, -15381910, 12162940, 8484731, -5280304, -14038525, -9569164}, {10924154, -8238952, 10662028, 11586411, -10231798, -7854982, -53695283, 25786846, -5747327, -9244520}, {25416017, -3015298, 2232993, 986105, -22542935, -7403014, 26926670, 10959798, 26456258, 13853419}}, + {{-18813663, 25671181, -3327225, -14675081, -36027192, -15747345, 29400343, 5510556, 28265959, 25997330}, {12504319, -2673615, 7754695, -6359023, 24428200, 9725937, -986369, -8462474, 11649175, -4890996}, {-3886018, 2881276, 14485325, 5704885, 10124062, -2411325, -23827009, -2616965, -248597, -3411051}}, + {{43015230, -19466620, -3112785, 576202, -30255336, -18980032, 30566133, 13610387, 12538250, -2688932}, {-6324288, 8810792, -14431995, 13325638, 35085954, 12963350, -25633195, -7262641, 1592670, -1070658}, {-20025782, -5929817, -5948477, -12209150, -30422648, -5852552, -21153879, -10498881, 15928534, 7306252}}, + {{1369064, -174574, 7891892, -13901643, 18853442, 32561514, 1820385, 5914406, 40122046, 21924508}, {46303380, 1590416, -36037734, -516813, -2182578, 174516, -30062745, -24225382, 23144124, 50412}, {-29913522, -5202763, 10237212, 6911594, -11175683, -1789467, 30303688, -6420599, 7185367, -5903626}}, + {{10885717, 4105436, -61588901, 24307660, 19399021, 20354659, -1006139, -7900455, -46057752, -22251609}, {-19429393, -16605802, -2509963, -7054416, 23985299, 12887055, 31727579, -14897333, 17999672, -4749751}, {21240607, -9429948, -24614879, -11498166, 32785046, 15460686, -9241910, -15919920, -12629980, -8274375}}, + {{1555174, 1158950, 25220076, -4350735, 17963249, 8413985, -1843022, 5017864, 34521910, -19709895}, {23548174, 3859228, 25952162, 13795931, -28235101, 3069917, -29375156, 14878586, 11966332, 7752083}, {-10051192, -15202422, -2752080, 8776402, 18981704, 7873536, -20164398, 5937515, -22424852, -8610723}}, + {{24562618, -12686561, 34118835, 5129440, -1417873, 21377538, -35562536, 111702, -589296, 7759505}, {41538744, -12046915, -13795389, -14711452, 27281987, -4994032, 21029814, -2825392, 15603256, 25224169}, {-27185999, -8792352, 3312599, -5994395, -31599120, 3101325, 7539730, -16383545, 16053653, 12256453}} + }, + { + {{2117860, 21019143, 51468699, -8363520, 46685088, 1041470, 32562387, -17898779, -2873788, 4039881}, {51533770, 7511465, 13293793, -4059978, 11153614, 11009888, 11043633, 5149393, 61640404, -6800453}, {-4552117, -8561660, 23195450, -4554595, -27170724, -1970990, -4977038, -13883135, -5725165, -15808316}}, + {{11711306, -7715099, 13402543, 4886294, 3948457, -16861821, 54588649, -8627574, 15335566, -13496004}, {47849638, -7676775, 10746151, -25318768, -22127087, -97467, 5139847, -24024518, 45927328, -10995204}, {-2282561, -10611488, -4674912, -6559561, 18594050, -16435781, 11874818, 3046069, -17026318, 5728361}}, + {{41856251, 12950385, -49564258, -3338865, 17211570, 9374416, -17508886, -84564, -11279731, 14738720}, {10571673, -1007843, -10278648, 4715025, -22625794, -13812080, -36837170, -10092196, 27964543, 12132548}, {31633897, 5333003, 17305989, -15620601, 31420706, 7077450, -1282785, 14064373, 22859149, -5366780}}, + {{29401271, 17590888, 40211130, 16393297, -16781728, 21756168, -34072615, 824872, -46599901, 7258734}, {14907187, -6894438, 1941780, 910997, -22528838, -7424968, -13182161, -8108566, 19729241, 601214}, {22111325, 686053, 20766182, 16117728, 8108657, -7431453, -32100036, 7690467, 20467985, 2064394}}, + {{-9563965, 1799585, -55856440, 24457121, 2609002, -1619031, -20010702, -8967675, -586297, 3782758}, {14310681, -14492783, 11159344, -6800783, -24070908, -29321517, -3770592, 7183761, 37294119, 29117522}, {-21492008, -10816384, -16589540, -1859657, 11525668, -15915177, 23032110, -6363217, -25557687, 5298613}}, + {{-25032759, 10137207, -21211248, -1034086, 39026407, 7671727, -43707450, 27535838, -15322601, -4497902}, {11942565, 7163909, 42601550, -24698096, 17808541, 14931203, -11547292, -5943574, -28868475, -26215578}, {14343863, -10932853, -5696991, -15930429, 1361756, 3515646, -20327658, 11789280, -8527009, -11974718}}, + {{-11359733, 6002309, -8194230, -507343, -9059323, -6304308, 24341964, 23549098, -59528413, 15137157}, {-50282777, -3995829, 55101228, -31906299, -23919849, -21007134, 6100310, -9828078, -6180425, -3361637}, {8981133, -9453900, -8051056, -8941797, -18262629, 8468728, -22819884, 15223516, -14658504, 11171251}}, + {{6674374, 10785646, -4108828, -20474317, -4107060, -9714386, 23875362, 16560960, -7939903, -5481596}, {18327574, -11544652, 6892376, -5234831, 27509434, -579964, -27318176, 957470, -31859127, -6020504}, {-4939268, 10764095, 4739768, 9712551, 25335990, 316087, 23616732, 13096853, -793009, 1895383}} + }, + { + {{2543110, -9808347, 4640240, -7010430, -47238686, -2552162, 4162536, 10379266, -9885342, -2539863}, {-26280850, -23281219, -59949252, 24374544, -686566, 18693896, -9672404, -20736822, -29243944, 29417147}, {-21990215, 14672579, 7157233, -10322365, -15041058, 5857122, 5758298, 11088514, 23812375, 842231}}, + {{-18705612, 2687256, 11824336, 4480752, -36363579, -7660875, 8785758, 8793908, -14316875, -12590786}, {-31902556, 14677678, 5320722, 16466372, -12295499, -15254163, 11452314, -13028410, -14238999, -15351652}, {18718379, -15630347, 31248183, 9915829, 6883322, 12295368, -18266196, -1000492, 9640603, 5026495}}, + {{32867173, 9713255, 2509886, 2391981, -3573937, -7843211, -13959718, -3563177, 22213554, 22944211}, {-762971, 8382357, -35082658, -29670317, 52550109, 17901337, 39668850, 12599955, -41857292, 434617}, {4175818, 6202136, -12981802, 10989660, -13446840, 13409458, -8145375, -398509, 30749406, 915555}}, + {{4634039, 1303916, -22754903, -21524256, 14068582, 16069808, -16878209, 22976842, -28822159, -8825216}, {17868875, 23791960, -24264405, 4862386, 39600206, 6002486, -9879199, -2411588, 24192121, 21457056}, {27118539, -3102105, 17342980, 1586278, -24597424, -11260946, 17727987, 14885443, 6489081, -16506177}}, + {{17995544, -8765498, 5909664, 12827982, -298225, 4966027, -21497021, -21247921, -9748613, -14917233}, {33627094, 19855512, 38840280, -9008172, 3438267, -20222203, 35781059, -1283183, -42823477, -3873729}, {32062430, -6288947, 23295494, -9453258, 227865, -7475030, -9517768, -2542778, 16094581, -13647547}}, + {{-793671, -14570717, -56571197, 6602565, 8352983, 5383136, 20073779, -5725618, 30790587, 2760327}, {18673609, -4434905, -9896767, -16492307, 19553749, 12166150, 46972893, 1214842, -17742015, -23402027}, {-29663253, -12436383, 5475870, -10905550, -857503, -12499416, -32109832, 14728704, 6093894, 14964981}}, + {{9481017, -7763642, 11376981, -4421714, 6488144, 227795, -39110010, 8413171, -1805191, -18704214}, {44704145, -25100814, -34948723, -4099268, -26111248, 3476373, -4360006, -9717733, -20338933, -5084634}, {-5048671, -10975302, 24921200, -14328979, -1143468, 930428, -29583430, 711968, -31536251, 4173233}}, + {{23571098, 17917014, -42844963, 27084836, -2723388, 9411004, -17205187, 20670486, 204409, 1032379}, {8062384, 12085736, -3230951, 2713858, -5187980, 16498068, -19462575, -6606642, -30054249, 3236679}, {11234981, -614076, 12581588, 11210266, 149116, 2959366, -19799199, 6852842, -23892167, 14326076}} + }, + { + {{-55407608, 10389205, -13719459, -2798022, -50197552, 14459564, 18222745, 21430201, 32575812, -8706832}, {-2564000, 13377951, -22379461, 11840346, 3388836, 13098300, -36010183, -4645599, 8583764, -15216002}, {8844512, -14692897, 18384808, 15191210, -31354755, -640150, 14796127, 2046560, -4888509, 7877940}}, + {{-31758000, -17823772, -11824015, -29062393, 8891526, -6664321, 5502853, 8024723, -22944602, -15063066}, {30418160, -2270432, 38309221, 1972107, -12567508, -19040641, 25038133, 21969139, -9754328, 6486026}, {-15209373, 14879569, -12278800, 8242447, 21217813, -2706193, -11674610, 3776800, -26436037, -2772941}}, + {{13887517, 2793678, 25907763, -16634306, -65840, -6202767, 55572925, 31310928, -8676929, -6897952}, {5270009, -20924388, 23172827, -13573232, 12490658, -5078395, -6139227, 273190, -1980075, -2701458}, {25806042, 13685317, 25123807, -3440883, -22680732, -10820546, -6184384, -14704447, -16822836, -13171217}}, + {{-24206352, 12893245, 4424093, -29853833, 19045229, -2822333, -20693465, -8898606, -28285556, -10932499}, {-39992522, -15746847, -36152997, -2454855, -30967513, -9484603, 40560125, -22691342, 3152880, 22543637}, {25251286, -4412149, -3137687, 12914226, 4215400, -6359262, 14279424, -9974704, -4975655, 5727071}}, + {{-12723933, 5664973, -32702910, 6392489, -38337493, 12732070, 10066344, -6355754, -43893475, 18466328}, {-53801615, -21581197, 18254024, -21559193, 15933113, -13981074, 14179938, 15136906, 2131091, 330460}, {-20916166, 8517295, -15047901, 7866106, 23068626, 2776944, 20230557, -13171647, 27542922, 1272190}}, + {{18625220, 20038591, 29117886, 2551065, 7597130, -24925654, 49173757, -14071381, 1652545, 12919204}, {36848386, -4455055, 32915122, 5036091, 12485852, -4465570, 12568205, -18115249, -62704171, 19541718}, {9730256, -274817, 32374106, -12264171, -23404505, 13869684, -8315359, -8284483, 8794383, -4179338}}, + {{47715457, -20478414, 26959996, 4620275, 41356265, -27076409, 5057058, 14750257, -1220827, -3274470}, {9295203, 7485020, -23371420, 19197583, 13649391, 1942759, -34609024, -2086483, -41922107, 25475742}, {15032034, -16351658, -25832415, 6367304, -29970907, 15969403, 27884976, -11464895, -16996239, -7730352}}, + {{19431047, -2260397, -10477516, 12987323, -28637035, 4788502, 50062278, 16109873, 12054936, 14649909}, {14068557, 25603425, -29318290, 14735201, -29487071, -3659852, 6013412, -779311, -25677432, 4593481}, {-8985336, 16768214, -17001696, 5044973, -30451488, -8576060, -24873505, -9261152, 20349988, 9722404}} + }, + { + {{16244425, 19386605, 13179016, 16779731, -30413594, 2771521, 26266816, -29965121, -19580065, -21702146}, {-10286589, 10328523, -3557058, 7082567, 9264482, 10014543, -33567546, 1785693, -28595425, -4403048}, {20613396, 3045350, 26511462, 846589, 1825114, 6510426, -1159746, 13715579, -4677392, 4700223}}, + {{32349255, -1888695, 10005871, 8154731, 51249234, -20187563, 47865489, 14968746, 26874060, -3634423}, {2327953, -26050361, -47093437, 23300365, 2090724, -12450009, -12126499, -8782200, 20557240, 2698983}, {3670930, 4474936, 5884156, 3007236, 18126028, 4038474, -10256988, -4400184, -24987311, 2654997}}, + {{5533532, 20562652, -635126, -7848089, -13086965, 13192141, -3410187, -9191554, 34865324, -11912506}, {-29597680, -3633734, -20926288, 14155461, -52963837, -19574309, -25891125, -1702880, 23825504, -237972}, {-18346199, 968436, -2131689, 6191929, 23849553, 13006847, -26057361, 13509301, -21018175, 11596373}}, + {{39453651, -1135365, -1065127, -2136909, 14021839, 373282, 6049833, -4481292, 29651109, 22055750}, {-2020135, 20780431, -30250459, 2974907, -19840931, -3341590, -11113897, -14225426, 4123457, 9244600}, {4040937, -8135822, -8225471, 13967399, -3430292, -2062606, 30224578, 1456799, -13622851, 14626044}}, + {{-48264804, 948333, -40876951, 2308305, -15905104, -3151435, -49326789, -5347391, -21668059, -22869817}, {-2938060, 1790191, -21896787, -15138945, 8333162, 40791, 5881669, -13278349, -36626565, 7065921}, {22908134, -10952941, -32040081, -4228188, -30346707, 14226961, 32514498, 9158454, 19853999, -13650510}}, + {{52592, 23183064, 12822258, 5295898, -30584287, 15141493, -40102815, 30555412, 15395867, -6057918}, {54410792, 7131574, -28912024, 12922570, -6534349, -9585759, 3731999, 257018, -29197749, -18737952}, {-174622, 9813123, -9335186, 11240533, -609670, 2141034, 11990383, 15382033, -27641020, -9934187}}, + {{-42856892, 2801630, -12092033, -7826833, -36150139, -3058418, -15797991, -22222372, 8853262, 15067461}, {-13333114, 10291648, -11261243, 16808507, -29620407, 16581608, 36763155, 3151030, 829028, -18276069}, {-32412756, -3132827, -3877653, -2633776, 19498083, -6681205, -24598890, -14645255, 30099164, 1501624}}, + {{-14564585, -5495570, 35218902, 11789804, 3723625, 4078436, 28190283, -11969816, -19233658, -15477722}, {1731709, -14408930, -20806568, 13954940, -27871721, 21453590, 38687519, 16951100, 20128750, -797404}, {-26482066, 13341206, -19287886, 14511797, 20664472, 1928783, -20158033, 13260751, 7633852, 2523852}} + }, + { + {{-43260040, 6473328, 1557622, -21385728, 24624685, 11053362, -24465831, 12027121, -1296883, 9498438}, {-16064298, 20871518, 11964026, 5201486, -36037983, 18277458, 28053689, 17963957, 44543663, 10070674}, {-27698134, -12414407, -17523137, 9603262, -15925455, 15527330, 16231856, 12548929, -8177364, -6027408}}, + {{54662134, -16031162, -32531502, -6748029, -27373251, -17154859, -2919279, -4967069, -19857396, -12138642}, {-4528692, -4676104, -532628, 22644343, 23361237, -8451575, -19988603, 13755583, 38755320, 13494238}, {28034349, 16011370, 6132375, -8026861, -19955403, -7342119, 16292641, -74506, -21896084, -11403465}}, + {{-27593454, 13094223, 35050187, 1112152, 45305703, 10174602, 4540352, -22476723, 8851103, 26977909}, {27603070, 16225037, 10003177, -10210650, 3042761, -11799892, -18967616, 3300265, 55941741, -1322865}, {-975595, -8515612, 20576907, 2962944, 12376740, -5009942, 21475070, -16247744, -13639259, -16622990}}, + {{-6110762, -12336453, -2318130, -5293577, 10242972, 21717357, 9484750, -21048697, -16405325, -3121616}, {-36766202, -10738143, -12260760, 2799389, 13880050, -5957397, -56205822, 12279109, 32843571, 19087862}, {15875026, 3224511, -12725397, 661269, -16504206, 10113042, 671550, -10167884, -16476069, -5775251}}, + {{24174059, 16800154, -35453149, -20683887, -16630766, -235749, -49655106, -19201968, -14957929, 302652}, {21095113, 16413642, 25034797, 12281045, -25995382, -15574183, 11387976, 13951464, -6296971, -3614340}, {7701316, 9057097, -12978262, -6751617, 16046484, 14808471, 18295322, 7703037, 17283873, 16412759}}, + {{24766011, 3466911, 20112996, 10045961, -11731260, 27258118, -21214589, -5138226, 22956653, 20127633}, {-13819457, -19663829, 3731692, 9071875, -24835514, 3391776, 5955643, -13096752, -15111547, 12696429}, {16184053, 4573318, -17066559, -472613, -2224225, 2916776, 21667607, -10476553, -30048037, -1341833}}, + {{4557388, -1972662, -34743601, 13494495, 22917070, 22449028, -22203466, 4083592, -30902632, -4735027}, {11406160, -19148786, -13354069, -508601, -26264648, -745760, 7422244, 701712, 30980020, -21199307}, {14333857, -5590987, 6336464, 8243629, -1569954, 15610409, 4031224, 5913240, 30974437, -10097923}}, + {{60565938, 18605270, -22643533, -14144463, 4580055, 14974313, -42658993, -17338515, 55114833, -14643191}, {-1959344, 4923498, -9091303, -18659853, -14989713, 11476693, 13934329, 10418799, 9581511, 16236503}, {1739437, 1129470, -12558964, -14599784, -30795209, 11604674, -5463951, -5930706, 12186005, 13818430}} + }, + { + {{-35478255, -19403058, 29130078, -3642192, -34054760, 12773830, 24323609, 25676557, -26930001, 6357793}, {18267019, 5036964, -17784856, -19703634, -23254380, 15482690, -4580859, 6326055, 24342013, -9259319}, {-2950009, 3333325, -32927075, -12107849, -6923141, 9900443, -3010914, 5671126, 16389078, 1557327}}, + {{10712172, 818755, 7114214, 10157030, 19626281, 8732952, 33425659, 17622561, -27215469, -8473975}, {19409164, -9071443, 59470274, -6383510, 19652897, 20077708, -29602987, 9423745, 3533003, 23726147}, {-18023673, 503440, 18201137, 12757869, 22934174, 1069362, 5479785, 1332067, 16669690, -3732180}}, + {{30095728, -1023560, -34998228, 3543534, 7033440, 30383354, 7008416, -12802313, -39158980, 21350261}, {1500790, 32163628, 15195912, -4749332, 11244090, -345690, -39114600, -4356623, 20191942, 5711477}, {18544374, -2437080, -10415432, 8680001, -8473986, -10631562, 31052589, -4760889, 26647148, 7652851}}, + {{-310955, -16499706, -635305, -686453, -44988759, 9642745, 60244219, -10445966, -7916156, 6506535}, {-24768229, 7400614, 13965641, 11719377, 6626005, -18788057, -2556845, 1486824, -7401572, -25244247}, {-4820920, 12142029, -1139587, -6661198, 27235613, -2483020, 10372730, -10526385, -11360259, -9895901}}, + {{20981792, 4993609, 2988489, 14558375, 22384493, -7571434, -3059548, 24452930, 7152018, 8227212}, {-20323276, -28219857, -6886853, -6962443, -31824749, -13156966, -10764090, 2798338, 22844258, 23870578}, {11918979, 3062159, -4786142, -3857810, -26146709, -15843897, 9528498, 15484827, -10327136, -1746398}}, + {{-36733054, -17098633, 9026429, 19135840, 37747779, -27559988, -26286152, -7444604, 21768385, -11637434}, {1811862, -5871527, -29000157, 13727644, 2680547, 687652, 5779176, -8569598, -44773239, 17208944}, {27919463, -5431219, 4145592, 4896258, 23901878, -6342172, 7447305, 12138807, -21821064, -13317856}}, + {{-63347, -9814554, 7668513, 27954176, 21976240, 2241302, 11545847, 4113160, 13342234, -437965}, {55895825, 22698358, -31745797, -4544224, -7756956, 11469750, -31063721, -4707422, -44478960, -25234225}, {-28786201, 15355265, -6595787, -5899836, 22617098, 5066812, 4049296, -554708, -2282219, -10143923}}, + {{-57035299, 7525263, -7759463, -3860455, 7863270, -12163150, 13088274, -34470, 47799063, 3872567}, {7751963, -9466541, 13131857, 3765811, 49026840, -7923420, -2137972, 29165054, -4573467, 10747679}, {-7889899, -15989294, 10543109, -8174449, 7082557, -6339215, 24191217, -15720948, -18571862, 8288783}} + }, + { + {{31309227, -10120033, -13429146, 3234061, 18088861, 3111663, -8801175, 17996011, 4769010, 14877554}, {28378843, -21528929, 10080100, -23750517, -4265317, -21010053, 14789483, 8513905, 47848204, 6371606}, {14817669, -5700112, 16317964, 4628849, 14421506, -2827628, 21780208, 9496046, -1975569, -15947664}}, + {{10708579, -663718, 14424671, 11438950, -4290406, 1370867, 19810548, 8964001, -10534574, 25360025}, {22613355, -15549820, -22727309, 3537740, -18558418, -19889309, -44420352, -20699201, -6487080, 4086117}, {-33332299, 14506969, 13111404, -3065059, -5334306, -15140417, 314023, 6631436, -24016063, -13927512}}, + {{47577230, 26081704, 44087640, -12653324, 44880330, -12535475, 4091120, -5980698, -16019469, -6988148}, {-6316018, 254878, -20381742, -19059830, 15070988, -1975275, 49017536, -25812022, 38570443, 4733444}, {5941462, 10715296, 20618971, 12996738, -27961003, 9287116, -13261369, -14265766, 19222667, 9694024}}, + {{50424099, 15808062, -228330, 21105609, 23247468, -17656986, 40809196, -22805126, 3651122, -25519565}, {-9303781, -15714356, 56345338, -3627083, -39042480, 5749722, 2755528, -2410224, -38591278, 1621663}, {6784609, 11617250, -8516435, -15425251, 13363912, -3305824, -6389143, -14881764, 26775080, 328929}}, + {{-6343434, -3807555, 14111814, 142075, 26569243, 4377956, 21258632, 28483037, -14604571, 5428106}, {-1825334, 14697797, 51742052, -19721041, -14807097, -24634572, 45205776, 2753003, -9906043, 3227470}, {6843194, 13129334, -25344427, 6959244, -27940482, -15930143, -25342017, 8526681, 32584402, -19181}}, + {{48603459, 1622843, 10690168, -20815014, 42891414, -685473, -23520500, 13623750, 23771584, 25338055}, {15821205, 14084935, -53143204, 4755752, 23247376, -27381429, 37299558, 10926412, -38889646, 5703581}, {979907, 12364857, 15521822, -6791124, 125160, 653393, 5818060, -10976810, -3077837, -3561753}}, + {{16247896, -6972098, -3117418, -23371848, -14508093, -24209133, 34053148, -8080607, 8768009, -2819682}, {-2542448, -7614620, 57701658, 7104698, -20507567, -4917351, -16909516, 8057001, -36253219, 29603518}, {10602149, 14586027, 33238613, 968724, 14073078, -14262826, -18990197, -11128373, 17933689, 1865638}}, + {{-1685718, 2399540, -27537630, -3785648, -24186603, -2815001, 15877013, -12997876, 10506457, 15106158}, {-31268322, 5974314, 2565124, 5022928, -29203089, 17059499, 14032757, 8734438, -52574125, -14648992}, {15590977, -4990683, -22095383, -16512348, -4299452, -3852649, 9403715, 15655990, -23393954, -14460372}} + }, + { + {{-37369470, -4604374, -13299226, -12500975, 1090943, 9931909, -2540543, 3345536, 8805568, -3847581}, {3448882, -11039762, -498478, 8160031, -32767971, 14059967, -8274027, -29682076, -23057400, 27264979}, {6733683, 12574311, 32233740, 15210420, 30532307, -4990676, -11354801, 5044573, -33368350, -7055348}}, + {{3332860, 7330151, 14119860, 548331, -32089682, -13355081, -62005018, -3262142, 11384920, 1613906}, {-20989898, -9767083, 26727662, -6555871, -31170204, -18158849, -361110, 26372934, 40556624, 6592026}, {-14382, -10034696, 21180475, -13481209, -8858357, -879701, -10010244, -12628483, 5381832, 15522788}}, + {{23442936, -9645451, -3095778, -1972364, 8661736, -6340237, -28010800, 11065785, -14487431, 12313579}, {-9498676, 4731359, 20794022, -27114326, -45878634, 9580915, 18659456, 21026965, -26651563, 9257031}, {20098670, -2165836, -22463512, 9495619, -8584563, -14416361, 28126763, -10967903, 15508507, -13170138}}, + {{25913605, 1969581, 864912, -24569567, 20475136, 1302815, -35026388, -13316709, -10841039, 2655272}, {-35890007, 24248971, 43076998, 989791, -12095108, 8863341, -4423904, -12105939, 51462723, -6235022}, {28032028, -9287453, -6706938, -13875364, -15082336, 4173292, 20614416, -3672459, 20376541, 3730791}}, + {{-47966139, -3723482, -23105532, -20264332, -14454715, 10507468, -17799502, 14906682, -30484758, 23141559}, {13962911, -5035296, 39238248, 7090710, 39307349, -11801732, 7498818, 16807300, -24044194, -9491447}, {9876300, -6253555, -5795237, 16623989, 15150684, 10230086, 28143791, 14904824, -25321821, 12582879}}, + {{13878510, 8136782, -44827884, 211696, -23663124, -27674970, 43180760, -8111421, 28806806, 1871728}, {-20937788, 9190664, 9063434, 8148344, 33620962, 3292652, -20283470, -25052025, -27042338, 26507414}, {13269905, 5741364, 6572729, -7083198, 1063870, -612394, 18258440, -16729936, 30210502, -12036586}}, + {{-43340533, -1659297, 32502357, -8168562, 14551290, 11303417, 30633369, -16404919, -6687359, 2697908}, {18797601, -30823125, 12697389, 25216842, 4085606, -9751835, 13690333, -12522671, 21935261, 9453278}, {21604819, 11323086, 31609022, -16567650, 27157754, 6691142, 5270536, -8989324, 21208395, -3994233}}, + {{4491535, -3901970, -17432264, 21965530, 15209514, -9715706, 38557094, -7374169, -7383038, 1560053}, {-40426265, -23815208, 22565190, -6206930, 42106308, -15153260, 8756382, 2019395, 19169788, -16659457}, {-29803206, -6105424, 22810027, 6907244, -2770486, 4787824, 5434016, 8936077, -23072042, 6465499}} + }, + { + {{1359526, -24496517, 12739718, 15825090, 13757731, -85826, -5634793, -26099760, -12697211, 18193534}, {-30665532, -3700315, 35823346, -8583334, 48650885, -18459174, -11166307, 4088974, 4409515, -13737722}, {5883165, 10377734, 28162516, -1270493, -7170962, -14378797, -24381074, 15601881, -2015194, 16340442}}, + {{40776751, 7628001, -36800135, -23784731, 10527576, -2276280, 1005673, 5305084, 34977839, 7027929}, {25785539, -8358493, -14169157, -941665, -26727096, -8572452, -37347281, 26636568, 5428891, -16363291}, {20812660, -16641501, 16501026, 11766799, 8242740, 8504683, -32152645, -13636741, 5182832, -12868494}}, + {{-11426179, -16123489, 9211968, -3793779, -1415467, -24016961, 44379617, -19425014, 9288996, -1283140}, {-31623749, -7257865, -22402126, 5544031, -19404557, -4057317, 1073669, 9849860, -1911856, -28320334}, {-9189155, -5231005, 28794763, -2421382, -8377667, -1076498, -25284938, 4798666, -30829635, -16494880}}, + {{7748378, -8485428, 17925664, -1037621, 29601847, 28681986, -28410463, 23057803, 2571240, -12202391}, {43967412, 13465308, 31093816, -3101433, -6966813, 248984, -31559605, 2659161, -38301184, 367885}, {1077792, -10693550, -31685170, 12960093, -21815056, -12333718, 21110948, -8355869, -20551815, -13082804}}, + {{-16658278, -1776747, -49320746, 3268840, -9161932, 3366653, 13547568, 464960, -6663953, 31367815}, {9178132, -6190845, -1488318, -17126490, 54784914, 17732495, -51588184, 10003598, 45290107, -439977}, {-5745670, 14361424, -16869431, -7959435, 8475014, 149961, 5416937, 2316944, 5620355, -11502920}}, + {{-23119897, -278325, -40471835, -7725944, -36491612, -18075366, 11989701, 14246374, -25468931, -20403038}, {6774845, 12418993, -3607903, -232642, 3816628, -7391076, 32177423, 13233488, -41072015, -12292622}, {12249995, -1086614, 15059650, 14759477, -10480279, -2927245, -23701950, 8802868, -16881368, 13226705}}, + {{-4617370, 730165, 6275053, 2018584, 33324113, -20772082, 19313139, -5717890, 25081460, -748756}, {21700676, -18005757, 8939095, 17757354, 17339219, 7413892, -11924225, -26230164, 7336468, 10944214}, {27906889, -6186337, 2933378, 6045852, -22395141, 7566091, 20652, -9292812, 12869332, -7249143}}, + {{29306699, 11394548, -26402239, 9596096, -48987263, 15755348, -13990905, 3552647, 30504592, -11033892}, {-24214285, 12852074, -40141535, -4071498, 9210503, 9187860, -10030141, 5519251, 34591920, 5583424}, {-7379292, 9129651, -27605104, -2097314, 27463602, -10277545, -7870303, 607936, 31933339, 5106556}} + }, + { + {{4963336, 30566458, -37136792, 4067521, 23891759, -4720023, -12816701, -11241268, 55320303, 1681387}, {15572948, 1586798, -28125896, 15671757, 29155331, 17673481, -34717495, -11365824, 113643, -31577145}, {6762588, 10685233, -8185349, -15717909, 5086315, 295811, -8997093, -9079304, 27737567, -1733458}}, + {{13002352, 16645200, 35722894, -10650753, -747123, 17328050, -24844918, 23399376, -19265384, -17742834}, {14753640, -13174550, -30840888, -14673027, -44036543, 10285590, 7337012, -9120376, -3487394, 14269638}, {7874396, 10712779, 29245055, -2747462, 7138405, -6636924, -25434782, -10508735, -23592427, -5389218}}, + {{-50164345, -11794259, 19659702, -8196770, 20274739, -6312077, 2700612, -3027608, -5113712, 15337537}, {6999467, 16080959, 44188308, 6905376, 9606919, -18176839, 49565008, -27684824, -37868634, -17912063}, {-13996803, -15465353, 33254067, -4645956, 5129744, -9412605, -17163224, -11740413, -21611420, -12468971}}, + {{12532020, -16701407, 38834575, 26174269, -16525516, 12418955, 30854724, -24095435, 9173016, 24509775}, {40312388, -8767627, -6631607, 5517149, -50471458, -7397475, -14955174, 1762317, -4466492, -7050493}, {8010439, -11120597, -20666396, -5670804, -24665933, 6998169, -1215708, 15533381, 27712093, 11647611}}, + {{6295646, 7402540, -31719851, 1673087, 30802846, 28126431, 25335594, -16219328, -37404513, 17052354}, {35977310, 9516280, 11288617, -22896661, 33492032, 2192159, -2413372, 14896262, -8809959, 15613754}, {32482139, 1018569, 6746330, 9727262, 19722395, 15969951, 18153008, -5153011, -18580360, 15187146}}, + {{-9659530, 10483762, -7711787, 6503533, 23723680, -14168934, -18766723, 3380559, 15825727, -10678023}, {37979770, -4123562, 11687469, -23732759, 7044880, -4832668, 20773237, 9009651, 8899955, -21901477}, {-16637573, 9260475, 29195132, 5043537, 32477611, 16711561, -9855228, -2335720, -16457364, 3972439}}, + {{-27275346, 14198716, 37705088, -5737219, -5966388, 5310384, 30973546, -10799630, 11686946, -3472324}, {-26575214, 12416248, 12851324, 620561, 38402614, 18181650, 22087592, -16733900, 13929664, 9066520}, {19574371, -10420795, -28302872, 2640062, -26714255, -13400364, -13705673, -8131657, -14448411, 55284}}, + {{14540970, 29727830, -30602401, 18990126, 33980643, -16229364, 6699745, -5043718, 44511147, 12134296}, {28598058, 3700600, -267003, 7852376, -16837049, -13653616, 30860547, -25980090, -5529243, -1996986}, {29512945, -7269820, -18080422, -3726556, 19414872, 5420554, 21801352, -6568354, 24841549, 3679173}} + }, + { + {{391066, -6119647, 53075195, 21658749, -2381210, 8221754, -9761010, -27409326, -10197081, -16082891}, {41715756, -9154201, -6700157, -3279735, 32254248, 10719048, -864674, 2811352, 37636847, -1358927}, {-18493825, 13328651, 30775311, -10858279, -19652172, -15451753, -25193859, -14919662, 22115005, 15238952}}, + {{-37909950, -4192427, 30763759, 4709595, 6440100, -2496575, -8313792, -134671, 25584787, -17709141}, {23415766, 507961, -8540857, 19584539, -17226726, 20277901, -4744136, 9020001, -18669633, -7221827}, {-13944774, 12082688, -21867733, -11816481, 14018582, 5580472, 29102869, 8058592, 19045045, 7370374}}, + {{9705609, 7038527, -58230350, -2209017, -57423030, 4600011, -32248810, -2169572, 16216102, 26345175}, {16418235, 18291867, 680530, -3210101, -3828314, 19652983, 14073034, 21243878, -9207572, -2288927}, {22369071, -14609655, -31116570, 2112500, 16859660, -8092573, -14483593, -6949857, -1972633, -7815412}}, + {{-12800678, -13905288, -27451889, 30926977, 12519625, -10453572, -18014280, 3951332, 37755617, -17506232}, {49451072, -690596, 5460063, 824367, 25433997, 3255182, -568244, 21039574, 29149223, -68094}, {-22170908, 11982726, 23379989, 15914039, -19728121, 4718196, 16063195, 4276575, -30749654, 944442}}, + {{3507922, -1425483, 29783822, -12479867, -15770827, -9983485, 11572826, -2076547, 26346169, 5967647}, {-62870078, -29517849, -23683284, 5935613, -50475545, 3076951, -52330402, -30033345, -9663027, -17932715}, {25162683, -6473299, 2353629, 14862607, 18708912, 1571931, 16861776, -5747884, -5108055, -3109486}}, + {{1234152, -28457094, 37980852, 2473998, 41455415, -5755878, -40492603, -3808641, -62657876, 4804142}, {5492734, -3579724, -6764702, 28414580, -1758437, 5241018, 25397671, 3228983, -1588100, -24365962}, {-2763454, -4585844, -20110752, -15332706, -27379233, 7178363, 9970084, 5116494, 17538635, -3624594}}, + {{-20805311, -5931254, 56412512, -1608050, -11523407, 23859878, 21365865, 113887, 36730200, 15056083}, {39914069, 19449542, 3892770, 13534694, 48838993, -3952798, 11326589, 24503511, -948032, 4774861}, {11185844, -16645023, 27830878, -15207952, -31579784, -1217890, -18632641, 10274575, -5164967, 6798995}}, + {{-3943884, 3750725, -39942933, -2202737, 26663773, 28874785, 19208707, 19642878, -5073211, 20630016}, {1531932, -6260105, 21645569, -20776181, -22015031, -1049151, 44581341, -1150520, -36055919, -10315592}, {-20274886, 3155403, -32509797, 6623133, 9261194, 2412207, 30805150, 260264, 30935086, 3378893}} + }, + { + {{2456609, 5044184, 27761770, 15627626, -3940971, -9335846, 15290318, -17081414, 42038554, 19706346}, {-41097223, 5892414, -15032582, -12463660, 32708353, -20099178, 47350188, 2522908, -21093508, 13321318}, {5518369, 6348967, -25201570, 289887, 560978, 16568987, -15355900, 568715, -31190019, 4727475}}, + {{31185336, -10483456, -37299080, 8356920, 27424791, -7362674, 24036320, -6022865, -5078922, -3574816}, {11177636, -20684076, -13686546, 16140950, 25909933, -18451818, 14995958, -14234263, -16615184, 20696602}, {3813290, -3117879, 15037061, 3816371, -1034575, 2871123, -22604995, 16662721, 24637410, -16185671}}, + {{-8987896, 13194029, 11155201, -8963227, -37870035, 26494547, -28330859, 27932297, 44786771, 7961589}, {-45578616, 2857209, -521875, -11450219, 4802629, -5386173, 4688241, -3348823, -3783463, 20074769}, {-12147244, 7998077, -25771417, 14239968, 23951091, 11211112, 26698027, -8087972, -15680427, -9159835}}, + {{-27243225, -17438566, 17434233, -10890708, -14737439, 12480835, 16491251, -9343239, 19565049, -14877451}, {23555493, 9071130, -26367681, -1168928, 37963929, 14731387, 11305463, 579837, 8934479, -4076145}, {32635109, 12910790, 8282213, -9490747, -7579958, 8628252, 18891913, -814219, -482373, -15415349}}, + {{-34497475, -12678735, 3470092, -565063, 34727988, -8464845, -14968563, 19053231, 11257197, -17824793}, {-5609425, -10735585, 22720772, -23774369, 18822870, -24738365, -28219297, 8527519, 40109007, 8196727}, {5899615, -14070754, -25725508, 5046551, -11104529, -12447238, 2609755, 7511132, -2422836, 13603924}}, + {{50279223, -6542922, 57577079, 4157343, 28588577, 10816789, -4169143, 14389080, 18933993, -11936162}, {-2892733, -13291544, 4167479, -6050935, 8843247, 13500705, 5440479, 2716608, 21774931, 14816432}, {-1515500, 10096176, 15458216, 6580225, -15799990, -13162512, 11945, 6056042, -29278354, 7784731}}, + {{-17292251, 22921824, -41980180, 6880360, -20277830, -385380, -6248053, 19142825, 39153746, 24117310}, {2365821, 8923556, 20174252, -7419762, -5987630, 27493092, 42106317, 12657137, -4887740, -4018944}, {22418897, 4406093, 14754619, 16080495, 16667366, 1275772, 18794492, -13435985, -8834707, -8557653}}, + {{-5519360, -22306381, 17393012, 132810, -28174213, -5967401, 19543649, -8522749, 18008387, -12925150}, {-17725306, 10765521, -8350494, 10589526, -38535239, -175247, 19787205, 16895045, 8342735, -5746916}, {-19597732, 14277837, 5271372, 8893441, 12867329, 10024988, -30069463, -16722246, 18027331, -8111094}} + }, + { + {{8211443, 6846191, 6945247, 7074724, -16163053, 15261919, -4711628, 598717, -2132537, -14458264}, {43176173, -2930209, -27378935, -17199378, -50191235, 10250513, -50228070, 21301081, -53402185, 7938340}, {-10404692, 238394, -17223298, 6317408, -4597422, 11845257, -25086201, 14106911, -13527225, -4046014}}, + {{-14175163, 15668594, -6576950, -7210777, -1888191, -366448, 25645549, -16272198, -4885076, 3841556}, {2511583, -5186496, 55890844, 23657615, -21883851, 27772590, -39009655, -8971750, 14765424, 19640334}, {26025475, 3849658, -28905409, 8029819, -27234840, 13808387, 24915058, 10020824, 29062335, 4425302}}, + {{1734057, -26209178, 26725763, -22326962, -5230996, -1052637, 6999425, 2262570, -19773062, -1700510}, {-15374263, -5806068, 32689871, -5088860, -31436222, -8321645, -40985977, -21502672, 35714796, -18222214}, {-14768861, 5265598, 27017752, -11383707, 25272910, -10608235, -19841735, 8143974, 14355736, 4895974}}, + {{2564989, 17774433, -39389878, 7381726, 4788616, 14437703, 46532039, -15500352, -35606481, -9383279}, {31821159, 11038283, -15096324, 17036130, 12947696, 6672291, 6712285, 10625526, 17575711, 17919583}, {-15547771, 5972443, 25740339, 5225389, 6240913, -14419532, -13177629, -14025954, 25433375, 6923784}}, + {{-39602241, -22451961, -6679348, -1879873, -31306455, -4673801, 42003200, 15633673, -25485306, 3618740}, {18966027, -2937179, 44083354, -11883267, -26013759, -21812007, -14601802, 15200437, 12874508, 24527692}, {-13595163, 13994428, 28115928, 9952765, 11976530, -3003087, 17405764, -11778077, 10153753, 10737243}}, + {{4758365, -18760313, -39703731, -5769023, -22327353, -12858180, 10132725, 25214914, 30390380, 22401913}, {43780679, 2887997, -12734617, 6126773, 12526713, -7150442, -27133987, 3407118, -25816654, -8843037}, {-4646664, 16249032, 12870592, -15878236, 17245698, 2787385, 15233470, 12902660, 6727344, -4068799}}, + {{41164736, -28920406, 11332370, 5410817, 1165589, 2906065, -14252437, -9444526, -33243955, -5692085}, {-9837778, 2527990, 4758344, 288519, -52472379, 1716431, -40267701, -21808582, 20704447, 9165943}, {-27558528, 1633938, 12095478, -3638629, -12376063, -11786771, -13580026, -10396607, 18139106, -6907116}}, + {{-20942300, 5288895, 16229812, 17290276, -21431368, 20894445, 9565998, -6703699, 1531117, -2716733}, {-42200530, -10464245, -17551450, -3224172, -6941756, -7526915, -49506544, 16138347, 29988743, -10203681}, {21142628, -9617101, -6798344, -12336852, -27439461, 14607255, 4827507, -7738199, 10888156, -11850843}} + }, + { + {{46442335, 20022981, -30174785, 1639361, 10908209, -15989410, 5883434, -9828987, -1342268, 8009605}, {19870337, 2137623, 31457303, 27150691, -36661303, -8047878, -20259582, -3473899, 30616924, -24381463}, {18884536, 6107716, -11768092, 3174545, -586100, -2552734, 7116535, 7778418, -11626304, -2320061}}, + {{5162076, 8030429, 20527820, 19052206, -16398563, -14931087, -5719020, -4303477, 14281076, -5514691}, {1715888, 14778911, 16583086, -5247974, -17403139, -14625025, 8168148, -7273509, -45753064, 3468687}, {-31998034, 5912797, 5381880, 2727614, 25852718, -11105864, 17721587, 9423814, -13913530, -5524258}}, + {{-12510292, 10558159, -54960122, 24194901, 23421792, 151806, -32597520, 30133382, 7071739, -20341567}, {29680924, 3605605, 9451608, 222173, 26833656, -25335820, 32494322, -979772, -27270479, 1146903}, {4227910, -8556105, 29479265, -5632632, -19995287, 11984129, 28326151, 10998690, -10999665, -717597}}, + {{34493157, -11459179, 11636869, 8222916, -22618221, 6526973, -12728656, 5088057, 9911920, -20256756}, {27537703, -12282099, 49626567, -229380, 6084025, -5156281, -15646540, 15368259, 3750196, 11875318}, {24873443, 2925400, -23926024, -10124859, 20453383, -6977954, -18933389, 6763057, -10825186, 4126459}}, + {{36484309, 9858199, -14454476, 2638398, -3973101, 13590454, 9296251, -447982, 47398700, 5497464}, {-27741289, 4777305, -33582564, -21758322, 54773125, 8843910, 19325083, 17636332, 1372052, 27106988}, {-31991681, 1193232, 29094172, 10252713, -7647724, -14588701, 12843696, -16151942, -23258064, 14243828}}, + {{-26316538, -4397665, -9106766, 6560489, -35540410, -5413324, 27757919, -3957618, 58253931, -10038267}, {15241974, -17355079, -16681030, 29171, -19551186, -6885608, -34766411, -23315986, -4968459, -2567355}, {22685865, -12865180, 11595686, -2115801, -15016214, 16721696, 33367997, 6993411, -7134246, 1287309}}, + {{4940959, 10255882, 22827773, 1050551, -13108547, -12542581, -9620993, -7105733, 7536868, 13015885}, {50033601, -17535378, -9884855, 26346557, -11906721, -17662525, 54356173, -13113075, 39890210, -1683557}, {-19387962, -7741720, 6697790, 16078299, 28696877, 5372129, -121762, -1120762, -7359916, 13971721}}, + {{-52447619, -7371581, 14542901, 6819160, -21375967, -4034422, 41076656, -3790396, -54001792, 8265953}, {6382427, -25826319, 23432797, -12740892, -33579331, -22041686, 1610560, -4106612, 930186, 2074871}, {-18646343, -3409491, 23427158, 15485903, -4577804, 11428084, -27871866, 9852304, -22329397, 384241}} + }, + { + {{22380193, -774208, 21177592, -9135097, -12430109, 15227152, -2091457, 4299381, 5285727, 12195441}, {17654285, 6758324, 31877792, -15536779, 43882115, -8603846, 62456331, -8223789, 56630889, 19626321}, {-2381007, -12555643, 32821184, 8760545, -14042905, 14417333, 16183366, 12199248, -25863146, 10648350}}, + {{20220081, -21581630, -18788235, -7356089, 15506206, 12511511, 16779346, -31746312, -29836998, 1581806}, {24956569, -6655186, 10990897, -7222177, 21123636, 19816493, -38245450, 697716, -9166186, 23184666}, {-4246751, 3261371, 14729629, 2041727, -18233351, 5192999, -9839070, -5946266, -15405468, 159061}}, + {{-9072937, -8909298, -22910847, -7238598, -30347664, -8961600, -3394074, -2568861, 1660466, 22542141}, {19368157, -9071034, -16352223, 2057668, 32937992, -12317132, -26418654, -14923613, -54167498, -5014341}, {-33187100, 8862843, 31013880, -2319269, -27771116, 14149783, 13009386, -12871355, 21345500, -10101248}}, + {{-3616740, 18307642, 18813789, -7488720, -774201, 853380, -5386311, 7683876, 27587359, -3296437}, {21380634, -13059198, -27783281, -21163482, 59302343, 17928486, -19508357, 22481818, -25233813, -15000511}, {6807416, 15503976, -2889202, 2342867, 15846120, 12482545, 29285683, 16765419, -31305936, -1578772}}, + {{-4437113, 26661900, -21096269, -2176040, -5177504, 17666790, -33248055, 12072430, -12604477, 14543344}, {-46735181, 3713100, 40958899, 5670766, -13443402, -1553320, -14158135, 2484436, 4569601, -9514196}, {-21813875, 14918538, 2763816, -10706009, 15620397, -9206867, -10288471, 6635873, -20366857, 8316067}}, + {{11441426, 12972742, -54071738, 23414172, -25591652, 1575021, 12645919, 11871072, 16112061, -14157153}, {8845736, -2674532, -11642612, -6956724, 18933990, 27663179, -37996041, 5689908, 27562457, -1329079}, {14001266, 4205919, 18709974, -5774580, -11201628, 16178451, 6093957, -5300086, -32187534, -15385905}}, + {{34997200, -26844355, 5907436, 221778, -15902142, 7448183, -37342831, 9466024, -2655079, 6593776}, {-29737398, 3876053, 8208376, 32952728, 14962142, 25197661, 20386991, 22638926, -45028933, 16459938}, {-31717996, 230725, 1915938, 1360014, 31922109, 2773834, -24697519, -72491, -32405369, 9504623}}, + {{47160139, -986585, 35161879, 17621132, 24998105, 12701886, 22519120, 14675719, -1385488, -16066358}, {1978165, 2663801, -30663103, -1179874, 14412471, -3351898, -39432286, -10893883, 36895920, 6196654}, {25771127, -13637847, -27697259, -13341976, -15772917, 6787999, 10241394, 13025730, -30853434, -5852331}} + }, + { + {{-10036944, -1178727, -54350809, 5762453, -35359980, 20916280, -40195417, 2111230, 10564190, -12460758}, {50100950, -24880685, -5896947, -5240283, 20836686, -7966896, -18105625, 15321160, -55233832, -16446196}, {13194994, 13360959, 1122733, -8329237, -2048617, 14809352, -7662514, -3064330, -32677874, -13712857}}, + {{-49416720, 26007386, 8911628, -11883083, 15918315, 21775197, 26799351, 3326989, -20778662, -4340840}, {-8613604, 1588042, -51972390, 1400871, 28236697, 9849093, 21231045, 19550623, -40267606, 19834536}, {20258676, 15794201, 3794787, -11921710, -25070311, 13635965, 23336626, 3428637, 26267934, 5059546}}, + {{45266555, 476391, -9428630, 19524463, 30098241, -17198725, 11410609, -16864615, -9829451, 17021686}, {6349499, 3802067, -524184, -6171585, -34279835, -6791947, 4351385, -6399333, -27592041, -14173394}, {20309102, -3527400, 6582513, 11881128, -20844031, 11697089, -10446543, 10376697, -2006210, -534397}}, + {{-8576479, -28049474, 15849114, -5944461, -55834690, -17308430, -3228531, -20220061, -6152375, -5881115}, {32113177, -3178742, -8800150, -9509109, 4174646, -8947340, 55116929, -8386317, 55302133, 2238051}, {-26181277, -4964839, -1641604, -12138242, 7401998, -16629768, -3832335, 16719729, -13044645, 9754033}}, + {{-29411565, 9635329, 13850390, -6916814, -37441870, 28492705, -33171881, -6669723, 60737155, -26451792}, {-19429731, -13881909, -34766134, 15380856, 16826408, -2552535, 16029129, -17345175, -3200145, 1033670}, {-28035038, -1199811, 16014261, 8163815, -23622951, 8331133, 2923740, 9634702, 28894924, 4005454}}, + {{47184039, 6885890, -39935156, -8159085, 39619139, 7241498, -18993360, 2281368, 16811900, 1749927}, {-4260141, 17484926, 11669026, -22713899, -13064847, -20599818, -20931716, 13517220, -25720518, 8811041}, {21774659, 286194, 2605428, 15962307, 6591658, 13085920, -27468990, -9189507, 22275785, 14139829}}, + {{7479565, -3942697, -15964766, 11314364, -26316534, 18837305, -15116415, 12881705, -8128062, 4717458}, {13503535, 21520361, -17031866, 2459288, 7075930, -9316021, 6913585, -16779315, -45429892, 2113414}, {32020547, -10540229, 11668446, -11578723, -16478716, -7961648, 24488273, 5250452, 16748276, 15880086}}, + {{-31433645, 12184154, 2862750, -5343990, -12296416, -1924057, -7816956, -8611828, -31569254, 1993397}, {22307675, -6130664, -26008624, -25704110, 44938842, 1475961, 3231360, 13106454, -3830980, -11546473}, {30443454, 13936992, -15314957, 11774100, -1951081, 5775511, -29535429, -5730092, -23137303, -14182245}} + }, + { + {{-12330803, 1143085, -32624931, -10751183, 20669126, 2776129, 267303, 27522394, 2325333, -5581150}, {42745701, 12837201, -9289373, -17923323, -10061932, -7082793, 48448417, 1886454, 42366673, -6564326}, {29644466, -10209851, -7696381, -2168964, 21680763, -15148007, -17534596, -1769759, -30632614, 5768687}}, + {{7457057, -8078131, -56306823, -4227591, -48285590, -10963522, -9493381, 12540517, -28610554, -13629656}, {13037701, -13157827, 10316191, 26452677, -15846010, 20467394, 38344655, 9672583, -27004432, 4785818}, {8915618, -2828481, -33309771, 13346242, 28357898, -12173265, 20492967, 711607, -2009724, 9308573}}, + {{-7658141, 4541601, -14839622, -13289209, -1699297, -11696381, 45936866, 23381502, -41063118, 6577904}, {20805365, -821979, 46076620, 14262441, 39869267, -7088223, 14243928, -9619942, 13243712, -6475322}, {-11838456, 13743429, -24834644, 257095, 10863556, 14209528, 25334969, 132943, -15278828, -9889544}}, + {{-30268002, -6165457, 34643735, 418570, 32951028, 5330868, 32344142, 3334065, 21296460, -9057932}, {-11969880, 847181, 14079977, -19809942, -7170664, -18947672, -11231422, 9306689, 2969482, 2550636}, {1449176, 4869547, 18336933, -3191085, -27767424, -7773488, 8997162, -11418487, -26372279, -9829096}}, + {{12082909, 4327811, -15961017, 29819219, -36191567, 17377959, -49308509, -6926541, -11612298, -372702}, {-41196689, -9987043, 22213559, 1613413, -27234283, -11588861, 16263433, 11421503, -23087420, 2151008}, {-12247082, 13631630, 28043816, -11947450, 12638460, -12782345, -11472468, -5636958, 8979710, 3596526}}, + {{-11009312, -5512300, 43850138, 30694300, 15579577, 3017073, 8031303, -6196057, -33385293, 26189167}, {-16376082, 9431638, 14720450, 44634, -6537145, 28864587, 32605347, -1505253, 4679871, 6435537}, {30018183, -6069455, -25725588, 743254, -16385537, -7878880, 11861000, -4338799, 23419142, -10520518}}, + {{40243971, -1341160, -29529293, -11171831, 18008168, 24820416, 35534712, 14118618, -46992849, -9439465}, {-26170575, 28489148, -4178205, -6932623, -523666, 4179118, 11620422, -251962, 15427577, -22090507}, {13657932, 15910284, 8978373, -4361060, -9718502, 5496408, -17699573, -577430, -2490610, 84652}}, + {{-31655697, 5877788, -1537102, 16982041, -58451201, -11430351, 35475010, -13519178, -16742258, -20584639}, {5297037, 14437542, -53952082, -7884927, 4306431, -5558257, -12149548, -3133052, -22262956, -593287}, {31169591, -11578699, 28435945, 6797090, -29588415, 14663912, 17434039, 2549174, -4630565, 6639184}} + }, + { + {{-16077699, -4871953, -17068088, -10604271, -13091755, -12191697, -5653585, 2444499, 12787652, -18664055}, {47496039, 11262291, -17960294, 16918239, -15116133, -6529245, 34601187, 10425601, -25901004, -2101747}, {14091554, 13940974, 9489758, -8458363, 32933998, -13957122, 33435792, 13929468, -27760484, 183561}}, + {{8240048, -21495785, 3348697, -15022023, -32237092, 7755881, -54284203, 12858872, 917532, -21576371}, {-41073382, 5890643, 4437149, 6758029, -5745246, 3556615, 5584519, -14119054, -11690882, 11146349}, {25886453, 3934974, 10725582, 544784, 30968282, 8197276, -21998269, 3990031, -27190165, 16370408}}, + {{-7962900, -5184139, 38404475, -9536744, 44161380, 9957181, -16526435, 4756329, 51547511, 9194889}, {26706586, 13056357, 515183, 13665754, 2334688, 9415641, -41899299, -15205537, -9485115, -8870681}, {27209742, 5390552, 7712247, 903017, -19722339, -2721273, 22707290, 15873800, -16041171, 7940656}}, + {{-38385245, -18970700, -9348812, 14996362, -5190427, 9722239, -13488902, 6746020, 10950281, -26543218}, {-21194087, 7627968, -40044192, 8571554, -24165097, 7566229, -48572974, 26517994, 30899149, 4017914}, {-9349453, 12011098, -19742503, -12383817, 29097452, 7811101, 13417314, -7894957, 14580221, -4092451}}, + {{-3160113, 12482369, -24884617, 1807399, -5489908, 10892782, -43722918, -19675386, 6934105, -24102004}, {-12244283, -3379461, 15381571, -9495467, 34352170, 14266294, 9566882, 2349204, 48496045, 7808884}, {-8436830, 8568202, -25205482, -6157173, -558641, 9520439, 31487547, 3265867, 17748893, -217261}}, + {{-22246624, 3541471, -16988801, 14038944, -10028097, 2854976, -8344494, -19399989, 2760371, 5157469}, {-35733864, -10396393, -23229601, -110182, -3209495, -352442, -13740102, -12455075, 52463675, -27628957}, {-10364393, -13698860, -14359281, 16388345, -11913002, -6429765, 13953751, -5758523, -5230703, 6103627}}, + {{4898350, -19574659, -24191410, 3168148, 7901310, -10187883, -45321764, 24638522, -31644266, 12497637}, {11574480, -3053415, -18259930, 7639208, 46578954, -7162045, -20607222, 3489230, -29154168, 20924959}, {-9274133, 16538460, -22829785, -14674045, 14354342, 3648609, -1407179, 10793178, 18168152, -3492942}}, + {{-4069522, 25031597, -14981410, 6217685, -21372347, -12211681, 18741794, 8407040, 32842200, -11062489}, {-35108682, -2939505, 36719574, 5040095, -44879755, 20849955, -12067896, 20752956, 14130366, 5176139}, {25154123, -13820491, -10490402, -2716227, 32896275, 8062637, -9065595, 16138075, -31346054, -1235067}} + }, + { + {{-24275686, 18585821, 60870376, 14695828, -35827449, 8922231, -15197593, -12084623, -10512611, -7885255}, {-7555556, -4456495, -1246332, 470002, 26469059, -4122555, 14000727, -8800995, 54755155, 24563641}, {23989392, -12342090, -25601619, -6862450, -16938891, -5179609, 9601924, 14488460, -27658088, 2804299}}, + {{-4093521, 21924647, -7682247, 4959658, 1074577, 4245873, -26266998, 6854880, 31529862, 23238557}, {-53995709, 909867, -47194201, 22232554, 32157413, 7508409, -37706860, 6134432, 29468104, -3269391}, {25743468, 7856445, -16487295, -3162068, 10094228, -13975139, 17163271, 2565920, -17508456, -6769045}}, + {{8650007, 15674276, -18719406, 6607069, 40509273, 5718999, -41941372, -17099507, 3481737, -11686756}, {-20601981, 10777586, 38296910, 1249629, 13715287, 22335501, -14510044, 10359233, 43001939, -9355462}, {-12935014, -8269153, -33527032, 8380729, 1859999, 2477818, -14778899, -4188028, 17150746, -575640}}, + {{-32652154, 14667869, 18517568, -19143560, 40484187, 15990714, 16281632, 9876087, 24550757, 2202907}, {-23428650, 15712725, 36821068, -9599364, 1881653, -1663938, -4562586, -17769171, -33014463, -13209263}, {-27129276, -9542608, 30921893, -10287936, 15166350, -9716832, 20830480, 15162498, 15631251, -14332645}}, + {{-20751106, 5664865, -22663193, -6291889, 4972690, 5395501, 13866143, -10918946, -33130404, -10187752}, {-4600188, 8325367, 37777479, -2943499, -30181984, 19249681, 27900745, -7650506, -24274346, 386940}, {-8127806, 10013726, 19146133, 1913608, -7044610, 14721699, 9485033, -1338415, -26578859, 4988210}}, + {{-20417441, 9343563, -52822506, 11642332, 29353193, -8334153, -27778308, -15959603, -10640422, 10736555}, {-39826465, -4659195, 1848736, -9595004, -16579109, -14898577, 17220948, -1806129, -3492958, -2687331}, {30341613, 15459851, -13654809, 13222522, -14798883, -6904613, -32408200, 6126396, -22535718, -7589584}}, + {{30160553, -28293430, 33932267, -5707758, -56132185, -4412706, -21869648, 11941975, 17572114, -8342403}, {-22790887, 532754, 24622353, 18017270, 9810403, 2013680, 34818586, -17072925, 18531420, 15441025}, {22209464, -1751800, -10958223, 12660076, -19237236, -15520139, 9479748, 14656075, -20272152, 7658749}}, + {{-7322772, 3421924, 33793374, -3666974, 28824200, -5615820, -55178202, -4124604, -61611521, 3886869}, {39029764, -2812128, 21418062, 20591602, -14784680, 6557610, -10977016, -13499450, -2107627, -10712343}, {-14542223, -1797166, 32221055, 14879140, 12441631, -918701, 29124516, -14719167, -24611598, -330993}} + }, + { + {{-14965935, -3081309, -245121, 23310995, -37786183, -1176708, 2787027, 8262215, 1509139, 1608445}, {-21095169, -8323977, -63526063, 364499, 26363617, -23743256, -13013389, 3360011, -13958441, -22506559}, {-27924233, -6322140, -3128444, 12134434, -16681588, -2944858, -5148397, 71764, 11969447, 7312666}}, + {{-21443993, 22782903, -32139077, -18735366, -38522465, -8049071, -33332368, 16085756, -53244646, -16248183}, {24229469, -3311245, -19141103, 14062650, 8503919, 1721089, -2169028, -6799618, -4679170, -1460303}, {8700676, -16776829, 1250533, -8747786, -33236237, -13798049, 31012017, -5647992, 551684, 14704598}}, + {{17206080, -15466406, -4104150, 1964600, -51768655, 14101752, -24768310, 3149284, 38150714, -1258159}, {24549480, -1156012, -13067086, 13001194, 14007553, -19031174, 22684294, 9474468, 4186074, 20947461}, {14477435, -14254425, 28912486, -8941225, -21344859, 4462146, -7741583, -7175021, 687135, -7379188}}, + {{-44923402, 19847908, -30053309, -14549245, -5827256, 12824549, -28543325, -367084, 26273433, 11121167}, {20297124, -12156998, 1365687, 5830819, 29493544, -13228363, -1008283, -12711536, -11571275, 11686193}, {-24252006, -4326029, 13973466, 10109813, 7811467, 753645, 32855840, 2859514, 11131016, -13636295}}, + {{27071989, 10045897, 13822425, 16758349, -38736123, 9315461, 2153745, 5935554, -27804304, 6829558}, {19423051, 14109257, 11976047, 1709289, -1243789, 4741937, -57935185, 8692824, 27294558, 2193626}, {13485706, 3691821, 105301, 13152145, 205473, -2967944, -20241208, -13270952, -32297397, 5755055}}, + {{-5148022, 16694606, -40604950, -15388679, -46160474, 22834965, -2735431, 5834358, -4660717, 2723537}, {-36947570, 12253142, -16705146, 6592167, -12454994, -4597087, -23373039, 10996596, -35413129, 12348191}, {16099257, -15770052, 28015466, 13188742, -24401191, 2670699, -12907784, 9264742, 2715512, 3053692}}, + {{-4131032, 14200387, 22623170, 16210391, -14552056, 21112595, -20542463, 9492499, -11633087, 28770205}, {-52038290, 2775533, 6141282, -5294329, 2228044, 10662545, 37773107, 17725543, -18574571, 1129745}, {27573577, -1130880, -16678767, -11811991, 9369649, 8193739, -30524832, 10571190, 10718862, 10266584}}, + {{-13670117, -11979452, -44425879, -23076654, -3394139, 20156689, 31003764, -4297210, -10514190, 922673}, {44935189, -1287278, 18038093, 1264440, -53737611, 10137807, 12357312, -5574926, 33325362, -21736471}, {-28673983, 11561639, 11492688, -14879231, -26686587, -10507978, -1603528, -909712, -10263694, -10833814}} + }, + { + {{-6149938, -15961306, 1768492, 464537, 4514197, -8106416, 4087271, -10806766, 31926516, 11666885}, {-8602796, 13102796, -50515890, -25075885, -7436747, 15700580, -21221355, 21152402, 13767024, -11516601}, {-12834353, -14483673, -4399756, -15054663, -24421122, 12979651, 22145289, -7770474, 22171576, 5852029}}, + {{20420150, -11251, 32140283, -13915662, 9857788, -2595421, -25180507, -11105261, 16204690, -3434549}, {-32933582, -29022755, 17005181, 16977288, 57238240, 24745383, 40775553, -5508543, 3886056, 849859}, {6260560, 1725159, -22979654, 3334386, 1140826, 7461970, -31250723, -16274746, 818393, 7223834}}, + {{16122180, -2590100, 15830006, 12470846, -32242752, 17882764, -43731753, 2016139, 23846925, -21194961}, {20595150, 18351586, -30857572, 12483282, -4265502, -5415720, -14204273, 3834831, -27131605, 7730115}, {-21268674, -5126381, 22669729, 682159, -17845187, 9434000, -8122140, -13106337, -30055656, -575262}}, + {{6057852, -4488437, -23620524, -13595276, -10014390, -4465270, 17914766, -17539515, 15832432, -18009279}, {-41056872, -28560503, 33713164, 4639408, -10214704, -27164382, -32959764, 10954725, 49291180, -9797843}, {13903039, 10264833, 26047182, -6049697, -14086595, -8600709, -31847535, 1979127, 6050181, 1229728}}, + {{22663958, 3726149, 12459368, -10055670, -18154295, 6317181, -9182952, 5137832, 23175783, -5649718}, {8890220, 17607059, 16937352, -20479804, -348713, 5899865, 3848004, 22683582, -21181741, -23858116}, {-290744, -14827929, 29582898, -12527855, 6972646, 16626318, 30074986, 9562086, 12403211, -4896385}}, + {{-41830917, 8299665, -41105872, 16067430, -26238463, -906604, -36731065, -3315165, 2130295, -25266504}, {15628125, -16014373, 11214306, -9289978, 3100347, 1551886, 16394107, 15090137, -38895607, -2893004}, {-31177646, -15086545, 12819661, 4629958, 20607739, 1417445, 20204874, -8143631, 20811174, 8518762}}, + {{43299800, 4499391, -26442195, 22280867, 46461525, 20625889, -48088816, 6430312, 13159232, 1015856}, {-23506606, 16687725, -7378951, 5714389, 1578501, -8614487, 7479424, -21963748, 47157850, -10790868}, {17562755, -3350576, 23344247, 13770084, -20073087, 1184377, -2100985, -14484858, 19129300, 6591827}}, + {{-26845075, -11467602, 359909, -9547177, 37150536, 5075840, -31408603, -25176716, 37260826, -11603837}, {18302961, 13877698, 626441, -4331645, -4532834, -27049826, -9924941, -1304610, 27766772, 5320093}, {-10309634, -5562757, -27818757, -5840693, 23391665, 14832354, -24191575, 3571749, -22604014, 16344263}} + }, + { + {{5667034, 3110145, 45307642, 111469, -41959155, 28411302, 28097759, 11969087, 26201392, -18879483}, {-33532914, -4500273, -2139366, 19129225, 8004819, -4052432, 3836053, -10914731, 13906386, -7857815}, {49033, 658065, -29504796, 13128215, -1115699, -311235, -6659448, -5038373, 19015182, 7348486}}, + {{29395281, -12451081, 3887739, 15810788, 13855073, -19507014, -30720696, -9882946, 6894461, 2660804}, {-10725239, 9629427, 19773977, 7943236, 6323723, -9389876, 26908968, -21261220, 38056121, -18588326}, {25319146, -11533696, -14394908, 7121539, 20648772, 1152642, -8619146, 9328209, -14006152, -14138888}}, + {{30696528, -21939260, -1237921, 4578424, -47496075, 23050600, -44875619, 7674648, 15546603, 11120728}, {24197946, -8612502, 53554049, 19661888, 11861785, 3224960, 14548947, -12334504, -16425089, 222962}, {-2916482, 10948319, -23783613, 6893699, 25672714, -5777322, -31406997, 4838666, 16885491, -1395114}}, + {{-46881, 12028884, 17537599, -14168942, -16520380, 3564052, 46562440, -1288918, 22873348, -9261105}, {-24004675, 9762552, 12601821, -16347460, 32073830, -21876332, -182850, 298066, -25359434, -21626415}, {22032182, 15941636, -16919076, -9460721, -6058805, -5072374, 10653706, -11915427, -8129074, 14722785}}, + {{28484005, 22460910, -39904683, 23000855, 9247363, 7189785, 4921919, 4669948, 11487196, -14003452}, {-34837687, -5344354, 14029235, -3843425, -11436283, -17620191, 2803721, 12119926, 43080540, 13633030}, {12818992, 1990998, -19799337, 7472472, 28152523, 15197231, -19926346, 5086113, -25075877, -8359309}}, + {{6593347, 18326428, 13447191, 17897168, -38147926, 15725373, -19113428, 5633255, 23729515, -11131937}, {27486785, -2612982, 17618139, 3843268, 25414244, 13954813, -26327014, -24901477, 14640489, 6891937}, {27811901, -5492966, -31953163, 13935272, 24193240, -9485637, -13227860, -11159819, -29264743, -6133141}}, + {{6645254, -1052051, 20064138, 1030104, -7071436, -18997732, -8485043, -2487473, -56198046, 373570}, {-44473388, 27493613, 45121738, 7627536, -42862996, 11089950, 38456561, -20721191, -5600602, -17638964}, {-30437631, -14994705, 8167759, 3272512, -3178985, -1695159, 9945417, -7474696, -9041240, -6680359}}, + {{4387973, -29674349, -26528441, -4332124, -25986678, 1714648, -7371503, -20084181, -7000771, 4527817}, {-44675847, -321177, 16948867, -415160, -2018198, 25795942, -51361817, -2070277, 129285, -25800947}, {22859435, -14313065, 3135184, -10905638, 21609405, 12214462, -1396273, -5378204, 28665183, -2126652}} + }, + { + {{-18011698, -5063501, -31026256, -20550845, 20119567, 859468, 29070010, -14692563, 31324961, -19315826}, {46842698, 25940563, 24327998, -3082235, -38182885, 17900270, -12885390, -17527613, -25484381, 1950248}, {-11983217, -14230420, -2879362, -5460886, -23179949, -11862385, 17931235, 13352494, 31137456, -15910046}}, + {{41022720, 1610062, 12973782, 17643810, -15715632, 11732337, 44313118, 5264056, -31936223, 3554519}, {3211768, 12354914, 26573118, -5566922, -37980604, -18836117, -2589274, -13311556, -28919299, 10768447}, {30557421, 10566275, -26330181, 7995848, -32787174, -8705350, 27019213, -2178187, 15593423, 1784678}}, + {{-17257830, 18961672, 50137922, 10645555, 17524948, -16102471, 36916900, -931346, -19350137, 17768272}, {36527660, 11801834, 11968934, 21796761, -22693258, 7914073, -29833324, 26912302, -33189891, -7955698}, {-19039808, -110184, -28803828, -1230840, -18703781, -14008297, -26794668, 1143570, -23155542, 15437117}}, + {{51350209, 12414086, 27472212, -3239756, 17621156, -10558139, 17572042, -4905421, 26041862, 4614489}, {3572225, 20592798, 4667818, 3845230, 49249474, -21420153, -14608222, -8963765, 8529154, -25652601}, {10022776, 13962768, -30719547, -8457969, 19210702, 7845647, -21708846, -16259458, -20884794, -318869}}, + {{9853927, 22545275, 13442128, -715853, -12193242, 3360537, 668424, 114894, -47779478, 690575}, {35761327, 2888407, -6674526, 21791631, 17296064, -6706781, 7100850, -1716614, -15467376, 14441175}, {-20880846, 1640137, 8361119, -9935676, -5078191, 14778108, 31889895, -548689, -16026862, -6658382}}, + {{-438480, -15961773, -18926622, -16667001, -43786490, -20224863, -613173, 12627717, 7941167, -8073057}, {-4832616, -11106537, 20841592, -16634581, -23029168, -4610139, 54636179, 7848931, -20219417, 7143829}, {22719107, 7504236, -16790409, 7984459, -21347693, 8991284, -32685915, 4873930, 25465096, 7828544}}, + {{-30691440, 21600727, 31949287, -13371278, 24292080, -3065150, 1099478, -1633043, -1911830, -8578389}, {-26703780, 8805787, 34585069, 823450, -38984890, 10371950, 34294052, -19915649, 37687642, 10720017}, {-25149299, 9814017, -28086450, 12105687, -16690193, 9638489, -15255343, 15039521, 20758484, 6261619}}, + {{10945487, 31750512, 45774032, -15500045, 26895933, -14090736, -42934621, 2842170, 3229426, 4821889}, {-46821711, -656442, 18864572, -16206047, -18907973, -7850188, -2027387, -26397778, -235658, 16963859}, {22728565, 13531960, -2521144, 9106743, -29535885, -8266896, -7275023, 7237440, -32749614, -12062037}} + }, + { + {{30482783, -3539076, -23942491, -297735, -11891225, -12001003, 6069179, -7583453, -12755578, 14180918}, {30721073, 24740612, 43149017, -30877415, 23245533, -21026127, 9138229, 16567983, -43054972, -1237428}, {-30864606, -6692250, 25015085, -4987651, -1944488, 6711292, -20348234, -10165779, 15756892, -13134734}}, + {{10509489, -4286251, 7919515, 11261265, 28731723, 26136429, 13612912, -5737581, -41040271, 11759714}, {-22296989, -5919281, -15353709, 5754431, -21361663, 3562559, -22524816, 23962997, -19056343, -18025024}, {15807643, -5550548, -15869403, 7383156, 3061642, -11234173, -10104923, 8171991, 22248078, -2727994}}, + {{27675369, 4851060, 4741427, -5026636, 19612669, 14390933, 42667451, -11194815, 14804093, -6272893}, {26705347, 2425322, 58908121, 8861092, 43125183, 18606705, -17338799, -19388335, -12520343, -7251899}, {-28704869, -13418046, 21431753, -8147678, -12087642, -15798041, 27640372, 6183513, 21762596, 11909994}}, + {{-15451744, 2499700, 16217268, -28485189, 3107559, 493576, 25525023, 1822124, -14173125, -4507514}, {40630266, -13774118, -39289082, -895353, -20824855, -15175954, -30162801, -7364676, -26250633, 13328314}, {15145853, -11579062, -394678, 4704532, -8014559, -6492526, 24862101, 15666460, 29187210, 12572565}}, + {{1629152, 6190082, 45187641, -32064692, 30775207, 522837, -1094740, -14386624, 33279326, -2184058}, {46114518, 25619656, -8239841, -1322844, 34175415, -14728257, -38914900, -13105064, -25912890, -20408364}, {-15427277, -5159064, 10281448, -4151178, 6461960, 4532643, -28316554, -10346390, -17885321, -16621647}}, + {{-18098727, 21490993, 8828669, 3621981, 3409449, -5319823, -35024428, 1120257, 4810083, 4262176}, {-11164139, -3491169, -44840937, -16704381, -57133421, -25118167, 26480158, 9437685, -50746805, -27165434}, {5178459, 16025867, -14614723, 10765661, 22852478, -11145040, 13115158, 14463292, -28661535, -4645029}}, + {{25283403, -4672726, -39248911, 10074524, -16226424, -7632015, -28015953, -17555553, -12099627, 30431328}, {62631, 26935122, 20407295, -19914460, 37379362, -21135943, 15346477, 12287, 16467143, -2386890}, {-24984543, 1212989, -18812296, -12854467, -32751934, -12150034, 25928171, 9785034, 7255938, -6074826}}, + {{7561277, -20717156, -2547310, -1029649, -2934258, -19157902, 21993495, 14254246, -18848869, -659100}, {22198685, 3107960, 26691326, 17685985, 18675126, 3830928, 40920207, 12494954, 21660857, -21876054}, {15931175, -4834752, 30548740, 3478497, -2669521, 2031616, 27165788, -14460204, -942591, 13205301}} + }, + { + {{-18350282, -5619521, -8234683, -9762916, -42055665, 16320474, 45168308, 1046861, 54081539, 13127149}, {46411488, -17634349, 40229697, -16189708, -12386523, 12914066, 21475766, -17128257, 783853, -2426865}, {4299199, 7744759, -7398198, 10474049, -19935309, 4413921, 1577092, 7155308, 17005665, 1950406}}, + {{-17235550, 2043974, 23962594, 7694883, 23100954, -29480529, -1290117, 8617518, -33291876, 1334190}, {-5441980, 17904384, -8835576, -2050723, 43129574, 2867735, 630489, -7868152, 29980310, 16300766}, {13119730, 207127, 13045935, 3238455, 2716542, 14996271, -17781201, 13970902, -8285479, 12468570}}, + {{-18737276, -21712206, -10242020, -16433787, -23227637, 16909084, 2096647, -69131, 490867, -14532578}, {47329756, 5218862, 48135750, 979645, -32716241, -9936788, 32880437, -18102927, 32301071, -1369640}, {5426848, -7729229, -18699514, -3504234, 11025601, -14892042, -5497164, 11797418, -23599077, 16331942}}, + {{39120913, 16671342, -40082554, 22347792, -30010638, -5265514, 1105400, -4705441, -63405855, -23333449}, {-13605823, 16738302, 21559630, -2334802, 19932948, 1971060, -53824754, -17477431, -3307517, 561979}, {-4683345, -7111455, 13021905, -1857981, 631462, -15159045, 16144015, 4901744, 30386625, -14652465}}, + {{48283255, -4991022, 49978208, -1643748, -45802983, 6398831, -2235508, 841836, 5810239, 25467582}, {-10670207, 23197216, -14641170, 22872208, -9742231, -20895951, -10733158, 21627860, 48036693, 2649458}, {7599460, -10891376, -4606550, -15658616, -1426138, -15450732, 4104883, -3864178, 19275178, -2766225}}, + {{38594964, 24713096, -1326729, 20661522, 32699719, 754655, 5443278, 13882987, -2613139, 19434704}, {-1316990, -2382558, 56427605, -5337956, 3930105, 16167605, 46272614, 1224397, 12167819, -360918}, {-25858707, 6075614, -22004506, 5602028, -32925455, 16083954, -8775562, 14421937, 20652995, -4990991}}, + {{-6680391, 11712996, 10728491, -1974281, -13260636, -21936740, 56420748, -8738739, 51316031, 15672840}, {9249689, -21554752, -14874459, -21437743, -26642762, -3432764, 10138360, 3195837, -12009137, -6648442}, {-15322474, -4099943, 25577032, 15010949, -18087753, 10148193, 21753308, -11381978, 24920941, -7186311}}, + {{778269, -30002764, -23597417, 9665291, -17938686, -7982645, -54487477, -24226484, 21814226, 554352}, {21828057, -1849718, -31960819, -10325739, 5781770, 15532819, 6642763, 8996044, -20350134, 4440702}, {29685405, 14062662, 28060298, -10696777, 1067072, 2961430, 28536687, 11005956, -24196142, -11160858}} + }, + { + {{-1960230, 23384140, 25862295, 2487283, 24565203, -11566964, 16357212, 10174710, -15523768, -9632117}, {10934880, -3904758, 16198345, -16389711, -1820413, 3951654, -7454192, -1046894, -11582432, -6681729}, {21581929, 10652514, -10887288, 7104048, -3270509, 14460920, 33218460, 4694233, 12517854, 10563185}}, + {{19519888, 7001121, -21999039, -10183106, -37087520, 18834209, 51765895, 9169380, -11564825, 23286409}, {18186536, -2644655, 21046655, 7571250, 4701532, -5563359, 3037945, -10322148, 33132687, -7146329}, {2371774, 11054652, 19080617, 2645559, 7570559, -11152672, -9834565, 9658888, 32535339, -9449345}}, + {{7621256, 2684922, 5897826, -15112285, 11070292, 3659897, 29965078, -4313522, -5548401, 3821808}, {-22759400, 17898744, -37187452, -17052659, 52956104, -21841639, 14927064, 25406264, -26783977, -26089530}, {11707971, 15804502, 23574353, -9450473, 7900408, 11983346, -14547413, 16327592, 7576102, -9085228}}, + {{-43366442, 9466902, 30806326, -19917973, -6276039, -24350125, -28887713, -13791380, -28345333, 7970465}, {-7593872, 13748626, -31160462, 8417081, 42185535, 417631, -14366197, 19563846, 9004619, 6784321}, {-24101968, 12368798, -13781516, -16623087, 10246168, 15483707, 32125145, -14810169, 1098411, 5465506}}, + {{-920815, -22392489, 12909046, 6145976, -14623780, -2271277, 5354014, 794203, 43045970, 5646107}, {13237005, -2179149, -50569872, 4691402, -50286604, 13989483, -37929608, 29766037, 13219852, 25219789}, {2029608, -14065469, -9384689, -16016330, 33190562, 6932606, 1894474, 7081878, -20098687, 7522690}}, + {{7561297, 13475462, 9683655, -11932233, -33714519, -20151657, 48694304, -5310808, -14862524, 11549813}, {-59534903, -5433644, -29610315, 20282723, 20601553, 9113655, -4113074, 15543460, 52069186, 2186895}, {-8558987, -10176903, -12755947, 13933707, 33193566, 8321460, 32668838, 6060337, -2701190, 4580815}}, + {{28449931, 13840790, 33312251, 15968595, -6516946, -9754255, -24219314, 7029229, 19250679, -8573402}, {15096671, 17289750, 21866487, -12451447, -50646082, -13109745, 28431952, -20467117, -24746153, 24528604}, {15883515, -7979703, 27231058, -7568473, -32194874, 11833960, -8031188, -13404985, -2483088, -16137831}}, + {{-37832548, 10481771, -40705740, 19417582, -55863352, -10191875, -1332104, 9320409, -20192947, -3462890}, {-23850414, 12895457, -5589606, 5202172, 8659872, 1340527, -44084058, -22316099, -6211459, 26238566}, {-9596629, -2883564, 27026337, 1157428, -13587089, -5093462, 15162268, 402608, 16314011, -14651535}} + }, + { + {{-36135171, 11259808, -25530423, 5341468, 51244599, -7149697, 63840467, -9761334, 19732234, -15414661}, {-19359895, -16780024, -1969181, 11977098, -4578147, 24513805, 1463611, -20135458, 36217632, 4393131}, {-11515840, -8672379, -1713217, -15073795, 32896088, -12749816, -15691954, 11592582, -15644828, -15653665}}, + {{14537560, 22130269, 25043355, -9942622, -22443820, 24863387, -47799392, 13123752, 41947168, -16017278}, {8009582, 4519273, 5235533, -7886720, -3739236, 3007753, 10574782, -11111888, 3890018, -3386556}, {1659623, -13918385, 13470461, -7613812, 28961651, 9155334, -13337505, -1860546, -28882595, 13106224}}, + {{-2116528, 593689, -6641219, 13026571, 48371289, -1372172, 33202749, -24445354, -23083499, 21634585}, {17219676, -13844639, 53144625, 5568191, 2848929, 5952392, -1650167, -3332656, 9154385, 6702789}, {21183607, -4797073, -27278343, 4414871, 6723493, -9194010, 9421562, 1606691, 29257493, 13759966}}, + {{-29474321, -2239497, 11623396, 3370949, -34197780, -22480710, -11417658, 4928430, 4199123, 6857854}, {28582967, -22634531, -50526380, -1367097, -6990186, -60708, 12171334, -23300052, -45432383, 1794804}, {-2846841, -7698790, 2182683, 13145669, 9501697, -8960002, -18626018, -2170049, -8934859, -3556362}}, + {{54522402, -4478858, -8553426, 9570135, 42166565, -7773550, -4433461, 619275, 18596151, 1458808}, {-5514982, 25148834, -1734684, 13282685, 15525379, -1772338, -24316051, 22690161, 36622989, -24651808}, {25933792, 2510086, 15910471, 352613, 602345, -9541031, 4380882, -2225183, 3955267, 13899102}}, + {{4767909, 5272007, -24767547, -6607470, 8287496, 6705266, -5347953, 1901015, -11719540, -13675335}, {35080973, 4774855, 13568349, -14819810, 28893436, 12696204, 16811065, -4986345, 44531286, -16499265}, {2443435, -2512829, -4490328, 11644891, -14506109, 6558854, 17510163, 10479708, -32590283, 12330004}}, + {{43473308, -12001478, 32016830, -614281, 24112591, 17632411, 6576306, 10271114, -38111023, -19592756}, {2543494, -21478956, -30483992, -10032857, 7451625, 15909227, -35959828, 10320124, -2144921, -10511270}, {-7411430, -16205342, -25795665, -10674243, 27566078, -8778753, -15754606, 3126350, 24016607, -1285213}}, + {{1738947, -10453884, 40017859, -12344387, 23773558, 5728318, -17836723, 9336201, -22970850, 9770553}, {26295865, 19975784, -5978717, 9785393, 24103472, -95302, 42077713, 13385687, -32352546, 17883427}, {-996798, 4882062, -18645127, -2741650, -29074528, -12880499, 872224, 5725399, 26953514, -11662986}} + }, + { + {{-9711242, -24660091, 59831857, -21652521, 15211448, 9312754, 18707334, -14377756, -3062343, 14039577}, {1292530, 1655795, 3211629, 8144685, 41076934, 5044874, -30632694, 13820848, -2370347, 4571575}, {-4974507, -8855215, 3089378, 2530286, 29830871, 11782247, -11656043, 10373949, -17868864, 16621802}}, + {{-39813536, -10061740, 30826340, -3327110, 6725751, 6917096, 35772528, -10465914, -39545236, 18727027}, {-17155820, -13507634, -17858902, 20180914, -37366597, 19842038, 20595746, 6523388, 7913018, 9397053}, {-20471037, 14568028, -22463044, 10145497, -16723180, 136904, 14480426, 6773671, 20326999, -6554507}}, + {{-59830341, 2092949, 3994365, -17640894, 8912261, 5276749, 24926789, -8156981, 33387707, 7191425}, {4435973, -4893179, -11029997, -8314012, -18881965, 5210479, -7410961, -4190643, 12399979, 8378737}, {4909514, 9037026, 28322279, -4629659, 7427235, 7911101, 27358016, -11229910, 17630020, 16164682}}, + {{-33621441, 19982083, -12353033, 14697763, -7381971, 3683295, -31704847, -5884532, -27535721, 6007835}, {17428919, 771973, 10044567, -18191603, -40782297, -21458847, -26640533, -9887798, -16680171, -7893351}, {-28280845, 11038172, 11085797, 13174912, -22954779, 5160137, -19346379, 11993405, -26479407, -2496915}}, + {{1173857, 3376591, 6511072, 7569659, 21466328, 15094784, -15462495, 14145091, -52072721, -2578544}, {-64929667, 28502485, -23923394, -11691121, -17221158, 6238148, 19353821, 3934377, 1550073, -15201318}, {-13156709, -7502305, -21476389, -4490502, -31855871, 10535120, 25439814, -16493932, 6539442, 6881101}}, + {{-118439, 29845467, 36942582, -11151420, 6588690, 4394329, 2061200, 13783949, 60082727, -14717446}, {-9792313, 1367985, -12181622, 2760900, -58967280, 9287283, -36938834, -18486015, 4902125, 16588036}, {-10594679, -14333565, -15237274, -15466125, 31306228, -12355905, 33459482, 8376869, 1805838, -10636182}}, + {{-5402617, 8202912, 2614200, -1215083, 4909674, 8426721, 16627746, -7800962, 5889648, 10152491}, {-3357145, 12424868, 474376, -7067429, 33874198, -16022437, 7759044, 18647886, 8971522, -19406233}, {-113444, -8901869, 22380116, -14825561, -4587246, 2442182, 9442227, -15475265, -12931590, -2531570}}, + {{39455221, -17126481, -16114848, -19641602, -35269429, 6134274, -4332956, 18052281, 23881726, 22752985}, {10075009, -14133513, -70074, -4495914, 7127711, 11438088, -43286674, -10172341, -27365908, -8220659}, {-2213774, 13962815, 32148126, -1294400, -31447847, 10080428, 18320844, -4531750, -26355477, -14297565}} + }, + { + {{-16773618, 11671353, -38055315, -10609511, -20057542, -82628, 10556781, 5300747, 44864962, -5187281}, {-16959332, 5420905, 25578389, -14214587, 12377448, 7465890, 35488287, 7377241, 2090208, -13546075}, {19313172, 4721754, 13231764, -9675570, 8383079, 6549129, 4002446, -10733162, -25554889, -14124383}}, + {{8766721, -10955055, -43972707, -18787085, -1900352, -9389696, -42332159, -2881433, -14737616, -3003390}, {55793339, -20837847, 1426025, -1402585, -38754332, 837696, 10954951, -4043921, -37626704, 6556416}, {24887701, 9060370, -23932321, -662244, 17477317, -552784, -3260861, -11716013, 15903339, 12126795}}, + {{-16792389, -17397915, 19086054, 3059062, -614429, -10203097, 46495463, 27650286, -12917216, 3891207}, {-34626601, 8812771, 23936322, -20226460, 28778113, -963629, -9092873, 3607930, 37642812, 22376149}, {-27632297, 4099588, 23211695, 9938769, -21033406, -4384137, 15561628, -10787186, -19135346, 9226417}}, + {{28879676, -16184395, -35430707, 20791088, -35325001, -22235887, -31366089, -23834864, -16207179, -914140}, {19440300, -16850569, -1790509, 7951042, -26781441, 9548561, -21876537, 7401572, -44116137, -21811396}, {-2758864, -6388640, 1437790, 10895317, 12714152, -4387256, 5570406, -1031995, 29221173, -15700913}}, + {{-25511264, 2380837, -9853237, 17781, 26557435, -1375633, 31271014, 15524874, 19340405, -6384995}, {6092904, -3703557, -36351135, 22861469, -38332685, 7774917, 8614466, 14723234, 11995975, 4538483}, {12045260, -16075550, -14354085, -14066581, -14168970, 15666235, 32956483, -8210523, -11701257, -13603519}}, + {{-2366110, 1744000, 56461338, -28210195, -13005109, 15757820, -10870938, -28957444, -28578903, -5070408}, {-30926166, -26255906, 7571906, 4406307, -22899045, -13885376, 29440830, -4573846, 13822435, -25913082}, {-14203080, -5954298, 7200620, -3278961, 26188220, 16237208, -20362366, -9464074, 497469, 186838}}, + {{-25907110, 12248204, 28314799, -8145142, 38539069, -339459, -4763841, 12565494, -44711413, -11043585}, {-674158, -7845814, -37702427, 3204772, -25815477, -13360609, -50403183, -19645970, -6709805, 14756549}, {22161928, -3849992, 25683298, -508470, 3832006, -14880064, -19607207, 11690942, -4059446, 96424}}, + {{-2761540, -11437055, -50520011, -17700545, 21023811, 3766059, -9164893, 14538903, 37227749, -5246687}, {-31060750, -20824373, -6723857, 5115157, -5476521, -21382943, 38940813, 15938569, 3712347, 6069957}, {-25479380, 14778084, -16964379, -7972310, 23719456, 12440670, -20307049, 1027289, -31317021, 8723370}} + } + }; + const precomp_data_t c_point_H2_precomp_data = { + { + {{23610453, -10197163, 10334660, -1046801, 28262922, 23750756, 37087102, -21947201, -6803415, 4692852}, {-1734415, -16841411, 48353496, -3092747, 32326978, -4115300, -20574968, -6369407, -10503341, -17594610}, {-1247968, 15942191, -32202222, -1358983, 7143418, 15927757, -9352400, 12396253, -14973030, -6368958}}, + {{17755505, 12894802, -23987473, -3257850, 23634369, -26289278, -12209287, -14935238, -40028276, -30983511}, {8875627, 10858572, -11862557, 7456586, -28151737, 1241520, 41063381, 17507356, -1328068, 1514689}, {-25303051, 8258917, 28704031, -2421967, -4727799, 10997196, -1644525, -6151933, -5563523, 9799204}}, + {{47118159, -6637357, 26730232, -12431766, 12075361, 4565753, -888637, 22837710, 3493396, 7848575}, {-9148317, -16884047, -5737366, -16771976, 22811149, -7473475, -711611, -575766, -44156924, 8544179}, {-25893401, -16528654, 13141632, 6865639, 32051656, 15250249, 20843742, 13316750, -10857994, 11925667}}, + {{-32759985, -10673291, 10628477, 8303284, 664857, -6606738, 19296263, 13409361, 7612818, 18982889}, {-5304683, 2445705, 26290523, 20839266, 59572603, 26944470, 32618913, 13063829, 39274036, 7682265}, {26372079, 8750710, 21277144, 8989302, -23975261, -2391322, -2944708, 4030089, 32409876, 5341227}}, + {{45100691, -585597, 6765334, 24838367, 664798, -6723481, 12077649, -1093433, -40798545, -1026535}, {-21550983, 16062439, 44583522, -7009965, -64485034, -12832191, -10275177, 12338273, -17766243, -29085867}, {13385028, -4890080, -16855119, 3670999, -26654461, 13818535, 12976988, -3624089, -16290439, -14486598}}, + {{-60319207, 8986121, -40021847, 5055134, 6153569, -7297941, -1857158, 3303310, -2125776, 20377154}, {-3731461, -692441, -21494781, 3381506, 25219331, -25180023, -43792600, 8781696, -17190212, -11590964}, {-20685896, 6277532, 13239062, 8809213, -18620912, -12835415, 18186334, -16146762, 11884264, 11853646}}, + {{28956819, -15792195, -28723537, -7543141, 45151417, 25200898, -15652788, 10947254, 3013145, -10215920}, {2261865, 16437773, 4187195, -10935411, -6457075, 2013660, -26005186, -21934994, 14612669, -19171662}, {-18829066, 7839851, 26058003, -4333209, 1671208, 1627868, 25442175, -2385068, 23451972, 15535658}}, + {{-22395440, -28910877, 46940867, 5692433, -12502626, 5452727, -8254590, -4458344, 30749193, -31534208}, {-22507698, 3969289, -17709601, -24109049, -43218660, -20798999, -22153068, 26773432, -32174549, -2004442}, {-3156810, -3452724, 30798060, 14916829, -32623602, 3219559, 5772241, 4373987, -2681269, 11704334}} + }, + { + {{-20034677, 2793757, -5691269, 28918384, -14931901, -20588194, -24026474, 29121661, -54093011, -15214214}, {3026193, 26729439, -24010413, -3113416, -10464013, -6452146, 4859500, 3776949, 12234675, 3897924}, {-1505758, 5331777, 15179416, -4976123, -12323937, 14423591, 4389319, 16297479, -33410831, 8103492}}, + {{-9153308, -11509288, 21368648, 9775977, 27399820, 3559009, 13234285, -1909513, 30787262, 3594378}, {16898018, -20899144, 36682048, 23243173, -8952002, -18570919, 28378567, 13160573, 6930692, -3150740}, {4792947, -511449, -26657424, 6462286, 24205795, 14794771, 22985471, -15149066, 7853377, -4303746}}, + {{-9576682, 8963562, 28696180, -20127107, -1935288, 4589286, -19692690, -3502380, -9934955, -2507743}, {-3653422, 8614208, -21531954, 11016347, -16387132, -19439856, -14752834, 13096524, -56781185, 20263515}, {9294991, 10631362, 22058885, -1571357, -5979351, -13170753, -21183311, 13139231, -18133908, 7769266}}, + {{1647299, -12472224, 28451628, 8668059, 4354749, -5585797, -50797202, 22282046, 21735112, -16569680}, {5591193, -8806398, -5947156, 24329437, -416857, -13730775, -2512106, 5973498, -21575118, -11647074}, {9696406, 2894616, 25648801, -7312874, 29635185, 11722015, 32019359, 2832667, 30313601, -16766676}}, + {{-34826610, -19473647, 24116279, 7662284, -43276419, -24819955, 3799955, 1815731, 33681656, -18659056}, {-12723970, -9318793, -39583641, -23887066, 20837261, -3968337, 35095995, -22863895, -23767900, -3307210}, {-33339234, 14758149, 2538384, 7778526, 13724029, 3532965, 17108365, -5456741, 6907760, -15909473}}, + {{-55816078, 19897571, 30916593, 7325727, -44301640, -9135525, -15643364, 26326651, -25751547, -5212259}, {-3523370, -9790613, 17183517, 1896533, -11635272, -1128603, -14554190, -3209249, 34771801, -4394401}, {6232369, 8354610, -5737998, 4577123, -26334194, 3109061, -27891834, -5423878, 25514483, -5913640}}, + {{15262452, -13072717, -51172700, 13571264, -29880994, 811995, 57944293, 10157809, 14691660, 888388}, {-12416476, 3735271, -15304116, 3961668, 14065192, 4842113, -266359, -2450965, 9643760, 9706648}, {6951241, -6052340, 27448200, -14365454, 16633820, -5275760, 30785445, -2103785, 32220672, -6886415}}, + {{3684964, -151508, 38066858, -7037875, -7616828, -1318260, 43061286, -11775969, -14052688, -17567087}, {-58732772, -5421540, -11708264, 7604465, -45808494, -4083228, 12277976, -11339615, -38187456, 11811679}, {11730541, 12744338, -9733274, 11669097, 33458593, -2195273, -19395831, -148040, 23800597, 1650782}} + }, + { + {{-14724575, 16440443, 40350416, -8279882, -35573071, 7084425, 451753, -17313479, -50101344, 4266775}, {-4225159, -10252219, 5501110, 23915638, -10438293, -15550817, 24867535, -303761, 9986890, -565121}, {15055785, -7923531, -16528133, 7731362, -7871094, -8117118, 30990862, 3476810, 9308229, -4614296}}, + {{-14758431, 10283514, -10922843, 11048915, 3112425, -28350336, 11944016, -8853544, -21585011, -22485275}, {-51897993, 18055446, -9364401, -5902927, -19289541, -1689070, 16791058, 14821558, -43781863, 986017}, {-13009087, 3656388, -31387104, 8741572, 1463959, -10222543, 5579290, -4018764, -123630, -5698414}}, + {{29239628, 15999601, -44683953, -23930934, -356731, 19107160, -14719351, 9381990, -14022131, -6489065}, {-21162206, 2088333, 4811881, 9121716, -34781453, -2549986, -1013783, -4798106, -40421789, -17316661}, {13518436, 6993028, -1095696, 732379, 21246838, 15962915, 23545992, 15403408, 32083560, 16276410}}, + {{42486736, -27947783, 9089008, 10694575, 59611971, -13152397, 2435517, -650430, 14352885, 24168703}, {-14744714, 3107667, -37941256, -18227197, -3528033, -14420201, 8000625, 25165456, -17518187, -721787}, {30523716, -14312839, -19753346, -7689847, -25619183, 6368165, -22087608, -550760, 17487950, -6279928}}, + {{-7244498, 11793136, 3847324, 19090337, 14092544, -3608956, -38845618, -15066943, 35138832, 24621170}, {30542, 1693362, 9921686, 13916893, -7950056, -607080, 5802106, -2283435, -3376992, -5348992}, {-20489093, -2004226, -9859271, -11433986, -11545872, -7116294, 30480536, -79605, 31739411, -5587724}}, + {{-1872218, -3126679, -15306611, -9292298, 11030547, 12550324, -43456217, 20418278, 19844162, 7125039}, {-61827536, 22194559, -34266869, -2253800, 27189767, -16858506, -10290747, 13116026, -11735076, 6308189}, {-19331921, 4286924, -1617640, 3931267, -5659779, 10011539, -2539694, -10684967, -4855502, -14338144}}, + {{38000273, -7875032, 42447977, -7683284, 25708997, -13116905, 41126314, 1998099, -12251179, 5595177}, {-9881583, -23698148, 13855457, -8140698, -19434201, 8802445, -23028134, 24094513, -5058417, 17557159}, {-5432625, 10619389, -1308206, 12691920, 30959143, -3607328, -29980221, 10685818, 29350398, 11537191}}, + {{37371343, 14877476, 24709379, -13411181, -7503542, 16045099, -234750, -25932520, 32292539, -6688909}, {-22892931, 742678, -4377969, -8093901, 53452490, 4648829, -1867326, -1549360, -20583917, -22696067}, {29333999, 7104917, -10169373, 9695952, 596892, -2655631, -14926444, 2273427, 21336726, 15631847}} + }, + { + {{26133029, 2893146, -20026194, 8306573, -10666150, -814324, 6118993, -10519093, 5970690, 8767152}, {19007521, 13339434, 32875070, -19497763, 27640618, -16157802, 60591895, -21332445, 32404752, 1139816}, {-6126462, -6789887, -15511621, -12520897, 29701063, -4199950, 28091989, 9448981, -20857463, 12863811}}, + {{-4199478, -21754692, -8722132, 20445470, 11560923, -10625363, 14609823, -6628736, 1477710, 5551610}, {-35924504, 8857454, -45032362, 6093000, 30214809, 13389775, -10317951, -15798260, -64478240, -3200926}, {-32078097, 15549780, -13918853, 11740353, 29202268, 6788459, 9231245, 7114353, -3093924, -8875636}}, + {{7477389, 7157155, 46869714, -6967000, -7002432, 15122711, -39373689, -14013504, -44871181, 17315277}, {-898231, 7522291, 14050152, -25568922, 31498166, -6650291, -16407583, 16414650, 20191187, -1335191}, {-22727631, 10386983, -31350889, 6626608, -27024239, -11960121, 21613613, 2101958, -20208160, -14994732}}, + {{-29256113, 4991897, 42170171, -17575198, -34268742, -19587473, 11853891, 16079871, 37173516, -4874019}, {33696909, -19392621, -1993615, 4521016, 4320412, 9646943, 30780215, 11031437, 18241268, 24349241}, {-28171680, -12112427, -662507, -12174971, 32810403, 11566509, 13301937, -10196786, 1981075, 14435433}}, + {{-30887427, 3188726, 23346623, 18238828, -25157860, -1696761, 16314340, -3618957, 15158432, 31818780}, {-31224553, 16165424, 8993117, 9849222, -427432, -18389513, 50021340, -10329597, -12602608, -547904}, {14136086, 16168803, -1149795, 2836927, -21464573, 7236755, 13571289, 7213996, -9632949, 11894669}}, + {{26307181, -2068672, 41764199, -5290138, -22060663, 2286219, -37950240, 32138589, 31590206, -2334490}, {-25515967, -7491760, -8182973, -20491418, -23355005, -13940545, -8924944, -957731, 11980022, 30484664}, {2167785, -13796440, -16771248, -15201569, 18341386, 155682, -16375673, -12946436, -20704690, 16366062}}, + {{-14851091, 3834241, 23500615, 7352839, 15378973, -26973092, -23868357, -6381556, -52830929, -6411228}, {32116001, -2083367, 39449867, -11115641, 45034733, -1969130, -33371589, 4921204, -6906713, 3888680}, {-30088676, 3734464, 10326777, 4080086, -5745945, 976639, 8600626, 6227353, -4009424, -13874351}}, + {{27110177, 6970429, 12985075, 18195205, 13035461, 23608908, -21508551, -14595570, -13260572, -8052168}, {36677643, -3408013, 25445137, -782973, 40550479, -5211098, -3189183, 8435268, -33524190, 17377748}, {32550115, -16650662, 5167635, -16768200, 22925505, 12479081, 30907141, -5455749, -17591881, -10462184}} + }, + { + {{8433594, -5281514, 28743388, -27585707, 1957245, 9638769, -43302973, 10098494, 38292641, 6604950}, {-31069768, -8992758, -22353880, 4099243, -52025267, 3727331, -9703643, 9970704, -20482539, -696196}, {33243480, 3209120, -21486924, 9305640, -13012910, -10086177, 27422245, 13728436, 16233991, -855978}}, + {{16547645, 2377427, -7645304, 6593644, 28695743, 547751, -3808941, -17976783, 21905009, -47955}, {-49983965, -1415191, -52153056, 15097614, 18660125, -31627509, 59703961, 15225859, -39915959, -15450853}, {22813482, -11987249, -27630393, -6894053, -21830697, 12422562, -15531016, -3816008, -11418140, 3952649}}, + {{41339876, 4856753, -28073776, 14044740, -44935123, 13426469, -44863083, -3207137, 38478330, -4154045}, {-777504, 13884953, 23849386, -6483530, -4646659, 11749323, -4393183, -23904789, 13557864, 21570933}, {10451757, 10221921, -24533663, -16091676, -6526648, -8451170, -606907, -16356501, -31074807, 15194543}}, + {{14726565, 6760794, 33029166, 21219911, -4902918, -15593805, 24382667, -630486, 26482148, -11963664}, {36357299, 1729620, -18523596, 1150127, 18257866, 8214477, -12103791, -24311444, 10702066, -9770904}, {-9677925, -4942029, -9135581, 11783500, 32373628, -15657475, -18830790, 16450132, 29225444, -2404334}}, + {{-7856575, -26295132, -38977785, -3497626, -32099658, -12988324, 23312401, -11319206, -24680215, -9410840}, {34771979, -5013240, -27641227, 11259976, 6916156, -3609654, -42999121, 14488526, 40461251, -21823154}, {29640410, 15261060, 24778523, -482602, 19242559, 9885319, -22285103, -11786425, -2720304, 16429871}}, + {{-11225024, 8594224, 11301766, -1483214, 6521310, -926474, -16070436, 2802545, 42497233, 1756108}, {-19998878, 12421046, -50092558, -3883148, 24660864, -6044404, 25191484, -9214383, -22111817, -9000308}, {14535542, -2782853, -2624890, -10292291, 27831852, -11532908, 1530707, -8735937, -1835514, -13778559}}, + {{33697322, 1689611, -21314096, -17869138, 26463755, 1672256, 2730835, 19984585, -18127152, -9087688}, {-19497240, -14983417, -8154854, 13196202, -13905997, -20895092, 47313915, 9205505, -15220296, -17704226}, {29951904, -3288605, 2501602, 12506806, -17346544, 13421420, 30053387, 10627815, 8850046, -14187876}}, + {{-16778101, -2671049, -7169161, -19819047, 16899914, 10402487, -12191365, 2771458, -54771607, -1847822}, {-32733551, 11014271, -6016161, 7677153, 12933912, -15587383, 45953301, -6844804, 3425627, 21539478}, {-17026422, 13782402, -2087319, 1223799, -17511782, -8479009, 7518008, 595556, -15284465, 11443290}} + }, + { + {{-4912019, -5957006, -718330, 13600497, 25963507, 5477154, -55021761, 12570139, -1120374, -7677310}, {-53879637, -25942626, -4174846, -11945355, -16189501, 18265652, -454975, 9774447, -38065456, -23493278}, {5731776, 13545348, -31543713, -10489396, -24526802, -12042548, -20255794, 15013795, 28201443, -2518481}}, + {{-55413758, 20467831, 3917403, -14086196, -40241592, -7342363, 7872566, 18631892, -39955624, -3567519}, {5780922, 4150171, -13904305, 6672342, 9142962, -18586609, -31827656, -395776, -9271856, 6591845}, {228728, -15203967, -20407515, 1943522, 1235999, -6410713, -2348515, -4920516, 20848237, -14205641}}, + {{34326441, -6029585, 16180666, 6524526, 15710404, -276602, -25003437, 2280285, 11560278, 8884249}, {-18085781, 8971971, -39315214, 14330858, -37076514, 9859918, 230247, -6953787, -45877550, -2666691}, {-15018925, 15780755, 12327319, -1057402, -20317956, -8368744, 24800838, 943542, 19769142, 16549089}}, + {{18412730, -25786085, -7565998, -30927058, -1171729, 10160031, 9558305, -21711595, -35549127, 5278754}, {36903206, 4968005, -55451572, 2296134, -49434531, 12506377, -10832613, -1275733, 29307367, 23846112}, {1230678, 1729663, -29732587, 451081, 32951765, -2881788, -16476865, -13995906, 17285176, 16723767}}, + {{20264328, 2704707, -52004434, 14327074, -21883652, 13197618, -42435285, -6263934, -16317382, -7314715}, {33014758, 24866911, -11533294, 12187418, 38235796, -3130262, -4890063, 26506154, -45593360, -22951807}, {-11172678, -2389242, 31822323, 12375549, -9928997, -14225737, 29607613, -46028, 4333571, -13318325}}, + {{20716717, 2218620, 57640816, 21933071, 36441999, 20472871, 21871024, 14986202, -17312619, -14438073}, {-25676649, 9442512, 618152, 697079, 21123583, -12828549, 13696030, 2765820, 18890525, 15770455}, {9160067, -6341821, 24463025, 15086299, -15307748, -16252573, -32514043, 5892754, -22561037, 16076197}}, + {{21607715, -379296, -18661611, 6080823, 42028638, -5620093, -8887505, 13093550, -16226014, 11274317}, {39756499, 12576244, 48029803, 23508537, -1530388, 18070173, 7020175, -20195360, -14970764, -11707185}, {-18404446, 3581272, 15662048, -3802070, -29054680, -5907690, -29867985, -14343739, -6140471, 11213427}}, + {{-22187341, -8684346, 55836905, -16228496, 42481807, 5870584, -31836533, 24799856, -29470004, 4144324}, {28713681, 5459258, 11124941, 15336254, 23512065, 3733118, -5447753, -7971072, -5760296, -22512082}, {7073035, 942719, 5602019, 2800655, 31010500, -6093617, 22283843, -9486169, 731962, 7356198}} + }, + { + {{7740972, -7022247, -17297381, -20976461, -4107637, 11933789, 18219552, 8911812, 15120174, 17113873}, {-3430360, -7952127, -30062851, 3148167, -38131433, -8029739, -11325692, 12437974, -45609420, -11842431}, {-29331386, -16183625, -33034033, 12676157, 347216, 8779411, -28828299, -2399616, -24177952, -4956823}}, + {{27495132, -16103732, -7814039, 5697805, 16599390, 25427890, 38242581, 9474710, 19651758, 9212219}, {30059674, -16637360, 7420339, 1460291, -5427130, 229190, 24760877, -18543152, -10719178, -13286133}, {5559646, 7313368, -8835893, -11098930, -30509283, -12129762, -2818997, -6511934, -32986721, -1501007}}, + {{-22157950, -11795250, 54115948, -2487099, -12557689, 10093689, -17314542, 14235589, 7599955, -105828}, {13033122, -16062246, -8854464, 21387387, 12886011, 1096091, 41415196, -11582039, 23611267, 28141332}, {-22693401, 6715552, 890911, 18916, 1456723, -13351692, -18222348, 14476059, 27271787, 16550727}}, + {{20578300, 31064455, 38600758, -7225755, -27239721, 5723006, 8693893, -28850224, 19666208, 21287325}, {39709612, 1512307, 21340716, -17030971, 37456295, 6133416, 19975937, -1224798, -12751978, 6672455}, {14484051, -13910897, -18448585, 14858847, -28216107, 5901991, -21625461, -7280254, 18057160, 1569806}}, + {{-11974612, 5944460, -3917683, 589122, -11807707, 18800759, 15383044, 9273334, 6670448, -2358582}, {-14626402, 24695748, 49448293, 13619778, 38040959, -11117575, -31015660, 11107310, 19185570, 12340994}, {443925, 15625757, 10325567, -2159394, 21731532, 3376696, -20166043, -3141704, 7093221, -6165625}}, + {{29070350, 15096134, 13004338, -10931429, -36340198, 14719935, 43957308, 9875187, -4790376, -10867548}, {-11863658, -13084386, -3282962, -6374763, -368554, -467567, -21658844, 11014405, 47465664, -21561720}, {7698683, -2951603, 26726925, -9303198, -27975568, 6939863, 2681841, -3717620, 6894736, -14089352}}, + {{19955480, -1472176, -56903209, -24901238, -5971675, 14617121, -1208357, -9896607, -12138653, -1219039}, {22113604, 10963142, 5671789, 4053510, -54728829, -17081071, 10116973, -17760743, 45479397, -3692131}, {-26634914, 16352624, 15570714, -15003401, 11685316, 2244492, -14014926, -3705114, -10458055, 2151035}}, + {{17560720, -15107137, -13004435, -7624337, 60154435, -6615448, -2470116, -28515130, -2689142, -3133113}, {-19968864, -1833917, 17729213, -1539251, 5312435, 25257678, -32425146, 3171098, 20142216, 5321209}, {-26131327, -15354316, -27201089, 15294823, 29235539, 8177033, 31750532, -13180804, 9795573, -6341949}} + }, + { + {{1709594, -6764999, 5058302, 6467823, 25003101, -4960497, -19723790, -4518096, -44629248, 297107}, {36633556, -20917513, -16687140, -3908081, -737089, 14636139, -3332650, -20368716, 6959730, 24344615}, {18285571, 9168132, 550262, 1733404, -19807074, -4167230, 32169889, -15717122, 6393103, 7007288}}, + {{-10748395, -13244870, -6994062, 12904473, -18957380, -20989332, 51529300, -27410805, 32283115, 16825933}, {-3914105, 19945096, 12632334, -15342137, 836554, 9771652, -10885036, 3891923, 17789639, -3585951}, {-21869924, 8099341, 27176997, 3993493, -6503292, -3167195, -15186988, 5908065, -14023591, -53042}}, + {{28430102, 11260999, 10294873, 6445973, 6147664, 21187743, -3112334, -8025619, -10029390, 4687018}, {36145182, -6264909, 46669893, -7027597, 8832590, -6596555, 27848112, -2246677, -24994832, 15820322}, {15753971, -4975167, 30369075, -13583450, 16557778, 5495984, -12686338, -5030297, -11110828, -10034464}}, + {{6678999, 4066374, 21286452, 15916437, -27378518, 15119177, 30419784, -5107094, 6725301, -3848374}, {-22705395, 12903586, 7798992, -6114427, -20657270, 4126515, 34670936, -11583158, 34737123, -27435392}, {-25889745, -20277, 30156072, 12524679, -18893395, 3083754, -26647413, 8838869, 4511624, -16633945}}, + {{11559610, -16794157, -32091511, -11056905, -23156576, 1469293, 48647731, -1928391, 32221952, 19350492}, {23010166, 16409067, -16639463, -9970647, 27971232, 28654623, -7980493, -6430959, 4533894, 2811394}, {-22085302, -13691835, -7495272, 528654, -348024, -10028278, 28985332, 15977545, 23940801, 16121274}}, + {{51383485, -6137396, -34052011, -10111093, 9328200, -19243755, -33255620, -25271502, -2442694, -4325415}, {-11214355, 20793934, -4725083, -14349559, -36836486, 11014453, 28824674, 4512366, -17230914, 13649301}, {28323530, -1506670, 3341384, 6644922, 28065254, -9851207, 10876499, -9541164, -16502736, 1445810}}, + {{-26342253, 19775372, 22707058, 23551084, -628599, -7337175, -20492792, 29423907, 4279403, 15296549}, {-23227657, -10542956, 32230500, -385196, 8240223, 17194429, -38983718, 1573743, 2973809, 14790431}, {-23802098, 5253656, -27900875, -548693, -8011737, 13065997, 16272532, 11403888, 12550985, -13688979}}, + {{54413719, -6911486, -49205797, -25703116, -7648320, 8522704, -32838290, 6333609, -8716194, -5152881}, {-9986157, -17484646, 523895, -762352, 57951446, -8862230, -15244226, -24844463, 8374102, 12866865}, {7211386, 2436005, 30489771, -7337251, -26804882, -14687022, -21258678, -2975894, -16816388, 13598905}} + }, + { + {{-30750658, 4322504, 9774638, -11010650, 4490014, -535825, -37791205, -14724401, -8755973, 2369806}, {-29460752, 4559748, 35211824, -21791042, 47582522, -31967857, -16973521, 10931821, -43024739, 9708894}, {26304653, -9191791, 20688320, -15845384, -20406793, -8332741, -3333767, -4164249, -1763126, 3255590}}, + {{40555939, 16845244, -17475511, -24012291, -27846037, 605095, -15442588, -11923084, 13423283, -20171283}, {19624633, 16449508, 27852435, 6076521, 12384603, -30908067, -4032604, -10699776, 51343235, 7716021}, {-6154355, 3441983, -17521120, 15229391, 1811733, -15487254, -1270122, 15254781, -6223867, 4118500}}, + {{-61955099, 12996014, 26714235, -4109203, -4229287, -9175064, 32480480, -10850756, -20093037, -3233580}, {779533, -1187024, -22187815, 9542329, 46144495, 6365352, -17338416, 11525334, 23349375, -23172826}, {17963740, -13729332, 6262943, 14060843, -5813318, 8330712, -13820169, 4147564, -10924379, -5149270}}, + {{24324508, -115349, -2876938, 10042, 35461492, 3306667, -13733255, 1493340, 43139360, 23710805}, {-8550406, 9417841, -8627208, 8881290, 30679310, -15127095, -4791871, 31912500, 21114856, 9595463}, {-16390338, 13089242, 1710124, 5770746, 882392, 9085908, -29433376, 15236377, -21411656, -9196424}}, + {{-2509118, -23614787, 9075743, 14882181, 22958508, 16405809, 8888574, 5989660, 23344644, -25742374}, {22578616, 3081689, 47838145, 16324989, -44046478, 2752763, 44266894, 6168204, -2241978, -1329554}, {6028634, 6360042, 10962670, -14488379, -26034920, 128004, -17294535, 16510447, 15809534, 15150696}}, + {{8011032, -5564523, -10755051, -5509139, 14967804, 9243973, 11910970, -8884552, -14357746, -24053365}, {-4702938, -2742433, -41636653, 19041029, -49442792, 14509631, 47045148, -14802624, -29838494, -3195501}, {-6978238, -9692532, -12018455, -14998792, -24538187, -14279720, -24387323, -10315732, -22286236, -10814112}}, + {{-26242516, -30159939, 19683916, -5964233, -18798573, 1260879, -33141870, -277366, 21649547, -11629387}, {-9025588, -2626683, 12887160, 3680459, -24993005, 6902223, -19430166, -20303862, 22565337, 16267783}, {-28712910, -14358908, 19106383, 1794762, -23574467, 6298834, -21226959, -2141624, -5574967, 17516}}, + {{3912021, 5634389, -37246402, 1402208, -13385108, -4129927, -8178715, -16447407, 6327478, 21304566}, {38987111, -25120695, 19511804, -19906912, 35181692, 8054125, 21775119, 633117, -18592220, -10864560}, {-17680532, -589993, -16271264, -11475361, 851465, 1092592, 10540768, -10518762, 4216841, -6902398}} + }, + { + {{30914954, 12146126, 8526006, -3266450, -15424357, 15434375, -48397892, -6694812, 38231161, 1896064}, {24794562, -8110468, 46102702, 12362792, -32567789, -10299139, -4780436, 16339322, -3744789, -31645562}, {-19443713, 5564725, 25048577, -14135563, 29215505, -192506, 22232127, -9071733, 14128945, 8795047}}, + {{-7433894, 24383229, -392555, -1490876, -32016000, -16516888, -49283055, -13078101, -6259504, -2018168}, {-49623750, -4038235, 13992073, -7098018, 17385806, -16920560, -4333085, 969079, 54528094, -19824426}, {4223080, -7294741, -23998292, -16385580, -30565982, 15169602, 12335917, 4240903, 2103630, -9137633}}, + {{-32805198, -3998613, 29810641, -3230756, -50965107, 2425722, -13650156, -1712020, 33652058, 3879391}, {27846158, -28469341, -4660967, 16358016, -9069969, 30360174, -13463520, 24032692, -2212234, 21677905}, {28660304, -7583602, -16609945, -678383, -8225903, -11456306, 18028044, -11924499, 1186370, 9895410}}, + {{9679280, -4163722, -16056077, -20144317, 365795, 5457414, 8792098, 16203617, -9844847, -463953}, {-33243610, 4026096, -12217873, 9533429, -51162923, 22753580, 39552418, 116161, -30146633, 4040387}, {-27734353, -6809888, 5586103, 8469490, 18774284, 13137587, -30215519, -12438654, 16638716, 4560733}}, + {{4371115, 7498100, -23388106, 10354103, -7785516, 8436388, 32399487, -10597087, -37272536, 2809025}, {37803507, -18813218, -8345820, -423917, -31248638, 17095330, -1462607, 6899351, -22633782, -16543659}, {16182472, -2573450, -14968428, -11800360, -24497100, -8398876, 30765205, 15264971, -6170771, 3460644}}, + {{-15812881, -2643411, -16412924, -2726639, -4941238, -25722704, -9018240, 15333560, 2874478, -12986986}, {17994683, 21453081, 24157834, -30619609, -38171934, 1869468, 19455606, -11276752, -2898378, -7910112}, {-28009686, -5796885, 6480577, 9154995, -30896303, -8593053, 9806116, -12697706, -5243237, 2536179}}, + {{-9621374, -27115803, -13632784, 14440150, 34135760, 26242974, -4404474, 5261522, 34019656, -683444}, {47952380, -2406675, -4827054, 16781782, 21528390, 810504, 14919678, 22792690, 26553984, 19882784}, {22528843, 10074794, -27906239, 4876428, -26716387, 12437646, -12096861, -9949277, 14448071, -10023899}}, + {{-11835138, 16601287, -6327046, -12021637, 15299731, -5013486, -52113028, 7299666, -11479598, 10301855}, {-13581288, -12004661, -3722102, 12123765, -37199837, 26011192, -7128570, 19327616, -17602338, 966831}, {6556201, -13049320, 15804839, 14063137, 4312990, -13530475, 3838047, 15682163, 30124468, -9393252}} + }, + { + {{42794524, -2381231, -32439940, -4035209, -24853724, -21830588, -43816418, 14156542, 42935431, -1079240}, {-16272504, -13600845, -29475756, 17078293, 24494158, 3429354, -9841628, 9448534, -22309709, -10073892}, {-3418021, 16032315, -32755454, 15131056, -20288352, -7805532, 24623019, -86803, -3710510, 12631391}}, + {{2573856, -23071879, 7701848, 18073791, -37785761, 267256, -8763844, -22895023, 9928634, -11094702}, {33524328, -906579, -30575080, 11309359, -17414001, 390368, -42148726, -9030841, -3009618, -4928154}, {27474522, 7987637, -9800345, 8769843, 23420548, -15599528, -19619385, -11327210, -30141887, 8017353}}, + {{43669655, -868197, 32856492, 15428807, 15663183, -11770284, 16787406, 532645, -11148431, 1558690}, {8680473, 15086905, 16341510, -11918567, -4463421, 21406912, 1356280, 9524311, 14009921, 14957340}, {22042740, -14670074, 20632004, -15163654, -19192419, -379101, -6618630, -15612305, 31532434, -6250743}}, + {{-32318010, -5052771, 1141731, -594160, 7069936, 15786855, -8044069, -16889047, -1312350, 27008636}, {19196752, 25793505, -12950563, 18315158, 51125260, 977399, -41955363, -16381137, 65105100, 1584088}, {-30026416, -2557077, 16729378, 5684158, -5640886, 13763766, -11840485, -814808, 22137261, -2664475}}, + {{-14670579, -2452657, 26445137, 7734423, 4011308, -21801567, -5635281, 15605926, 43285416, -2813168}, {20600277, 9081945, -32850367, 24590459, -34959430, 8329831, -48126563, 11472426, -6605232, 8910046}, {18503895, -15782879, -11642995, 14314085, 29834937, 5335074, -26404884, -6667127, -13329384, -4271988}}, + {{-30497387, -830385, -1375842, -4090360, -44366916, 9814725, -47493003, 8170861, 31507261, -10458140}, {22218223, -28046349, 26554538, 17509158, 11980798, -3676183, -10953087, 7661783, -30791989, 11106814}, {18561295, -11584840, 12547454, -2722773, 29235962, 6154795, -15732346, -425300, 21227796, 7936601}}, + {{-18067742, -15872387, -49524017, -7347618, 48866038, 23374212, -18779797, -16608108, -41684810, -149402}, {13686196, -17251061, -12552661, 7656326, 12176840, 9965110, -47792567, -8203744, -1358006, -9176846}, {-24053375, -7583283, -4843297, 638032, -6386949, 6837891, -21520100, 8966685, 23738469, 3341022}}, + {{33697762, 13127558, -22831209, -9610315, 6653293, -15224091, 27529257, 9549014, -11863714, 26978237}, {-13317824, -8754148, 37663467, -21934285, 49368731, 5491453, 37428167, -12833670, 25387784, -5610553}, {8796480, 2250199, 2524635, -1942307, -33401320, 12669113, 25948686, 1983218, 29127136, 6760762}} + }, + { + {{57806240, 7228362, 20616580, 14284504, -28782463, 2823013, 9206849, 12648486, -3623747, -1803087}, {-9038902, 26095202, 31469060, 16157526, -23074249, -5578189, -3889855, 6996890, -59596763, 29088873}, {16685317, 15153911, -8902375, 9468465, -6249345, -4381316, -26531497, 7009707, -13674428, -16743399}}, + {{-13182275, -72602, 28138250, 18664812, -26404672, -5276177, -10798397, 6434402, 13417386, 10013045}, {51333993, 3401274, -18422022, -9892712, 33627848, 18117161, 714659, 21293674, -39140894, 12848871}, {-32648888, -12517069, 8530370, -1879077, 26651729, 13181320, 14227346, -907330, -1333745, -16249377}}, + {{-21167492, 18566106, 21233922, 11814353, -35772598, -15577841, -28749665, 15701737, 9341751, -6459617}, {-26841386, 6496998, -8216180, 15789815, -22164518, 5867523, -33252475, 2157813, 24405321, 24789123}, {26425025, 1383760, 12767512, -13808201, -29841745, 11762682, -607609, -16052614, -5241033, -293725}}, + {{9177274, 11565804, 2825778, -12681290, 12592839, -21589838, -5754909, 9516205, -28139086, -11238614}, {50763678, 507178, -58046652, 12715732, -21757915, -4267498, 27547629, -17232997, 26177180, 403794}, {19918606, 16358380, 13719493, 5430158, -4144315, -1099418, 10919664, -15388160, 20266821, 15633966}}, + {{9574571, -7375454, 31851660, 9073740, -25221253, -14355273, 2794859, -17024722, -19381344, 6647589}, {23056921, 11159026, -28969440, 16281246, 38514673, -10931343, 1466753, 11701660, 28429996, -9982721}, {24317270, 1280065, -6044486, 11382262, -4042300, 14335214, -18837253, 14288789, -12338213, 8393929}}, + {{-23374473, 23279135, -24972725, 14952027, -7545313, 2795496, 7779098, 8576359, -11485645, -18769700}, {-21919037, 8048199, -17950731, 4277469, 2728791, -1500556, 35150694, -8789173, -37326133, 11001626}, {-4666832, -5748346, 30788583, 6571845, 15503000, -16278643, 10378253, -14846675, 2035436, -9466514}}, + {{-11559482, 10915777, -21542537, 18417532, -15143966, -14542926, 10660378, -6187861, -4420575, -2661860}, {-27704630, -22262109, 18416975, -12921584, 18005326, 13550930, 11183814, -8496739, -43066727, 21994872}, {-15365697, -1195130, 19463943, -10687805, 29628533, -10944808, 11987077, 12823981, 26639169, 7230847}}, + {{62322254, 1657040, -12299495, 11306683, -58392225, -17094618, -3171101, -4573598, -4809133, 19549114}, {1834044, -12331760, 1254495, 20820981, -6690165, 13535338, 35363253, -22742632, 18066591, 3782754}, {4548426, 12956410, -129925, -14391324, 15341604, 3815469, -19427362, -12381336, -1979714, 10910600}} + }, + { + {{-38552334, -1674113, 13824829, -7707137, -38246571, -2776238, 6007454, 17680412, -47692495, 781973}, {-13484588, -13692401, 39983639, 9893593, 4642169, 23617908, -57486186, -12510648, -7743095, -10884967}, {16176947, 13645689, -5220781, -5134791, -3834690, -3923418, -23840838, -15301830, -31177373, 16659305}}, + {{6157405, -10462727, 912143, 3840737, -13751776, -8704048, -22403706, 21941179, 51052856, 12402937}, {60642057, 6624811, -39495199, -1606279, -23344440, -3344022, 31725842, 7479395, -4017546, -8256901}, {-33350972, -2197208, -8878619, 903920, 5738083, 16409768, -9852952, 7108453, 17599689, 6848797}}, + {{-39277321, 14582070, -9521145, 9982836, 48637199, -18673526, -27720961, 5370770, 7117766, -23728685}, {-14006475, 13970368, -29170739, -14829578, 2130755, -11892984, 3295431, -19058226, 41819084, 5523103}, {-2104061, -15973762, 23645554, -1687583, 17940242, 5600506, 1412545, 11022192, -3039763, 13294268}}, + {{-33867168, -6091684, 33986476, 18833587, 7817636, 25365379, -27563800, -21928376, 1906175, 7763458}, {-18721644, 18333060, -5286710, 6609657, 55044558, -3151875, 19890076, 7167678, -42074971, -4845472}, {2007142, -13990815, 11407379, -9973400, 14642474, 8584678, 26859480, -9160366, 13585466, 2992722}}, + {{12967633, 4152282, 2150258, -7589830, -8849272, -4983507, 27997326, -17832677, 2709915, -3583083}, {-27376669, 10647490, 47762316, 16329854, 49904088, 4531285, 11865942, -2804177, 163707, -23964201}, {15705786, 2935047, 9390318, 13193964, 23115832, -11519649, 20133359, 12377882, -1344753, 140488}}, + {{-8799804, 18948774, -30892571, 123022, -25926079, 4960734, -6090411, -22324977, -25361643, -2167132}, {-28717210, 8697646, -9749505, -32951390, 11502509, 4594706, -29227535, -1414993, 7741851, -5014568}, {4650499, -8478108, -24234179, -5976394, 28331190, -10943442, 30087051, -7919740, 18817885, 7188952}}, + {{30165814, -3069837, 30101180, 6008318, 13668287, 11820720, -31131002, 25156808, 27901561, 18904336}, {-31716998, 8813227, 597464, -9379422, 36959323, -15102790, -9007846, 2320316, 19323359, -4138334}, {-31298362, 10253492, 6664395, -16317626, 885300, -12741158, 8160207, 8350209, -20339801, -5264656}}, + {{-27244760, -8547892, 50279040, 4134124, -34582954, 973191, 32905874, 23822243, -14449954, -3181538}, {24282140, -14077998, 2933130, 11324368, -2880596, 28637719, 8132098, -6556207, 3785372, -1798604}, {-28316408, -6555922, -20197428, -15990077, 5162908, 11249778, -25883916, -2545329, 6596172, 5270674}} + }, + { + {{-38667392, 13210848, -33307206, 5850996, 12145811, 23373861, -35656976, -1789964, -38566886, 10582119}, {-8543892, -9571188, -23473058, 19100686, 45509655, 108361, -15742816, 31197730, -15119888, 22704295}, {-18472517, 1629208, -5362290, 8854934, 11051026, -10324782, -3993819, -5955589, 14771, -14391565}}, + {{38443193, 704092, 15188765, -12896432, 44193811, 2194475, -8595905, -3092667, 9710611, -21131290}, {-10995957, -9649678, 10446831, -129182, -14679713, 14996019, 34719083, -6862053, -49349663, -3302412}, {-22021726, 15445154, -24262574, 634789, -25198277, -983430, 4185055, -2352078, 22668225, -1722550}}, + {{-23718274, -21887065, -9513369, -7091534, -14870744, 13484647, -16058542, 945861, 22125110, -655019}, {34831924, 2392289, 17288431, 17937944, 48862138, -14093787, 12201322, -9544239, -33739394, 25913119}, {-17970941, 4004116, 25769446, -1053913, 15780980, 3165620, -4455598, -2472824, 2834803, 3417684}}, + {{-8397652, 19358521, -11963686, -3036062, 7546576, -6921071, 4844564, 12468145, 6430929, -6838056}, {-8274054, -10148467, -2906088, -24297872, 24652242, 4192509, -10397362, -17281041, -59288565, 7201022}, {-20915932, 111530, 16241897, 2478728, 3406713, 1256919, 19698614, -8699613, 9035742, 12182261}}, + {{-32995188, -15115632, 37258684, 17430696, 47552834, 8794301, -2060438, 18101965, -40984287, 16632799}, {18651726, 6528182, -12706870, 2674756, -11310250, 21894611, 31553714, -6465861, 23883313, 4998257}, {-10614176, 12469321, -12339175, -12747778, -21155744, -2540745, -22556916, 7741387, 11428660, 12299369}}, + {{-42679880, 23000554, -32228427, -10908892, -9318270, 4545974, -58832230, -14942697, 23024210, -14356561}, {3774922, -6937510, 14508043, -19178364, 29786202, 13012958, 4950256, 8804383, 1642790, 1371531}, {-14455491, -10477211, -28254508, -474780, -2194307, 9122980, 32050743, 1155505, -11713511, -16747011}}, + {{-53547702, -5320176, 5102765, 1474641, -31217815, 32849077, 6647165, 15695209, -3792131, 12531790}, {-932750, 23568448, -11508473, -6986319, 360491, 176275, -46541063, -9459947, -46409297, 18452054}, {-1125544, -16388332, 20686417, 16595423, 234001, -16349458, 5942241, -3784534, -11880382, -11724241}}, + {{-2655528, -8075382, -48931117, 5947432, 16717737, -1653214, -35438877, -18141466, -17861017, -7543645}, {20611566, 952546, 18155437, -20285314, 21833189, -7656072, 28513395, -1692066, -24691439, -3322263}, {-28128553, 716673, 16150942, -7563589, 26623406, 9599383, -17399126, 14291296, 7294390, -16283848}} + }, + { + {{15951474, -6165063, -24713108, 3020202, -21126305, 6580972, 11338787, -16318446, -3181650, -11259016}, {-26909818, -8392267, -27094078, 4789702, 41947599, 13583584, -49187389, 13487774, 46338732, 10811840}, {31401188, 1843916, -30394342, 6462582, -25241060, 9172182, 27707571, -12852177, -1090419, -4399935}}, + {{14593295, 12868025, -17695553, -19073336, 28485259, -14550490, 24559545, -24522582, 23773820, -13892509}, {-45228611, 10023323, -16335629, -10257946, -4285115, -14444742, 22579651, 1781890, 3109558, -6840133}, {14242295, -3273120, -31754910, -15307970, -25033843, 8857398, 15856525, -11286375, -18860555, 240513}}, + {{-10981981, -12506190, -47455560, -6701671, 5755731, -13776354, 53550070, 7020704, 22980087, 28880300}, {-25008291, 11239272, 7342260, -24408967, -13503775, 13049946, -5496898, 22285892, 7702877, 1550722}, {-7309743, -7512914, -26198389, -5268732, 30062279, 8648380, -22789201, -15251718, -16593277, 5025464}}, + {{31675213, 2666747, 28374317, -11696736, 20540832, -12644373, 4809514, -28193847, -4543699, -8893966}, {-24385595, -29063763, -17155075, -14520186, 18464716, 5378247, 55140562, 372559, -19606765, -18275082}, {-25178714, -14527666, 15482133, 7813962, 2829666, 13928039, 23512340, 7093410, -1027501, 14004062}}, + {{-18442473, 18501140, 4432715, 9976722, -18757918, -9496918, -8061222, 8917810, -7369978, 19298341}, {2496041, 6587216, -26091171, 5676636, -41124196, -19853332, -18007750, -2258546, 47768812, -295205}, {-9606265, 786277, -7467533, -11301640, -24008558, -1014297, 9669707, -14466099, -19237504, 3722080}}, + {{12016113, 1171181, -9068133, 12952596, -17026125, -2373911, -26348505, 2376042, 19982346, -5124419}, {-30847405, 23521629, -37962973, -13586972, -942005, -7409027, 28883483, 4611452, -16763204, -11286081}, {32796282, -11777689, 20818262, -7507646, 21797715, -12850907, -29262075, 9013853, -13555524, -13244605}}, + {{17981215, 26192017, -11356892, 5561863, -23128861, 17400289, -9617210, -6747416, 9689737, 13543395}, {-14332371, 3748205, 16494752, 17324005, 35761461, 11936211, 1070490, -11205368, -23011931, -2984343}, {21669580, -14138005, 22855790, 10983889, -30324463, 12873947, -13228577, 6740440, -24103611, 12124086}}, + {{-45741381, 7738143, -36056761, -13165187, -30175580, -17624680, -52997180, 10091280, 33449354, 14238430}, {19082763, 11813981, 30559763, 2432633, -7376964, -10447030, 12327684, -1596574, -30603158, -12928940}, {15909369, -8895034, 29479442, -16565154, 14673542, -952999, 30925730, 588157, 11548416, 2933685}} + }, + { + {{28069860, 1877175, -19879034, -5335257, 20988053, -4708031, 18159376, 14578108, 2445060, -2025653}, {-34015378, 4845815, 24102402, -20562117, -26424633, -710069, 5535764, -6291716, 57092020, -7081101}, {16381298, -12870384, 14484367, -44687, 30299161, -14186383, 7419883, -14247799, -19582782, 4084076}}, + {{-3171570, -21804057, -15564411, -6845524, 26219945, 10630100, 33115123, -28178759, 30095246, 3400652}, {31704056, 6076381, 7332161, -20990058, -34126791, 9027192, -22318129, -5168499, -19065500, -27760784}, {7488585, -6136453, -16395525, -7965906, 454030, 951042, 5629664, 2678657, -28566004, 13527904}}, + {{11887898, -9143190, -24098626, 3620260, -3177084, -15628638, 2445925, -2917326, 38183188, -6307758}, {28621564, 14449764, 29523464, -13982930, 45654000, 4800782, -41285919, -14669908, 21692482, 1289580}, {-27206189, -370472, 23194933, 9563131, 3338308, 3077760, 12847343, 13688850, -14052670, 3760635}}, + {{41549906, -1912894, -509598, -5485806, -4353869, 9561787, -28514181, -7298876, 1310324, 17676319}, {20975262, 13871306, 35903860, -17845494, 38431737, -4990997, 16979027, 23284948, -26396126, 13457065}, {17287694, 12793917, 24588923, 4098363, -25209332, -5192583, -4050773, 1817968, 9117098, 13732701}}, + {{-51709512, -14803577, -33158229, 26433818, -694500, -15809365, -29787867, 19881765, 3123617, -23071146}, {-7433568, 11926265, -4157311, -4233896, 29108964, -9210253, 23185565, 12481585, 9605777, 7121526}, {-522124, 9045629, -20970385, 9130673, -33199548, 838118, 17118221, -13958169, -4019157, 13351332}}, + {{18294551, -7161526, -30839606, 2163071, 18724391, 85963, -39775208, -15489265, 12054016, -22379855}, {-30757971, -10977124, 18653818, -1249481, 11144959, 11517761, 17742716, -5370439, -29531146, 6964539}, {15289642, 8154819, 13081681, -7848620, 15002584, 10694084, 20407358, 12392892, -18847996, -3930071}}, + {{-50599246, -2795410, -33637676, -9186433, -19939199, -2572823, 14969974, 15216433, -16661021, 4696220}, {-2175068, -15086708, 28384364, -7884463, -3858661, -29120007, 25421116, -18274813, -43962457, 10416192}, {-29504887, -11161369, -2172272, 9297440, -19278153, -766763, -19260277, -12385764, 30852696, -11187220}}, + {{-40727924, -4627313, 32065847, -1293590, -5746940, -26696462, 14309374, 1667063, -4607115, 4383687}, {10453014, 434007, 2121837, -26273270, 42046800, 3064812, -870924, 5996809, -13954321, -19974335}, {-8722153, -15621861, 559085, 8054133, -24822921, 4366202, 24393788, 13098730, -11502807, 10601459}} + }, + { + {{-966450, -30402611, -12644169, -53673, -963301, -16438426, 8220767, 14379783, -56455508, -4353391}, {53321322, 2974589, 16991801, -25000617, 21017031, 382366, -10303755, -14141547, 9265824, -21328631}, {-24556348, -5687794, -10763376, -12078400, -21952764, 3592903, -33183940, -6201967, -29227322, -11822114}}, + {{44619219, -16334077, 44024690, 27695822, -37052357, 12661787, 46208222, 11867330, 31137121, 5671685}, {-555221, 3693281, 20631972, 1306950, -24253561, -9147863, 14680196, -4185504, -18532373, 1083803}, {-30953814, -15165724, -9275486, -7890591, 27453208, -9604106, -1000474, -2286088, -13567856, -12218450}}, + {{-16952569, -3750531, 8349941, 11470578, -15048481, -318484, -55246746, 11673740, 26158134, -5014861}, {-18935191, -2484045, 41560879, 14437248, -22848099, -9952280, 6161298, -9352392, -6881974, -26020627}, {31460808, 153148, 26585404, 3019357, 666041, -16237331, -16963433, 10955987, -20045330, -9829343}}, + {{-16115204, -13665657, 17177759, -1291792, -37726815, -88365, -7377865, 1849876, -30252688, 23155168}, {-48115178, -3929103, 13478747, 197348, -21117613, 26871619, 38466083, 5303224, 21401868, 7587128}, {27003283, -2806951, -28229348, -9536569, -12364426, 7974619, -14157275, 5543898, 28049418, -11073580}}, + {{5637937, -4856136, 54506869, -6298031, -10279955, 13481493, 9358571, 8578289, 18111743, 4335206}, {-24755, -10559160, 9648859, -12827439, 42300115, -17355863, 12207415, -9385941, 8637021, -20246160}, {-26547052, 14396388, -2040183, -10514442, 2689497, 6789836, 25429098, -8850507, 25426132, -813766}}, + {{-4978857, -18809765, 9046106, -26154978, 709570, 11424894, -35987352, 11837396, 26325368, -2742667}, {-32165499, 8572883, -23515986, 5308114, -17243130, 7876742, -14657218, -1315188, -7160952, 13678181}, {-12306051, -6770458, -29616752, 2299356, -30830648, 251423, -5912285, 3301306, 14337248, -5525478}}, + {{45769709, 8698111, -16598074, 2947372, -43702160, 12189976, -23092259, -16011368, -26058863, 625353}, {15058455, 10790581, 36399450, 128168, -13472814, -18266142, 41951993, 2511548, -29224801, -32357471}, {16727436, -14582452, 12745776, 2420150, 18806762, 7234328, 26064656, -2800247, -25732629, 4380244}}, + {{45060466, 449204, 7721178, 21642765, -155775, -13458270, -15548838, 8979986, 19909825, -21002300}, {11237752, 7642748, 828622, -9374495, -18573837, -18941418, -36400644, -1172904, -26806027, 9205816}, {-20470965, 7363766, 29175534, -5831980, -9392275, 3060228, -24512627, 5531105, -23804044, 14076624}} + }, + { + {{-18258446, -3318270, -32848356, 25675553, -25361929, 27857758, -2913052, 12881837, -44123302, 2619052}, {27637822, -25944186, -11125438, 4486755, 11429423, -2404882, 11455944, -18492289, -7720872, -19356708}, {-17848879, -11195199, -29015579, -12558098, 14111422, 16102748, -15220813, -6853985, -20600529, -5182416}}, + {{15486582, 18289085, 7268246, 284838, -12217841, 1110733, -23506508, 9533700, -24204709, 7975104}, {-22341782, -4208559, 3878536, -19445298, 45901049, 9931439, 31044376, 23730138, -40245929, -7316852}, {-26693296, -656940, 13290249, 1110970, 8151646, -5676179, -19885726, -16095731, -32104593, 1357015}}, + {{-54715728, -28871527, 35056270, 23213976, 6986703, 10629506, -13241869, 9311894, -22141970, 5914483}, {-1934762, 2874575, 24305628, -6476528, -24607221, -22175888, -49997475, 22348634, 39493466, -15179109}, {24850203, -5611149, 10501270, -3696248, -30839791, -300360, -31733851, -11170382, 21347498, -1731647}}, + {{-18694325, 11758642, 23864952, -7378016, 15405248, -11460879, 10377122, 243203, 27760782, -6814983}, {45014951, -14312226, -7610556, 9219988, 4282952, 10784739, -33101240, -22481951, -5898594, 19790389}, {24168738, 11942278, 30806566, 6711907, 22569134, 11352821, 13750688, -1211435, -17003358, 8504337}}, + {{-20990924, -26726112, -1561220, 2581464, 36703966, 7384891, -20437684, -963986, -12017574, 10078352}, {44546398, -6195706, -13263876, -6889370, -9990314, 5490315, 17790102, -18305424, 8094996, 13150402}, {-18185856, 10614524, -16249958, 12105960, -8110176, 14331748, 3789535, 7446683, 24636781, -3336522}}, + {{-29465188, 656996, 11322325, 3242789, 22241845, 7979077, 7316933, 12553368, -2082808, -11928000}, {6775954, 31848720, -47793421, -2745711, -41535829, 21621905, -26651319, 10575258, -62509450, 4264872}, {7387092, -13963122, -1618411, 7695297, 21762133, -3426288, -12195905, -8101472, 10545621, -9748140}}, + {{-44234101, -10508452, 29445192, 19601939, 55011618, -16064604, 9615770, 22419939, 9350874, -24151813}, {-13779747, -19920456, 11806564, 7403467, -8696642, -4730874, -1931636, -5373001, 12311304, 3259565}, {28884484, -13411087, -431383, 14160742, 23402768, 16185028, -29742381, 13402248, 32007430, 7561845}}, + {{-27108654, 13384827, -2825517, 26811819, 34570487, -17192999, 52176956, -21289465, -59408482, 15463205}, {-9434982, -13497623, -15948585, -6050805, -23012011, -10771169, -3542714, 3026177, -6705634, -9477233}, {28231455, -11946194, 16087307, -8177657, 9669996, -14601577, 30102267, 9782975, -32621834, 2932348}} + }, + { + {{16969320, 17234676, -22732950, 8227063, -56388696, 2973270, 15749100, 24899433, -3766821, -25955931}, {-25711458, 7696992, 31164412, 10426945, -8320462, -14626458, -41368926, 2897705, 20231473, -5290195}, {8223521, 9196688, -214582, -5544595, 10200703, -8273658, 16993083, 2087643, 2123428, -9883122}}, + {{1194080, 14703913, -15188387, 6141181, -6351354, -13184431, 4700374, 3525079, -28559097, 30633359}, {-28539494, -3795177, 22031421, -23108319, -21618798, -7278871, 53755342, 5793003, -17859245, -35627}, {-17459370, 5245982, 33161617, 6310472, 14748129, -2461490, -32444142, 2043962, 31334894, -135868}}, + {{-15953062, 3881209, 4993659, -11928638, 1192579, 3836314, 25594841, -7554134, -35705922, 30118995}, {-19066562, -13929513, -7371689, -20065786, 34762841, 11610024, -13907531, 11579956, 19576998, 2727053}, {14303644, -15830796, -24284748, 1205837, 29361854, 4709922, 3016836, 648247, -18761361, -16753367}}, + {{-26257905, 1283683, -9233769, 20703674, 1569047, -12159426, -2882244, -21990395, 11640748, -866783}, {8977685, 29521265, 3275429, -6912834, 10925315, -9813230, 42344210, -8302515, -1413644, -5235063}, {-29257080, 15828249, 27975331, 1591540, -8088139, -12931733, -7563789, -14479631, -21581550, 8055875}}, + {{34520562, 6352844, -4095819, 4635627, -10839447, -2495095, -14160925, 11849402, 1402663, 8997259}, {1106530, 10419646, 50964787, 9952297, -48024183, 15598061, 13183775, 6540034, -22415195, 5951121}, {-762108, 3904485, 19158577, -3538817, 14764022, -14546828, -18445729, 9331397, 17146507, -16766684}}, + {{-21161214, 6202497, -26368382, 2164595, -42507709, 2980669, -38060784, -16387029, 45143123, 25756280}, {-31376490, -13482135, 20511660, -17278199, -14098323, -2527735, 17388740, 7725693, 16475625, 7215334}, {32356341, -15570266, -14832424, 16715481, 28755912, 7286123, 22390081, -14648250, -6832801, 12446510}}, + {{55964494, -4605394, -10849265, 1481851, -17781660, 24541923, -44665025, -1263850, -12022806, -7041674}, {-3134048, -7807798, 35209161, -28466591, 13468314, -8577539, -18997419, 3947150, -37939660, -22343534}, {6369081, 6180251, -7872600, -16032841, 20244109, 8650901, -26794383, -9145933, -28851158, -6960118}}, + {{28103248, -8705428, -19169873, 830532, -4377671, -24253347, -35750672, 6846600, 16979763, -6132725}, {-18316378, -3169184, -825123, 10764318, -30750411, -5501313, 692460, -2488596, 2565163, 804967}, {4476935, -14373935, 790324, -205802, 1151114, -7932135, -32314175, -14646915, -26721453, 11163434}} + }, + { + {{12424935, -3449399, -53321825, -29949789, -24039420, 6284672, -21611232, -4913079, 16572914, 5570618}, {-53125547, 10159197, 4423999, -2238463, 25969514, -2767014, -31950282, 18989929, -35225774, 7081418}, {6091323, -14658033, -29899729, 10677201, 9308624, -13209939, 19490453, -13405934, -14927449, -9603962}}, + {{37597755, -12955933, -19085719, 14951484, -7775969, -8344037, -53245291, 2305231, 24411922, -3467018}, {-26616793, -1894205, -27180615, -5823704, -33781219, -5561249, 6184881, 9779385, -3965220, 16892040}, {-17833968, 12924928, -32152531, 8827095, -3353236, -2121315, -15313632, -8364937, -29465225, 6386200}}, + {{4283943, 1009693, -54504831, 8074023, -18980721, 18529801, 36358451, 13315461, -17587000, 12936945}, {2037579, -25769481, 2913001, 22517299, -44918265, -6292433, -2709445, 9808345, 20168244, -8759595}, {-1930938, -9097937, 12481376, -5397528, -16938280, 9840609, 16466705, -6747606, -32178070, 782236}}, + {{13980821, 6758030, 18061861, 16978070, -7971412, -26092470, 21668597, -10479903, 8987858, 2953783}, {-26243053, 7293246, 26458749, 3600164, -53859664, -1607850, -16456353, -13917693, 44069908, -29900787}, {-180078, -2771119, -8538678, 2969107, -23850993, -3352251, -29715092, 9416339, 2046898, -9526062}}, + {{-31747597, 23854701, 10559273, -943622, 50738129, -313044, 26771418, 18179175, 10869233, 5295165}, {29246117, 9321157, -7789851, 27459176, 1458113, -16840720, -9161520, -5641519, -14442651, -18587231}, {33228819, -13455556, 25672265, -15110283, -24778489, -2301770, -18228958, 5792840, -13192705, -5737719}}, + {{45096486, -24940475, 906955, -19221577, -26519898, -13442027, -36130657, -9206943, 19608784, 7494867}, {10762104, 1104907, -18979559, -12673179, 30111418, -15696671, -5105381, 7881807, -34730342, 14751043}, {-9249323, -14499636, 25155891, -12493225, 22699522, -6914061, 16402255, -1884250, 18826668, 7371701}}, + {{21784549, 9703671, -41364139, -282496, 26578843, 13628399, -41205202, 13652163, -51756783, 24389386}, {23284893, -15494943, -13981341, 5433862, -10771465, 418285, 16005920, 11006309, 509879, -1844740}, {10918370, -5040304, -26869254, 15357203, 4838247, 13059509, 19964070, -9207574, 21131674, -15516155}}, + {{11785541, 22018343, 5369226, -18839722, -23638407, 628128, -18986744, -21727402, -15861035, 10857150}, {-16828749, -6288963, -32255206, -9263498, -31260493, 19576090, -3404032, -7235828, -49652267, 16792576}, {25499178, 6758661, 26939079, -10298607, 9088272, 9477881, -28544561, -6022609, 4557153, -4644304}} + }, + { + {{27512318, -7557993, 5355984, -11897770, 12640055, -7738845, -13609771, -21756843, -49672819, 4810580}, {18764394, 7450569, 25475874, 18800020, -27668151, 4442009, 17988093, -4488327, -11634737, 17162862}, {-31931739, 13899134, -19453302, 9259831, -19003826, -16264365, -9994605, -672241, 30174360, -14356336}}, + {{25173939, -11144381, 27550844, -3246798, -30373504, -19436490, 49403767, -9121574, 31674056, 18702182}, {-24468887, -10733667, 2079448, 21229662, -34108862, 8415258, -1803971, -2185814, 31859758, 7389172}, {-6098113, -4138622, -27668167, -1550502, -10607159, -12386679, 1315120, -10879027, 11427428, 4210121}}, + {{27025317, 3042520, 4191743, -3570900, -4170398, -4079519, 34768006, -7785905, -11816567, -12046569}, {25184891, -18385410, 23515223, -17319072, -53070244, 11171831, 18640200, -17799219, -50910185, 19867329}, {-22460255, -9544952, -28488125, -5302884, 8254972, -11506979, 32029916, 7054717, 14796967, 7187195}}, + {{-10709958, -8789411, 23052298, -9162003, -36675284, -7152223, -34050444, -14125112, 41622236, 10971232}, {6954590, 4356549, -10067032, 6681119, 25975138, 12130373, 15293362, -18530686, 1939530, -484238}, {-32117218, -11582846, -11223524, -10416400, -32041872, 11400119, -32870814, -12681231, -25272944, -5305529}}, + {{-5658434, -7801507, 19023416, -168234, 48724503, -7677825, -58150303, -837731, 2669511, -10761181}, {-41113188, 17884909, -32745606, 29056746, 14749629, 2150939, 7345679, -29096687, -21077023, -8155641}, {-28140721, 16171494, -21262539, 12820399, 32070932, -12417211, -3735800, -2206805, 1517902, 5781829}}, + {{-38550612, -2780789, -47546320, 20705923, 20958262, 1097646, -64011135, 21187111, -60993642, -19572175}, {24817358, 19879443, -16772584, 2310157, 16901698, -30806424, -2273999, -9979407, -3651772, -6824805}, {-27062814, -1574409, -2919655, -7459533, -24823809, 1691306, 28669487, -11490125, -6491745, -6417443}}, + {{-39430014, 6425937, 24601643, -22505609, -5620270, -20510652, 15352019, 2856252, 13053719, -5521392}, {4871098, -24695083, 26725419, 2636087, -50666488, -9790016, -40971609, -5022, -12163751, -2590630}, {33515979, 12221244, -18627345, -16002739, 9166746, 3747507, 303798, 10520970, 20929735, -10026153}}, + {{62859648, 19520624, 39007696, 15028484, -22465495, -590499, 55022326, -18542, 860519, -5832795}, {1562852, -3849288, -21460624, -17277932, 911031, -29333693, -3436336, -4794594, 37213285, -12632115}, {-3699785, -10857473, -13767629, -7262623, 9936077, 16629185, 23824764, -1205576, 12223576, 10757929}} + }, + { + {{34925762, 10968294, -8267307, 9866088, -8913536, -11786485, 4566139, 7431515, -11139562, -18533512}, {-2415354, -12393144, -37577157, 15206404, -31440918, -15212141, 12875363, 25626635, -5196272, 4486232}, {-19361008, 3713816, -17917997, -9658705, -21681821, -7324642, -22443757, -12669502, 20343009, -11236153}}, + {{-18516237, 429863, 4714232, 23219551, 13870705, 19509491, -41379142, 17665608, 48039822, 12331926}, {-9671591, 127767, -8962072, 6567487, -37079111, 4977285, 1130514, 15231408, 10995454, 5177764}, {-11298519, 3649040, -1638836, 9583437, -14298386, -15747976, 14676019, -1854524, 2703093, -8681723}}, + {{-19798899, -3871552, 19906595, 46772, -44856455, 6941284, -19688721, -9653102, 3808716, 24784276}, {-6904191, -23611898, -42785705, -3641674, 20555425, 26239536, -3735543, 1730492, -51196162, -1796836}, {26232540, 6963531, 25931188, -3510906, 23742047, 6696445, 29264160, -10661874, 8334083, -14045517}}, + {{-32301401, 2463799, 30175949, -13276747, -6048294, -3555713, -12917714, 13099945, 8986575, -7554189}, {11772721, -2232229, -27159809, 12371745, 9424298, -29845271, 37551480, -4175051, 38478023, -14209269}, {9026199, 8195352, -22697161, 1927558, -19239390, 14758919, -696302, -5191580, -11239378, 7729390}}, + {{46905910, -8483233, 36780835, 5100016, -13585677, -4802768, 6251061, 3812952, 387110, 9806453}, {-14807030, 19932787, -16365117, 17351678, -28227295, -11721452, 29285925, 9509548, 36755022, -20352267}, {-28935712, 13874573, -2546502, -5851443, 7531639, 16524377, -29678302, 6633546, 28313353, 921649}}, + {{-24903946, 21922546, -19260516, -2366543, -43821587, 17456675, 4783767, -14781401, 36980392, -267613}, {14657150, 92630, 31633338, -13080675, 20345729, -7308485, 6662695, 2745013, 19541906, -16155983}, {-11049871, 12279382, -20842653, -9865370, 25734390, 9799492, -2250713, 2237554, -12194048, 1799858}}, + {{109274, 3335765, 26487200, 595661, 13406892, -1644809, -8642854, -3512970, -29136672, -2431349}, {57800484, 18971161, 18347992, -3519269, -7503286, 25110611, 45047684, 13452224, 13251332, 8547571}, {-232469, 6655636, 16845815, -13387722, 15156149, -3830859, -22811691, -11471615, -503172, 12232133}}, + {{40521306, 17685131, -15339419, -5626639, 35780177, -8911021, 15313562, -5156075, -23304430, 9267515}, {871880, -11492283, -13083447, 4278101, -10968521, -18639029, 47303174, 22510795, 23657226, 10416285}, {1528365, -15036127, -26250973, 6792947, -22723868, -7494357, -22805928, -16408225, -19227962, 15927708}} + }, + { + {{-1423943, 19524099, -5247172, 13868955, -23267366, -5753678, -39415254, -11938850, -8302758, 12818804}, {45544923, -824325, 55686744, -14469601, -22671872, -4289656, -3316360, -20339502, 54994008, 8651854}, {-26254604, -4043901, -14054807, -11868335, 28493523, -3048363, -18336029, 6707620, 32666516, 11056459}}, + {{-7721316, -15251135, -35450127, -9681428, -34070677, 3639387, 29248791, 15759720, -837790, -6151614}, {-56371412, 7045833, 24798439, 5107612, -9815651, 9551743, -29786877, -13003504, 11635362, -26813058}, {5927126, -7958644, 23263856, -2733007, 32528045, -7083978, -17748736, -9472339, 32082732, 4734075}}, + {{-51064968, 637992, 8452171, 29886034, -11757697, 12429826, -9843274, -8155393, -18606753, 4957564}, {-907196, 14405046, 34388889, 68744, -39098729, -7955384, 13841872, 13917375, -2281339, -5855690}, {-2748474, 8997861, -8871038, 10338485, 7357588, 10088, 12166520, 3418358, -1315104, 5114321}}, + {{-5645837, -5691594, -11776744, -1630751, -5214715, 1291044, 315868, 20529419, 11468652, 6655299}, {23701205, 25184464, -29112992, 22192831, -6550945, -58796, -50160230, -8681855, -9644620, -7607349}, {32260619, -11304317, 21188968, -57304, -22611514, -9164398, 29404909, 7064910, -16732112, -3139718}}, + {{12290912, -4459248, -29963772, 5238219, 27039979, 9771718, 44602162, -153154, 28153610, 19989971}, {-35214026, 8374738, -19714848, 1316893, -11735551, 6564020, 17591394, 12474764, -19904788, 2792231}, {14212330, 6292165, -12957477, 8070605, 14250545, 7663469, -32283559, 2087281, -22650110, -3433926}}, + {{5539059, 6238809, -19811080, -610180, -7317314, 25637119, 16472853, -15949027, 26189006, 15553978}, {-44785057, -6987661, 512094, 17104278, 37522256, -3021799, 41973353, 10599485, 28891922, 7817024}, {29703001, 11656746, -1723371, 5899699, 22527490, 895591, -12547251, -2682520, -26216488, -13029539}}, + {{43693671, 14141467, -24958060, 19936483, -4634552, -15097598, -403647, 623889, -47054557, -10798267}, {-11707235, 11636021, 37878606, -3855301, -5995036, 11721240, -63311319, -31794565, 5408607, -10604791}, {32374395, -12940199, 3314518, -4020119, 20490662, -14398446, 31628346, 5366985, 21238103, 14346803}}, + {{-44404558, 8878453, -36115029, 14203784, -23661477, 22579354, -20036310, -4501706, -11329544, 4318958}, {9603456, -14831073, 12681789, -3054508, 489709, -3707858, 13490628, 6537444, -43699668, -27492570}, {-14543640, 619055, 14984400, -8839512, -5190805, -9901441, 811326, 10494156, -10747860, -7471311}} + }, + { + {{32142955, -14234107, 19184741, -17747145, 8689508, 18561262, 7496575, 14921346, -49036425, 4450677}, {-32814455, 15460001, 32472523, -9002931, -25331434, 11075040, 38426719, 16592306, 3765077, -1267167}, {15821339, -3737218, 25574186, -1471289, -31438111, -2617507, 11080214, -6765759, 899125, 16148510}}, + {{18683582, 3965032, -147692, 9151759, -32068523, 4316680, 23305702, -28202780, 60964743, 16525789}, {30724434, 85394, 48975902, 8972435, -28256953, 21356716, -29693896, 5272784, -2187249, -5024005}, {-12513295, -15802354, 2015919, -14469021, -14545679, 14153212, 18882500, -12113215, -16338042, -16046539}}, + {{-4773237, -2130724, -16972793, 14769971, 25279295, -7282194, -43805081, -4714762, 25812630, 3083386}, {-42706305, -29684202, 19475275, -15957155, 39062453, 1562672, -17780397, -19648540, -38820868, 1962588}, {-614264, 14982935, -7849474, 2930005, -24905938, 11306140, -13730780, -9555652, 14021609, -11062773}}, + {{-18832558, 12197703, -23156800, 4768765, 12806438, -13942309, -35974235, -3743307, 36385852, -19742197}, {38556308, -13950671, -13578048, 21803767, 20741898, -17919929, -3266761, -7969173, 26562114, -3073243}, {-20170752, 7343934, -7541981, -13410891, 10141195, 10446273, 21905429, -6440795, -14831040, -12515083}}, + {{-18932315, 13127699, 6820553, 5495106, 1960517, 10421282, -18712383, 4634381, -4355479, 10027615}, {-29717477, 9281683, -38759853, -585638, -51528067, 19275836, 21432803, -7184863, 43016751, 20236285}, {6576903, 6948015, 31188994, -4727511, -16021372, 14867226, 32606854, 13079982, 7304891, -13172603}}, + {{-18166850, 19187800, -45014384, 13661463, 3227516, -8834860, 456120, 1889594, 6631576, -4243204}, {22692492, -4412464, -5257584, 7516215, -38333328, -8005116, 58405076, -30590872, 6583294, 21130060}, {5554996, 759793, 27065433, 6201701, -12308485, 4185005, 22643252, 6296810, -7050038, 7916347}}, + {{32597259, -18231697, -5959173, -13354428, -46089079, 4159362, -5453582, -2532797, 8839265, 25666124}, {-5590957, 9606273, 59810143, -17322186, 8223399, -3986384, 16965376, 15378203, 37770041, 2070162}, {-31073238, 13893232, -845267, -16676671, -21258018, 2854278, -27507451, 15527104, 10973693, 2729142}}, + {{2566384, -9440423, 37485538, 5438592, 4159191, -602710, -9791057, 14087580, 18336825, 7907713}, {32651048, 20826157, 27580292, 27871120, 17134577, -15500340, -23137773, 13698840, -4860475, -25042877}, {14304456, -1696809, -13034450, 15503161, 4430663, 15397873, 30969618, -3036150, -24358494, -6513865}} + }, + { + {{-857230, -9485579, 23552403, -11039089, 26131571, 14416567, 12771157, 17681843, 2240483, -13665691}, {-26128406, 19183455, 33598005, -18885517, 33505033, 3628675, 14364673, -13064561, 62932161, 11241919}, {22529449, 10400780, 3114202, -3127238, 25820725, -14645285, -17246222, 3543721, -10559855, 3410062}}, + {{-21203888, -26394583, -2030002, -18591333, -41701030, -31307517, 21202609, -16950400, 31872542, 9413196}, {5545628, -4328203, 11546928, 5386943, -1411554, 143129, 24828505, 5051844, 9554670, -10008718}, {-28670131, 6174081, 21670660, 15929513, 8091846, 9973174, 4016395, -12093222, -30968586, 9298545}}, + {{-23486358, 8839324, 52212850, 9072376, 9892877, 20617547, -14002543, 2559370, -39415702, 16686864}, {-16714644, 22175336, -7387454, -3719964, 31435391, -10105161, 31806339, 9318296, 11739638, -16603042}, {-1914678, -10255818, -18333956, -4090878, -10396208, 13713384, -14008910, 4128697, -23017589, 1638209}}, + {{58853069, -16727379, 31038469, -535197, -7152765, -7769610, -11044232, -14097842, -46104681, -6594829}, {-1820893, 10840377, -19534793, 17202043, 53836377, 9831562, -47770056, 10186170, 9640919, 4015489}, {-8860848, -14813381, 3891229, 16398617, 4387760, -10967061, 7112070, 777585, 26413033, 9151808}}, + {{-3484777, -15865911, -46624656, 21026078, -3438226, -19091358, -30787, -13117583, 2955970, -1412784}, {14365179, -8657089, -4575200, 12256488, -34169360, 6927670, 6489451, -15034975, -31018200, 16694030}, {23974024, -4695344, -25735147, 1849074, 9002353, 5704357, -21374919, 16776491, -31484292, 966955}}, + {{21716456, -5957992, 40581840, 15312351, -28976962, 6734286, 64951503, 6581321, 28927804, 23885069}, {-38617104, 10315948, -14167134, 1108241, 9415872, 21531848, 1556797, 2706429, 7429342, 6653301}, {-26995015, -5880669, 16361897, 5842721, 26930976, 15486318, -19174572, 15758906, -20956566, 16333713}}, + {{37636271, 3539061, 19586838, 928921, -14066177, 2924468, -47241307, 11097811, 1905367, -1520269}, {-23123431, -3313085, -4711932, -8488395, -51731741, 21428632, -15225463, -2322025, 34066075, 12317853}, {-31047858, -13676722, 28093087, 15465818, 22787487, 426738, -4841535, -15620892, -25789810, 11208546}}, + {{-16222562, 19745771, -36387031, 18275320, -12454610, 28772765, 15109989, 7978600, -29158249, -9769882}, {-38711780, -6503517, -1336521, -10507952, -44894980, 4416389, 36712485, -4356406, -28079219, -12116410}, {-2739324, -156151, 27501166, -15272775, -20826195, -14069020, -13050709, -10074879, 31374950, -10528115}} + }, + { + {{-14075800, -9399340, -12285950, 13139767, -12200289, -1415459, 16340171, 23389367, 22044922, -4933136}, {-19800318, 19665578, -15837062, -6651705, 47095113, 26184149, 23472667, -6770755, -35702468, 16378518}, {-19257789, 8326531, 2126376, 10409852, -13952914, 10952229, -15042613, -14537407, 31086406, -13992609}}, + {{6324061, 21513221, 27534592, -11680911, 24988272, 776777, 49028786, -6191180, -16044389, 24251280}, {-48600917, -3504997, 15834618, 6776249, -21384884, -32190121, 17026272, -13583214, -44522959, -6191052}, {-11477141, -4739885, -18547021, 11032317, -3821556, -1568687, 13236197, 4586148, -28039321, 5334661}}, + {{-2619358, 22512042, 2241930, -15826919, 13562409, 27594158, -25679190, -2084515, -9064737, 12332302}, {-877092, 2850102, 24911692, -14227753, 15702129, 1019146, 230084, -18381601, 57982277, 14405892}, {12130539, 2336856, 17056493, 5912685, 30138703, 4316057, -22568172, 15528462, -24424532, -5548561}}, + {{-52972512, -4981211, -12634050, -25446031, 27049436, -26411159, 33429513, -2094461, -25905172, -12386442}, {2634218, -17843515, -8852632, -5412381, -25557678, 3237315, -240719, 8694519, 4347238, -14171538}, {-9908341, 1163932, -7451503, 13637099, -2802628, -13219563, 21169668, 6125015, -249123, -8494004}}, + {{38186145, -3058580, 29809585, -8395125, 7163965, 4826511, -53103150, -21478203, 5486419, -1068758}, {-3558435, -13641834, 30730977, -3913631, 17329933, -16423241, 11101940, -78463, 2255853, 17005196}, {32312362, 16773765, 16518712, -12027454, 5900170, -5137849, -8634192, -10594433, -18488305, -10341519}}, + {{24190553, 17572765, 28701366, -29613504, -13866358, 6594642, 31867683, -23657434, 36525052, 383257}, {19368499, 2762667, 7708080, -2272096, 18333904, 10858678, -21814485, -6142076, 21566776, 15259963}, {-4294074, -13742435, -920227, 1796123, -4563244, -13426141, -9631993, -14111736, -19327234, -6213940}}, + {{-32684508, 4383726, 11858215, -17708657, -57553080, 4832659, 26634910, 22990568, -50359035, 2015531}, {14989942, 8809736, 26333397, -12976593, -1495178, -6841723, 39921656, 10345260, -10265025, 20685407}, {-2242168, 1543553, -27142733, 16564501, -23073118, -12431211, 13122421, -3894952, 25414823, -13752663}}, + {{-19767683, 2131098, -16591047, 7078616, -17656611, -9707019, 23065468, 11353498, 44773685, 2587764}, {-28976777, 16184616, 40088455, -22478058, -18088847, -23460733, 30109326, 5506666, -4722083, -2040686}, {-19288724, -1868825, 24732477, -15504375, 12960881, -4985132, -14623906, 2657502, -1827315, -13595382}} + }, + { + {{-8936079, -624212, 17371152, -2850516, -28384497, -8137346, 26687379, 16146721, -5732, 764625}, {55989277, -10151044, -38088438, -29288274, -27405495, 22976954, 9069537, -2679253, -26093856, -11364643}, {20694731, -10228796, 4251326, -4091115, -15141256, -2943096, -18818842, 2384024, 11016559, 12794368}}, + {{40646283, 14514015, 8902129, -11735239, -8821263, -22670335, 29080985, 10607398, -3214977, 27524141}, {-20677911, 9051949, -37551969, 16728521, 39064527, 7537021, -20403881, 20821592, 21061613, -4825179}, {32173032, 1473973, 6485660, -8417283, -17755228, 8960238, -26330720, -5250731, 11481558, -11225370}}, + {{35700029, -17567466, 33511166, -27856027, -1585208, 5664916, 25085093, -15019861, 11538646, 7375866}, {-11738419, 12553846, 10803406, 581661, 54956572, -6591880, 39640389, 11617463, -55252814, 11185526}, {32173647, -10628329, 598580, -8522520, 17990667, 6919274, 22886872, 1459775, -4157645, 9509268}}, + {{-9299184, 4441397, -7228378, -3090046, -8861529, -7314148, 42460574, -4877779, -19532772, -10505248}, {39703118, -273979, -51213718, -13414682, 55734397, 25584678, -19592638, -22836377, 16908416, -20801490}, {17117149, 13458836, -5864262, 8890227, -2555331, -10048017, -11135890, 1873321, 25877864, 7268867}}, + {{44143903, -9745505, 5446202, 7489679, 37435312, 955223, 3483756, 6441665, -4848247, -10421083}, {13676857, 7500655, 42355678, 3389713, 13327726, 30617045, 52884588, -25438959, -4842107, 5938227}, {-31806912, -14215249, -8111925, 6791380, -10384573, 9606611, -15178218, -11872148, -3214751, 10257702}}, + {{-45940845, 23443796, 3323080, -15747783, 1227119, -25701334, -26721620, -12253851, 466570, -10655820}, {20468875, -2925362, -50270794, -13686541, -17664951, -6616, -13152836, -15116867, -7781678, 18540692}, {25450632, 7658693, -32092065, -11429089, -31045454, 1316157, -22278049, -11102465, 3710638, 1021259}}, + {{2860417, -11480252, -44851855, -30453893, -8953103, -22612976, 17044811, -30231067, 1622435, -4601836}, {-20675545, 5911266, 2920499, 2523165, 21487869, -7646092, -2462535, 981501, -41871177, 25706774}, {18904592, -2778600, -32863561, -7136314, -31361065, -14054167, -12346058, -5530035, -14413329, 7894741}}, + {{25398772, 19186422, -31322310, 21466355, 40832827, -9702273, -19046501, -1527989, -9323858, -12517635}, {14825684, 7154806, 14268656, 3616685, -10534257, -18436583, 19638265, -23341155, 31854416, 8021487}, {-30028109, -7485277, 6136224, 6157215, 19526013, 7206629, 25599471, -15516603, -21830485, -2378940}} + }, + { + {{30209710, -12136814, -1916338, 7065944, 8939954, -20966499, 7552139, 10546452, 31038701, -2874977}, {35447076, 18349298, 7267608, -5213386, -23933450, -1725633, 52675117, -15215440, -30685315, -7268561}, {6356887, -11681156, 33071618, -10365216, -754410, 9603242, -12103852, -765715, -25290960, 5702386}}, + {{24013097, 14053868, 22613110, 4132376, 449379, 20163477, -42858381, 2208105, 37684861, -16117030}, {-37317277, 1136464, 39327598, -2292778, 53439725, 11084415, 10426621, 28451959, -9126587, 71718}, {-27701957, -15869075, -31502603, -1506411, 11849132, -6446750, -16227862, 10721043, -30078713, 368527}}, + {{-12473016, 2814820, 19011417, -9923852, 40512521, -1202041, -9231787, -24738399, -33079348, -4703748}, {46365632, -3327190, 35922439, 4375784, -26509577, 11507685, -3440145, 277473, -1336798, 5503656}, {30974829, 13350517, 18821201, 4870009, -11888251, 10366408, 28885516, 5985354, 22497265, -15639317}}, + {{11471315, -11081232, -21735702, -1776143, -7183060, -1918321, -941542, -11349561, -5461366, -18786047}, {-8364605, 14227320, -28420498, -11592453, -59127574, -5373595, -59611798, 12108279, -35963070, 8635591}, {4746578, -13407997, 18323668, 16532670, 11131056, -9626746, -22869112, -14363864, -13298798, 173999}}, + {{-1763077, -18448405, 25697776, 20713767, 16236594, -10134398, 28986449, -18196009, -16481896, -214038}, {57572269, 7723477, 4103648, 4879773, 29822812, 21912786, 9949145, -13837069, 18828366, 11938130}, {-6596556, -10136682, 951981, -9924963, 10171395, 9878507, -12834721, -13809230, 3313618, 10217624}}, + {{2010972, -10591760, -35636905, 6528427, -17675326, -21338214, -13577869, -11781316, -48814573, 18789255}, {40210200, 8210760, 24458609, 3406401, 21613600, 3914014, -11450377, 14644418, -15961259, 599025}, {-1698843, 2786491, -24001199, 4497816, 9590116, 4559892, 2828221, 9283569, 12305326, -16305274}}, + {{4324312, 9780992, 37550755, -8726335, -3066238, -19608225, 14398144, 3396285, 56793496, -11281779}, {50556186, 10777892, 20257441, -20441969, 59803598, -5998319, 51211510, -4851201, -5399940, 18943709}, {-6234933, 6554323, 2962738, -67063, 11026438, -11328215, 11760473, 2334415, -1683529, 1997343}}, + {{-28726810, -8363831, -64496629, 181911, 47256033, 2092844, -16571926, 16374091, -55975864, -20189330}, {36412292, 12810389, 1769755, 11947997, 8296283, 2846528, -39909634, -14465219, 2114814, -13173814}, {22914282, 1461641, 9478566, -4509861, 14925927, 7960522, 6192780, -13404007, -20484559, -1124372}} + }, + { + {{-48356557, -13583095, -30052214, 14265614, -24244, -6544158, -36555718, -14990097, 19571659, 4254750}, {5253575, -12816731, 672382, -12672324, 32469208, 18848746, 18007584, -3740563, 27915383, 26900610}, {31788392, 12983075, -5589487, -12593692, 24935609, 4845313, 14897764, 8591081, 28221720, 10075125}}, + {{7935423, -22787606, -18329320, -2688602, -6931935, -8013917, -7731891, 18683789, 12045352, -5487624}, {-43716823, -1328044, -27456354, -14287776, 53916523, 23806877, -28575745, 8636531, 30518226, -12995618}, {-28099053, -818544, -31373885, -2976712, 19028916, 16395582, 20250507, -1728685, -13578109, 9957552}}, + {{-1562624, -10989062, -18179938, -11310626, -45993350, 11634620, 12634721, 11287051, 31614119, 8213565}, {29619932, 12775220, -40218418, -9733114, 17041914, 15739232, 49097927, 9378315, -17633593, -11768909}, {21099784, 8606062, 23763716, 1601132, -23395830, -3019104, -19482091, 1808464, -2411989, 1018595}}, + {{22937598, 1838098, 32470918, 7380128, 28629672, -399855, -9806796, -11492909, 14882232, -17300888}, {-24555288, 16733010, -22418858, -1031154, 34017890, 23935503, -56293956, -8885819, 38509354, -7906696}, {-13568330, 15036664, -9250347, -15359398, -33390767, -4966302, 24779792, -4366832, 29989605, 10417522}}, + {{25481955, -2971417, -9243091, -5701292, -9101774, -6462099, -43119587, -22200474, 2358414, -19730111}, {-2141201, 11418059, 16352079, -5332818, 14679580, -20503457, -23182047, -9484436, 45194680, 1265757}, {8170761, -10557984, 31893455, 524848, 939434, -11211186, 21534099, -9355934, -30402679, -12977960}}, + {{-26458562, -200710, -5547300, 19666549, 6057638, -4838379, -20541871, 14482648, -34086864, -327946}, {-19707632, -262700, -15184978, -11421759, -27610948, 1236747, -33609799, 12122536, 5641328, -1102644}, {32481726, -4894475, 9764775, -15288225, 22718090, 1968754, -670351, 15699563, 27713188, 11123973}}, + {{37074940, 15949138, 23657077, -1349459, 23376913, 2730287, -28050327, -17532097, -6367233, -8087241}, {22843200, 11318246, -8466753, -17821045, -27704923, 15516595, -10125189, -15014005, 27762999, 24657151}, {-22939333, 2151132, -30402250, 6428690, -21877119, -6210357, 27068901, 11258091, 22014806, -12368131}}, + {{3928213, 10610759, -32281880, -21725016, -8410662, 29003345, -39232312, -25441570, 39540090, -16047354}, {-8399711, -10879097, 33651302, 8131276, 2824482, 399681, 18113604, -7600042, -23501990, -2750372}, {-32371872, 11017221, -18870913, -12340972, 2903156, -1070081, -16480170, 9021909, -1362829, 7132558}} + }, + { + {{7198550, -790465, -3539049, -21880346, -1838471, -11017531, 54705489, 16117265, -22220767, -11478716}, {19759704, -2856005, 16759835, 8015336, -62575097, 7818605, -587103, 13589089, -22032795, -14835900}, {-16500089, 12447130, 415528, -15467095, -13949277, -3107739, -19988593, -16687131, 24142377, 14636241}}, + {{32051407, -16489353, 1780611, 11706957, -313444, 15547126, -26481454, 10421533, 43817482, -760064}, {6888387, -14809577, -15646819, 16421865, 49796222, 8740356, 27918734, -1031295, 9298014, 8923066}, {16319645, 9700648, -28775170, 11271508, 30869129, 1691406, -12588888, -11255191, 29805557, 10534822}}, + {{-6147902, -5938808, 43823571, 4091494, -17544361, -24378157, -26687671, 7466258, -18243738, 1234620}, {-32101896, -12209518, 5715473, 27018702, -36131751, 6933055, 2019421, -17870480, -640456, 8623550}, {24092151, -4993781, 28076876, -1299404, -14623116, 14877627, -3756995, 3672951, 25616949, 9498537}}, + {{29858568, -20921731, -1325368, 3820945, -2899207, -14219729, -4091943, -7080801, 11921852, 2676756}, {28525116, -8942833, 16659802, -16425585, 20848969, -380381, 46414433, 3430315, 37901266, 22799864}, {-17619557, -3143602, -20813443, -1788233, 21445578, 12287313, 21288662, 8323067, -17926738, 2681405}}, + {{29816944, 18817708, 12408238, -15144529, -3323076, -6386331, -36926058, 9734772, 26971585, 29971242}, {32945520, 3466400, 29541766, -4967599, -17829474, -25229227, -22020928, 5777560, 10105247, 1916122}, {-20885121, -4592196, 16082014, -11679847, 26795101, 1589201, -9583407, 14993606, -15327676, -4223514}}, + {{34152503, -12806367, 49843136, 16572132, 10766134, 28653778, 49045554, 5231702, 48312918, -14320689}, {2509787, -6908337, 12776026, -11727558, -4021036, 2439578, -1877850, -12811498, -17651202, 16104565}, {18193446, 9942891, -6307165, 12005666, -30113179, 4238270, -25355194, 6893190, -25394433, 2925408}}, + {{-19427063, 3213285, -26539268, -4158110, 36153071, 9164947, -38867627, 2337304, -15459446, -7319451}, {-42886597, -554777, -1239812, -16773902, 7726651, -245367, -20966287, -26093072, 672094, 8120691}, {21386735, 16225707, 8432961, 2943899, 13327603, -7276609, -14463221, 6566920, -10652520, 2160268}}, + {{-18541219, 27448115, 8409101, -9566646, -30174482, 1451808, -39839508, -6461572, 7579055, -3571553}, {-28062385, -2567119, -9900245, -1454908, -29247856, 19869432, -9549530, -858614, 39377171, 29087379}, {25789199, 96213, -23912495, -1235268, 23049914, -13015811, 26015603, 4286937, 1215656, 7580405}} + }, + { + {{1474379, 767676, 28046259, -510249, -4478062, -11331252, -21652843, 17113336, -47658788, -11827075}, {-27157567, -8336752, 32392083, -1382887, 15167394, 18719724, 25512739, -16101398, -12394698, 15734839}, {11332719, -3762724, 4567390, 9539265, 17165088, -10586494, 24471075, -13417333, -5036958, -7062524}}, + {{-17100196, 11080469, -4877685, 23482882, -34581688, -5453369, 29387974, -19298785, -39759097, 7469060}, {3882450, -15097029, 26708189, -5589086, 23723098, 22309807, -37280820, 14041345, -12888481, -23265886}, {14149250, 9686184, 5636871, -8702290, -17773072, -6118224, -1732763, -4871910, -30113489, -904725}}, + {{-5509993, -9173760, 24692369, -7003990, 31128190, 18085235, -9284958, 5810220, 32186999, -18761294}, {4731997, -19004378, -30052527, 8359588, 6375166, 5446345, 8329288, 353138, 1267859, -14456476}, {-13564966, 14077469, 28342131, 13226695, -29479434, 6874442, 3661577, 8859108, -30294100, -10391685}}, + {{38872717, 18247047, 22003177, 8443285, -39340091, 11685709, -9852806, 19312236, 3587913, -1854817}, {-16116081, -5852595, -33383431, 2120723, -12461487, 8998439, -40717610, -3968154, 37572397, 2579557}, {-6923224, -7914839, -23084058, -7901660, 27042873, -10681515, 28541629, 6861003, 232162, 11147634}}, + {{-38312832, 10967558, 27504529, -19754503, -18005786, 21906477, 20939182, 756778, -5490643, -28020368}, {-12799940, 21671414, 21365697, 12118217, 47771016, 6295023, -2430544, 26945436, -23326131, 4202242}, {25696407, 15917313, -312118, -15301808, -3830230, -11581913, 156455, -3436414, 25524791, 613491}}, + {{-25566549, -56080, 31493939, 21225921, 52961329, 14264305, 40304781, 10822622, 40892046, -872935}, {-32658801, 16227736, 24407093, 650197, 4018469, -14960869, -20535111, 15324344, 25483028, -3583427}, {-12063057, 10551264, -24463098, -14410296, -6552165, -14108746, 18193369, 4542824, -16278909, 3905086}}, + {{32805835, -2192892, 12790592, 9585591, -16666892, -7907341, -53398583, 5539631, -34650839, -4410024}, {-2863443, 29634720, 5551534, -19773515, 24037792, 6247963, 10364953, 14489359, -11747867, 27860702}, {15589296, -11914797, -28208475, 9908443, -7631186, -15786947, -21098983, -9302795, -10091076, 1611389}}, + {{-25562706, 15752324, -9341517, -13233468, -46999934, -13285091, -914197, -20139420, -16355215, -1798356}, {20110980, 17615890, -21824287, -8358000, 18811852, 19433161, 46762075, 830092, -3657265, -20867414}, {-13752464, 4287126, 12171345, -14324878, 24085231, 1211565, 2659414, -12356834, 18023416, -12727905}} + }, + { + {{1351240, 2121699, -12971014, -4971252, -9311706, -29554026, -50398696, -6826969, -7131437, 8145328}, {12357802, 28327197, -10092702, -8703594, -39863048, 2658130, -383684, 17883761, -31320429, 15580358}, {5888787, 13384381, 1299211, -4061897, 20267237, -6419675, -10469872, 7667392, -24680870, 5017539}}, + {{-34005260, 10119527, -3580853, 8989378, 895381, 8143539, -10533987, 11608957, -8161742, -1936625}, {20464188, -14863795, -48007427, -5314450, 53637779, 15869943, 14107835, -2972969, -36483108, 15668553}, {-13808714, 10893271, 12599331, -3348740, -794353, -10155873, -29681092, 16701014, 29195457, -4022766}}, + {{-43411893, 3577206, -28037224, 16807034, -25289408, -9418693, 16197448, -24544154, 40225060, 18636381}, {16445477, 14732604, 7589850, -15217354, 5748166, 19712723, 44786330, -2143212, 26073708, -8248061}, {-5788750, -8494845, -12219966, 10257966, -14425665, 2702211, 11875879, 4087042, -33467271, 15326962}}, + {{-1141122, -5652491, 28815066, -3483722, -10471953, 8334983, -64851051, -1787741, 22834042, -14162113}, {21777604, -13977131, -14752690, -6724722, -7596903, 14167459, 2157753, 20490823, -30058230, -3148469}, {1569197, -1316784, -8937866, 5052647, 18233833, -10068412, -20654955, 1919659, -15604453, -8741437}}, + {{19947058, 18751944, 37857632, 12045670, 51794406, -22809990, -32506734, -18029052, 28094178, -16218916}, {-4378830, -12495588, -6315320, 10868332, -1606450, 9964854, -33270284, 1485524, -9206258, 1757942}, {-12632192, -15623307, 21120199, 5234349, -26483174, -11415028, -21412231, 4220004, 26555223, -13528462}}, + {{-57119433, 16843357, 22397659, -4486492, 10112303, -6050645, -22438743, 7863291, -2120258, 2079086}, {1640119, -12137173, 8291069, -14033902, 13243601, 14168897, 25749283, 23299113, -1546122, -20357040}, {22479625, 4777302, -24070230, -3331738, 15909669, -6249610, -10354202, 14585573, 22188176, -16196881}}, + {{58840856, 12044546, 6190726, 2063481, -3984173, 1111942, -42173456, -7097491, -22383958, -18043949}, {-2812640, -508700, -31787092, -27220355, 35020199, -8234422, 660122, -3082503, 17406366, -8641009}, {-17008359, -2886561, 18650764, 8661589, 31166214, 8543335, 18617610, -6914556, -30200445, -10186459}}, + {{42976243, 12315309, -36415092, -6774977, 3181972, -27727570, 3009046, -13426824, -9830591, -17287570}, {-6588685, -11116589, 15354244, 17761537, 39679660, -2290850, -34498476, 5767046, 45903503, 10498496}, {-13053087, -291457, -18943017, 5484483, 10438655, -10528915, 19871984, -16503341, -33303222, 1552718}} + } + }; + const precomp_data_t c_point_U_precomp_data = { + { + {{21400817, 3163693, 22274602, 1860235, 12921482, 1217493, -11010042, -1386984, -15511344, 23938104}, {30785711, -8713869, -11504484, -6188623, -35803896, 20705931, 27072746, 27026120, 50090152, -6224356}, {-1226464, -15432576, -15257994, 7722966, 5301836, 15823262, 12121778, 1127837, 29573438, -10846212}}, + {{45327989, 5871829, -21594162, 14686109, -4371676, -21253280, -22930729, -16081648, 1113028, 6113431}, {20703019, -5933743, -12557770, -13311857, -58245242, 173658, 36988907, -4687232, 1813788, -5769667}, {-22224350, -10189375, -33502324, -8837358, -24941208, 2322074, -4449737, 102988, 22334713, 5211518}}, + {{-40433145, 15676162, 24174310, -5452025, -28574992, -10027714, -17820899, -15072104, 2824082, 2984497}, {21270833, 5317458, -13140896, -11765051, -32117936, 3735404, -13464599, 10077550, 540454, -17926889}, {-20312935, -938058, 18992962, -6806474, -8113796, 1188520, -7182097, 1160431, 11617041, -15673135}}, + {{11598233, -11778045, 34249849, -2615407, -44314803, 17924865, 10170798, -10830372, 6192954, 7353666}, {-6124853, -14828989, 25116753, -14794893, -3102119, 9585375, 35636402, 13895290, -38805522, -4671304}, {-16956137, 3817673, -29557250, 2045834, -9572915, 2591103, -29509266, -8549542, 8891002, -801087}}, + {{-41967606, 22877756, 1990357, -4034603, 1692575, 23004174, -51002576, 21174571, 828401, -13030510}, {-15827162, 9380470, 22320399, -29334007, 39740385, -8244670, -13046724, -11955551, 43264599, -17758528}, {-12066457, -8379790, 1536996, 10598975, -1739367, -16406896, 7889871, -6492654, 14788936, 779109}}, + {{42857109, -7040391, 5234992, 24780567, 16763369, -8281032, -7873761, 9570332, 24965615, 27017395}, {19124589, -3398123, 55594858, -6538179, -28875407, 18600156, -18212993, 5186814, -22204219, -630987}, {8399475, -4775346, -2933541, 16133392, -30265491, 4957974, 2019696, 11267383, 30760770, 7936054}}, + {{-26931544, -18046377, -47201091, -7802111, -11092383, 13783932, -21729506, 7106849, 27873134, -158273}, {21811244, -12626227, -6754731, -14202005, 9589809, 8001416, 16323792, -26428371, 5627506, -166141}, {-21859253, 10600718, 26921550, 4044339, 4505490, 12102917, -13774706, 4209054, 16481168, -6927667}}, + {{55260815, -10410945, 35442582, -7640429, -7395681, -2391876, -47948153, 11525422, 4043023, -7661067}, {8483789, -10513719, 20297604, -3810215, 19151559, 23743620, -3236399, -19713798, 45690193, 9352781}, {-1892598, 8388723, -10847476, 10245778, 23648170, -3843865, -10668156, -14489545, -16648787, 15188601}} + }, + { + {{25506571, 7945237, 41600708, 11844722, 65265347, -17270926, 5047425, -31135447, 60975653, 9157525}, {-15792503, 19784533, -6958908, 5608070, 781171, -11283938, 24272321, 432561, 1613055, -13163005}, {21513897, 9636317, 16941719, -6911072, 6195929, -3671325, 22791277, -14570606, -14700953, -10948616}}, + {{33070143, -10765333, 25103670, -11212169, -12402674, 18423482, 49348287, -5353246, 19708628, 4751521}, {-19124641, 15715391, -21079244, 16965343, 7229218, -2226310, 11745475, -21568376, -4773822, 9908963}, {20883861, -13761293, -1522628, -14785625, -11823055, -5836644, -31702871, 6202713, -14389333, 6429013}}, + {{-11223367, 9697587, -16427304, 4474359, -3392450, 1554389, -59409700, -3167599, -15488847, 8272507}, {-1992285, -11115335, 10389108, -24898801, -63334200, -21692137, 5519670, 16655461, -37762011, -24713223}, {-30140237, -16218231, 12775094, 15125862, 3890378, -3728490, 10472548, 6560970, -21966672, -13082644}}, + {{34168899, -3485811, -28209517, 28775381, 2302824, 8320216, 49024020, 4318521, -5533315, -9380818}, {23647575, -24091067, 4047869, -3725269, -13858824, 20395678, 12041412, -10571409, 56559289, 13382532}, {-14715844, -4451100, -788220, -13945913, 12870848, -3520187, -24568277, 14413924, 31674092, -14163866}}, + {{-8933277, 19450408, -27687797, -25259231, -6301687, 15620015, -62311319, 7352453, -37907278, -9143933}, {-11319961, -5873170, -1989343, -6264895, 7859775, 17647595, -1742729, 14421953, 28821682, 8809}, {23015648, 5308572, -21881258, 14710766, 6858446, 12585267, 30716303, 9314280, -17397279, -9354899}}, + {{-22082137, -7230564, 5140405, -9409185, -10273540, 20543491, -46279432, -7773660, 5107999, -20657602}, {-12411819, -6960452, -53879503, -10241687, -49373306, -4627803, -9618562, -14654672, -46208021, -3117826}, {10393974, 14869052, 19368793, -3280110, -8659708, -15809183, -20313348, 10911522, 27192683, -16200195}}, + {{16349460, -13126197, 13146431, -1111546, 29461269, -12594359, 8895140, -2187638, -9766695, -3297816}, {-17120700, -6995019, 15340103, 12094536, 33467457, 16063025, -35182096, 15999426, -52282685, 20048888}, {3493927, 4160370, 26629316, -12296895, 15033159, 9309960, -32556256, 8393376, 18158430, -4881495}}, + {{-7169172, -3379761, 27359109, -22709263, 11040054, 22141768, 22373571, 269576, 3767580, 13538257}, {47694186, -239293, -23191091, 5600227, -50256446, 867788, 15746955, 20662518, -2343950, 607267}, {-18444565, -9996701, 3087961, -13584228, 4563432, -12519946, -23085936, -15217747, 21879690, 14546420}} + }, + { + {{-5194639, -17405206, 12246799, 9986762, -6317394, -7160137, -58574601, 9056940, 54692645, -16024377}, {-49065489, 7814000, -44469597, 6546786, 11290552, -4685507, -2130541, -6279448, 672321, -2895325}, {-8375034, 10820574, 1172628, 1905088, 15930430, 6361886, -17706862, 3371162, -197968, -8645992}}, + {{-26427495, -22741364, -26845176, -10271264, 18066812, -26723285, 4723313, -7963587, 13780571, -1244501}, {30665383, -5164136, -18325886, 1192976, 17727240, 4673639, 51223995, -14734927, 31296541, -24445765}, {28800614, 7788910, -9626102, -9373933, 18176018, 16434454, 29271334, -11709612, 4676187, -14110139}}, + {{-3947612, -10754833, 27591523, -27467688, 52133421, -8929969, 45487466, 1515672, 43342755, 17872513}, {1280422, -381637, -25447861, -4119862, 12742175, -19779443, -20013910, -27800488, 14275151, -6363545}, {-9479163, -3758477, 11737093, 12702205, -17637712, 10363181, -19355887, -12578140, -9396983, -4776752}}, + {{2096513, -2267196, 11936679, 1782723, 20448771, 11778946, -19475709, -6099403, -43536990, 25367994}, {-34096629, -7171850, -28317139, -28745247, 28947737, -17050368, -19085329, -7896939, 10344190, -253598}, {-31290702, 9800542, 11290998, -9464834, -19598255, -2161841, 12873495, 4689289, 22954164, 13514304}}, + {{-3787120, 3973012, 30558934, -25709373, -61620640, 19443021, 20468873, 15111302, 9225851, -19454170}, {-2748378, -29020866, 4385170, 2185963, -4233858, -8297455, -43689849, 5607494, 39333339, -4273002}, {-22648318, -1360902, 28875203, -15070101, -32848173, -7465791, 13736107, 8320313, 26426802, 2774517}}, + {{-16067241, -2791905, 4046103, 21113860, -17899048, -7267429, -4789130, 4183094, -13998320, -2476735}, {7591683, -17845351, 59286301, -11317040, 23158166, -4217383, -18301942, 27269986, -31214972, 21888213}, {-11165442, -6027294, -24570471, -13115491, -1401089, -16204326, -19616912, -187756, 19605199, 7170146}}, + {{19272481, -13839902, -13039890, 1437516, -10582784, 3982984, -27483243, 7376024, -41926009, 29385359}, {-34790885, 12009258, 28590, 20870862, 25497374, 28724304, -21349539, 483196, -18318997, -1175729}, {9229787, 6165257, -27305092, 8748874, 31704322, 9094389, -20225216, 1016337, 21874897, 5964388}}, + {{47302564, 11715632, 627035, 7025881, 15340764, 10151256, 14562363, -5840511, -22115537, -11899643}, {15477906, -19921498, 16159813, -20825445, 37392754, 11999780, -50034227, 19923643, 13353775, -21373517}, {-3453479, 4121616, 4612837, 14947539, 5028183, -5409464, 19507391, -15370708, 11765359, 7397361}} + }, + { + {{27076818, 4524251, -34226325, -19462953, -28535350, 11770006, -19392859, 29406929, -7191906, 26037625}, {-2677336, 916831, 28740215, -11380649, -23568166, -4562024, 27088031, 2705799, -58172370, 5114555}, {-18501073, -13529826, -5813540, -489954, 9077115, -5099869, 19502351, -11229239, 19357306, -11398725}}, + {{-46911801, 863915, 43881108, -23891609, -26296305, 2968177, 34048949, 4665302, -31275000, -10769706}, {-396939, 24161397, -18867668, -2860891, 32136939, 5313905, 16644033, -1038800, -27250952, 7741148}, {16746505, 12865776, -21968774, -203381, -9105630, 13163165, -32465242, -221738, -33424817, -3062980}}, + {{-8210801, -26209480, -26679135, -15480950, 12303016, -6048446, -3492734, 10531172, -25038375, 23046362}, {42590927, 287556, 17584803, -9046782, -38841108, 5190, 23196008, 19971946, -18424177, -690238}, {-22401260, -6810210, -4122210, -9473286, -18524699, 4687565, 11145141, -11649840, -3844979, -10677206}}, + {{52306617, 12584365, 22664274, -13132153, -14847854, 1983428, 7941050, 1083003, -656554, 15296442}, {14719121, -2093329, 15606776, -8606493, -27328422, -4205130, -26554306, 10329115, 12649024, -9038552}, {-18470727, 2509443, 20553916, -11220716, 1033280, -8460030, 4333659, -242755, -22473618, -15635893}}, + {{14545158, 8832150, 24650238, -10787567, 47634984, -1737658, -7934640, -26997285, 12105430, 8353682}, {-42390788, 14686046, -29717384, -6798805, -12825344, 27213328, -42349040, 5549975, -6549564, -18933724}, {-29829740, -9294276, -29488424, 5325172, -12746994, 14209437, 18113419, -15318009, -32007530, -9731684}}, + {{-7800316, -19075152, -25543723, 4672022, 4948390, 17415014, -28512674, 257557, -14855162, -757655}, {52915554, -4793556, -39212767, -25519070, -7460576, -12082014, -6147096, 22056243, -41293964, -29224299}, {16192336, -4280048, -11362898, -11497151, 21377601, 360081, 6472272, -165764, -2516455, 7287911}}, + {{-1322555, 11190443, 58060280, 7606875, -21936236, -6852947, 56142145, 15639580, 12468310, 8497246}, {37756747, 9685009, 4460566, 5668117, -20704860, -20981389, 5158869, 8983688, 37507162, -16248348}, {24185168, 13891564, 20630317, -9688438, -29541532, 11312669, -33288378, -16739778, -25340631, -7348754}}, + {{-10122935, 12057038, -10118730, -10095215, -31143731, -13646125, -7593764, 29724284, 26550398, 7084395}, {-52212269, 3335262, 38828316, -19665313, 5683557, 19150955, 22359824, -2289626, -13464534, -3115701}, {25567444, 14101706, -29034029, -1802169, 17624061, -10644450, 20839963, -7953766, 308794, 2161336}} + }, + { + {{-53632147, -19297912, 7851043, -19252445, 14673089, -7540948, -5053916, -13567430, 13041628, 2702244}, {3265277, -3169432, -52429811, -9234543, 42224393, -7535492, -10346398, -17435050, 42830034, 26763220}, {-11499612, -407539, -19405702, -3417701, 28667824, -4712709, -16633706, 14287193, 27529852, -14804943}}, + {{-8301357, -14900350, -17375714, -3660324, 47967085, -4543541, -38274004, 3281764, 25894277, -12561246}, {20987349, -16326790, 4110462, -12897112, 2722633, -4901387, 22350170, 6963924, -26307375, -6443544}, {-2563812, 3599819, 18829948, 3183156, -12197117, 5129877, 29150342, -14897435, -19190851, 2122615}}, + {{-16069099, 14771196, -14778229, 15381287, 51127423, -8635291, 27351265, -16501607, 17994466, -16222381}, {794113, 9191748, -15924201, 15412365, -15533765, -21467457, 6308539, 6843923, 47315244, 15799959}, {10088614, 5952697, 27537331, -1544805, 24574773, 13924786, 31119711, 6301629, 10303499, -7287322}}, + {{7075939, 18188428, -40247109, -16502560, -7223662, -25685700, 22637065, 2884203, 9026750, -22469568}, {-49597223, -13630182, -11524239, 9975492, -29541480, -7017266, -36556527, -12297061, -39503516, -10762316}, {-29976429, 7980108, -18082939, 9182347, -33445980, -10362838, -17271146, -11680127, 4699758, -16708223}}, + {{25341363, 11776665, 31744444, -11419676, 243644, -25427420, 31957294, 8004336, 4446158, 9676944}, {9159503, 19691573, 7788124, -9120656, -41866304, -473450, -22633936, 12391048, 9397710, -14761412}, {2176050, 3093922, 28099816, -4056095, 30379992, -12625193, 25514304, 11141377, 9537024, -11749925}}, + {{11874013, 6619415, -45978048, 19241982, 34593233, 11566782, 18188546, -1365421, 17464619, -4714579}, {28186675, 18734191, 11704546, 5057494, -5844419, 7578296, -2670132, 21398537, -25437539, -2813399}, {-29773614, 7521501, -13581548, 10189780, 10221976, -9641327, -20027861, -16116914, 17230353, 1768638}}, + {{-3254002, 17609610, 23438741, 10401967, -29386498, 15470644, -36983910, -13296870, 13417255, -1309952}, {-25997506, -15766158, -3848077, -16853213, 30112220, 4704934, 19839126, -815994, 42172439, -16667738}, {31601561, 4387898, 19403396, -8066749, 1731270, 13103102, 9654742, 13702377, -18212837, 9952789}}, + {{-44139895, -15956322, -1957914, -2500572, 4566616, 10111288, 28971372, 2891716, 23352576, 3717199}, {-10910821, 1666028, -31990134, 3797314, 47243712, 16585440, -9724960, 11409606, 18148620, 15664225}, {21172951, -8001181, 23183655, 432573, 30241199, 4892338, -28903830, 8610070, -7562878, -3980656}} + }, + { + {{-11816810, -19915072, 37188575, 6470387, -31312211, 13246135, 20092706, -7506079, -15718424, 715126}, {24022790, 1956096, 8841263, -18290443, -31127755, 16005317, 40649566, -2905019, -34241314, 20967056}, {13055553, 8117336, 18719627, -10365508, 18397015, 14640603, 17467129, -1986190, -320941, 8361948}}, + {{-14521183, -23769948, 21191246, 12247482, -3562472, 2707409, 10434951, -16936371, 5782639, 25639197}, {-51048857, 8631686, 32411618, -17284250, -3407982, -14563907, 32796079, -7019501, 52589169, 5372049}, {-32250310, -9817791, -32637302, 3725332, 28293155, -9050488, 20728637, -10324377, 27717987, 16267042}}, + {{32023888, -783150, 4785230, -17138565, -39648428, -31034576, -40383990, -3634561, -25769739, 7689973}, {6912362, -7909410, 4303540, 966043, -6096238, 33366, -3787830, -3292555, -1326115, 8539691}, {1381231, -696710, 15240934, -6947313, 25439302, 7832102, 11958236, 9121109, 32276529, 9721629}}, + {{15611385, 10451860, 7671020, 14013035, 16120236, 7361510, -4011236, -6487063, 17796936, -3693871}, {-39353005, 13952346, -47949076, -14003915, 4003532, 22499616, -33360884, 20534449, -2972380, -14582167}, {-29390304, -14549954, 30381525, 12364253, -23605127, 6869491, -17326770, 979791, 30841144, 16060616}}, + {{4080064, -12497594, -44198573, -8081902, 14616558, -7768002, -41675050, -8377750, -29772327, 4705291}, {48835856, 9779674, -15927079, -14998518, -41701442, -14682958, -24688548, 12322916, -16759627, 4709337}, {6589560, 6227897, -23163418, -8970289, -12171602, -2919728, -29547009, -1785520, 27672278, 3650290}}, + {{-22091384, -3625527, 32715760, 3651334, -58539472, -7090241, -16937807, 3169616, -24203624, -28036760}, {10376200, -24403595, 21025242, 14294718, -6449086, 585479, -41405829, -21889836, -36418472, -4899164}, {-7327120, 14833697, -30806744, -9850547, 26681265, -3568703, -16608041, 3541556, -2412469, -1012658}}, + {{-32676245, -23992860, -32952502, 1989465, 3238914, -2336243, -16914311, -15838377, -6014409, -16522751}, {-5851991, -5958798, 2445376, 28237383, 60531312, 638899, -291729, -8874337, -26232113, -3597917}, {-28173937, 15302781, 26271996, 203601, -22845788, -3307013, -18135061, -15871767, -18926213, -13496340}}, + {{-52426849, 21754560, 10090652, 5337450, -15538526, 1801084, 45714336, -17116940, -58319637, 20128327}, {413919, 5706932, 11535956, 4627188, -40617692, -31734786, 10899228, 5962722, 1024087, 8194973}, {18337047, -7284893, 7491958, 10525473, 31961567, -1678768, -1547025, 14371604, -22744796, 4698159}} + }, + { + {{43351150, -588882, -36366579, -26056933, -9619574, 6925998, 31478572, 2692096, 24354711, 2682425}, {20923520, -24204434, 21893893, -5408851, 12914668, -16049166, -6993296, -21602360, 469807, 26686163}, {9339777, -8207030, 4314230, 9570787, -3516856, -4024696, 33090081, -12756335, -30468354, 13396906}}, + {{9203288, 23961019, -26767913, 5516456, 25105329, -18076407, 63608830, 4060334, -15052739, 13229365}, {-1348838, -3556357, 10475321, 25265070, -33254321, -11599699, 2857072, 23309682, 22732619, -15901463}, {-32525251, 12169067, 29336863, 4101986, 2151670, 16052581, 22276645, -11493640, 12676394, 10258694}}, + {{-17554809, -13787712, -11025142, 14876753, -40118174, 18974318, -21578599, 6796514, -4053262, 8677611}, {48568723, -32020, -35620496, -11274647, 19006276, -1767732, 7662943, 4925442, 56424884, -22047261}, {29743608, -7733462, -12177671, -5865054, -12183413, 13583398, 10721348, 2811407, 1213662, 9131075}}, + {{-23816021, -8048064, 7868206, 26337902, 19324726, -1399859, 9702712, 19484799, 46764827, 17231076}, {-38024843, -7221068, 49939882, -5860408, 3327122, -16446701, 21964702, 6789343, -19098923, 4737778}, {29374697, 11481730, -32802579, -4503681, 27181806, 10360625, 1447634, -472403, -20234666, 10334446}}, + {{41668297, 10359775, 8669632, -6178194, -21825744, 11802716, 24802855, 3427172, -25778662, 350618}, {1230315, 22325029, 7807580, -1823752, 10186616, -20560370, -28424085, -19670254, 38957216, 2824804}, {-7886425, 6499919, -23283594, 12359535, 965805, -10236454, -32549462, 12052952, -3758080, -2471270}}, + {{-5547854, 19784999, -35447435, 20553317, -17701114, -13187984, 38467376, 1171395, 9365841, -7062164}, {-56513536, 9696009, -20127221, 972081, -14231294, 8821764, 17262234, -6139307, 51949033, -9436610}, {-4687806, 5999100, 25178467, 14797599, 6952404, 4546284, -15627092, 5991648, 219807, 16032050}}, + {{-1047468, -7243345, 47365456, 23365970, -35553916, -18767485, -25391721, -13883062, -53555913, -9484644}, {20495300, -23001887, 3392056, -2125134, -14556524, -709017, -21609347, -11561124, 349451, 1294384}, {7676867, 1006260, -3758076, 6765762, 28290455, 13072227, -11609734, 3166723, -674222, -1134818}}, + {{-14972664, 17633897, 1692511, 185566, -21244527, 25518826, 7394720, 4751801, 29267882, 19972782}, {3928634, 14533081, -24038345, -17238092, 40171657, 1175224, 35340550, 22960517, -20135988, -5866276}, {3652859, -1778288, -33487780, 243434, -4743221, 7049705, 3082275, -16457788, -18804698, -7144338}} + }, + { + {{55331044, -1420309, 4435479, 880031, 31089417, 5467239, 54079640, 27991572, -28455899, 7854713}, {-4121464, -21536325, -48237411, 29665535, -14298975, 18917965, 6477192, -4128210, 3344415, 13060395}, {20285583, -1135092, -24544630, -5255955, -25710050, 9403569, 25174527, 495402, -32916698, -3009540}}, + {{-3153458, 11796963, -15716455, -16741866, -17429005, -7030645, -12176607, 276827, -411254, -5332283}, {-36493560, -11175759, -37255759, 8658492, -17112879, 18763657, -28083777, 5905875, 3154188, 609487}, {12273567, 15749129, -7429755, 14903661, -301173, 865323, 6457533, 6428510, -5953631, 6259914}}, + {{18617203, 8815703, -12153981, -9554751, 34912102, 11514624, 758291, 10163248, -11418724, -12025821}, {-26115019, 22708635, 2086307, -8941743, -2498150, 5363060, 39909701, -20358666, -29782214, 6119971}, {-752715, -12596371, -56598, -9459133, -22132101, -5358562, -19423309, 11966194, -18210258, 5690985}}, + {{-26520151, -29215183, -2253624, -3348221, -54325373, -27573751, 10957145, -25991202, 7653165, -15497401}, {34099361, 967115, 58612226, 24239965, -893363, 2849437, -25248007, 3763624, -27612985, 11542815}, {-20772267, 14145173, 5282971, -8812179, -7078260, 8921497, 11940792, 10279761, -19464323, -8010440}}, + {{25813128, 16480356, 22679498, -16049051, -26598203, 27580462, 34953514, 5601637, -44501, -11843411}, {-24733698, -1961384, 15201966, 13112221, 38209529, 4157132, -19844052, 9816241, -45732865, 1367475}, {19351532, 2382159, 27418270, 4524477, 2503389, 10539383, 7846614, -5738295, -32795192, -10752993}}, + {{11520857, -13340536, 15491968, 26289791, -6372351, -3173916, -37363664, 3995146, 15417852, 1129412}, {-4305067, -6282000, -31514358, -602935, 18198007, 4142140, 8691400, -21592724, -32500830, -24545160}, {31712935, 3292838, 8835775, 6582377, 14669388, -16006981, 7471269, -4726128, 17614270, -9248409}}, + {{-25775103, 249526, 18505028, 25688636, 8967600, -27361044, 20105651, 16235853, -7335341, 7387083}, {-10584561, 5040868, -13182150, 2344132, 25998968, 282136, 28758755, 15095675, 8647171, 12932595}, {3950884, 384926, 10816601, -3063259, -4401418, 10769962, -28456035, 11676938, -25115260, -6146523}}, + {{-6677137, 12328716, -16678017, -2379406, -29707775, 8666753, 6060062, 4945120, -24351387, 6195581}, {-57759185, -9754408, 26491971, -8899700, 16611093, 10609973, 25225046, 13811756, -14235955, 16118427}, {-33021547, 10353715, -30309957, 13458071, 29472936, -1856233, -18910184, -15721056, -11724525, 1838630}} + }, + { + {{-12779114, 17814598, 9239159, -3170050, 14621128, -2679121, 5908225, -10464729, 4260814, -10774047}, {1889722, 14432906, 7229891, -17837374, -35444232, 30144593, 35835389, 20676355, 4715542, 8290169}, {29833003, -7400284, -8366833, 766560, -2543398, 3834907, 24315777, -2101078, -1435092, -2602241}}, + {{-13682017, 19857047, 6817675, 13785135, 4367821, -1040013, 535585, -5601948, 48929678, -3956130}, {-25745197, -4229737, -27877193, 5257331, -59618795, 11766533, -14198617, -8883652, -14726808, 1267258}, {-26727260, 9005423, 31812111, 8781886, -18526320, -7055834, -18816509, 5439406, 29536692, 9974094}}, + {{-21267201, 18105230, 1083455, 16094635, 27393470, 7683511, 33072266, -2369824, -27676569, -19852422}, {14754309, -4117502, -1777927, 8089063, 2108552, -19123433, -23738930, 22149874, -4630903, 265854}, {-4889417, 12389622, -23363648, -3918822, 26063762, -5273380, -9616626, 11353698, 21231496, 6111283}}, + {{27797966, 19826492, -10461777, -4091506, 52836276, 14186155, -24277031, -17159288, 26299275, -4668060}, {-31605914, 12637110, 47660677, -13376080, 13010250, -7889567, 24028743, -1663304, 36064107, -7118774}, {-25005770, -3561701, 26194375, -967881, -1382406, 2544746, -30285897, -12719084, 31220348, -5596773}}, + {{-10467, 22955672, 3411582, 2704035, -1351543, -13479051, -35912531, 8562645, 2597061, -676511}, {53760723, 596788, 4630358, 20615363, 7523231, -6986771, -6767329, -20320143, -49467619, -25896591}, {-17790000, -9956849, -1824537, 6140131, -8411040, 12088420, -16159680, -13117618, -14291890, -12872811}}, + {{17995859, 22254211, -54008885, -11288046, -8815298, -9819763, -11675856, 21929989, 8303064, 5889278}, {48546871, 2485065, 7920073, 8942916, 22525378, -9888759, 7660488, -995037, -6845272, 22512440}, {-28333343, -500191, 21873009, -3807879, -20817827, 6650332, -32238067, 5789174, 6554628, -1701304}}, + {{-2051226, 5442098, 46135450, 1835909, -14243459, -21188523, 23811933, 28086848, -21490573, -9636746}, {-38839776, 8066970, -15057216, -24537195, 32155947, -3789769, 30490089, 875290, 22694133, 22235590}, {19095043, 16671712, 31277513, -11165139, -7692084, 10667847, -31097462, 4723628, -29147100, -9587365}}, + {{-15119167, 8814272, -5174893, 26643847, 36097719, -12590537, -45059703, -2666881, 28587804, -7335038}, {-16289069, -4962940, 10285903, 5254617, -10257473, -8946379, 3335545, -28042491, 6431198, -10650104}, {30038894, 7725118, 2808985, 10736215, 15023633, -9406449, 10497389, 12045126, -27094617, -7548629}} + }, + { + {{14918785, 18024772, -4722298, -4424152, -6076214, 2304917, -1706576, 1208063, 21016376, -18211117}, {-17327411, 14808258, -30060848, -7069016, 53967720, -19620835, 63589680, 1112827, -9712322, 6550357}, {-1723307, -11804555, -8589229, -12134750, -28201370, -8188855, 15157936, 8755658, 4195758, 12686901}}, + {{20914772, 9115799, -22056090, -5818874, 26663128, -18071637, -4934263, 5199490, 19322986, 17648253}, {19856262, -17965947, 25643562, 7863524, 6595748, 1288697, -57895535, -25350548, -39344646, 843711}, {-9420126, -15553069, 2424906, -10198389, 19420543, 1033386, 29818850, -8136028, 11164437, -1236018}}, + {{-33498136, -21636094, 7616807, 11089259, 40667805, -8362729, 64000, -15648705, -3125491, -6908722}, {31362760, -11080620, -45897793, -17501295, -6431949, 11603447, 3359312, -8832559, 16344239, 6756022}, {-19871429, 11694145, -32861505, -13666198, 12591691, 2861761, 25663027, 16736068, -12965933, 13879093}}, + {{51027461, -11163235, 16469464, 6657424, -20311839, -6717721, 21748092, 20378605, -28072861, -1110054}, {8460111, 13797263, -30167508, 3847426, 5683747, 16866133, 19569376, 4930909, -17835641, -28075440}, {13558742, 16398711, 4344721, -14106344, -7583263, 12087066, 32447873, -12969717, -967399, -13532136}}, + {{12074185, 7881773, 26469634, 2638374, 12839268, -8384330, 7629071, 8732121, -35756987, 659600}, {42181985, 8960393, -3534036, -19125798, -34219226, -8021704, -58068487, -19679081, 888127, 6105738}, {-2756963, 13596323, 25849130, -3226454, -2209421, 263891, 12153527, 11673404, 2839249, -12420891}}, + {{24795253, -25810134, 34311448, -64578, 19467911, 25523867, 6824412, -19014212, -18028036, -1244695}, {-18626657, -6609900, -28261860, 19242644, 31222285, 3097585, 52859228, -12713832, -17247356, -25502553}, {-30585191, 14658695, 32758140, 5017987, -19319587, 4147693, 16328924, 11544909, 31354105, -10014276}}, + {{-35899892, -3360190, -1409677, 1927137, -40801073, -19297291, 5204966, -1571298, -13085851, 19409965}, {-8680608, 25637368, 16526103, 31471237, 8496117, 3137959, -15456740, 14460736, -46852731, -6883247}, {1073308, -14496333, -29239477, -16342522, -192958, -6688842, -6293045, -7109357, -2298146, -14025476}}, + {{-15182674, 2513800, 4912099, -21331461, 63424337, -29130680, -41842028, -12762921, 15037127, -20913842}, {-18270498, 30316820, -26347623, 2496021, -2661307, 1918928, -23230248, 14368073, 46305879, 8375506}, {10274789, 14728503, 32886420, -14214374, -24656508, -12470783, 994457, 6486555, 31976259, -2064185}} + }, + { + {{9990203, -5967259, -30332837, 1055274, -18783335, -12780352, -21409809, 6219889, -39376677, -20652491}, {30876017, -20522249, 22246067, -8056110, -21244829, 1336982, -36898153, -9493909, -15913415, 3256617}, {23859788, -4043697, -16223224, -6754761, 9896599, -14885134, 31298122, -16340146, -12250956, -5305952}}, + {{-53319311, 3106654, 8721301, -11395142, 13140040, -9129418, -15357883, 7203076, -38674320, 13888072}, {12605857, -13192576, -49237133, 8613668, -36140560, -7851688, 15805915, -4180380, -997028, 10789668}, {-5297326, -5777508, 23302902, 14842703, -12562807, 11020072, 2987886, -15082645, 29774821, 6247520}}, + {{-37564715, -9016525, 13794389, -18536733, -1032967, 10506215, -9922525, -14568811, 41830860, 12975603}, {-21916819, 15871973, -6306461, 14798307, -62193347, 1770329, -20035489, 13914217, -799588, -8987421}, {651070, 6371430, 29015104, -12763830, -30584778, -543170, 22140204, -9608478, -30165575, 6322648}}, + {{-25144413, 520510, -3729071, -23346798, -8240287, 3991741, -7330644, 8639522, -21362215, 919329}, {-10483395, 31191720, -62299449, -561558, 13189023, 3120357, 27786486, -22321778, 43469341, -17397899}, {-25322560, -2061845, 367197, -11394346, 20390480, 11750136, -14206323, -9047122, 31199947, -16650219}}, + {{-41299908, -12790343, -28239884, 12445701, -20762490, -32194987, -31455913, 4740323, -17248352, 2771031}, {16221936, 14750765, 35569402, 4954223, -12518312, 253349, 18576205, -2779111, -34541718, 25337427}, {-7973759, -5847015, 25455621, -3879582, 5139126, -6373795, -15407115, 13219501, 13308272, -11727506}}, + {{-45941112, -3476303, -12717164, 27994331, 40824020, 14135375, 37778174, -2091169, 35585628, -3824899}, {19724364, 3721529, -21562592, 3959139, 18430156, 5219205, -842232, -22301357, -27212694, -7721703}, {15652879, -1922681, -26056293, -13276870, 25823596, 1502634, -26171908, -5297454, -17206011, 1798182}}, + {{25513553, 9228159, -41225286, 1075272, 27566243, 26740475, 847083, 12721834, -23652663, -21583787}, {34329181, -3898851, -4680698, -21651996, 30934081, -2986925, 56667207, -13616386, -11872671, -6419859}, {27711615, -2610993, -29650256, 479315, 18032972, 8495595, 11809682, 10764680, 16163597, 11782681}}, + {{-1080167, 20913279, 11222009, 5231033, 19586685, -19081404, -25560724, 3060413, 9369581, -21037334}, {-55853605, -604871, -30586595, 11184291, -44377297, -12410506, 546040, 20831127, 54768427, -2020408}, {25111202, 4937874, -19359157, -10888901, 52262, -4871270, 6947793, -7167452, -2708633, -13933048}} + }, + { + {{-37490698, -1044014, 13172992, -15792835, -29278609, -21703359, 17587066, 13822930, -25063775, -5408585}, {-14506614, -4554562, -24975322, -15121369, 31918211, -2815099, 9245590, -10494948, -32218177, -20194407}, {33095577, 10772817, -30109058, 3735455, -903060, 11779796, -22276963, 5647339, -19898785, -2427259}}, + {{-35567230, -8298746, -30427298, -2008615, 6578320, -28333482, 4647843, -7203744, 21410852, 4935677}, {19449456, -12021944, 26998278, -20985261, -10001164, -3849334, -42124703, 22950244, -43841566, -2386869}, {6188251, -16387018, -26256516, 11523151, -27111541, -14694407, -30832690, 2347978, -9338022, -15708579}}, + {{15434287, 6643431, 23435499, 578214, 1545961, 6256578, 29410474, 5645137, 7298830, -1190423}, {-49873669, 6172407, -2815369, -13320018, 17718471, -6647968, 35792074, 26128923, 14935630, -3855593}, {-6561401, 6082764, 10619558, -12080069, 3736379, 8205603, 7726617, 15485177, 26425072, 5964669}}, + {{-19009143, 11144788, -26170506, -7469698, -12042595, 6769324, -46424487, 7188576, -54190, 13467043}, {14833485, 15106902, 39786628, 9576478, 7682467, 12427144, 18962549, 21453064, 46849696, 8135823}, {27102186, 4002428, 3820464, 8059627, 9296768, -16573407, 29427330, 6056765, 31299382, 11434844}}, + {{10147554, -3304203, -31566020, 7455365, 9054617, -7026253, -26004212, 9417844, 33148937, 5567818}, {-30957680, -15079499, 12503190, 12210223, 12492353, -13255867, 16087858, -1724966, 29065181, -16903384}, {-8689265, 16342304, -29112667, -13948144, 2271372, 13680506, -20647317, 11265632, -6271831, -13550605}}, + {{-43981712, 3667339, -5774353, -4127724, 49033143, -20763656, -4362649, -5585012, -6097844, 23047690}, {18241914, 18780295, 17835175, 23839864, 10367743, -7932052, -17351125, -10024804, -41459272, -8899310}, {-26184270, -13291747, -23818836, 9003362, -13056713, 1731343, 17126866, -15849032, -7620786, -15197126}}, + {{35225841, -17608455, 52560174, -14493248, -3202298, 12453088, -19300486, -146725, -3685468, 12252323}, {25224829, -5151489, -553432, -6461064, 803174, -6826920, 12356718, -14804525, 21520816, -19497989}, {31581702, 13887699, -11113271, -3509799, -29892103, -1339694, -23766891, -4379212, -27361250, 6521470}}, + {{25689009, 1301840, -32432264, 2041722, -9292384, -11455248, 16822275, -12529983, -25278496, 11030628}, {39827663, -23485080, 10195846, -28093486, 39482802, 21857762, 13689719, 16786591, -13165936, 10604194}, {-24235173, 6299697, 17500880, -4675077, -15297533, 1159291, -31114335, 4151979, 4511865, -337858}} + }, + { + {{-28331035, -932771, 25317856, 18389196, -1654470, -18747303, 20165848, 25259009, 40793161, 8387571}, {-31555707, 70687, -29207696, 12039632, 4692468, 10360981, -35700940, 5605229, -6454753, 10933815}, {-4039096, 13783539, 32581867, 8360647, -4024823, -13078472, -25287757, 8105424, 18055378, 15459087}}, + {{-31034575, -8782829, 4438967, 3487891, -3842866, 73696, -20992160, -632729, 40548482, -3821511}, {20154487, -12110395, 25790203, -14732921, 50263830, 17079256, 16189826, -24550693, -11591350, -27192289}, {-26957121, -232995, -25926181, -8068404, 28968615, 8439329, 4177301, 14600993, -12309690, -7683509}}, + {{15113767, -20210410, 9862332, -24270992, 6750959, -15722016, 57587876, -8785178, -14388356, 22486190}, {16294061, -10374390, -13940832, 5386570, 22589699, 14408744, 8621304, -7678460, -27908864, -1454410}, {-17932180, -11489769, 24239088, 7432798, 26783544, 13155981, -5946726, -1824310, 20243099, -16583330}}, + {{-5341368, 4089037, 13994677, -2321488, -25886605, 1955838, -17713115, 10096472, 22063283, -20840893}, {43013314, 10849261, -49484229, -12925370, -18395631, -3755188, -9363551, 20854856, 11741859, 10408771}, {-15708765, -13112700, 9648732, -5986263, 11569212, -979061, 16059478, 11274274, 22182219, -14445752}}, + {{54036905, 4378170, 4458469, 1068139, 33946900, -6741746, -29127999, -4191304, -33312792, -4447126}, {-11572087, -24675294, 42086451, 15598001, 26972182, 6198910, 22922963, -8631160, -22811142, 24506016}, {-3691007, -5680657, -4814481, 6540764, -29270991, 13196195, -662301, -7429681, 29699892, 11841653}}, + {{-35195742, 1316948, 19158145, -14467042, 15561375, 21590178, 6585959, -9918082, -29668441, -25037241}, {-16843434, -26783648, 18148929, 5763658, 23408021, 5201398, 24855689, 2985416, 36007991, -8323065}, {-26289045, 5805905, -297042, -2018399, -2687990, 1174877, -20931135, -12873489, -11140391, -13339997}}, + {{-4693919, -7359640, 3999575, -4185824, -28261425, -11290306, 57089848, -24004471, 6955189, 7297210}, {-27387317, 4854504, 63054037, -4958334, 17673385, -15681226, 507320, 2150569, -15708635, -10900332}, {19256573, -14400625, 9588188, -16152506, -13220658, 2766395, 15435464, 12740678, 4188656, -25347}}, + {{62186136, 8388256, -1011792, -2221534, 61444893, 4236051, -3754780, -9218215, 30908178, 342327}, {2923566, 16397468, 58662336, 16605610, -3674617, 561073, -53256148, -7100625, 18583054, 14876091}, {9460626, -5314354, -12636528, 13071581, 29516597, 16199649, 12119025, 7338875, -28755942, -8966924}} + }, + { + {{11511840, -1665259, -19136370, 6532560, 54685096, 5713989, -14697619, -4366344, -32184502, -21914214}, {1771640, -30141505, -20388968, -23647180, -423212, 23744461, -22796913, 17113446, 29916502, -5848786}, {15791191, -2109811, 14327684, 8764175, -17786032, -10430002, 4964801, -13412377, -26772786, 7688229}}, + {{-7902173, -6019250, 40686331, -24334672, -29056443, 6966900, -36105368, -28821420, 34143326, -15682381}, {-38263067, 13050516, 19137267, 6754728, 23211307, 25975088, 27086126, -2207410, 14310880, -13075993}, {-26941894, 8202847, -18600854, 921448, 11680995, -4671504, -27324300, -4380528, 23083931, -15469828}}, + {{-43940803, 6112622, -55306089, 11959216, 1735450, 6341156, 37310734, 26669520, 7354935, -9435487}, {-9665877, 17972374, 1946167, 16787448, 1956736, -694100, -6947230, -380162, 19480077, 5882021}, {7490942, -10521386, 19442185, -7215960, -14036843, -11619923, 25178526, -9062626, -24632881, 10852529}}, + {{-26492998, 11342117, 28884660, -8177643, 3439950, -12251595, -959766, 15748278, -8223278, 3943321}, {-18038654, 6403417, -34265994, -18153447, -61286870, 3856099, 11140474, 7165146, 27891324, -12776499}, {4577308, -15878030, -3903294, -7330277, 22428625, -6625135, 20662741, -2434892, -27534336, 4208334}}, + {{27688057, -5060984, 44641245, -6577389, 49639352, -2511484, 25822546, 17766635, -9184372, -8105914}, {29700193, 27440946, 8555541, -26919561, -1082862, -3528740, -28694946, -135249, 46942038, 8495726}, {-16920911, -8666716, 21343143, 12774679, -13739185, -12807704, 11544306, -10114116, -4880213, 9344665}}, + {{25176266, -6433898, 27677827, 313210, -16240450, -7181904, 30164031, -12338723, 5393388, -8005398}, {-28318212, -25699654, -24936345, 26738450, 37211692, 11983534, -22679709, 17739395, -14774276, 7537428}, {15535300, 7022682, -20799105, -7889266, 12927080, 3712147, -31972106, -10255157, -16621777, -11151260}}, + {{-24410108, 3479459, -41589759, -4447761, -18568451, 22663701, 32748895, 11115308, -12284407, -15389900}, {-6760606, -19837809, -19530593, 14152921, 35427657, -5027879, -15474589, 6745428, -14443949, -5772916}, {-15250650, -12583248, -28636511, 546259, -12004342, 15967832, -23455893, 2920967, -22538806, 5055360}}, + {{-2219393, 3321283, 8170070, -8617562, -20147954, -9278498, 35722589, -14081358, -19999667, 8982741}, {-33763235, -23843485, 221098, 15173648, 2296064, -7218468, 13278565, -6586432, -597671, 1120995}, {-27539003, 1778274, -22789481, -3688017, 14635861, 9115454, 12318310, -709741, -28204433, -16352670}} + }, + { + {{25257545, 11533366, 25218272, -2494770, 18802692, -2363380, -26097661, 14576356, -38512485, -5187941}, {-30381359, -20830496, 27741414, -28574206, -41514748, 4998680, 36635147, -15195432, -27578093, 9305681}, {16606172, 11705746, -14147913, -8770685, 31186589, -8644456, 31402982, 9388599, -26387100, 5576153}}, + {{-6148291, -11616611, -2001017, 4460180, -46961444, -993243, -17399939, -2775375, -19302330, -8036435}, {49979399, 14878019, 57820349, -6099824, 2891926, 12054841, -21659107, -24212901, -14593944, 10783693}, {-24091814, 12985630, 11144932, -1429148, 14875805, -2078873, -10111610, -7702914, 10846607, 13747257}}, + {{36911364, 10948579, -28413656, 24143747, 4515461, -3960858, -2348996, 27345124, 10316530, -24949901}, {-21692652, -22405245, -17453212, 8169457, -16515159, 12190660, 39981308, 3609692, 17157480, 3121209}, {6077504, 14029113, 4337395, 1306459, 9684798, 15918966, -3244009, -4229876, 21040785, -10798988}}, + {{7668306, -19090854, -5293078, -22956488, -38340520, -16339453, -34484174, 28548090, 31375307, 8091612}, {-51989388, -5808618, 3622130, 9231498, 8844936, -9458099, 13324236, 1509330, -30007183, 18296042}, {8831229, 2675955, -24740796, 1567748, 11964637, -4511275, 922779, 11925288, -23562635, -13199293}}, + {{-8459824, 17776744, -16794531, -1634377, 11496794, -17660299, 14450538, 23701697, 38902693, 26600308}, {21667500, -11524526, -34133815, 1769437, -17166618, 2763111, -10753286, -4172125, -18096967, 5418248}, {-12178112, -4909537, 25582507, 4680118, 7059472, -11280879, -9003908, 8866899, 13329639, 4238169}}, + {{42443042, 6292956, -2084303, -11763676, 24975474, 11368292, -30898668, 5572274, -45565766, 9398246}, {22723190, 312074, -17099501, 16350856, 8515958, 20547652, 8807846, 2765002, 15999424, -4068078}, {-30614567, -11470659, -19762629, 7071817, -24095797, -13388644, 29419234, -5810613, -20924314, 3837380}}, + {{-22469114, -19139340, -20702469, -14754774, -5718158, 18391345, -6231317, -8141877, -15897665, -18559777}, {-41031938, 10389662, -41776673, 3185884, 42439276, 6033273, -58815329, 683441, 7702333, 11399897}, {-21367884, -6025163, -12057795, -13996675, -27339696, -14111499, -31851211, -8971979, 26601810, 6660546}}, + {{-5232669, 15939098, -2119211, 842888, 16119703, -9667841, -4642603, 9814654, 32706526, -858959}, {-59608155, 3697050, 45791883, 2064118, 35254379, 19455477, 45614343, -18331084, 19371274, 25640931}, {-28281021, -1101796, 24885422, -15255417, -5592209, 10253751, -22422564, -8414043, -27911262, -10623034}} + }, + { + {{-55057202, 6378825, 19631718, 756405, -34988934, 4516814, -16435470, -4930571, 30624761, 20330609}, {-8208226, -14288525, 38404288, 8942131, -25299612, -25976524, 43933580, -7922601, -31050791, -10908951}, {8786645, -15297829, -12483842, 2869450, -9683319, -4239050, -30933725, 1062188, 27143818, 5886214}}, + {{-26737082, -1899955, -367625, 27274173, -8454719, -11179265, 13427152, 18642181, 47786141, -2273639}, {19969048, -19849713, 46685033, 3293785, -14767899, -1216797, 37244964, -3381615, -9556757, -24219143}, {-27567744, 9961330, -3088138, -13054108, 14790952, 3220167, 11478440, 8221775, 14761946, -6757723}}, + {{11826681, 352716, 23222433, -15455054, 42599497, 10063600, 23755789, -17252467, 21355038, -8827818}, {21775839, -15993184, 36435609, 3291826, -7381825, 16933248, -39535739, -8709807, -45486390, -14515174}, {30205341, -9479593, 2037871, -16638944, -2228154, 15931842, -4436386, 8631014, 6187979, 108908}}, + {{42318821, 19249862, 16194985, 2121230, -14990441, -12137969, 15615270, -2683529, -13323686, -16340510}, {13992761, -829274, 8933097, 4520642, 29444599, 3475757, -49197208, -26194147, -38686216, 14181818}, {-23798899, 2330895, -4652825, 14830432, -25678753, 7862970, 32146306, 149740, -20686016, -2171183}}, + {{13228166, 8683127, 29199684, 5702426, 44442457, 1826412, 28424691, -25618736, -4207569, 5199421}, {-22335274, 23961463, 4370798, -2889588, -17790505, -27266890, -34418235, -1614424, -49498341, -15752993}, {-31492371, 5156621, -6391078, 8593133, 24504251, -10312562, 563525, 5921880, -728680, 9599279}}, + {{21416355, 22195779, 16210636, 17033980, 24374302, -18731958, -3027469, 23784111, -45806750, -11451168}, {45145735, 11149429, -6951660, 14464006, 9971454, -379628, 42374839, -3726251, -16347552, 14823674}, {11795482, -1089103, -29916118, -11131363, -31036091, 10270300, -6711465, 11097938, -4371724, 5871181}}, + {{-11214574, 16908005, -12291457, -9603906, -1652526, 28466696, -9044973, 6916569, -6520907, -10285873}, {7762316, -3647905, 26127669, 7573394, -14182596, 1930208, -40489431, -785703, -48431371, -22612509}, {15935391, 2290505, 22952617, -12403000, -10101040, 8832520, 387081, 12538506, 31956379, -14946003}}, + {{-7686129, 137205, -4370712, -8918193, -4290947, 9475151, -20484825, -8423193, -33056437, -2554745}, {23723239, -29344125, -62499762, 5718101, 21573291, -4261653, -24657439, 19863043, 29031919, -25727007}, {-28374288, 8875243, -23132911, -2298412, -19931997, 593979, -7405445, 11680489, 13236130, 14839068}} + }, + { + {{-987051, 5562425, -11800666, -22103535, 8673924, 9678683, -14053355, 32972854, -34158331, -3338884}, {-34388941, -17948089, -52721330, -3615805, -51554588, -18737381, -50727173, 377542, -28652825, 19619218}, {11300961, 897205, 5130351, 13808650, -28542799, -10549305, 16340952, 6714098, -10660298, -2170878}}, + {{5790482, 6491469, -1330045, -14939952, 53564095, 5240620, -19790260, 969656, 16860529, -8405479}, {-20560616, -3707443, 53641243, -8691694, -748775, -25868396, 20842640, 21529108, -21913019, -9631965}, {18284543, 637113, 33128611, -13266843, -29697975, -7329960, 5200253, -11890204, -4071145, -1028192}}, + {{17888677, 20530997, 22220029, -18276070, 1663089, 3318263, -35915575, 29684594, 15354062, 10216201}, {-24491755, 9458137, -23127177, -13623564, -50085809, -23123747, -4156083, -3107162, -38248080, -5679355}, {-7819256, -10810159, -24715405, -11711408, 17617655, 2047218, -4024978, -15281372, -32865239, 4373586}}, + {{-51344261, -5158703, -7793863, -18441242, 9734330, 21318358, -46581642, 11058039, -54707399, 19439764}, {-3382543, 22542463, -50416971, -3924910, -6465114, -931770, -5429136, -21875927, -8590093, -11902142}, {-31960433, 9373829, -14915278, 14819514, 8095096, 6833029, 12171935, 8564995, 32065227, -11120642}}, + {{-16515561, -13196709, 27138445, 404024, 19894347, -3954293, 5339438, -9746382, -6588923, 6843627}, {30249921, -4130527, 31556997, 6593292, 6593869, -19282455, -26052504, 22029184, 5569383, -13916983}, {13674504, -14033856, -24276015, 4706385, -25265137, 2200830, -21480691, 4602582, 21098137, 701605}}, + {{21847532, 12175368, -12371944, -8104195, -25736914, 31845971, -60634207, -24155009, 12393531, -2287134}, {37929796, 8543650, -39600578, -10358787, -20684020, 1053969, -2757197, -5879487, 39244193, 5946608}, {8484480, -5939254, 14313729, 12410469, -20549288, 14398210, 18548293, 7100757, 2495604, 10724295}}, + {{16926943, 9336241, -2438882, 4471603, 20510598, -8651640, -11418532, -13753237, 28597327, -7267630}, {-16010267, -12762075, -18689898, 17857223, 12591056, 11098402, -48288252, 5804891, -3723889, 4365132}, {13764499, -8280239, -24942451, 4889060, -19904099, 727785, 4209862, -15163390, -7325828, 8495506}}, + {{29407842, 11465377, 37317837, 4655927, -30071787, -8993417, 11865876, -11075201, 16714864, 9510229}, {26949728, 14486351, 11630615, -25707221, 11735667, 13746667, 39706876, -18263647, 16171558, -4321793}, {-14293430, -15528155, 3488620, 5525440, -8146317, 3348549, -28951018, -9275972, 22227490, -14658006}} + }, + { + {{8341526, 9135376, 36559071, -18590417, -48714375, -19066806, 3627180, 11898351, 267776, 21143530}, {-40942664, 23890018, 18779557, 8871265, -14008243, 12620922, -104184, 6714037, -39469180, -4258372}, {11033913, -4888297, 16500898, 10571855, 9498786, -2249341, -21778808, -14301778, 24638927, 1112183}}, + {{-32059891, -2418396, 2874336, 1644452, 28119630, -780896, 29186072, -6247365, -26592247, 7877172}, {2366275, 8543026, 10691886, -3228808, 6963720, 13391140, -4845522, 10528353, 29250131, -10725412}, {-5657077, -16444590, 6995443, 1960854, 23986040, -2319907, 23781513, -10020120, 10326676, 12107890}}, + {{-7434652, -9185555, 8061655, 24720318, -5364033, 1840387, 11780320, 9824041, 23974906, 7822326}, {-1465520, -22967181, 39447969, 5215706, -25707159, -6114731, -12687172, -16978581, 37637112, 11131730}, {12773617, -1342447, -23786450, 5289410, -18847162, -2347558, -7839726, 4406978, -21344733, 16013542}}, + {{-36243101, 3070801, 34470044, 4639401, -7933367, -11783223, 31630698, 1849951, 6030251, -12527787}, {-29433879, -618021, 19941798, 23023291, 19799845, 7130937, -5349534, 18067503, -39078123, -13668197}, {-28927723, -10470735, 32230972, -10476071, -14028070, -15297342, 28119397, 15338897, 9961760, 1054851}}, + {{-25097562, -1321059, 28292687, 3727672, -31711122, -8653209, 30985925, -626922, 31016711, 23146477}, {33047704, -25929301, 34894649, -20896684, -31897618, 8834545, 7947427, -19361640, 16957405, -4073057}, {28044587, 9495890, -31940851, 10333746, 29762300, 13075082, -8375364, -15214581, 18651589, 13094016}}, + {{17213979, 11054986, 30533135, -3934956, -43588530, 478355, -37505792, 14964349, -386537, 12341855}, {13448413, -4693866, -23046777, 5235722, -13998564, -5167259, 12996444, 16679831, -64586551, 9052683}, {-30174882, 10093711, -26757581, 1084986, 8051687, 618977, 11146731, 13311402, 21714652, 19368}}, + {{17503336, 12363630, -49927974, 13612196, 42258047, -26268747, -40765390, 14503737, 36455904, 13310907}, {-45598212, -3129198, 9397682, 6570264, -19614387, 657789, 2074636, -6716569, -17993662, 2709105}, {5791858, 320094, 1215501, 1331958, 15210784, 3686874, 24240223, -4048687, 26876685, -7784262}}, + {{12793810, -1755324, -52080827, 18621135, 5803810, -5130130, -5634768, -11609347, -31596597, -2230481}, {50920392, -7032796, 321339, 2922571, 44466672, -23553212, -58540700, 2418495, -14131697, -23139655}, {-16121097, 14645489, -1367010, -8903827, -29838753, 5051785, 20140313, -12701143, 6017429, 603307}} + }, + { + {{404050, -7741972, 330502, -6081106, -51939030, -20431548, 26783096, 8633269, 7119109, 22345526}, {20912120, -23711036, -5336750, 11880854, -9651254, -359076, 34210766, 24432809, -17697159, -5715664}, {22458831, -12336979, 23629108, 16228749, -16861491, -3578057, -18947629, -14549213, -12447100, -5543440}}, + {{29093191, 17582584, -23163120, 1199904, -16158920, 26236961, -29484535, 13348310, 12176383, 6986504}, {-12320591, 5351896, -28844080, -23271960, 852822, 6570223, -34307581, 5655588, -44144655, 15067840}, {-31001499, 3972157, -13089882, -7611522, 13388450, -979320, 19561119, 2434129, -9204239, -2193769}}, + {{10062081, -5556064, 42967175, 3463476, 2554725, 7233097, 10758961, 20088224, 41065460, 16721167}, {9227033, -5471040, 11316055, -6232944, -12102343, 17841869, -35517661, 11900928, 3846820, -12410655}, {-10494456, -1357396, -19828924, 6937013, 2549215, -14791397, -6099912, 1952413, -8500482, -10563420}}, + {{-1376309, 11276878, 11963826, 14279110, 21775767, -5267980, -44242608, -29629663, -32566241, 6387326}, {-63261213, 16758266, 45407304, 10897038, -17274961, -21639730, 16962290, 1982899, 2489767, -2933976}, {-4368283, 16502157, 26891628, 13616133, -18161528, -15747170, 20015242, 6342508, 10520032, -4966647}}, + {{-39406051, -2813234, -8357141, 17831256, 10659844, 24511868, 15252319, -18060818, -614659, -3717078}, {15735657, 27230990, 25961169, 1534360, 41783784, 1332700, 31990407, 13214644, -44855883, 2608634}, {14156816, -11435795, 26857235, -15126941, 13609716, 12432857, -16937857, 5422930, 20368290, -9613082}}, + {{2475341, -6632035, 20617578, 13486704, 44146687, -2141, 21469294, 15768566, -7493267, 19637701}, {-28756049, 26812869, 43329014, 4954580, -1835737, 9411829, -25245990, 7723982, -35669253, 884141}, {-11759833, 6116980, 662187, -13313409, 32439104, 11791946, 31148147, -7273741, -2431450, 2135258}}, + {{-4922235, -5222084, 43014952, -17637310, 16286411, -30258137, 1613202, 14724323, 13638373, -889552}, {48928035, 26976454, 15692716, -14233376, 20185675, 3180091, -4011708, 13515099, 13550947, 4169954}, {2489717, -12340755, -4603758, 2457203, -21740260, 9369185, -24424090, 12201995, 31929392, 11461713}}, + {{5906009, 8158769, -17575, 11419456, -8639988, -1744376, -8382686, 8728158, 1878456, -77536}, {-9655359, 23316245, 24981345, -8574668, 42441016, 29193660, 33159422, 12778906, 36797796, -1311526}, {-10913350, -4107965, -28867768, -13873545, -1477459, -5372942, -7475698, -15717960, 22040610, -15630804}} + }, + { + {{46456823, -23535491, -26797598, -1260148, -12127215, -1531814, -5643008, 4798561, -6393937, -17797758}, {-12588679, -6404931, 30220700, -18842962, -43728663, -16072178, 33062136, -7484305, 32210625, 13434344}, {18269665, -12820853, -22130632, -7380028, 25497206, -6489483, 21663560, 14774309, 15215702, -14107459}}, + {{-51502018, -26654721, -16242613, -8207162, 13341598, -164756, -24240060, 13593316, -880047, 7281934}, {-11915866, 1932441, -26162873, -21455140, -53555250, 14119198, -11420984, -13346978, 18791377, 21538844}, {-4326243, -16321878, -5640471, 1617206, -28670839, 9802783, -2239304, -3321085, -16717219, 1237042}}, + {{-27149780, 7077606, -46683038, 10920998, 5295723, 27801857, 19910592, 20232699, -10232114, -4474841}, {19961540, -26112530, 1784894, -3938428, 5909123, -4644973, 7212108, -11699965, 41930782, -13893293}, {7936103, 11566587, -24367556, -8347490, -27200037, -1873506, -30028971, -14623039, 30853864, 5270946}}, + {{-6877084, -19091010, -45617631, 135087, -3868409, 12047480, 13655016, -27664778, 41310036, 2705169}, {24214380, 305106, 11556141, 16467973, 15778645, 13087470, -20210126, 4278430, -4411252, -1240137}, {6901797, 2223022, 17366396, 15250809, -18833319, -8020076, -24216545, 11984084, -14303230, -9915763}}, + {{-38037179, -6671142, 4355944, -11569093, -5275350, 23156277, 44586329, 319656, 20702811, 26469898}, {-9243193, -23295134, -27603604, 15430501, 26023798, 2537741, -7261677, -29732140, -10784125, 5716680}, {3777622, 3369244, 26282752, 6314395, 11639080, 7957693, -11901022, -16547275, 19116266, 12459246}}, + {{-40691049, 2778209, -22047928, -27209209, -19821550, 20740610, -45761975, 1535890, 7738640, -1910061}, {-25088877, 26262435, 41637190, 4129293, 29488220, 2090844, 19870777, -13590190, 27070674, 23775643}, {10612005, 2125825, -13957850, 6538830, -10288042, 11830865, -24317686, 10933861, -22220109, -16154094}}, + {{38562370, 14378227, 12484217, 19177777, -47355614, 26707819, 49377645, 251260, -43114316, -16602797}, {-26808892, -965889, -28117557, 8763997, 17407410, 5813345, 14923081, -12669566, 5464842, -1730965}, {21687422, -11430003, 18812409, -5130186, -7383548, -5236189, 6023111, 15787364, 17582223, 6892633}}, + {{-12032591, 10248317, -42585785, -3845574, 53986023, 20154060, 43786405, -25612960, -642869, -2918800}, {25777833, 15946475, -10544123, -16217584, 709313, -9444308, -19925505, 2291406, 5633127, 8717624}, {14988937, 5457937, -20743481, 12004409, 7320105, 10748807, -4363890, -14164562, 3243784, 6227597}} + }, + { + {{-22923850, -5555182, 40377373, 13604901, 12247301, -779024, -20841135, -13024139, 16307497, 15132661}, {21999582, 5224700, -3324157, 4773983, -28222069, -30489276, -3622777, 1324435, -18268923, 255675}, {31627320, -1226688, -17074672, -4781650, 5273733, -3066321, -18594146, -6957259, -32991896, -2977514}}, + {{1815644, -1914359, -5078016, 28164063, -55329536, -5411845, 16709725, 1267925, -55460021, -3130507}, {7206184, -6688241, 10636646, 2551779, 6257804, 15422727, 36221259, -1539373, 10162101, -2231089}, {31029007, -12422438, 3387860, -13582127, -4523047, 11861943, 21068164, 14029970, 1455735, 13002171}}, + {{-60437892, 25279933, 7268339, -26031520, -34648833, -2999157, -26186194, -2164710, -27072724, 17532815}, {-4153430, 3697419, 58301913, 4171216, -20060343, 829749, 18809056, -11075424, -26569754, -1472447}, {-19857132, 7885685, -12419001, -16535955, 14206520, 8160375, 25070127, 14223275, 30157906, 648789}}, + {{36559589, -15880007, 11516278, 21612696, 11872070, 3639563, -9565112, -8721682, -3242922, -13105382}, {16100215, 10511505, -39614918, 7273284, -18796566, -3289769, 40925738, 14513702, 49205668, -10624240}, {-30348338, 11601261, -8588238, -4401100, -10179505, 13961191, -21558654, 15064039, -7766808, 4247048}}, + {{-8426452, 6781035, -18900479, 3121829, 8967367, 6152656, 14348919, 29700380, -32822910, -11026791}, {-1935248, 20932617, -3389439, 3876819, 3112115, -1202918, 12971999, -2379052, 12591612, 10081537}, {-22529436, -8692826, 30381171, 3298511, 28481585, -16661393, -10852824, 7188371, 13445185, 5030737}}, + {{-35136085, 757273, 11365976, 21773803, 32987990, -25537452, -10618646, 2704790, 18476915, -19985173}, {-30242937, 23497357, -15476128, 9392379, -31525088, 2220766, -20084452, -29375144, -21070633, -1395107}, {-15427379, 15020848, 8334960, 3093430, 7358696, -3448559, -19345403, 15917153, 3260156, 3856332}}, + {{25027144, -5479262, -42810252, -6371772, 261777, 17186623, -8974417, -16194871, -25138105, 23534389}, {-31628594, 4089756, -11247582, -5757862, 64306869, 6963607, -2788153, -6243821, 38157095, 5890485}, {27034602, 12655182, -29407594, 9777026, -21467567, 12867916, 7964266, -13385223, -11734950, -10171169}}, + {{-51075004, -20344219, -1458929, 14018787, -1652907, 11800757, 40150506, 25248275, 28859508, -21625891}, {-14879998, -675609, 28433595, 9789929, 18944317, 6642099, 5430144, -483869, -26095342, 6999495}, {9286180, 7442362, -7028254, 15839862, -6598437, -7501046, 26460087, 3091629, -26965804, -10770393}} + }, + { + {{8728274, 17051302, 8600130, 3624135, -5853975, 11796199, 8110745, 3531605, 3638044, -17510793}, {16047072, -8173472, 14466736, 8273501, 59415349, -4521159, 12177173, 8035379, -48293432, -1154197}, {-8301373, -9195531, -15897839, -9757666, 17168039, 11557098, -1305837, 9889389, 27398697, 16382160}}, + {{31709505, 384789, -22135475, 284026, 33005822, -19797065, -9515371, 2236752, -25813971, -19150546}, {13541913, 14549455, 21976781, -32339968, 13483854, 8695097, 49848275, -2836762, 9562407, -10453222}, {-22834552, 3304728, 14613251, 8074645, -3858624, -15144087, -7827521, -92062, -24346779, 746851}}, + {{-22760032, -3379324, -33872202, -6549210, -11906093, 5063730, -12639066, -426272, -45295500, -9416033}, {-21196376, 14022434, 25600942, -4343276, -40144475, -27922354, 7230886, -28798928, 11258374, -11087789}, {15751392, -15199175, -4274743, -8868442, -24667940, -1574930, -5220072, -16174443, -24241625, -11627928}}, + {{29058654, 12885739, -1776644, 2476833, -19362622, -1535032, -2535015, -14799679, 17461187, 21474351}, {-25745548, -18423355, -1305842, 6190705, -11109982, 14895596, 37691773, -18231889, 13475551, -10009505}, {-4056015, -13025210, 3293376, 16184496, 7158044, 6599588, -12428643, -13162720, 1290113, -3890088}}, + {{30335495, 17486276, -5952509, -1180672, 21988768, 6582000, 27264677, -12569124, 35628270, -17628778}, {30113805, 7586420, -22496137, -19699052, 15857568, 12495578, 26467287, -11167802, 28668736, 12227052}, {647097, -4591418, 10303807, -14376937, 242186, -480702, 674765, 3609842, -10109818, -6469112}}, + {{20196954, 10979819, 29548427, 583186, 26115250, -5925385, -39841669, 7154129, 7696245, 10883754}, {-41434246, -16991743, -6511711, 9008446, -13930548, 12660829, -421737, -21252285, 50313413, -2219586}, {31319850, -16074086, -24140983, 307177, -5608349, 16213395, -26497910, -11795151, -24922192, -1202439}}, + {{-49065196, -4879580, -39622848, 13296055, -7149416, 10001310, 18161241, -17865154, -17347704, -22833707}, {-14156954, 10321424, 22916654, 7321919, 27535496, -2323716, -10814467, -1117300, -19218440, 1296697}, {-11882811, -2514678, 26403745, 13711217, 24270415, -7464488, 9407476, -4569810, -30789642, -5954590}}, + {{7541117, 6770422, -23074921, -18173687, 30761719, -19429178, -37300486, 2176346, -28442655, -24712383}, {52316953, -10265214, 42525907, -1056833, -16651657, -13156788, -15128680, -8060864, 25419135, -7537035}, {14618434, 4926921, -24487582, 4021056, -29619859, -8812469, 27667633, 12037151, -8168237, 1839658}} + }, + { + {{-47265079, 15044385, 27967853, -5989120, -13949326, 17765209, 29258884, -16204684, 33286176, -7078615}, {-17287243, -5199215, -11335005, 24399378, 48066896, -15159427, 24447920, -2235590, -14578446, 17598295}, {-2821248, 1791599, -22157216, -9605755, -4830261, -14079271, -8004687, 16636639, 19641394, -11934374}}, + {{2700555, -20264511, 7576935, -16467834, -33915860, 3308658, 33301737, -3821959, 2431901, 10763276}, {-4339597, -9002107, 37050817, 14093368, -33022044, -9947096, 2080221, 12291707, 10700443, -2423406}, {-24570320, 12286179, 32096498, 14866908, -24023771, 10476507, 3101048, -745752, 2131008, 3905640}}, + {{2066568, -17118783, 31691983, -17980245, -48769966, 20277627, 17875575, 4834517, -38291583, -6082975}, {24750766, 9014861, 19885069, -5749069, 4837512, 10025491, -28740283, -11827173, -11103423, 22647761}, {7467605, 16178466, -28121660, -1439327, 3505647, 15941077, -24010595, -8922211, 19879397, -442436}}, + {{-19266702, 6359181, 38504427, -15620108, -19657947, 2370404, 12394637, -1150843, 12634671, 4724772}, {-16323372, -2874755, -21448441, -13297556, -40210257, 11324608, -34245109, -29959117, -34049545, 23022456}, {-24390449, -15699014, 26846832, -12727572, 12784032, 15832708, -25400430, -7908507, 14474076, 16662407}}, + {{11312008, -2341146, -5169014, 25104527, 18241336, 24625254, 13837791, -2898199, -4701851, 13134951}, {54146394, 24027340, -30243094, -4816993, 9011646, 7851636, 9314351, -20090509, -32220851, -8382357}, {30847011, 13013245, -12062216, -12016233, -15198633, 4462233, -24774898, -2328568, 29420201, -15080900}}, + {{13844983, -1768163, -28630150, -1945930, -30326231, -12863663, -56988115, 3536346, 25782786, -7355188}, {46409187, -19417123, 12452258, -29612192, 20077523, 2739989, 8108487, -21229602, -22184726, 1292384}, {-6082331, -6285247, -12403758, -10970529, -4298154, -690180, -10234638, 14465308, 7362888, -11116200}}, + {{-26821652, -7763053, -45210230, -7051423, -572961, 2751508, -35704515, -11049191, 56659004, 4751779}, {12316490, -8734715, -8343274, -8891043, 22989299, -3264194, 523855, -5937901, -998662, 28246749}, {-1937941, -8328216, -26181039, 10006101, -25155749, 5936680, -6133181, 4549091, 27660263, 2195433}}, + {{-1951595, 1204779, -36912737, -7354312, -2040302, 10978640, 8351774, -6738966, 46654365, 15007657}, {-33248491, -32003065, -18897305, 16335018, 27823660, 7176086, -40563684, -19547746, 502543, 18540735}, {18699843, 8239701, -16138985, -11477323, -4459333, -3286544, -26068838, 13219267, 23288971, -13002950}} + }, + { + {{-39086040, -9139271, -15802662, -14561742, 24298787, 23731258, -10092461, -10641140, -7332530, 17738188}, {-11666546, 21185089, 3351980, 2388784, 40170541, 9007700, -13344185, 3263560, -42827248, -7835024}, {-26554159, -12547841, 11827677, 800092, -12775000, 2948320, -4804345, -8984531, -9893513, 9852661}}, + {{-28548133, 2207511, -2426156, -4381836, 3543792, 3282897, -9996535, -15778566, 53390566, -4399737}, {-35061477, -31004671, 38499408, 3563278, -50566546, 2528317, 32655573, 3048894, -4886652, -16167111}, {-12311587, 3865772, -22341946, -13841850, 11325227, 3405904, -25313715, -4268399, -20462952, 11414295}}, + {{-35793880, 7173705, -40932727, 1440566, -499452, -2732388, 9611134, -22591999, -30833, 14243192}, {22628784, 17708971, -9099979, 31102546, 62241852, -3145648, 46558730, 6683383, 8715915, 14522198}, {31100735, -9289283, 6683360, 6500820, -5018632, -6670026, 22752090, -13728784, -3284671, 9112387}}, + {{-9520996, -5641012, -10624066, 3498994, 17802577, 13376272, -25029438, -7176059, -11001963, -12399975}, {-1286004, 8699394, -47540094, 18058700, 11730635, -8313304, -7800784, -19732961, -7282187, 7263453}, {29710087, 6492136, -26386898, 1708539, 1357589, -2570452, -28141072, -15133121, 30091876, 4246345}}, + {{-266389, 11426632, -31615458, -1414069, -22879186, -10518565, -14372145, -14663465, -11883820, 13923297}, {-37127355, 19941626, -31071518, 1515345, -43234864, 9242989, -2106319, -2850553, -49265312, 19048827}, {-20015165, -3147341, -25385089, -9131901, 8512033, -347015, -12828402, 10378369, -1606157, -196000}}, + {{-28278546, -2049463, -16258570, 15757294, 48818856, -9457235, -5936047, 30097589, 20307641, -24341972}, {13005642, 11565419, 21631530, 15362938, -3532144, -3704381, 53767877, -2268977, 25962833, 7126498}, {24950461, 8374617, 12989681, 2747021, 17679041, 13404353, 3626542, -12855331, 10528185, -1143695}}, + {{-33425850, -9739004, 11380669, 17918867, 7189368, -13248264, -17594339, 22434556, -12614809, -22982276}, {-33140152, 12022716, 29479353, 2484187, 38602976, 153634, 36401593, -8048456, 31604181, 8190276}, {24767633, 11452180, 15130812, -3406247, -14546597, 15891807, -3157181, 12064601, 29787307, -4660625}}, + {{-28850999, 8829007, 59072466, -9735468, -23179130, -6363735, 9157187, 6901090, -16218080, -2173370}, {-37858901, -13000853, -2776800, 7679436, 28986496, 21156063, -21148173, -25323428, -47509784, 23078896}, {-10412415, 8568171, 2891528, -6240979, 32956538, 4892991, 2498371, -13053880, -19314114, -11533260}} + }, + { + {{-6798592, 2865990, -19870192, 2217994, -8034107, 12309066, -7133459, 11538679, 57505907, -18309735}, {28096866, -9649308, 15274128, -12615726, -50929929, 9475814, 58365117, 912027, 933059, 12088251}, {-22355268, 1502605, 27500451, 15453435, 15111070, 9700576, 26503320, 3611306, -28850031, 3359397}}, + {{-19631592, -2464233, -10589012, 2585665, 4999749, 352148, 17531454, -19707786, 1418865, -19460977}, {-19566470, -3313379, -25880908, -30537833, -7916383, -19822508, -37322214, 10720204, -50741555, 7686261}, {4336617, 1227470, -654152, -5911688, -19480893, -9945594, -15385990, 16260592, 15785293, -14667016}}, + {{-28973032, 14147662, 20455909, 4507057, 1415984, 12652605, 694189, 13069043, 889603, -27166604}, {-27236136, -15069186, -31524717, -14535279, -40756674, 5977525, -59918157, 19233159, 15824999, -1622224}, {-32312952, -5820342, 32069839, -7356037, 13981799, -3941953, -10830463, 16284281, -25288312, -3703752}}, + {{-20782860, -10275499, 11045596, 1927035, -45827724, 9628686, 35695506, -17483530, -41277323, 3277006}, {-33466152, 16373195, 20612170, -24240265, -8773878, 11911034, 25637830, 11302862, 8286629, -11629948}, {-1415775, 11002899, 33180965, -5015538, -20316680, 13784087, 20294380, 6979821, 29547283, -6881147}}, + {{41186940, 21363252, -14606938, 2084721, -13837673, 6056516, -42121285, -7517846, 18262785, 6833148}, {8863438, 5031930, 50291188, 22741977, 15258335, -26282646, 10839273, -6622668, -6496259, 5530736}, {-2663101, 12461283, -16935567, 5513486, 32103531, -13450651, 6734378, 11801712, -6888115, -5894605}}, + {{-40737929, 283885, 11032750, 13073453, 27081140, -18568468, 18976944, 1463142, -33869259, -23725473}, {13815539, 7947577, -31858250, -2062353, -28472314, -12188652, 40099138, 22643320, -30060245, -4670727}, {-13546593, -9778820, 4483917, -16291673, 15345496, -1322602, -30175900, 13087670, -19502906, -9894161}}, + {{-51458984, 25466955, 26626968, 4989301, -3831619, -18286376, -6066743, 11910020, -36604178, -4737300}, {9294614, 4208111, -5159362, -16255537, -48309591, 2523444, -53932033, -4193178, -4231388, -8214234}, {-5822256, -15877538, 25304291, 10997483, 33520679, 16235718, -16594075, 9453350, 15193436, -11702926}}, + {{7513104, -1302983, -30758065, -3180399, -26836242, 25193640, -51864366, -15347565, 28696554, -537298}, {42721804, 25993825, 13921233, -4846033, 34545258, -2121612, -12000000, 3353441, 29517028, 30903198}, {-30158356, 13596867, 543864, -16389812, -9077550, -16367201, 460417, -16279319, 20863560, 10144047}} + }, + { + {{-4308726, -7761298, 34810064, -581777, 48978698, -19750524, -10205100, -25782686, -38701263, -10087552}, {-5441058, 1628912, 13871134, 9746575, -9830696, 7716160, 3125930, -1388950, -4132795, -17148064}, {27394240, 5593938, -2918651, 2394704, 24372047, -11764024, 24447171, 11424405, 11420526, -5782788}}, + {{15906666, -19985369, -19171361, 13031394, 25527102, -6243850, -6343134, 6651889, -781445, 2696038}, {-45350286, 6488585, -44537833, 12583966, -1465378, 4998382, -36330436, -2650059, -1741275, 15441722}, {-31894236, 3009576, 5227337, -10729943, 21389375, -6671001, 20338060, -3851759, 22951285, -12757211}}, + {{-14453187, 8175100, 4207069, 1243877, -24179117, 11062394, 12783317, -10793213, 21070435, -17844326}, {51156507, 11012832, -52003911, -4186075, -25413723, 15071934, -2072457, 16415021, -278333, 8633138}, {-25034748, -12655786, 25139144, -10181834, -23069772, 4590711, -19569450, -4241464, 7712811, -13492146}}, + {{-9934525, -3757850, 22432462, 963498, -15708635, 9983624, -9666020, 16117851, 2998544, -5059373}, {-16015009, -22190720, 23595696, 21083842, -875089, 15938140, -25278368, 10122107, 10401816, -1537031}, {-21476348, -2146882, 16301341, -6566558, -26860592, -4098336, 24051928, -2581646, 26112716, 9955914}}, + {{19068167, -18375999, -2216334, 4694057, -12007904, -62763, -25783231, -7266226, 41166542, 21748339}, {-27066991, -1262081, -50656950, 20222863, -948176, 29538865, -5687709, -2112042, 5991758, 10101383}, {-31607825, 705687, -12058053, -11379024, 9280883, 5524815, 11293838, 833453, -24702623, 3430888}}, + {{-37666253, 15013045, 16972156, 4486451, 12430995, 6340369, -11266788, 12224290, 31436469, -18503575}, {7485707, 14336629, 25843236, 26366269, 49241431, 24476935, -34119870, -2367448, 7044707, 6357487}, {20030467, 12615520, -13961332, 2068738, -8958093, 10787560, 11507305, 4144883, -18868406, 12835569}}, + {{27213136, 11907390, 7994644, 2046027, 33697006, 8354926, -2677475, 5040073, -1390254, 7790874}, {-21523416, -15386820, 59067854, -8932233, -20584000, 11773766, 12383219, 13232631, 18386530, -8604402}, {-11429204, -10415045, -14047623, -14255914, 15280216, -3236912, -17652895, -5269741, -12238277, 13158926}}, + {{-20892869, -2967, -15699107, 4981142, 8383424, -2531192, 50162938, -20871788, 16369001, 6876718}, {29561145, -31464577, 20738735, 26176828, -1614538, -29702704, -3861374, 239286, -20551569, 24034322}, {16746666, -14221941, -21795265, 1348851, -18661573, -5632707, -3540875, -4390284, -5616955, -7730410}} + }, + { + {{6154975, -1327631, 46895667, 5406121, -36071287, 15445555, -42232883, 9936332, 449254, -11525245}, {29299569, 8174717, 6903403, -12536407, 11104975, 6084711, 7451409, 15650704, -16881170, 4624275}, {23266700, -14093209, -1885983, 9133528, 12581344, 15638739, -10024096, -8658155, -2568111, 690476}}, + {{-25785424, -23733047, -42038847, 4214219, -37085773, -3219058, -29534247, -15120504, 2654980, -11178384}, {39906430, -390921, -2305163, 7139763, 12890961, -22673412, 7763845, -17227966, 63037834, 7278496}, {14166467, -16276761, -7428666, 12818281, -16359036, -1441680, -11120692, 7758049, -32872071, 9420303}}, + {{3872057, 12083699, -7989677, -26293176, 7892710, -5061961, -44473636, -15471772, -4463687, 8603541}, {22278301, 16417825, 38723645, 4238654, 358274, -18754603, -16096090, 7167810, 61931285, -15619787}, {-32849309, -13562471, -19524347, 8385958, 32690729, 7979712, -18218834, 11159938, 24949071, 16519111}}, + {{-43304418, 12381045, -2248602, 11637593, -34747294, 1140999, 42949255, -11283022, 2640681, 60384}, {-5658868, 6266775, 28658666, -12947181, 14062358, 9416293, 2526199, 3168970, 20732091, -12634886}, {-16540080, -12281379, -21912978, -8732011, -7627663, -6603379, 4845895, 6798936, 15629762, -15484118}}, + {{-6241358, 14123225, 7990304, -6230293, -32121522, 6788882, 1321877, 15579735, 46168100, 1094526}, {59521290, 17379495, 27093570, 13297729, 16419210, -20228708, 4701769, -17587215, -16197008, 16600488}, {-22981454, 13037600, 4804609, -13825535, 10859162, -13870970, 23705637, 1787046, 19305937, -3436666}}, + {{-43223096, 2424348, 3949521, 14665317, 15470028, 21953792, -8610620, -8137114, 29016300, -29868995}, {-8489914, 20596370, 50870883, 15582467, 36141528, 9136612, -19071800, 19951894, -28783952, -3210411}, {28663358, 8578444, 16773988, 3721180, -26100146, -13849438, -21816989, 3491747, -19508628, -10641718}}, + {{-13554234, -4269196, 14660944, 28220037, -12665117, -633062, -4175694, -1712187, -42118903, 12382487}, {24527100, -12082470, 41670592, 4157887, 2500895, -5634172, 37856426, 14476347, 9522249, -1318373}, {-31497721, 6490377, 10298222, -2004081, -27699338, -16401910, 13298222, -10447333, -29806091, 15052234}}, + {{-32188752, -30812149, 3288396, -1168348, -32742669, -827708, -2619825, -16507606, 27538821, -12857524}, {-6853712, -1414445, -37850348, -9050828, 32827241, -26059954, -32472691, 6433306, -26839769, -3855226}, {-10516253, -1903386, 1136364, -13884075, 4108212, 14678247, 6986091, 14058543, 15629290, -12069165}} + }, + { + {{19043048, -11158751, -22412791, 19580575, 29030423, 5952440, -20550561, -2968156, 48293408, -7373061}, {24848376, -1930831, -5866097, -9884885, 19302533, -13288180, -9918159, -14807388, -7432200, 2651987}, {17608058, -11179157, -17345761, -14881390, -7393602, 13602629, 20769287, 14553297, 25663193, 2863240}}, + {{-36697212, 20408385, 2155539, -13979836, -15026041, -22353110, 3836020, 23525635, 6440003, -562694}, {-25836354, 4525637, -2890603, 18188312, -31155367, -10743650, 19765218, -1507607, -26046849, 18325092}, {-3854072, 5901665, 10838121, -6460548, -13969838, -16334174, 22958429, 12934534, -7811105, -4349524}}, + {{37684334, -6945567, -43334493, -257316, -56193161, 18008017, -12031414, 10099613, 3630258, 18484523}, {24144678, -11489249, 10393199, 19646648, -3681003, 6727115, 48969088, 10517589, 40864878, -5711797}, {-22124624, -4687825, -16694937, -1206589, -3408745, -4324170, -26084442, -14630587, -4272268, -1486019}}, + {{37238966, -8225776, -10422896, 13925140, -21500222, 11799383, 9434773, 13601467, -1393114, 31674193}, {-21438464, 7639226, 43423348, -2306904, 44846712, 3807553, 14168045, -14211745, 7538526, 1511183}, {23049310, -7397764, -15930122, 8913438, 8113942, -11271712, 11802400, 6801972, -11756002, 7481414}}, + {{34973879, 3854583, 2240915, -9171425, 32182406, -11477749, 2486667, -7668072, 20920187, 21468109}, {12190257, -23300205, 54210245, 1034593, 5793784, 4046317, 42521059, 19926768, -29945111, 10577783}, {5483467, 5537708, 31270988, 15853568, 31465905, 12697548, -15644379, -14831462, 32704069, 12734655}}, + {{-17315785, 31223134, 18941656, -11524168, 48402250, 24344403, -25607204, -1068221, -15307045, 15880342}, {13643125, 299248, -15784310, 20405378, -14160558, -5260651, -38817082, -4590997, -40777683, 9211568}, {14538963, -6980857, -3878247, 9216616, -4863854, 8594013, -11160520, -9333194, 11435004, -15077899}}, + {{-24396246, 16764623, -43417959, 15166367, 8449472, -13141818, 5177336, -23728168, -20698976, 1223185}, {12960016, -10955765, -19862613, 4287407, -23274048, -19471566, -45301530, -3332884, 3796024, -29880163}, {-25411170, 8156721, 4536509, 13436096, 28177758, 5389321, 18254594, -12934119, -15770614, -6648705}}, + {{21546772, 16638523, 31137237, 5797275, -7541773, 12432411, 28110943, -7722413, -23581888, 2754516}, {17583014, -1544745, 17561387, 2716119, -40170709, -11243435, 8446453, -3157181, -12749564, 7412966}, {-21910806, 16605247, 26181759, 261054, 7265576, -15568518, 4857917, 13412686, 1262015, 11882132}} + }, + { + {{455099, 6712577, 28008806, -511803, -14627143, -17933537, -2516458, 2322206, -49930903, -6006745}, {-32946091, 21061033, -16052556, 19167397, 36021137, -7531661, 60158270, 23127510, -4742145, -5687399}, {31169025, 6976264, 16583672, -15934962, -6712272, 7236931, -31124844, 7303698, 20476326, 11538948}}, + {{-28260274, -7826252, 5609897, 14001160, 27218440, -7597269, -33781746, 22822893, -3006740, 5191276}, {-22246590, 3841106, -59905437, -1009146, 2299552, -24715251, -16349880, -4872415, -52866218, -18136214}, {-4678744, 5839195, -28817727, -16224902, -25312296, -3165444, -31665829, 2076739, 21905224, 12955274}}, + {{-21167818, -12343459, -43119910, -29459784, -29857002, 5305355, 34178604, -24028913, 31423389, -7488887}, {36094410, -19112779, 10016806, 2407594, 25150482, 9935463, -31037274, -2753143, -27766183, 9668717}, {9019763, -9878832, -32405854, 2812270, 31750066, -3170391, 29375997, 11143881, 17766608, 16435198}}, + {{39382705, 26245298, 49307946, -26536297, -12551662, 10015293, 52036244, -9245152, -2355717, 30895486}, {-23683751, 5594630, 16048590, 5908677, 22386650, -2636093, -57054, -13264714, 15503247, 1953626}, {-26885157, 16602373, 11192005, -8701859, -10517925, 9836031, 32722367, 5818327, 28925916, 5468368}}, + {{2173626, 716088, -7688895, -3935673, -33719332, -1573138, 5441090, 10409765, -17608416, -4928175}, {-4324294, -7210262, 29703353, 21579955, -30249226, -24243226, 33747184, -2585605, 45063606, 816423}, {-31484577, 9602077, -19039908, -2437135, 11013304, 1161468, -17723919, -10820529, -1937866, -5628742}}, + {{-40203088, -14634159, 15462880, -6622396, -696770, -20006949, 32803778, 8041373, 15364829, -527761}, {-11503560, 6334161, -36006182, -23969174, 65608910, 7743545, -17705244, 10866415, -44320597, -20011937}, {-11081774, 2271147, -3085285, 6381882, -10440829, -13618892, 26009551, -10488572, -15808495, -5097188}}, + {{22100181, 24475296, -6069968, 14668892, 56142829, -13972494, -51206120, 14528474, 26176209, -21167215}, {-36681749, 5632410, -19753044, 11913232, 7405039, -15879740, -8633868, 7232868, -19657685, 4119047}, {-14333824, -14956457, 27767270, 2279435, -18432412, 14744271, 5883425, 16402092, -22794933, 9448897}}, + {{7417308, 14032088, -37431263, -6738139, 40425088, -8120984, 19670583, -18490177, -22720733, 8015627}, {28870804, -16371842, 26932487, -17716287, 25968790, -6585424, -9262099, 977667, -40256557, 15633173}, {-25813414, 12599253, -15234699, 11816034, 12949624, 14772195, 29199304, -4412113, 8132817, 740828}} + }, + { + {{-2030230, 20618348, 31062598, 4018711, 56694731, 3989174, -2563829, 361570, 23437119, 6778967}, {43325502, -3542332, -28020096, -4061023, -3558021, -3169148, 235755, -10892880, 18530913, -2094835}, {-20222117, -14253451, 6758909, -706825, -30149299, 12653544, 2014140, -161183, -22008553, -13173419}}, + {{-43516037, -14086245, 28184267, -11024482, 60620925, 17431754, 39182614, 15751474, -18759124, 161713}, {4729683, -8069315, -1792645, -7208636, -56789, -12751630, 23458598, 13907982, -35420664, 198359}, {-5807171, 1099543, 7343878, 4583497, -5767064, 16155071, -33275584, -8141370, -21852677, -12312367}}, + {{17505893, -14046918, -26324808, -10562467, 21731961, 25803496, 28282100, 15979011, 22771019, 1597476}, {8854983, -7550666, 26040598, -17109827, 13712141, 7175168, -16264462, -16205507, 20496363, -22407094}, {20605360, -5970971, 11091782, 10193769, 29733876, -5046281, -28712397, -10884143, -27531604, 13637921}}, + {{8416581, -12374720, 12861292, 12145640, -57254515, -1988240, -11324726, 636145, 24087094, 25804437}, {40587133, 3594284, 37244902, 4080504, -8924063, 7006452, 34037594, -19084445, 12983006, 1090731}, {-19080442, 160026, 21222210, 14602893, 30451522, -10082475, 17497585, 5104507, 33024859, -4084859}}, + {{509304, -11633970, 29727695, 14560235, -19635227, 12528010, -29002291, 9233101, 228870, -26617625}, {11859306, 16012302, 6312131, 17493827, -11444307, 6022290, 6769927, 7971725, -6532882, -2093895}, {18370249, -12536324, 26233524, 10374124, 20779194, 12823119, -7314456, -7510601, 20728149, -6051812}}, + {{-2294574, 4576374, -14343898, -9686494, -40627092, -1657579, 21567658, -12834678, 50200945, 1374066}, {22741386, 22566322, -30018176, -22815168, -18295392, 11734155, -43870532, -11903518, -14914565, 20328280}, {21011817, 13149059, 14296848, 15820987, -28783032, 12996035, -30382383, -11958806, -3601928, -3137672}}, + {{41504363, -852805, -53234768, -1469239, -7490324, -2569964, -22966519, 2356435, -31750627, 13689591}, {-22384459, 6375005, 11586486, 22458329, 51888930, -19720468, -5675145, 4467951, 25467085, 1883021}, {26918878, 6967172, 31853010, -13731280, -27214586, 8270178, 1099559, -1979823, -23941717, 1287318}}, + {{-22166771, 2472850, 16401636, -6201821, 4597610, 7189329, -64612654, 2006293, 41489684, 7799866}, {13731431, 20612128, 46467752, -15330561, -25649108, -5523175, 746152, 1025145, 10213772, -7789908}, {-400784, 6883307, -21065306, 14605541, -6878792, 3135059, 24975218, 1852365, 10150954, 14928567}} + }, + { + {{24607714, -209575, -20404066, -14725257, -27010732, 5700195, -3774563, 3275553, -26699439, -17342658}, {-34332006, 24286963, -23539408, 11024237, 16581588, -1067749, -20525769, -19103199, 49863, 197284}, {-24655565, 4836455, -32607763, -6874765, 3293039, -9962652, -15676880, -16222288, -1582769, -14127546}}, + {{30505728, -13762931, 7066973, 31164960, -34523744, 18443788, 32795565, -21064252, -8757755, -23605120}, {-34813620, 5542679, 44130199, -909496, 10934654, 1510884, -26930579, 3301648, 56570223, 6277588}, {21433837, -7453079, 28548229, -12265274, 3070157, -12876735, 20459713, -4479937, 22946665, -15697418}}, + {{30913415, 7701282, 49015476, -10848782, 46414057, 623053, -3800700, 17025444, -25700243, 3790315}, {-26539703, 19996034, -12248622, -9340832, -19138601, 22641411, -42292694, 13824332, 32760891, 9700259}, {-27413992, 642997, -29628648, 2778992, 12236340, 2246672, -29815886, 13758802, -1110289, -8634591}}, + {{-10768286, 13883285, 40119830, -15270939, 24226394, 7454822, 13382572, 7222611, 26021676, -8385696}, {-42046718, 17146817, -12278880, -7449625, -21272636, -16967538, -1037602, -21155367, -26663156, 11881804}, {-18385654, -14956148, -14326695, -13461520, 28666062, -3855530, -6607651, -9927191, -6620149, 10051578}}, + {{-2371004, 9774777, 3803781, 5457594, -29927250, -12743801, -4352591, 262539, 691137, -7905711}, {58314158, 6327839, -42951677, 7873996, 18055152, -5109547, 30261705, -21651689, -43182039, -13520737}, {20669823, -12380627, -18244835, 1615510, 10283843, -13700563, 7447350, 1401693, 25383846, 6172176}}, + {{-22821906, 5488084, 21086780, -25558886, 22252680, -21699607, 50702206, 4327724, 24677981, -372375}, {20887362, 12058690, 22618110, 4539020, 26349768, 8900173, 15705602, -3794254, 13774527, -23541627}, {7468380, -7994630, -33268380, 7969418, 29999094, -5607830, 28248730, 2554714, -8674808, 12535347}}, + {{50659, 9867436, 8530474, -10476653, 30062327, 889699, 3030675, -2948987, 19420240, -15118129}, {-34279531, -17885776, -8955624, -18310967, 12012643, -31893989, 20434517, 24330161, 8445430, -11828513}, {-33133221, -5796760, 22274599, 4599804, 14989963, 11486836, 14135821, -12742220, 14990697, -8047746}}, + {{-61336608, 8593845, -874124, -1373303, -4756185, -21471525, -20142611, -13319568, -5876976, -5820787}, {3540074, -8091289, 3867720, -22455239, -48226401, -8514313, -28887731, -16282344, 60765196, -11589793}, {31379768, -8252534, 18313303, 1987366, -4803041, 760650, 23065504, 9740160, 10477923, 9247310}} + }, + { + {{-13741009, 26909276, 1241107, 15933805, -954041, -1452312, -20149884, -16412320, 34502400, 26150857}, {-38781453, -2036516, 10786365, -14546773, 64310057, -11486366, 22676530, 6678686, -20041108, 5000877}, {32820874, -6997790, -16859176, -11031315, 20460470, 16675995, -2420787, 2717162, 12584284, 6625237}}, + {{9022780, -14861876, 19059868, -14041893, 8194389, -6468749, -2792195, -665723, -15811767, 7197654}, {10776156, -3209336, -11798700, 12496483, -48377379, 4825143, 12922921, -18715995, -36753743, -14195268}, {11793976, 3804449, 28585923, -2963650, 31031643, 15655009, 19457944, -12192250, -28405142, -640594}}, + {{-15240081, -4032455, -42362123, 11846734, 24485029, -682507, -31321558, -2747237, 24890288, 18168131}, {-46657089, 26917229, 14850187, -8077188, 22343971, 32432621, 9355184, -14821869, -12220236, 4610131}, {-24507391, -9283547, 27152155, 6700897, -31611090, -10220025, 12401123, 763637, -26598113, -3417122}}, + {{27232184, 22336091, -17019043, 28439417, 25041529, 8684528, -7855730, 15280436, 26609024, -21823089}, {-18505354, -6813535, 33104155, 3101437, -662589, -2139912, -49858058, -16656438, -7632864, 162057}, {-2653248, -6577513, 26248188, 2540997, 8997775, 9693846, 15724053, 14411565, 29404978, 2294504}}, + {{-29352353, 7659111, 18307208, -5132698, -34923855, 2987786, 26940026, 19760432, -25790650, 27314455}, {-2734231, 18164883, 20381250, 25081556, 25161409, 16472984, 1828398, -12091628, 17271306, -2905941}, {-41192, 1114983, -28068506, -14150245, -26255990, -16678006, 4258735, -13459782, 22573379, -1984925}}, + {{39946682, -30419824, 12246211, -4314417, 36691407, -8353801, 45984250, -6054958, 8193854, -5201230}, {25882254, 600490, 12835805, 20344417, -6527017, 8815201, -17479928, 2883244, -1927296, -18971086}, {-7597807, 7510887, -30542614, -3227164, 19961694, 50261, 15533539, 9885203, -2494096, -14370163}}, + {{-27701408, -2454992, -16752906, 14268123, -34121062, 7499401, -40778319, -3526663, 963233, 9075617}, {-3911352, 13941856, -13668650, 1700501, -2375060, 13869797, -11142659, 16081037, 29487417, -24243933}, {17440201, 15732344, -30068222, 362868, -39844, 6029512, -4608024, -14684947, -4756, 11869296}}, + {{10119149, -1068356, 6736641, 188270, 59581482, 13772988, -45194379, 17322772, -27466934, -11605235}, {-51349923, -2585238, -28733843, 800886, -7233796, -3016776, 561391, -15370632, -20739574, 14178797}, {29930485, -10309686, -21239696, -16724754, 9322487, 7332189, -23348886, -13233982, 7762994, 14852945}} + } + }; + const precomp_data_t c_point_X_precomp_data = { + { + {{-9925073, 26743494, -5062208, 25549408, -23824429, -8353439, -8949217, -17987274, 12129322, 255445}, {1031237, -1929432, 33861812, 2513264, -39594719, -10522603, -42353743, 6231162, 9960060, 16637053}, {31813747, 15679110, -10191224, 16224642, -16487226, -6872092, -17580551, 8154917, 6688750, -10310772}}, + {{-26258524, 8249826, -11920146, 3220610, -24357770, 2758284, 33572638, 10160420, 29050799, -949892}, {-13180558, 17628516, 46801898, -14581552, -12176584, -18216314, -2631302, 3474116, -18397157, -5937320}, {23740252, 2896603, 16970314, -13205076, 53532, 7427132, -22291986, 10806190, 31874506, -16594478}}, + {{16623322, 18109907, 41423559, 5840730, -46771774, -19993, 20802483, -2611191, -40637520, 27693075}, {-8703592, -8836357, -19440975, 10495450, 6339720, -24160885, 37565017, 5918651, -4876836, -3083069}, {-31453716, 11855245, -23502269, -11985705, 25889705, -5314538, 29637309, 10820067, -28550748, -3813260}}, + {{7017164, -6897969, -33913710, 16583058, -8111349, -19406264, 9215154, 4350131, -44611155, 17532980}, {45411924, 6181163, 22622750, 1380856, 9222969, 12577204, -14000760, -28290001, -855249, 13913042}, {-12902741, -9688913, 25080009, -5038444, 5752883, -11873607, -9421806, -9565805, -18945978, 15802926}}, + {{-6101955, -14033093, 51429122, -10006715, -38781575, -13638306, -7164640, 9004893, -27181253, -8083663}, {3691659, 15570053, 1689402, -12800317, -26222541, 18378560, -35232774, -22877429, 38616177, -15390977}, {-15244972, -3907280, 14186228, -4066913, 20426089, 2483686, 12711062, -2570137, -912628, -14954285}}, + {{6276040, 4043466, 9840097, 338441, 4039527, 4572619, 17463228, 11584608, 18778626, 5603048}, {56126112, -16761180, -19107173, 22169291, 15049793, -22534551, -32149320, 12110460, -9403382, 22795358}, {19190418, -3110177, 14835489, 4377510, -14278199, -2822050, -14350100, 16595507, -9377841, -12291950}}, + {{2815092, -9621621, 41018428, -3528437, 39594537, 11866850, -52414734, 1419318, -8855129, 722048}, {10823696, -1907121, -15600852, 20928657, 16406711, 14276316, -6539620, -3186454, 36647913, 27546732}, {-18966877, 7522473, 6497539, -1590388, -3334580, 5380615, 17074346, 11369609, 26431835, -14438484}}, + {{-7166735, 1048159, -25949760, -1295085, 51229292, -15154352, -2022499, -20518673, -14230207, -23174226}, {26255677, -31929091, 8602602, -19027417, -5238014, 7479254, 25744591, -2675509, -27746215, -10299140}, {-22365641, 9338853, -18558509, 13708789, 14731619, 2442124, 20536292, 12086991, 25151000, -6539538}} + }, + { + {{-17021075, -1086156, -47131246, -13542165, -29424140, 2195133, -39945033, -22276920, -7282337, -11453561}, {27786437, -25084114, 4990714, -12465777, 20011752, 24561515, 767011, 9055026, 21277599, -4681673}, {9121598, 313272, 12015524, 9742163, -22229405, 12729123, 22987767, -8389509, -15264956, 838421}}, + {{11573410, -13935635, -5066484, -17416680, -17991065, -2069096, -24183113, 14208535, -10767307, 12879393}, {-40148220, 14456913, -33810098, 3432770, -17017009, 29326752, 14548051, 7893373, -31786859, -8932873}, {14518345, 8442387, -792876, -3670002, -11880446, -9677565, -29046681, -7419463, 16837240, 8745192}}, + {{-10591381, -8169660, 18482420, 15476535, 17119804, 9234289, 3416993, -2655518, 16936012, -18428353}, {-33344735, 4394610, 46182920, 7275483, 2439942, 14028071, 53750491, -10345208, 44840886, -8875647}, {-30859141, 2905823, -30189765, 11516754, -5605434, -8713831, 5303054, -6676518, -373180, -11645300}}, + {{4420245, -23788229, -29201201, 2914077, -12813981, -7469425, -46628490, 23492078, 27504167, 13974905}, {-49364827, 9087829, 2538539, 8768675, 30409945, -19926379, 20033162, 5476590, 26565685, 12524959}, {1868221, -15326706, 32811195, -10505065, -7928132, -419852, -10304072, -1816565, -6567458, -232855}}, + {{-9948680, 10338652, -40209746, -25851403, -7064323, -12113709, 6197722, -25056812, 18629073, -19644536}, {44958732, -20915350, -17356350, 873381, -24621469, -17392137, 20784430, -3526504, -28681823, -12180538}, {-28461416, -11105654, 7451953, 814288, -8844199, 813795, 9343984, 15837990, 18422838, -2907081}}, + {{20705878, -21114331, -40945256, -20308307, 9875081, -6938015, 60341196, 14675594, -6172905, 698001}, {38356990, 1606965, -5255562, -7503835, -49779611, 5332185, 5994582, 1466638, -4244565, 10134701}, {-31760956, 3554413, 21709994, -12125057, 23322260, -15347454, -24169173, -5832763, -6061945, -4852915}}, + {{-38153296, -15684075, -12330268, -15480639, -21241030, -1372824, -733088, 15431800, -7197638, 4386536}, {-27258378, -2735603, 14782618, 955633, -38527088, -17216618, 42881008, 214044, 43586958, 9041170}, {2575867, -13734991, -8036952, 7826637, 30781674, -4413255, 28134891, 14018278, 15475450, 8924675}}, + {{45207703, 15067912, -23507819, 676613, 11020367, -9893589, 2843960, -24371618, 16817465, -10001484}, {-18319171, -9311910, 35850813, 29870037, -4562115, -5235589, 63381246, -4824186, 3827303, -16647264}, {32865588, 6706033, -7660931, 8976827, 8006496, -12905440, -19842033, -14047132, 14857834, -15497711}} + }, + { + {{-22693092, 8017147, 29591323, -8080208, -6885791, 4571937, 20363651, 28828416, 6394698, 17166984}, {-20061494, 13152315, -17725009, 9457292, -21786217, 8691873, 17484039, -690102, 2655302, -2940198}, {6146204, 12560930, 18873445, 11923903, 27087197, 4596192, -27018806, -12348128, -9939415, -10205248}}, + {{50072831, -7019805, 2847706, 1627965, -9712522, -4973988, 19606569, -14135499, -1050946, 1407051}, {1840295, -3976735, 2716272, 720687, 38323264, -1774604, 9179865, 16150861, 33601464, 25583199}, {-21099596, 3820238, 33036488, -3887022, 20756498, 14956048, 1866130, -5557194, -13454832, -16269607}}, + {{6479923, -12555450, 13861880, 9268378, -15128239, -7433362, 23544668, 6779440, -54120528, -23623937}, {5866103, 9558424, 28247696, -5363770, 34812117, 18480860, -25246014, 20597862, -2015934, -1415437}, {21558574, 4502987, 23045216, 3464412, 8795334, 6481413, -14215967, 7868967, 10707034, -12940180}}, + {{4848948, -2686697, 17788203, -6140395, -42806973, -3126011, -12145118, 9756294, 18245466, -518932}, {33190324, 4089173, -38538293, -11668037, 18417269, 28454503, -34823286, 11108390, 9900348, -13650032}, {31446738, -6946210, 27988280, -8730253, 14094387, -10702688, -11256674, 15722699, -18254027, 4655186}}, + {{2775690, -4188982, -22064328, 6353788, -59271234, 379771, 1345222, -4160372, 34524416, 13627746}, {39502124, -2893462, -24282452, -23754812, -567730, 17162859, 17641658, -10974914, -4753646, 7124694}, {-5174634, 14108658, 16143543, -9702346, 31310094, -4068404, -17859348, -16192021, 26903079, -5209198}}, + {{-26044727, -17709228, 3714116, -17813319, -55797102, 10967436, -12110852, -16915226, -58986298, 19952785}, {1146995, -3849706, 8405880, 14968127, -10567256, 19000038, -17389550, -6936810, -819708, -5383323}, {25856642, 1227937, 29900997, 9382946, 5961425, -4744883, 27210332, 8613451, -32512286, -1906669}}, + {{-2997237, -26508410, -36133037, -18140637, 23078462, -18324638, -31053924, -17029633, 25000084, -11464033}, {-13122861, 3517674, -1337035, -5814281, -14781858, 9804458, 32208892, 1774463, 7728424, 14634553}, {3492189, -10152017, 16915533, 16634536, 9299741, -8779832, -5143673, -14176906, -23745225, -14643829}}, + {{-8310232, -11138411, 618693, 11923120, -31146167, 6722857, -22500141, -7864903, 29774140, 9674896}, {-8894722, 10567083, -18199573, -11333266, 28836027, -14154657, 27598277, 1141805, 17950008, -2385314}, {9789858, 12498604, 12737842, -2907639, 18619548, -9676320, 8707957, -742267, 10290691, -6486551}} + }, + { + {{13705950, 12450428, 9120030, 2465519, -15828491, -5562236, 37592515, -21358697, 12453347, 120814}, {-19566844, -17782026, 53185744, 25212389, -38821533, 17839750, 11456871, 3545255, 45083731, -6707124}, {26716233, -8638759, 3309314, -15895355, 7445089, -10101916, -25328595, -8358269, -3063496, 9172861}}, + {{5269805, 3639279, -41556084, -9881131, 839659, 14795347, 26835949, 15904041, 13126700, -1901164}, {-6952915, -24969237, -20179704, 5529059, -53620187, -10208001, -38743805, -1198243, 24168106, -506096}, {10298328, 10263207, 6861475, -9516241, 5270201, -9221672, 26729396, 16637124, -4694734, 7424148}}, + {{-37748075, -7288892, 4315129, -25874077, -9303427, 542817, 10671194, -15645416, 40859595, 3693631}, {-18546111, -6154954, -34931871, 3549833, -32374313, 12218825, -41429590, -8811818, -20954943, -1896183}, {17929209, -10979729, 14613278, -4466084, 21767705, 6905685, 6389555, -2300268, 4481916, 10678519}}, + {{-30898830, 16124895, -22984080, -5884104, -40280250, 28833783, 12667656, -9767390, -31285804, 16859115}, {-6053294, 1633667, -20072328, 14235096, 13683260, 2091841, -3212504, -8273222, -4702328, -6418859}, {9882818, 4628411, 29813118, 15987895, -14839248, 10604449, -25217399, -11319882, 22746844, -1187071}}, + {{-1915884, -3678535, -2246426, -7177863, -28347074, 14705733, 49024374, -8299944, 24245214, 280453}, {-64377298, 23591153, 62234218, -5717327, 13972058, -9658231, 2494924, -21795562, -13771174, -30735313}, {-9126427, 10912151, -5766111, 13765949, 30795859, -333123, -18879428, 3009229, 32082911, -2932925}}, + {{-36175496, -834709, -2640027, -892920, -36012132, -21161194, 21749145, 4321050, 34663554, 17748450}, {-21958692, 871163, 7932691, 9230934, 2677006, -119956, 23895867, -27471408, 25886314, 1942878}, {28528007, -14546005, 30045547, -13088445, 18380890, 15918929, -30103177, -5916713, 7313738, 11487581}}, + {{8432767, -24224946, -15556188, -18582243, 1345824, -13209265, -31025624, -9815700, -7814949, -2119715}, {30832407, 3088944, 50721150, 10899507, -25644184, -17859303, 17034916, -6078072, 5820017, 16813537}, {-17941222, 16449532, 11333308, 1321968, -13013805, 5565755, 19151187, -9767397, 17037669, -5091116}}, + {{-2172024, 8179575, 1451741, -15405484, 16866607, -11344101, 13140670, -4416747, -5617358, 10412573}, {23540440, 23568067, 7113067, 6554334, 34092659, -15644397, -21414620, -8721275, 45047848, -14660045}, {7500324, 2162073, 31143948, -14925908, 10715631, 860170, 24194172, 9222043, -7811541, 8635776}} + }, + { + {{33417021, -16477444, -12257057, -7665810, -44694155, -2003138, 19183172, -15823475, 35333901, 813879}, {25634161, -16286656, 54616993, 11397754, -13947065, 16533190, -39701202, -11821083, -13373597, 20341787}, {20823119, 1685608, 17501032, 2573292, 27721633, -16375351, 15431038, 10619705, -18295175, -4238392}}, + {{8369304, 13864786, -40937388, 635054, 11655695, 23402186, 16350073, -16089660, -25406748, 5144051}, {25354388, 12927444, -10327642, -6556414, 5503085, -9508260, -25581327, 12063066, 39326058, 4044659}, {-28124709, -6944253, -10857160, -12613978, 6601494, -6907745, -26640726, 5995244, 26707639, 8680838}}, + {{1157002, -25923892, -5114311, 13591500, -24861029, -5875947, 21241852, 1126622, 24697613, 19601732}, {-11984102, -5371810, -55230315, 83482, -29539457, 15163593, -23449488, 16668592, -30168265, 12985874}, {19802764, 8580221, -24653444, -929381, 750670, 3236963, -1172427, 6059417, -16734575, 13893210}}, + {{-22719120, -14677052, 20616602, -21048236, 8351548, -21171701, 36517372, 11239391, -1173857, -10069670}, {-25566894, 13221036, 21805880, 1885868, -7937988, -4227045, 22348250, -19700781, -63824943, 9382592}, {-32859384, 2108287, 19233257, 8885464, -5250139, 15331624, 29498046, -10485184, -2625716, -1310005}}, + {{12827255, -19954565, -32611118, -2985987, -9186835, 11164505, -25859105, -17815429, 15965668, 15498235}, {-40141975, 10457043, 10683464, -2791451, 10573731, 18433409, -20524007, -5182881, 40641240, 13911807}, {508289, 8485112, 9734998, 11170299, -9788621, 6240999, 30666318, -9079614, -28986462, -11826509}}, + {{-527778, 4743186, 15525988, 1608798, -15638258, -7475873, -8403490, -29431106, 14926115, 18524448}, {-4426554, -13172146, 20938868, -1510872, 32042520, -21426069, 46491348, 296950, -2351175, 14024614}, {-14057267, -3152186, 32396964, 16437300, 31379036, -6910223, -17758800, -13966108, -18898169, -3795220}}, + {{42823446, -21372965, -46746435, 29730653, -5498726, 11595227, 10202989, 5998412, -27981667, -8463264}, {-12879228, -7794387, 8905889, 2575659, -34146134, -12106825, -48282491, -18880512, -22270817, -10555268}, {-28245329, -6650204, 9884703, -16304671, -23417722, -1077640, 25012455, 6929759, -877869, -9767227}}, + {{2525725, -2218052, -26419115, -1321262, -4981994, -1472980, 17612658, -5897731, -27956222, 11094763}, {43857741, -8529860, -29685497, 29713588, 18054608, 2398264, -36055986, 11862259, 34729174, -1819829}, {9059392, -15013615, -21923917, 6249922, 20623501, -9365512, 14493275, 5484189, -20290605, 13306824}} + }, + { + {{7781197, -23872251, 24903650, 5464850, -9962504, 22597747, -214718, -10404668, -58092469, 19395897}, {58572843, 2397673, 41447104, 16449462, 19418334, 8293275, -18983198, -7914322, -6070561, -13199549}, {-9320084, -7902792, 9419833, 5179364, -17221978, 16748384, -14440596, 16450005, 22661752, -5959635}}, + {{7605771, -3209115, -18863410, 5402055, -50107383, -4544487, 2583286, 383747, -13334363, 7883980}, {-51198241, 5336579, -14593812, 27350173, -9246111, -19619529, -49340348, -14825927, -23997179, 24418786}, {-5725119, 14680141, -24409113, 8698670, -13043080, -5948038, 9922273, 6132427, -8237209, 14196159}}, + {{-11982836, -14437245, 25277016, 13787344, 6915674, -3178827, 89345, -2216600, 15143445, 26661343}, {36637448, -4390407, 32170910, 9628810, 2551210, 28282997, 46465813, 16632406, -24270017, -3590883}, {27494446, 9030249, -7253809, -15543398, -9001709, -6580636, -10418385, 14834819, 22738518, 13402679}}, + {{11712153, -4140331, 23847393, 7676907, -39571154, 530224, -22238313, -5527730, -34678102, 3620182}, {11933091, 498795, -17267417, -8846981, 5049674, 27385258, -15598879, 10612136, 29060570, -26309692}, {24486527, 1212661, 26010709, 9580499, -16677342, 2279442, 6943284, -3847772, 18149636, -1417711}}, + {{-8051127, 4117194, -12327491, 7343230, -20878, -14307016, 27435091, -17526912, 26807370, -19107454}, {-23753759, -24021010, -32498927, 8198422, 52097830, -6539890, 19853229, -7869456, -12783718, -10230432}, {-14298613, -12284947, -4538345, -4950001, 3010648, 5341923, -9268774, 7995049, 13713344, -1366889}}, + {{-44813479, 10215221, -23761368, 1290861, -7156268, 2925327, 29616627, 8731000, -23424163, 460738}, {-21612287, 8424771, -31528252, -27786811, 26604412, 9613569, -12495595, -94544, -16988595, 1480850}, {-26295779, 1263795, -29339759, -562114, 26936882, -12797839, 30057493, 14093051, 20985678, 3144123}}, + {{-11149967, 20512111, 50048217, 6633761, 24499123, 2996098, -2453910, 7037193, -34632758, 15413513}, {-17490501, 5576773, 11413689, 13735893, -5088787, -25620252, 16061140, -4049007, 22028686, -6334103}, {6476521, -8000266, 322964, 6555404, -4228129, -8729666, -17376684, -3241316, -25192721, -13006680}}, + {{-32933549, 6734540, -14069729, -7372171, 37945303, -11102991, 6053904, -1664098, 36260430, 6107596}, {-10801265, 17856494, 30427603, -3827155, 16080819, 21442617, 46736610, 8184376, 18041324, 21631104}, {11648954, -6927077, -20876261, 1153, -24604951, 6788370, 20270559, -1320581, 13070661, -12328110}} + }, + { + {{-3838927, 8946066, 3549599, -1729060, -19911708, 9167708, -49329485, 23366835, -30812418, -7863363}, {-29175819, 24187304, -45996371, -27411182, 38663122, -3872736, -7091343, 6647259, -8113822, -22804141}, {19872821, 2524097, 14632834, -2026936, 17227993, 10225307, 23867627, -332493, 20240346, 5658453}}, + {{1139148, 5031020, 44772867, -11875043, -39621358, 11855701, -15862588, 4734687, -8063605, -12988652}, {-23232102, -24469460, 9208535, -4694071, 18544666, -3689607, -42299930, 6570595, -41261687, 10749636}, {31740485, -4337219, -7287261, 13549385, -22964606, -4861393, 944573, 5592917, 15538877, 7588967}}, + {{4876099, -5603003, 54696426, -24075106, -369499, -550105, 28609270, -25900127, -7825168, 25713127}, {-35726323, 751135, -8368212, 9380398, -18475817, -7801643, 18137636, -3070081, 52672466, 2217411}, {-19934497, 6805369, 19741409, -8061374, -4121630, -16270404, -6239152, -11357129, 5149176, 15309549}}, + {{10972750, -9549629, -6866509, -13329860, 23902041, -3888075, -41305404, -11418468, 36536856, 4275522}, {-13502876, -12453779, 33257265, 11654262, 26796167, 13249095, -3390058, -9334918, -4796118, 15216970}, {578374, -9641998, 4235917, -8928301, -17735081, -2492971, -20495300, -10223647, -3234201, 11500313}}, + {{-44805286, -6953675, -4507923, -20765033, 10327957, 2649924, 34853514, -4956448, 11964540, -14608488}, {20630308, -15028891, -5427483, 9950831, -27331317, -8404078, -10841898, 22366260, 14320008, 18914094}, {11452089, 10807727, 7665005, -8320296, -10855984, 8892810, -5716860, -9070184, 19383200, 11673555}}, + {{28421080, -8407665, -37640427, 15575176, -37792345, 13262508, 49667403, 8020276, 38927974, -7752948}, {2272500, -12423517, 6015163, -9770834, -20300409, -15629408, 10207407, -14711944, -19252580, -22643052}, {6302340, -15939742, -831123, 9378674, -1567862, 13969657, -11884332, 5052070, 30142691, 4789338}}, + {{34684214, 5771666, 24463802, -3326522, 33029431, -5327469, 45516411, -13912463, -10750094, 32416976}, {29176214, 18120548, -24420374, -3207332, -30264975, -22644525, -4558995, 8212389, 45425618, -786578}, {31328129, -12145582, 2096803, -11086590, -18250048, 11346082, -27683390, 4314292, 18536695, 2521507}}, + {{-5168329, -7077097, -4615929, 2903099, -27443549, 13685814, 2068768, 15274759, 22004256, 18945176}, {-8824521, -3637975, -40579725, 28113849, -25014309, 6257674, -3077398, -11530939, -7840690, -13537010}, {25410120, 1724187, 17119604, 15206198, 31819350, 13295816, -22930641, 9401229, -27497255, 7824654}} + }, + { + {{9633463, 19022023, 33888879, 8168625, -8454388, -6465593, 314346, -23197429, 3856764, -6979123}, {51764025, -2356863, -23607655, -15867521, -46231348, 3103519, -64806666, 4799889, 39026226, 16620939}, {-30022012, -9109746, -7724838, -16245898, 19623957, -7566246, 28829868, -16310392, -3522604, -7659236}}, + {{-29379687, 10200010, -31910288, -25482835, 3983975, 3907793, 46863568, -4852990, -34845469, 9291323}, {18934329, 21435332, 20963626, -4073563, -53412467, -24688599, 11861146, -26481682, 20809759, -5940613}, {-20791200, -13841150, -24779295, 9325480, 13338835, -15576530, 4173723, 10010420, 20325101, 1871524}}, + {{-61092863, 23339718, 38524874, -15161353, 56174083, 436882, -49850362, -4503872, -46402848, -8094857}, {-3077431, 2094324, -8312012, 18097839, 378101, -2485884, -4310474, -24849174, -15294248, 17574937}, {15484284, 1704895, 14937434, -14787341, -10758627, 10726051, 10987595, -9032118, -15609854, -12712258}}, + {{-28708526, 648962, 26139151, -7773381, -50120651, -8564213, -48894023, 7607981, -63567381, 8507712}, {-9311400, 32377742, -23552425, -14883399, 16585693, 24110063, -16467893, -15690037, -2233505, -17312754}, {19862803, -14366842, 22497873, -5713553, 14272944, -2509295, 33285202, 13819558, 9433193, 11353155}}, + {{18254872, 148107, 10616064, 8663081, 7817692, -14250063, -5050090, -1248892, 16687945, -10231461}, {-18552634, -10466209, -42788350, -7179895, -46504900, -8143525, 60814050, 5400760, -9823067, 7310915}, {-32309400, 14643274, -9155565, -6884180, 13489400, -11838108, 26834567, 3153122, 27372500, -7068152}}, + {{-37690472, -10395223, -34750913, -9320800, -9764303, 10503605, 58536452, 5303841, 22315889, -6989491}, {18774894, 11320303, 972729, -13370994, -11559755, -10871769, -2661898, -11273345, -44401413, 8848277}, {17288840, -10777765, -5217896, 12629893, 30788509, -8763345, 33175474, -1044331, 7005680, -7837114}}, + {{-5940475, -6641804, 16107249, -26136265, 15111311, -22285541, 17640399, 2233685, 14602706, -4672795}, {43418481, 7840500, 38381785, -2312057, 24853207, -8055059, 43014989, -7256369, -20927528, -7858265}, {3457320, 8177085, 510551, -8815010, 19355487, -10661008, -10061460, -9637670, 29826183, 4336994}}, + {{31574019, 3809579, -22508527, 22652243, 43795993, 13936395, 17446167, -10644831, 10388397, 5290794}, {25799569, 19797219, 17700069, 983253, 15141595, 18240779, 25682163, -16041789, 50942243, -15906000}, {33433102, -5628405, -4206130, -6607006, -33360919, 11248238, -19655535, -4249099, 14682177, 11920747}} + }, + { + {{-23519789, 10406991, -46809255, -4784065, 490724, -27367194, 33105022, 1255552, -44489131, -3853297}, {-7269189, 7789797, 12114391, 15296039, -30974954, -2820992, 10410220, 4598304, -16412453, 21668293}, {-25760035, -9219079, -15505593, 3068385, -30628222, 7869335, 30225275, -2084026, 387578, 15035110}}, + {{11858284, 4765786, -52990305, 6796455, 28429186, -7060115, -9277332, 19417647, -33953751, -954065}, {-40755362, 8539736, 7078039, -877589, 4772832, 7172185, -40668770, -11756941, 7310117, 27161145}, {-28139345, 14001530, 8746141, -14360244, -24961820, -11666031, -24206229, -740468, -13490173, -16745850}}, + {{22660733, 15449395, -40905725, -17610557, 25037680, -4130114, -5167748, -10914968, 8964622, 1767854}, {29878289, -4322833, -8743227, 349607, -29483960, 11085302, -2615354, 10106182, 31851150, 16289140}, {-4208916, -4071575, -21914828, 5518522, 24050822, 13454051, -21543505, 7199088, -9993362, 3347156}}, + {{-25985108, 14401474, 18648778, -10269203, 45694807, -4157955, 19570750, -17965006, -4947942, 3910866}, {-6126654, -13158428, -21387364, 21204681, 7247131, -4270443, -10760642, -15295222, 36793694, 5452922}, {-16769619, -15211648, -1635154, 12370186, -15925548, 12407219, -8437298, 8155029, -3524633, -3199311}}, + {{2475991, 15803685, -23237256, 967965, -56799291, -12679736, -3533646, 16208206, 13354320, 8271275}, {-39383627, -7321135, 16068778, -11788879, -10182237, 5914566, 3574922, 16500084, 24520402, -11251911}, {-23011505, 13193575, -237673, 3317282, -22612403, -14153553, -26631337, 188911, 1844312, 6710881}}, + {{-30909140, -622071, -12484695, 3137877, -40581965, -19341834, 38913841, -15665521, 26710943, -12848095}, {-18729028, 26429631, 1694727, 8693493, 11329231, -4241588, -24979535, 5628123, -3540907, -1002645}, {-22195518, -11149016, 21539980, -8898580, -7048212, -6898265, 4171045, -16493069, 5535737, -5049994}}, + {{-8621017, 2452093, 28171278, -10095170, -5278703, 3331664, 11585851, -14187355, 30316770, -24971062}, {-31843233, 26126115, 8310400, -17249758, 38945201, -16090690, -21781465, 734413, 22142956, -1715802}, {-30834651, 4117123, 23300299, 5880686, 11904328, -12736297, 15634660, -15704869, -15005515, -13560465}}, + {{-37137731, -24139743, 48352752, -695146, 32448851, -6130157, 35875951, 5604310, -47841979, 4221117}, {-547897, -799509, 6828634, 31423322, -20417627, 6038685, -6883809, 23562360, -10067907, 17214641}, {-3051884, 4040580, 10045488, -16755994, -21674943, 7791887, -32559275, 4015114, 10614076, -15724071}} + }, + { + {{1772032, 6562740, -32765258, 19522226, -11014089, -1604338, 31163259, 27191143, 30760040, 18204251}, {15980952, -11501072, -32181484, 12628584, -27562797, 14005320, -26756491, -1139673, 3915074, -10137757}, {19879210, 15086081, -19617493, -9097496, -2730175, 11970752, 30951967, -4435125, 2716516, -2539676}}, + {{19521463, -3949233, -10860355, -2489194, 49494, -13950832, 43105128, 6607152, 48312455, -5648381}, {1934639, 21832443, -43890967, 23400028, -64128388, -8197912, 1331792, 897064, 946713, 8597279}, {-16507401, -6235703, 8260507, 3128911, 3409192, -2438562, 1256656, -13324301, 2588622, -12249350}}, + {{-54238853, 4355243, -49922517, -7115449, 17202782, -17185542, -7993070, -7583160, -40176346, 28676669}, {-1289905, -6280661, -2973463, 5383253, -10479492, -2710004, -33482746, 1850812, 13899552, 3850869}, {-2508306, -12785040, -12226153, -11184759, 5148014, -7507834, 4505285, 11639391, -22561547, 937240}}, + {{41333243, -10765611, -50610897, 1857287, 16762316, 11513673, 15250259, 22160801, -4624997, 4349912}, {169169, 16151463, -5451187, 15250731, -12066600, -9843421, 26556231, -7500269, -43193915, -21655612}, {-10993330, 8342750, 21656403, -11510214, 12918822, 5182173, 2621656, 8791455, 6329052, 6089645}}, + {{23811143, -9440291, 2754878, -18206922, 45829880, 857788, -40132370, 4508093, -2943759, 12463099}, {32497633, -2601911, 63227034, 4250836, 6241316, 26657154, -7432806, -24156365, 24852155, -5389941}, {-8127989, -12910418, 21816828, -142209, 7335542, 3319621, -5345522, 11161584, 31044453, -15030962}}, + {{-9584327, -8134729, -28261175, 14489186, 8222045, 16186498, -3852745, 1795619, 19336829, 17739098}, {-7730297, 19252347, -23159639, 14268088, -32247371, -3006398, -54382461, -27556917, 45982681, -5703162}, {9808449, 3945217, -32465180, -8796425, 31328457, 15880418, 8370728, -6148005, -15290446, -6557579}}, + {{-44687768, 5670824, -14722582, -4733173, 17122073, -847952, -5627965, 19009838, -23747165, -1453207}, {2234786, 10088248, 22316174, -15574667, -19272793, -18153464, 29156957, -7446492, 3251115, -25178741}, {29304403, -10728396, 25647583, 12198426, 27346955, 63950, 18242102, -16547413, -7574627, 10871964}}, + {{-48929340, 2968446, 474182, -6757543, -38388721, 15208207, -31806867, 14190812, -48845928, -1470502}, {-2545304, -24000016, -59811098, -1939209, -17623469, -9799745, 25683227, 12196064, 4214740, -14740518}, {26933806, 7407287, -13150154, -9490061, -29239123, -2802803, -9231566, 6825264, -21611219, -9933017}} + }, + { + {{43016965, 15705701, 20442551, -7940737, 2555029, 10725950, 29166376, -1667668, -20312657, -10689236}, {3820175, -6474265, -46035043, -13531173, 41430843, 10417362, -33288026, -14620978, -1401597, 8447294}, {-20433226, -12241763, -3016794, 1891356, 16496144, 7850955, -18347536, 10034820, -9746714, -14507431}}, + {{-48407507, -11683773, -18012190, 11863672, -29753768, 4683670, -36975564, 13576809, -14701774, 1535040}, {10239005, -9826803, 36891100, 1500216, -6645424, 9643274, -7509334, -9268757, -18155778, -6816944}, {-23498461, 9411269, -26557906, -6406986, -5272428, 12503415, -32831925, 11143016, 5590245, 8334430}}, + {{61031549, -1101793, 54103057, 9091967, -4436371, -9402358, 25991824, 30371397, -19841010, 7937313}, {388675, 27218059, 12612625, -2638969, -2964893, 4983792, 24305498, -2185609, 20428302, -21524003}, {-18960973, 7893016, 27045114, 4079921, 27536921, -9829181, -25958628, -14883683, 30398174, 10277245}}, + {{-1587781, -11497733, -11573560, 13126556, 20845495, 17270956, -30510292, -12694926, 27519491, 28729686}, {-7157511, -2397111, -53844340, 3627788, 16602851, -14027862, -696788, -2274626, 38222831, 2252584}, {-12405263, -1681681, -13159821, -6320119, 7316360, 3727073, -18309962, -4647016, 28529514, 15416492}}, + {{-13280399, -30506359, 5854795, 806575, 1954876, -3535888, -22784558, 10017133, -5618694, -9743775}, {-28028201, -2378015, -23019059, -29100543, -34330076, -24985398, 32985014, 16281077, 43725756, 18259245}, {11675001, 5510446, 22873075, -6864006, 27375376, 13662394, 5462602, 6927570, 14233094, -12971689}}, + {{12057457, 32210870, 20720679, 13354573, -3629017, -7026667, 3957924, -14338893, 41433789, 4136818}, {11158283, -670016, -4976523, -12123511, 44375853, -6403451, 5876206, -18558063, 24673395, 24834106}, {26168421, 8280272, -23051079, -14608992, -14879826, 3779315, 16641301, 15793570, -26079168, 9812423}}, + {{14770462, 12587776, 15869411, 20957799, -43788533, 20713332, -28183953, -3527847, 39048655, -1940462}, {-14714352, -13775000, 18145021, 10029113, 20649581, 3009514, -36394907, -11391867, -3506311, 12277302}, {28049054, 14229852, -8274110, 16738645, -25483858, -5691080, -29572070, -12661299, 22517783, 919782}}, + {{-22646895, -21484547, 1633663, -14629481, 11267690, -22274954, 12265181, -7887248, 8640479, 20949759}, {-30020693, 7329989, -24393997, -5132585, 47564484, -9776898, 24212213, -6248484, -35350807, -12327603}, {-7271169, -13975579, -5673027, -7308174, 26750467, 9831537, -27902974, -13239923, -29041094, -14755279}} + }, + { + {{-13480994, -11555397, -7529704, -9323042, 1116673, -9613410, 37881920, -20965519, -41828922, -7043913}, {50456984, 21529939, -41081758, -9848290, -3487467, -18945280, -8374910, 1480559, 7884372, 14936035}, {2346705, 3885707, -27465055, 10185648, -4812999, -4919831, -26651064, 14754641, 33071412, 5885392}}, + {{5173867, 2018447, 56311889, 856479, 38484641, 859318, -28292444, 13890182, 15709885, 13775830}, {-61593233, -29640793, 3972815, 3073373, 16652323, 11086676, 31894278, -14464524, -30278767, -2545818}, {32931840, -4763919, -14868942, -14614327, 3193474, -3158083, 22304681, -12183868, 27372706, 13117669}}, + {{-11094849, -63737, 11733891, -786851, -13472103, -23011570, -26315335, -7846878, -16360367, -14838937}, {-31144197, 11737121, 7255115, 18385417, -36011801, 6846178, 38611497, 2902212, -26285887, 11696021}, {13382936, 13178758, -12025171, -13254045, -27638619, -14364504, -5618523, 2391432, -13383826, -2150070}}, + {{11750358, 7914028, -23042152, 8030277, 39615918, 9182310, -25907301, 2699271, -21126979, 5751665}, {25292924, 17493830, 21577616, 3294247, -12797430, 19577632, 20037337, 13237939, -28093719, 2186785}, {-1082149, 15209818, -21738315, 10641033, 32225978, -8265653, -25257733, -882178, 28360034, 6570301}}, + {{9143403, 23839022, 35353980, -22505492, 114165, 5113169, 6089871, -19108137, -22789338, 31675048}, {45866659, 7422934, 24338976, 3658842, 13952863, 3126973, -35311739, 2024897, -31974330, -1710440}, {-9150036, 9331663, -30127934, 7261514, 28694748, -3426370, -16300972, 11615619, 7439595, -12065698}}, + {{-6946029, -3094691, 6122324, -6237880, 22728728, -1655440, -42516506, -12961649, -5854097, -6338047}, {37792697, 25767993, 34008524, 26933886, 1468676, -4740418, -16103580, -4686169, -12286155, 1802567}, {-24852984, 4608095, 18070382, -14845825, -23142308, -14350367, 23638504, -856790, 23672653, -14163830}}, + {{-23634568, -11958769, 61608906, -29050370, 41285625, 105434, -6561790, -4438594, -33292274, -7684946}, {-31517528, -20455273, 1591586, -2076804, -16316523, 33047852, -1322618, -4614424, 6659498, -5165052}, {-13737946, 12031439, -32382748, 13235148, -8814629, 13605013, -12461644, 5402562, -15891845, 4767741}}, + {{-8340464, 12290254, 9696374, -27635151, 5447897, -4962608, -2555388, 20864333, -18929971, 14682090}, {7326350, -14051670, 36958530, 5236393, 10585213, -1655034, -43306320, 1201929, 45742857, 1723804}, {28984607, -8062399, 12382644, -13411363, -8302161, 1185523, 5798259, -15291873, -10210235, 16755402}} + }, + { + {{16920676, 16715259, 38145133, 4785281, 1451168, 7735604, -33281925, -8688939, 1199163, 20394696}, {24193060, 15252485, -9385529, -16267613, 7141382, -8225994, -27882531, -12148187, 2459699, 9049808}, {-32556976, -1167865, 11418257, 8056263, 9550693, 7227052, 5964360, 4857140, 27143497, -4111365}}, + {{39817193, -9830193, -16026583, -1858407, 24498623, -10604985, 4840981, 18346064, -35506492, -1518604}, {17780935, -15507949, -40328285, 17134723, 37227365, -10294427, 37117755, 14077886, -24533620, -13386792}, {19434905, -6445005, -5302583, -8024017, 12497703, -6346095, 9276329, -11657559, -18713435, -9163875}}, + {{-2658895, 5484905, -23304555, -6179240, 7853468, -18159650, -42007502, 2244695, -1048321, -8867171}, {-9541025, 14553687, -22038865, 12406006, -4669674, -2533266, 11360372, -29353103, 35549887, 2878079}, {-19460989, 8848965, 11242605, 4720082, 23940066, -12182196, 19657279, 13861652, 14245366, -4262405}}, + {{20433395, 9138713, 16524632, 23665100, 33180240, -1312297, -34304099, 6222943, 9644596, 4167688}, {23398647, 17645543, -34768544, -490194, 13561630, -20711293, 31661255, 6093001, -4576544, 28813278}, {22277382, -7545728, -14268136, -12035122, 31230436, 1201743, -29397285, -12319388, -5571886, -8099235}}, + {{-3532555, -3063346, -2362686, -27218502, -34810150, 23173153, -21022797, 869907, -1416822, 11984683}, {-32690879, -29278752, 48411730, 5531838, 22586942, -8260081, -22395517, 15424083, 37340188, -12027481}, {-11898027, 241191, 12868313, -12540493, 33291329, -2895370, 5354657, 15636945, 17430868, -1528003}}, + {{-18239631, 7159148, -2492250, 9169283, 577887, 4929610, -26679656, 21184233, -18227970, 20271950}, {47007109, 16108010, 33364994, -18183881, -41920803, -22032508, 37374200, 9349329, -19872404, 200584}, {13795360, -9738463, 20295911, -8727094, -32972237, -12516214, 5607958, -3800534, -28273841, -8179638}}, + {{-7940918, 14445664, 37472019, 7673591, 15526413, 1142009, -1587886, 13426454, -25100819, 14531703}, {-8249900, 17975860, 18229797, 9000485, -33170559, -1385195, 39477234, 14779280, 3023371, -16826195}, {2613522, -7309805, -10698441, 13079416, -19673545, 8908889, -14262870, -14297501, 14984663, 12961997}}, + {{-36560275, -24678255, 25531236, -19681840, -23845161, -18340656, -38747189, -8124717, 58776406, 4415882}, {9262225, -2985175, 34127952, -12604714, -36318985, -11344174, 7597161, 1546003, -5014406, 29026088}, {9535890, -851902, -9132361, -11035441, 11548366, 9634834, -1946027, 7078086, 14212407, 7217403}} + }, + { + {{57423576, -10292629, -2592212, 2235804, 3661669, 18270881, 31537531, -22712105, -6195683, 7808912}, {7797084, 454143, -13161378, -18826374, -40734425, 6345021, 29967859, 2918283, -58754971, -10409200}, {-13249253, -7329951, 22231134, 4459089, 10882220, 4860743, -24698083, -9978431, -5670105, -12238132}}, + {{-53004124, -5167567, 15085886, 16736499, 22058360, 17546247, 33402290, -3482449, 4415911, 2060642}, {13490798, 25388575, -38810830, 7017943, 1924398, 5183359, -29909506, 1386739, 23387649, -22674070}, {-29458736, 2492433, -13556795, 11205665, 5611991, -2334748, -15775678, -748234, -1064772, -6627890}}, + {{-25413498, -11501850, -39078455, 3459141, -1312737, 11802978, 5222471, -12187652, -49890945, -2774679}, {-8545304, 10829884, -16118899, -2584317, 16517895, 19442656, 19487957, -10665948, -13785077, -1126361}, {26083646, -3365846, -7761387, 13193122, -16798931, -10773697, 10735134, -10064491, -631120, -3597651}}, + {{37713250, 25562955, -34148392, 19546437, -28591503, 22733045, 30032242, -8493268, -46165976, -1307385}, {6336844, 7177473, -17252068, -10225857, -117641, -970677, -5846042, -4627888, 16077668, 21643231}, {-1953103, -6202443, 6215146, 6858001, -31665887, 1767882, 9065802, 13748405, 4391154, 15125407}}, + {{-1246957, -5713173, -10965980, 21528319, -802220, -1581441, -34127986, -7208245, -1546234, -7831521}, {16315129, 18738101, -43749014, 8120457, -61330822, 11005527, 12851608, -14466907, -42071268, -24312427}, {18246764, -12570019, -32115190, -11475783, 28055067, -3268351, 12083407, -7144167, 1986840, -11974960}}, + {{-16495641, -6305095, -465574, 26891470, -14945650, 5686905, 51114414, 7396298, 17851979, 2075751}, {-42361147, -2756757, -4354846, 5332258, -20891836, 15194993, -2767554, -25458098, -33474145, 30974835}, {4354329, 13304857, 23978922, -10718411, -24725471, 11349719, 16727616, 756811, 31349636, 9287913}}, + {{4954258, 25212368, 33338703, -14077779, 26545665, 4848917, -27615055, 3427857, 17990812, -24979274}, {18233158, 7461744, 7720987, 1464809, 31058651, -14033807, -38319807, 18136481, -23330916, -7631018}, {16032681, 8136631, -23556212, -3150664, 16622171, 7980128, -25727701, 5626779, 5190447, -2344328}}, + {{31705814, -5147275, 52005727, -24537023, -7338334, 3638109, -49222509, 26008835, 32931979, 12843402}, {-27709400, 13248641, -8524705, 2457713, 41586318, -28938943, 3221771, -4119929, -12860975, 18037028}, {-21656822, -5210725, -6430278, 660178, 5940859, 6216710, 7908540, 11228907, -7911737, -11283781}} + }, + { + {{19447848, 12079480, 18084012, -19364727, 29309442, -14161359, -8563027, -6912806, -47392349, -7802083}, {-46591322, -18757630, 25853694, -3476351, 24526328, -4811551, 20172795, 25381790, -16367335, -12356703}, {7094404, -9637684, -10386451, 13743093, 21134780, -14567892, 27055785, -14632052, -6505660, -7976678}}, + {{24447028, 31663572, 32402997, -10532248, -31138504, -16630801, -48353038, -19147303, -64897597, 1158936}, {24922986, 917316, 15516165, -4507326, 3900200, -8263679, -6130850, 3765009, -412407, -25676548}, {10015781, -13588022, 6185149, 10420138, -12350239, -10426361, -24076311, 14497252, 13526594, -3129301}}, + {{-7280977, 17509339, -11260345, 10160761, 2323115, -13864406, -3146521, -13371384, -4944466, -2202578}, {-38303471, -1299679, 32240355, 4035543, -56302311, 5378430, 41929079, -1470616, -56609454, -1437084}, {4807734, 10589874, -30176402, -15726584, -32976194, 77734, 18517570, 10244433, 18191544, 12803322}}, + {{-31426453, 9478167, -42043789, 16661854, 5841857, 4378474, -20534652, 5627989, 26217404, -23194481}, {-27276087, 2045817, 3193901, -12870658, -14201131, -1952602, 36599648, -27467711, 30806230, 4980965}, {-3873087, 10746631, -21263291, 9115873, -30003099, 5027981, -16843621, 9760922, -21977224, 11975187}}, + {{25728997, 14671420, -29671617, 9545971, 16085808, 7356686, 28422751, 4087701, 11644116, 2800038}, {-16893223, 16591756, 33261895, 14044461, -51007496, 15573340, -23013943, 22191497, 36413112, 9718784}, {-29463084, -5675285, 10662787, 15123659, -9942558, 11004487, -20091178, 16640809, 12303796, 6569712}}, + {{-45464670, -15443267, -41363101, 5182103, 32816612, 11861614, 6778429, -8065578, -19759551, 12516634}, {-11130112, -5957825, -19862013, -15112507, 21294814, 18729764, 55280511, -18866902, 21394761, 12947556}, {-1557852, 4371262, 15721765, 3754968, -13847973, 4644561, -29260226, -16532003, -26854538, 13438948}}, + {{11530327, 23830935, -18227916, 7159165, -2384902, -13197972, -13004181, -3534851, -59294380, -4601491}, {25765887, -6930129, -25054022, 5806559, -64031010, -18150826, 14667767, -13684315, 877866, 7065493}, {-22828789, -13635377, -32460078, 6570579, -2081246, 4209314, -13879090, 3929682, 18018189, -11785201}}, + {{43086446, -940424, 4887104, -3791393, 6272476, -9751170, 5613006, -1645161, -44013374, -23002310}, {19876454, 8288864, 57206042, 18226959, -56007676, 15845474, -50037474, -3944443, -9809968, 751928}, {-4107972, -12891678, 23403514, 4567926, 12940627, -7298088, -8301375, 6655803, 15962126, -1598127}} + }, + { + {{-1571427, -2814715, -31976013, 1210216, 29042018, 3427595, -10167065, -19511425, -31601765, 3144951}, {-50719607, -47205, 8793361, 17693924, -1743102, -9314481, -33057089, -6662971, -2900209, 28716927}, {-12100043, -9596968, -13097994, 437903, -32638031, -3257815, -1315247, 5614343, -22590535, -6979661}}, + {{-13455280, 4468453, 28289229, -3425348, 29533497, -22288655, -2718837, 5361191, 7004777, -3469891}, {51483606, 16901385, -33813283, 6633534, 15131383, -3660957, 508813, 22752811, -50653045, 20727109}, {-31584628, 3360148, 15286482, -8723984, -16491044, 15088405, -26324370, -5284548, -13188281, -1431289}}, + {{26549737, 5387195, 14915140, -20434555, -14098228, -1416501, 17925290, -29253878, 8430145, 18882291}, {-17317071, 3862581, 30325710, -11928459, 23986332, -21615745, -2235258, -2333606, -4444593, 3141473}, {23362670, -10020277, 16626575, 13783623, 3127639, -110896, 21657368, 11839891, -8823705, 15673145}}, + {{24398850, -13259537, 32123665, -12098537, -39525846, 16528106, -34122946, -4150212, 38681337, 2190321}, {30885110, 14321117, -34368297, 15189965, 14885346, -7786788, -30598992, 29268436, -7991659, 24007869}, {-6105722, 7457049, 18756718, -9896105, 30265139, 3478624, -33127370, 4183499, 14245730, -2314081}}, + {{-29121228, 22130367, 10405634, -29133896, -1442124, -17735351, -5986555, 3256899, -30211779, 10459334}, {-7471950, -10470709, -43129432, -438472, -28755566, -12571235, -44867755, 18331991, -13798043, -6673726}, {31090790, -14430637, 2506609, 11709900, 18344597, -10525137, 21818404, -8786312, 32126131, 12845770}}, + {{-48373811, 9559789, 37042620, 21996038, 7453854, -22634569, 1086003, 5225244, 47823391, 1214140}, {-7558809, -15025707, -12931256, 8495596, 28851846, -2847845, 41101507, 10297290, -9559711, 812902}, {13711262, 9982769, -9898343, 1733229, -28802434, -12044815, -18354644, 8849330, -10034897, 3451680}}, + {{1108160, 11326080, 33383781, 24102167, 30332279, -21864759, 33265664, 17693415, -274492, 20184839}, {8986870, -13854146, -22073055, 2757829, -26354323, 813579, 15356358, -8914267, 55811500, -4915921}, {31781453, 5859939, 21838109, 689743, 15106474, -11026098, 207134, -11210873, 16130072, -5233974}}, + {{9615249, -18348909, -49401245, -5757686, -34015637, -4958617, 37761478, 24352231, -57305458, 11827354}, {43990315, -4491023, 13000533, 18331472, 8710495, 16278677, 24989444, 8467983, -5164130, 19176592}, {7206760, 14366796, 18553843, 14622639, -14270824, -4358078, -8218032, 7664097, -28607267, -14628083}} + }, + { + {{1892499, 1301069, -27743734, -8924509, 35981140, -10432725, -4754318, 8655230, -16406815, -339205}, {-50958721, 11127195, -11019952, -10307257, -20165218, 20063985, 21894512, -19900958, -30144355, -20656095}, {15607830, 7616443, 19713312, -12323979, -20964194, 4107936, -30447440, 6495422, 5992666, -10307573}}, + {{-21232449, 16431459, 12530510, 16695237, 12906731, -3768714, -10763240, 29654181, 59974317, -21800748}, {-44211361, -13375153, -32095666, -13501201, -11533529, -29643668, 10565180, 1283857, 815371, 10845004}, {27854714, 14161699, 1699881, -7967975, 15760551, -15577950, -23066901, 5022467, -14516336, 564619}}, + {{-17950534, -13299806, 56486934, -19559260, -34409780, -7218915, -11146345, 22094273, 39816748, -12234679}, {-46183462, -19123792, 26464, -6685880, -30478768, 23752647, 51609111, 4254955, -5574854, 20412299}, {-11422616, 5102964, 2738206, 11476294, -32399966, -2790740, -9993091, 6486712, -27440649, 1761067}}, + {{3439151, -29722082, 35417832, -1525657, 45042730, -1430905, 17467124, -22670777, 4719515, -1132811}, {-10222803, 2073120, -2377230, 21432397, -4221180, -25187825, 42489004, 849761, -28361529, -31769337}, {-31065392, 286699, 26599688, 9679662, -21314829, 4809486, 20702915, 4553314, -18747115, -8319858}}, + {{-1603332, -13585818, -38358591, -16079890, -10931437, 8490731, -12776452, 5215299, -12124365, 378813}, {25498658, -644766, 9756365, 475122, -7662851, -15572361, 25107722, 26515205, 19185213, 6224105}, {-21429699, 6351015, -16879801, 8380446, 9507014, 11769912, 23586254, -1807951, 26737090, -2008366}}, + {{7081450, 2677166, 22671383, -4828317, 17842808, -15335283, -3041432, 5399867, -1819170, -7720992}, {30161366, 9103968, 44382849, -10033545, 33076528, -11607557, -42368046, -22809965, -47760522, 5483306}, {1593389, -6024160, 3395147, 16575517, 7493064, 95550, 15558992, 16506356, -7042011, 8389603}}, + {{-4481238, -5684599, -35685590, -19080336, 53283160, 13406199, -10004250, 906158, 3289076, 16806125}, {26189832, -15004967, 8182468, 5716584, 6111736, -17915331, 45014602, -27581184, -49118074, 11755683}, {-22965161, 16434546, 24594714, 3578195, 9798345, -3698700, 5777307, 1926114, 17712616, -7068040}}, + {{59485861, 5072769, 692255, 5642719, 12193516, 5984165, -20420432, -17690777, 8318789, -7961945}, {5539095, -9840791, -60584193, 26711215, -31516814, -16062777, 39035052, 2837629, 46689805, -14152839}, {-2800992, -3638477, -11821662, 7268400, -27577991, -796098, -24672533, 13747705, -26016389, 13661609}} + }, + { + {{30605491, 5233683, -18648915, 2025168, -3231586, 9978261, 47401907, -10936090, 11058061, -1003749}, {-28718039, 1272771, 31278905, -27679744, 39451156, 21400207, -11209003, 11451658, 12210251, -27478759}, {23534670, 4113853, -32054153, -9593556, -24628615, -6776535, -30687006, 14199133, 8497366, -10031923}}, + {{-34921403, 2693281, -17918198, 25403779, 40434373, -19620678, 20053337, 8747850, -6150160, -12137216}, {-18562189, 13284305, 40707434, 7579221, -23136315, -13002288, 39016445, -8649162, 50464212, -14897864}, {29528755, -2518696, -28086015, -4005256, 33200944, -6589857, -16301731, -1100097, 12786545, 6236340}}, + {{21877076, -9653759, -46280374, -6059209, 54607270, -3842219, 6144769, -14831167, -54471346, 9719011}, {514702, -16351079, -20306558, 25172595, -12450502, -17335867, 19483881, 17066147, -5547228, 6176435}, {-33303974, -15303094, 84074, -4152103, 296884, -12624825, 22111513, -15126980, -27912698, 14821492}}, + {{4837397, 11485892, 16390648, -16411498, -33782265, 4594245, -9123571, 9652566, -37410166, 21597429}, {769821, -17556746, -22344850, -8660584, -7031031, -11081149, 33972831, 15307650, 14124834, 7085331}, {9069320, 13852193, 8781666, -2665310, 32998180, 4491983, -11645413, -2562603, 29676695, 10247957}}, + {{-25214309, 19553785, 11318253, -12272481, 42808410, -4352309, 6963919, 1108204, -23778174, -15807661}, {-21478791, -6580893, 54255551, 16102105, -8507256, -5811021, 21022471, -25765618, 41154780, 1950333}, {-24657512, 12995163, -16060577, -8507773, 18556150, -9892215, 20595578, 10347876, -27684225, -11424345}}, + {{26748617, 5217478, -37757767, 14419725, -9387810, -6808361, 23756843, 16095648, -26580434, 23233420}, {35969251, -16568118, 21145299, -16513097, -12942810, 18818351, -28126091, 11474178, 33397936, 5836170}, {-26462996, -9253929, 22646536, -14658531, 5071262, -8828652, 9072972, -10810039, -12377202, -2804440}}, + {{2018046, -1709, 48507269, -7787147, -28056527, 26387205, -255883, -8097302, -39604149, -10885642}, {22259878, -22451123, 8483601, 16952131, 14258005, -7112561, -10223101, 16257746, -10089653, -11357640}, {27412614, 11045568, 33397042, 7204032, -3944880, -6771874, -19083287, -12096530, -19977728, 12208290}}, + {{60919288, -19127799, -12608309, 15256300, -42904216, -1055666, 32441480, 19654131, 45013609, -7445754}, {-679860, 628111, 37171641, 4824046, 10752632, 7804374, 10004116, 4364635, -3386311, 10007218}, {29662446, -4860596, -21168821, -9838285, -20050937, 1941410, 25646132, -425216, -22341736, 396489}} + }, + { + {{-15193484, 2788165, -12181519, 3709794, 42199369, -481751, -19021085, 10410541, -7378715, 18806491}, {-27375094, 24835931, -39872275, -11792390, -12347277, 6866025, -40699781, -99929, -23356017, -5362725}, {33526364, 15737244, -26411103, 1851538, 29015293, -1595757, -8595260, -11612436, -8530927, 6897225}}, + {{-31500107, -5199030, 5079707, -13171164, -24538393, 7039991, -25071558, -20669002, -22698480, -1314761}, {27900021, 12288234, 19298847, -8119100, 38654067, -23272975, 39006784, -9038910, -39479518, -9056017}, {-27252394, 12068223, -28382014, 8487941, 13903446, 343731, 6801282, -9223125, -25595497, 8692445}}, + {{24382178, -16090484, -40674628, 5282641, 12906032, -4066779, -9743704, -22220867, -26888463, -20062337}, {-35328422, -2883978, -18340604, 8240619, -21614224, 7375113, 8364606, -5823919, 37740627, -12267491}, {-20682878, 13061381, -10485799, 14040118, 32996892, -5882029, -20610157, 13825235, 10364287, 8210274}}, + {{26284729, 383293, 37169244, 31100394, -6468611, 6388726, -20326624, -27009263, -1031524, 1170464}, {11852283, 2339785, -18011850, -2314762, -2815855, 19942432, -35450298, 6078081, 25270744, 3041866}, {29171716, 7019663, -20742479, -1118566, -3568078, -9910144, 31141797, 1555531, -13556891, -5756363}}, + {{15771167, -4873782, -30766854, 11344373, -11422977, 23660609, -315085, 13769878, -10987507, 12753408}, {-25681415, -16156792, -17085662, 19167871, -53549737, 403251, 11651317, 9480222, 30052241, -2064388}, {-21286638, -1233670, -28520950, 4287841, 4495089, -1679170, 539292, -12052974, -5118353, 8704104}}, + {{44846785, 10136198, -22108177, 25856249, -22615749, -10052046, -2583020, -4331118, -13081104, 5855409}, {18197757, 19651220, 23739125, -2404843, -33685161, -561938, -38195050, -18725610, 28155478, -14788537}, {23388591, -938413, -9710789, -14997126, -15060280, -11417608, -13969067, -2814196, -10387481, 376732}}, + {{20361675, 1291578, 31503038, 13978856, 9218557, 1027241, 12853225, 13267865, -26506324, -13628916}, {-31178027, 31394234, -15796976, -7394198, 11947197, 3178417, 44681635, 18544083, 38615548, 12992196}, {26330014, -16426657, 12841105, 11268705, 776927, -1239057, 22981633, 8158639, 18960215, -1177179}}, + {{-13504629, 17237673, -14038583, 12244930, 10017779, 13514040, 34630029, 19762283, -28530594, 6407882}, {-27580741, -3187769, -5677929, 458022, -34094587, -19402390, 26696381, 9486941, 15046978, 81160}, {-17705173, 15416103, 31126353, 3058411, 26848404, 16666221, -22793898, 5886459, 16469624, 9146198}} + }, + { + {{-29734036, -22468588, -38362848, 25094892, -35606527, -914829, 2747745, -13089201, 47543140, -13278696}, {-22459978, -2391576, -12956000, -6732944, -9397545, 2648507, 54081039, -18516863, -3236926, 16808512}, {-5991963, -487406, -32133911, 2522033, 19745315, -16223281, 1670937, -6597607, 6828882, 747789}}, + {{-19113981, 24361885, 30958985, -20641386, 12169016, 5180, -22828927, 9401377, -57422792, 29188486}, {22324213, 5161589, -2917979, -11448782, 26571604, 19159532, 122011, -14194923, -8829774, 1228164}, {-6564432, -206710, 23034799, -2305964, 11448685, 13852631, -6757732, -5559800, -10761830, 9235392}}, + {{22139345, -24859394, -3476901, 6564307, -45599688, 18371843, -4353246, 21279849, 6891787, 5909226}, {-15203745, 4995310, 34529277, 11712187, -15095434, -10971169, -14712264, 8146817, 2172151, -8281734}, {16435126, -4004221, 26140808, -3525150, -28634168, 13078851, -28179608, -16409319, 23142677, 640772}}, + {{-7103397, 1737046, 58560262, 20608710, 23465831, 15653906, 22354223, 2815185, 30940891, 1862603}, {-35661199, 13180474, -836164, -2416240, -40775515, -7908016, 6590117, 15823587, 19986247, 20334633}, {21667647, 12375693, 18588748, 13551272, 12238921, -16466422, -19798363, -14312401, 12923063, 11691182}}, + {{58372513, 13412053, -51717636, -14673861, 19135889, -10333378, -41242272, 3188039, -46425403, -20413821}, {55755, 17299671, 474110, 11085049, -13888145, -20438928, -9066290, 15651729, 4933453, 5638481}, {-30792139, -4504491, -23435833, 3259673, -17050867, -15255784, 24195029, -9374589, 5623044, 1300016}}, + {{15758880, 6032776, 5951804, -3482564, -10868027, 7429092, -8173543, 15840329, 38918720, -2726468}, {-42088266, 12583448, -54069028, 17864914, 30199323, 16504492, 24777599, 3265919, 19553510, 14535496}, {-13075624, 15836358, -5798448, 2761473, -174881, 7995654, -4743560, -3756902, -31547717, 13634612}}, + {{18169612, -8271187, -24775016, -2018822, -51210415, 10429073, 30039743, 14672026, -43725169, -17717800}, {12802166, -9323803, 3427594, -10388248, 9667099, 5397143, -13515713, 9777914, 7064345, 13045374}, {-5585305, -591177, -15352186, -16477297, 27682970, 15587978, 14051175, -13437493, -33451365, -6439289}}, + {{-22821437, 7348073, -57610231, 971502, 49917670, -8247521, -21081986, 11518620, -12892125, -10801170}, {673353, -24801559, 6458207, -15489076, 2230510, 12457365, 43074670, -506244, -21519267, 11006488}, {-9346991, -7484442, 27037940, 1875498, 19795928, -4956257, 20546628, 16409829, -32103044, -3770496}} + }, + { + {{-6053355, 5957591, -3096160, -14684838, -19509243, 17265264, 35558927, -1292717, -17686206, -29109752}, {-10335145, -2510531, -63618412, 4603640, -6388893, -10415332, 27468929, 6121407, 23442018, 2853122}, {-16531287, -4201170, -28979984, 7861948, 21847948, -6499485, 2398236, 8988299, 9454785, 2346859}}, + {{7027823, 14012849, -26067748, 2086198, 5416080, 4329447, -3632979, -10950637, -9243725, 16213552}, {12976523, -18179449, 21169212, 27492778, -42871986, 16383429, -15216263, -5416753, -36815449, -1697964}, {20560027, 16732727, -8009172, -12133027, 16680096, 2519568, 19666073, 11778464, -32729378, 9916572}}, + {{26185632, 19247883, 13581152, -20510005, -2230418, 23379293, 49152034, 20413823, -41079177, 3212648}, {18631446, 11664165, 28862132, -9589805, 748250, -8751757, -16555878, 12407771, -11746415, 28333202}, {-33150753, 4677831, 559938, -10005383, -24898218, 12996920, -14582876, -4351918, -31887190, 6477373}}, + {{-7747450, -13976192, -11307973, 4522662, -3369203, 10276650, 17257139, -2571323, 1005204, 3854170}, {-44591072, 1311192, 31124063, 3767098, -14402707, 439882, -15630889, 4915415, -51713468, -259270}, {21695387, -5142812, 17577428, 10717642, 14492804, 11348066, 3130461, 10524767, 19396835, 16302425}}, + {{-1321559, -2586468, -46091502, -5188924, -15950941, 23277684, -48813366, -402395, 12620220, -20626394}, {-57080789, -17364618, 12636502, 19193818, 38319131, -5588836, 13245760, 1003189, -8050568, 11192080}, {-28717465, 4010233, 990021, -11679532, -6579244, 13514138, 1721412, -15845396, 9781793, -1291292}}, + {{345153, 2601171, -11634960, -2335693, -18704106, -18573583, 43815987, 7941013, 34564182, -9914100}, {-39334757, -17199891, -39912054, 22582761, -13062860, -6411533, -18631029, -9485565, 23036810, 19377614}, {-18007015, -1043780, -6666455, -4014379, -23368209, 2497268, 19846172, -9985766, -11778753, -10032281}}, + {{51646069, -24408634, 33054920, 8392374, 29882271, 20849105, -27960634, -12074397, -20392903, 4001414}, {8017143, -7532302, 26470648, 7481626, -26950701, -8556155, 32513510, 13501595, -36260203, -1119152}, {-22748933, -6829013, 16647598, 11386422, 19202752, 5157355, -5884124, 13437553, 14302869, 12786880}}, + {{-63701949, 1819635, 29402356, -11913036, 37809359, 4877194, -13464801, -2685267, -24663653, 21367214}, {125387, -25804933, 36409802, 21113746, 10532223, 19040626, 16144795, -17613137, 1025477, -5721906}, {-33127540, -1588520, -32098876, 1654571, -23073070, -12232421, 27322957, 1129164, 24053819, -6589927}} + }, + { + {{1735329, 1628081, 11231213, -30193638, 10738152, 10308662, -19953896, 18375720, -4296858, 3328224}, {56354711, 24206661, -41241667, 816820, 19783692, 20183790, 26418936, 12544096, -583668, 29523826}, {-13626072, 11712188, 18618159, 3056994, -19955192, 12604886, 13144852, 11121563, 6927152, -6413613}}, + {{27172128, -19869168, 28648548, -8133215, 1928989, -5541754, -573629, 20185621, 52294334, -5732640}, {34239652, 2744418, 30275528, -2285233, -26355337, 23097640, -10613335, -858481, -6529684, -17844184}, {-16546559, -8403385, -5476328, -6298095, 28065830, 4077456, 2909570, 2606558, -27312956, 15234298}}, + {{-21608265, 5696141, 46683152, -6383046, -9406651, 19939635, 35117770, -10292698, 55102781, -11907009}, {-16459827, -19611397, -5058566, -10401132, 11221041, 8936151, -31257532, -1225794, 1737455, -2291935}, {-14779154, 13758551, -25503035, 3561561, -12169351, 5552333, -6887735, 5809516, -14201691, -3457541}}, + {{10489806, -25334458, 19316619, 3843737, -2001728, -15605646, 18687602, -9106868, -37429212, 19234769}, {-22388198, -4733810, -9950613, 22914669, 15187188, 3768550, -33370752, -6977892, 12472542, 10099123}, {-29543521, 14321335, 4531993, -10479902, 29540741, -16542774, 30757708, 6157960, 26449686, 11537214}}, + {{-15353460, 26732831, 7547212, 1493363, -587936, 12431131, 25712772, 16310760, 7319382, -16907861}, {-6361544, 6739709, -9210384, -4988941, 9209698, 628323, 1607162, 3656766, -23681102, -15592645}, {-16427761, -1751937, 13978822, -13716010, -5726380, -7964773, -30983087, 13376300, -6872599, -7993024}}, + {{23467673, 3233899, -55125596, 6731073, -55043395, 2277752, 24422551, 12613305, -11695896, 27691915}, {-33213633, 8983015, 6863898, 25737719, 4531733, 22734666, -11381677, -3434367, -17516448, 5310879}, {-8177770, 3449422, -12207556, -15928314, 4066127, 10281971, 21125971, -13911586, -13656309, -6493298}}, + {{7385689, 5209181, 39377058, 1409693, -42748330, 1257683, -3984412, -6899882, 31357716, -10405277}, {10819495, 2314213, -11449318, -16833093, 22584754, -23994129, 18964782, 12532364, -23447792, 23130795}, {-7374521, -4925285, -22285880, 1031410, 9590514, 11169572, -8444009, -15833407, 27442000, 9517778}}, + {{38427600, -1930552, -21520517, 5572927, 14179321, 32192515, -26181759, -10504508, -27064141, -2577263}, {-20942126, 10036730, -6326359, 1443973, 46750571, -274697, -9496931, -17698940, 38860995, -2712775}, {-23257480, -3999821, -28566943, -7985056, -21359934, -9723986, 13047655, 15663364, 2084243, -696998}} + }, + { + {{21888815, -27077762, -24364451, -631788, 23977222, 3017341, -7423642, 17517293, 28562375, 29083510}, {-9306403, 3176022, -32954593, -16833694, -19530782, 20535015, -35362336, -13525259, -11738273, 784528}, {23907366, -2472729, 19634150, 8228425, 16289884, 6574817, -27167746, 5378870, 18119192, 11110101}}, + {{4552584, 19017231, -6537129, -233087, 31002726, -1816626, 43261950, -18425438, -22728591, 17647556}, {47343362, 12495493, -17138979, 20998695, 23447210, 1684470, -9397734, -8251694, -39161659, 15667944}, {24980505, -15157779, 24057809, -55106, 25738505, -9625496, -29431441, -2186653, -428611, -2112901}}, + {{-59861155, 7730966, 5343067, 15171445, -3435152, 9904377, -2961978, 21575454, 39420661, -10779987}, {-3667411, 15290322, 11879213, -1018839, -9352930, -8984709, 14126448, 3779038, 3631293, -22182215}, {20208094, -10365143, -20674337, 12040353, 26649578, -16622096, 7047463, -9265311, -7038829, 6022238}}, + {{5844248, 9329218, -26837002, -12631765, -1924121, -5689527, 26115535, -8674230, -52993963, 13986275}, {-42646266, -21978310, 244490, -7283455, 2736817, -18753215, 2655267, 22200210, -4094895, 4618381}, {-4821381, -9313798, -12867886, -12119302, -22060598, 16605302, -13372899, 4183677, -3168975, 7670585}}, + {{874764, 1026080, -23020362, -6508077, -15431910, -12847778, -2593129, 3352636, -32829633, 22115317}, {-44558004, 20363560, 25304644, 25121305, -3297410, -7752716, 43644441, 7132374, -18807691, -1390711}, {25218336, -15105684, 20100384, -13563112, 31371446, 1816197, 10586533, -2368944, -30923243, 16517917}}, + {{18954559, 2712079, 28879420, 13861899, -34820105, 29906073, 13798235, -6224918, 5997482, 7179198}, {20445041, 22110151, 9040812, 9474421, -9631055, 2810215, 24098571, -4682070, -50100850, -12869832}, {9276152, -8467413, 28810655, 6767044, -14793005, -3071425, -30896012, -13809894, -9166284, 8320089}}, + {{126982, 3682839, -13109537, 5133041, 17639152, -9466584, -28575722, -32547751, 40505143, -14234705}, {2021270, 3551461, -52953301, -16029777, 34814372, 16859246, -10347600, 335563, -11336195, 1346737}, {-14159270, 13552339, 22825885, -12410953, 2132839, -773566, 26032624, -10986378, 3471395, 3605917}}, + {{-39399837, -8355182, 53059756, 1019022, 21207611, -28768770, 40157885, -10602106, 12385270, 370831}, {-13726691, -9794896, 7349732, 8726048, -9936421, 2579930, 7389197, 19985910, 30588216, -25659699}, {-23333346, -13598637, -24502936, 14926238, -593728, -3173350, -19125474, 9885020, 4383659, -10964345}} + }, + { + {{-19603802, -5643093, -43867114, 14332784, -61984859, -26186041, 38206081, -18398124, -44404725, -8159949}, {-43470756, 27088661, -15481990, 7674560, -2166367, -7218735, -17028855, 8286080, 20325205, -19537423}, {24613200, -5618245, -5571478, -4996886, -7421610, 971727, 20270207, -2956549, 18166387, -5795164}}, + {{-41434767, 4940396, -4389540, 49275, -11408586, -2866025, -15258140, -20837715, 24704723, -12476341}, {17462521, -14802094, -9532510, 33293143, -22563748, -27165253, 14296034, -4883745, 31696431, 1819053}, {31212172, -3426959, -33496665, 468603, 15839340, -10550360, -2448605, 15705413, 12062149, 13444284}}, + {{9973513, -21090283, -56842664, -1857736, -9485792, -1572883, -11660999, 139207, -17475535, -13264643}, {34784813, 8451673, -5581732, -31429532, 5344592, -2356513, -21949087, 5370001, 38548907, 11812955}, {13213453, 12708416, 14293484, 8158250, 26119855, -1595999, -18040690, 13476632, 26797235, 3391523}}, + {{4575152, 20662273, -19216941, 9501479, -60081769, 5359171, 34655556, 21158819, -15005290, -3790453}, {29834326, 6360697, -18289543, 18793915, 2001373, 14737819, 7894700, 9554467, 4822220, -13236795}, {16428034, 16356947, -5821995, -15681871, -26366898, -6264635, -23112840, -9368094, 12251961, 9528760}}, + {{-31952028, 5377655, 36187832, 7405111, -6228544, 2455875, 7245414, -6460559, -10867102, -15087550}, {30616426, 16242589, 30622406, -18981597, 10704936, 21369475, -23873170, -940729, 9176454, -17455772}, {33248510, 15373608, -27355698, -10566187, -8681912, 6962342, -5739495, -14073168, 12519634, -8066785}}, + {{-24168453, -16479408, -6649457, 15270338, -16646429, 15731444, 38681614, 9463522, -23939326, -1332658}, {4761003, 12875822, -39674579, -8918256, -11736101, -14823434, -17328630, -15912636, 14424698, 29256108}, {-469213, -8171959, -13549599, 1676962, -10981161, 15586841, -17705167, 2723666, -32041126, -1521100}}, + {{-6017212, -5549830, 27177484, 2166190, -9612618, -14225331, 24588380, -11839501, -5494342, -6384723}, {-10949774, 10762948, -10056596, -26714934, -30761322, -4031775, -22693466, -16365273, -36442500, -3306271}, {-3891582, -16198826, -24541082, -7243985, -7758215, 5537387, 24815381, 136784, -4589866, -15049647}}, + {{16522000, 18053634, -27371531, -8191948, -12154110, 8416557, 11081997, -8905964, 806537, -18964242}, {-32848858, -3463858, -4242697, -11037350, -31982978, 3449951, -29340819, 12677546, -11479495, 10289006}, {15203014, -5091561, -32723026, -15567904, 14761744, 2184359, 8059989, 936981, -33237645, -8854612}} + }, + { + {{9837677, -2607676, 20178357, -19688768, 2558522, -18727420, -58320446, 4144069, 30101922, 9585873}, {13129089, 12960730, 44982295, 11050610, 22792836, -5267798, 8687948, 9049753, 18305776, -5473769}, {1102353, 12666974, 22302942, -13537021, -11928818, -6085966, 26314378, 11472052, 25410139, 11377342}}, + {{986592, -15755811, 22009102, 20814482, 61267677, 27948149, -4491240, 14982613, 17538699, 10508198}, {1521066, -16858799, -20201788, 1483336, 1192519, -280879, -50475902, 4073211, 18960837, 285284}, {-8291661, 5575633, -13654168, 6343458, 8174236, -6708508, -32707451, 9271709, 26779883, 7692720}}, + {{-2957975, 37766, 9539688, 4921220, 11552799, -6115941, -6892506, -2212218, 596386, 16550818}, {37847823, -8063074, 4029294, 12811026, -46466477, -1095011, 50102376, -11294682, 15921834, -3412346}, {-9106740, 1285800, -19477422, -14551961, 2271228, -7359281, 519182, 9055293, -19544071, -12362094}}, + {{-39137312, -1718814, -1636413, 12092079, 32833389, 22829655, -34086853, 15680798, 40874209, 19815408}, {11108870, -18059802, -6998131, -11996791, 7165103, -512863, 26571085, 15206310, 25179629, -13659864}, {27510118, -4898975, -11390514, -15849140, 20658520, 15709350, -14256333, -3111238, -23081311, -16576185}}, + {{-8551498, 20401767, -58556332, 2510777, -58616583, -28822, -13231064, -7330565, 34348160, -1955173}, {11645588, -4816561, -3759348, 21406417, 4425465, 8778736, -8692836, 18797813, 21234836, -14185173}, {-317585, 1908637, -14377950, -12843490, 22768039, 12744777, 11022318, 7586747, -11226979, 9002105}}, + {{-47158640, -16772944, 26266534, 17873836, 1065635, 335890, -10031263, 22400922, 2083016, -22333226}, {-1740742, 10836084, 32483460, -15035628, -54748963, -26499710, -30024275, 3176738, -12644374, -2647560}, {-32143363, 15197820, 10833962, 11761878, 14569475, 3769646, 13424782, 464216, -15761096, -3871309}}, + {{11047134, -384577, 28158262, -13631995, -14591131, -8007127, -5121543, 1969265, -57638947, -4646192}, {-53201390, 21540133, 19969824, 17002409, -19385217, 18551101, 18902729, 19637557, -9184587, 16628338}, {10645328, 171115, 8988235, -7484204, 11308452, 10599320, -28836218, -9546533, -4508963, 13817404}}, + {{-18598715, -8204260, 46554290, -3972234, -5962527, 14684835, 42815485, -23799613, 4655468, -5981867}, {28113671, 23616250, 2657614, 10905660, 33258015, -10190475, 21391919, -1747023, 32773778, 5741719}, {-1205848, -16389911, -31335189, -13953695, -20458357, 10717788, -13377567, -11274027, 12742455, 10976284}} + }, + { + {{-41024668, -9877063, 610501, 687470, -57798428, -16151392, 708322, -28028073, 28553250, -22584450}, {4281748, -5235995, 29396891, 5455920, 5599012, -12829074, -18332238, -2776639, -13744578, -7846766}, {6867433, 541206, -12581916, -16526557, 25227505, 10499117, 3895512, 9663944, -25790398, 4119878}}, + {{39162052, 3903741, -3908266, 10929339, -23416889, -20866175, -32678760, 8939835, -6006117, -8891068}, {1619176, 9228347, 30746950, -7345217, -36932439, -11785083, 32906702, -2153265, -31496785, -17235316}, {-5856108, -1446617, 23743806, -5963008, 6136016, -1179313, -18888696, 519290, 19032119, 11408112}}, + {{-17916871, 8451418, -62562757, 21695852, 18340573, 11533762, -20301620, -7116805, 53534436, 4239090}, {-34979977, 21741928, -4483165, 11534852, 19886219, -12770244, 33723682, -22847217, 8220982, -11635912}, {29087111, 4758701, 32485056, 4746947, 24287783, -2902553, 11817669, 10462218, 4866160, 9028780}}, + {{-35069994, -1496165, -14338699, -3536767, 17190544, 26133484, 62946141, 19977771, 16845706, 1542120}, {7390112, -10386491, 12509883, -16005273, -2279362, -5145672, -309903, -9852861, -40675314, -809208}, {10345044, 10573183, -7060326, 6695983, -23750422, -6736076, 5325737, -11780767, -21876240, -1005965}}, + {{-29820773, -6455280, -64377582, -8642934, -6599634, 16184775, -46535994, -20248177, -38489384, -25008060}, {23334183, 17132088, -2201718, -9711938, 57876588, -110627, 5192392, -652085, 20983558, 5901490}, {-30515039, -10806648, 32348204, -7806622, 665784, -8719485, 5425851, 12686350, -13464374, 13539981}}, + {{54971182, 15357420, -37007372, 6545610, 22706710, -6863872, -21169289, 4265499, -7937529, 7919882}, {-8971078, -16360988, 20173958, -18706226, 18523514, -6238852, 28829439, 13078421, 18601537, -20973910}, {-28106111, -4354954, 6334668, -12161732, 11833871, 2040195, -12416467, 13780587, 24868210, 10112227}}, + {{-7531044, -10112472, 3967911, -23644951, -50441556, -14079072, -2266258, -18342896, 4792795, -1946429}, {-19982572, -5908682, 34770683, -2454557, 1259758, 5383930, 60118216, -7264338, 62246605, 26020299}, {-9908931, 12605782, -26560052, -12885715, -2949603, -1517770, -33539741, -1710018, 5185795, 1061232}}, + {{-18891275, -739287, 5281578, -8199782, -29521591, 18423623, -19813362, -7657935, 1514614, 603040}, {33589585, -9082515, 32880812, -3754100, 15747309, -857609, 19276620, -23511651, 30548370, -11888642}, {8538077, -16318295, -5911090, 11509697, -17677105, -10383284, -12717189, -11268137, -11316729, 4256700}} + }, + { + {{2142694, -15849014, 24642949, -8168588, -35495720, -5300219, -47512235, 11174251, -4002237, 6487240}, {-7198354, -6903200, -11356401, -3522832, 14799598, 16556265, -6838721, 10689091, -38154767, 7286150}, {-32453304, 3754344, 21497350, -8708497, 23859718, -762885, -3786160, 4076401, -18329406, -9356943}}, + {{30632067, -16618538, -11410768, 10780889, -23780183, -15953050, 38909299, 16493642, 25546403, 13830176}, {4629491, -8688198, 28256060, -17626069, -8167039, -12886036, -13529907, 13081088, 15766613, 4012036}, {-19067629, 2815720, -6029213, -194855, 6029984, 6601656, 10088496, -5109482, -21806745, 6757046}}, + {{-18313439, -9859853, -3348319, -6767975, -36349788, 1733947, 5245546, 23235525, -31496512, -14777305}, {11516693, 10971083, -31691415, -21132849, -5898920, -20719593, -44104056, 7111671, 28405808, -18692681}, {-15760155, 7563636, -4891161, -2781329, 17135328, -11210549, -5708387, -3846806, 12678297, -579271}}, + {{-14593554, 18119213, 29271824, -5599594, -4278592, 1977100, -23019480, -8440920, -6891717, 2699123}, {49567964, -13931331, 26123624, -24225222, 41330202, -3323854, -13937236, 13473938, -16320673, 8745215}, {22238002, -12832840, -9482152, 9889995, 30868814, -13607639, 25698514, -9069575, -3172120, -10656554}}, + {{-52181458, -1367487, -16340626, 21629825, -37452140, 9775973, -39054474, -12028429, 10602123, -3463626}, {7492062, -11819557, -36858712, 6494165, -7796010, -18657921, 26841482, 9719503, 42278031, -16674142}, {-15714027, 1109172, -22574544, 4777304, -13357338, -15757220, -3911290, -9824223, 14020326, 4504203}}, + {{-3685272, 13964660, 15572356, -22541543, -20930484, 19649325, 28036685, -12021077, -41201626, 8270178}, {-31993038, 11671062, -12810932, -5479475, -33796464, 6743959, -21790797, 3558825, 17425282, -22568356}, {-3170641, -13080450, -11570623, -858210, 21099088, -10525270, 3181675, 7744886, 32509643, -10541136}}, + {{61570150, -6351153, -24868635, 31892298, -191469, 9171670, 17228190, -15503187, 32010753, -2812745}, {1803028, -24293339, -29502163, -1438964, -14749855, -11300528, -16106116, 7991287, -7018047, -8624755}, {-32283293, -11848447, -21341563, -13862381, 28155668, 10919886, -21965432, -14763817, 12730861, 9683404}}, + {{10560557, -4082309, 3104917, 19655939, -2082995, -4813105, -15589911, -3288619, 4719198, 19347002}, {2772995, 27255871, -58184621, 2614383, 19130087, -22576163, 45143437, 13343095, 37539714, -11378394}, {25044717, 15236842, -32235571, 11729681, 29740450, 7156238, -31715797, -9349217, 14963091, 3673915}} + }, + { + {{17483193, 21467423, -1591323, -9006134, 18801074, 11142309, -20838953, 2747374, 45476742, 13010390}, {29023351, -8173027, -19512723, 15449896, 46841422, -19674425, -1872071, 6298660, 1423894, -9048748}, {33002451, -5227527, -29846033, -13346115, -6902340, 1048865, -24350558, -1880902, -854515, -9554958}}, + {{14688424, 12735655, -16937502, -4016228, 5749722, 825173, 8158230, 17898817, -60467930, 13198214}, {6117604, 10285301, 36932732, -21717834, -41364420, 14847559, -32440254, -12680957, 769558, 4637816}, {-4061555, 10529869, -10185484, -13911327, -30723037, 5397559, 4844125, 1225375, 7650683, 10764234}}, + {{13538123, -18674056, 22365192, 21872768, -9226492, 10582199, -4335212, -12794849, 24240713, -18071738}, {-15738093, 8388276, 1125508, -8440178, 1034048, -1911003, 1621042, -2682833, 41418595, 1990564}, {-11686010, -4564167, -10893177, 1771245, 1274582, 5313908, 12847994, 13511849, 20105450, 2384127}}, + {{-15285220, 6219896, 6451658, 12007065, -43657520, 6191896, -26819787, 15780173, 18711805, 12851607}, {-3019370, -22136886, -56742030, 7375391, -19279910, 2838240, -37954597, -15754877, 32582697, -9026927}, {-4060781, 945298, 32046953, -590543, 2850097, 3357802, 4740336, 16066484, 18576720, 8054438}}, + {{-14540432, -13269279, -34705466, 4315743, 14449688, 6027827, 8742513, -14139854, -13445047, -3461221}, {-23028730, -15811467, 24115012, 14231831, -21052122, 12642493, -53280697, -4602488, 8627937, -19321547}, {-1393968, -8963414, -19300361, -11822412, -8307014, -2798372, -16541784, 12421994, 1462153, 417792}}, + {{-4668059, -9968764, -8918170, 11309172, -11651694, -13971714, -17324805, -27382719, -25365707, 21970527}, {30752641, -17553672, -40000466, -9583496, -40769424, -5180062, -7416627, 986079, -38074397, 5151187}, {-25197975, 10889710, 2074302, 16701072, -1184441, -4609339, -18753730, 4636728, 4028379, -7159106}}, + {{-11870770, 5171122, -33503201, -876655, 23805302, -15237773, -29456044, -18986554, 8670272, -18256782}, {-41515584, -535906, 12681209, -29692675, 33310160, -852063, 11421114, 10285726, 35544994, 1056982}, {12221193, 7527020, 32458392, 7981558, -18039033, 4817434, -15335166, -8469665, -4117209, 13725893}}, + {{22663146, 29732869, -21269448, -1076707, -30326997, 2094147, 4524432, 1120603, -29329347, -4818916}, {30325592, -3609605, 10287160, 2912165, 3114071, 23238219, -57948022, -23788753, -9187799, -14680484}, {-20751568, 5188145, -1831778, -3602865, 18762455, -9657296, -26589846, -12327940, 2307772, -13531969}} + }, + { + {{3738470, 6806917, -6520070, -10897511, -24188055, 1667133, -23436367, 15141053, 5199139, 4977140}, {22140076, -261769, 59257688, -2820917, -4981267, 26792385, -16022953, -643729, 2939013, 18928850}, {28701875, -6219062, 8144979, 13251080, 28719284, -8848901, -13494766, -13548711, 21905725, 6311464}}, + {{-40123606, -6588069, 48611592, 14812924, -4609749, 22775660, 20594442, -27366042, -11691916, -19989648}, {11042516, 26822251, -4993288, 11822956, 60713855, 7396464, -38556710, 95792, -48261844, 1788236}, {-4787463, 6302363, -27799488, -14546536, -33235827, 12332815, 18034131, -9318827, 6947300, -12794262}}, + {{-41916317, -18498954, 12896682, -16525176, -40290202, -15788122, -27846772, 21471253, 664451, 1375070}, {7416637, -6453076, -2130444, -11534458, -26313296, 4371340, -27759728, -8306503, 13656297, 8436872}, {17227919, 16214490, 19267967, 7556965, 18770244, 5484290, -12831814, -14044493, -25390327, 2194539}}, + {{-56739346, -27308430, -55476180, -11239913, 9739286, -14341354, -8336939, -8847596, 55360984, 21987700}, {7977560, 857218, 769390, 9310163, 36476170, -12194902, 4947105, 18846662, -7961686, 2123356}, {-13576806, 7411087, -15045940, 861424, -10989411, 11825283, 9111155, 8488852, 18174871, -9752144}}, + {{-23036900, 2125692, -35712986, -2572408, 43165259, -12743182, -5197169, 8798203, -33814611, 16302899}, {-26159332, 15245172, -16953236, -16921906, 23674331, 11214856, 1598045, -6650711, 23572821, -3571109}, {26440449, 133755, 19758318, 5090892, 4788418, 1827186, -16320171, 9981219, -13252712, -630893}}, + {{-34314942, 6414556, 55563439, 4361353, -10556688, 6027376, 17799925, 20469385, -29767576, 21665632}, {27539656, 11508462, 685223, -1223071, 7166162, -22350614, 42303153, 9043559, 17199660, -1640106}, {-4033417, 15802033, 25471815, -13054267, 9916614, 12439096, -15857402, 11118670, 9012861, -11993207}}, + {{-1024639, -12108992, 4567250, -4821543, -33283727, 25812786, -2839767, -3634522, 53439675, 11411859}, {-37192361, 16503820, -73436, -89097, -4368403, -1339858, -48555041, 13376758, -2912495, -8702321}, {-3794781, -13136002, -13950925, -6247393, 18266603, 236991, 1041825, -994782, 7952989, 5302871}}, + {{-18119566, -555624, 58996406, 11596601, 46711212, -654569, 32013940, 5911401, 4438451, 23446883}, {-28110526, -22249960, -2152858, -16464333, 4074200, -13699569, 20968358, 21027297, 34923221, -8492061}, {-16904139, 12540396, 5620177, -1802274, -521455, -9335956, 29448915, -5702647, -7987239, 3630179}} + }, + { + {{12591644, 22159517, 45571918, 13029776, 46556602, 4830479, 41411109, 12046748, -58198390, -11596763}, {38301994, -8496503, 10446328, -19463286, 17655978, -26850125, -11315475, 18600976, 5412234, 20803831}, {-17632683, 8738447, 16357440, 9209779, 18829510, 13065089, -8127903, -15381601, 26220416, -9755705}}, + {{14177715, 9440160, 39938701, 4681376, -36096046, -10418968, 23065821, 27571057, -34577851, 7774755}, {30199491, -5650938, 13070879, 20267452, -6778768, 2790644, 4315115, -3334179, -31133917, -16191275}, {-9501784, -5031472, -29798389, -11258641, 17764614, 3899897, 27609666, 12319738, -8027490, -16630904}}, + {{-11699062, 3637241, -46962960, -10160349, 7273829, 23649189, -32924862, -13681360, 45590947, 16238133}, {44154594, 23741965, 9485802, 20274783, 28555987, 6947793, 8671790, 10989966, 12275299, -13298431}, {14652917, 14296411, -29770150, 10860994, -6026464, 13434770, 7429042, 9960010, -19218799, -9160206}}, + {{5366556, 11152466, 5823897, 2653695, 15133234, -7148640, 33719264, 9182005, -24816973, 18798375}, {-34762570, 9773470, 47732739, 2870449, -100284, 25962086, 33058498, -17547951, 5655441, -11863911}, {-14631533, -14184653, 13764627, -6461784, 4387385, 4866889, 25642753, -2157149, 10877130, -13910995}}, + {{-21626613, -8635584, 23871605, 11704718, 12257850, -6515884, -10653466, -17082100, -981817, 12604805}, {9115705, -19460954, -17068981, 6035042, 25291048, 7944066, -24555090, 12124848, 19202385, -6237263}, {-14533513, -15046020, -29795172, 1382019, 7783365, 12218772, 7664868, -1271157, 21001150, -10882000}}, + {{-22443837, -3278121, 45604952, -23413718, -51665140, 9773090, 10551883, -11001823, 12930311, 11981367}, {-31381113, -25871583, 8924620, 7668408, 10817278, 3861974, -50848635, 676905, 45970255, -16910009}, {-11191171, -1519528, 15007122, 4916314, -17211931, 967948, 9070158, 13268535, -23988397, -7067127}}, + {{20106485, -2843332, 865761, 2533345, 2929876, 6049643, 58194301, 466469, -41888370, 18988926}, {-41891103, -25124458, -55911967, 22418615, 62577820, 1554259, 7229937, -15630215, 19894016, 13655656}, {-18159525, -6243765, 29656888, -16099832, -27160808, -10436660, 16269815, 11035304, 29795808, -12945009}}, + {{19963474, -1354545, -43082808, 11482511, -39529103, 12846294, 30427313, -20848524, -31768998, 3348335}, {-30521604, -13791963, -3486620, 7003293, 16507403, -4510348, 19767065, 6204174, -5380610, -25751039}, {11012574, -5313970, 14922430, -16396213, -568274, -13259503, -21229604, -13485170, 29672659, 8020257}} + }, + { + {{33415314, 8935847, 20575732, -5989115, -2077310, -31629838, 10174297, 7918881, 14277654, -2522145}, {18796036, 11515829, -26341750, -18282497, -6278492, -959926, 32899969, 20876811, -32839540, 5864337}, {21550307, 2275228, 4927931, 14261390, -27648146, -4533352, 8248502, -2822002, 5613183, 2560827}}, + {{-223217, -22768392, -45525457, -4793157, -16121107, -11018665, 4789789, -10425166, 22605248, 13365262}, {-38969511, -9331626, 9825759, -26130137, 8260681, -10112241, -6922361, -9288414, 31646000, 8565862}, {11605023, -13465051, -15209306, -13612207, 19230876, 9598195, -32187147, 14824784, -5317844, -12122633}}, + {{-19339154, 21231144, -2166785, 7793076, 17270165, 7508588, 3515854, 11443875, 14226705, -12804553}, {-46617584, -10937038, -63869361, 13249330, 47239387, 21396988, 49200212, -20266527, 40611343, -4057571}, {-15987479, -2785329, -8472794, 2305526, 9347523, -12035002, -29608536, -3601332, -24047252, -9945032}}, + {{16192366, -4639192, -24929048, -10035998, 21769211, -3294602, -3774844, 10077552, -6047589, 10088555}, {-34221574, 28118666, 21558284, -12289236, -25844273, 1213590, -56913062, 19093596, 34323337, 22517731}, {-20367915, -9650057, 16080513, 4740764, 14926534, -13507506, -33435459, 7117583, -22421758, -773279}}, + {{-11590811, -12486994, 6857453, -10581230, 56247370, 8638570, -30639674, 96854, 12350869, 895287}, {52242329, 5271826, -46498149, -20728924, -1866918, 11946444, 22240448, 16899414, -47795731, 16012777}, {4652271, 13637900, 4000742, -2835219, -15676600, 15348101, -8685770, 15250576, -8140380, 9857872}}, + {{-12592837, 11554340, 23804250, 3350424, -15253385, -13215355, -45129304, 7870624, -45050509, 2994691}, {-46319533, -18565804, 19788862, 20214996, 8869841, 4656673, 13655346, -20171172, -13460899, -14137387}, {4722572, 10806684, 9487098, -3047743, 31196864, -10032748, 420200, 7795475, -5608109, -14642975}}, + {{31224954, -6899866, 28320056, 10750209, 29443459, 1008548, -25441751, 2525118, 6331705, 13112230}, {-25804448, 3068766, 25911822, 6380327, -26288837, -4340438, -33065685, -14811758, 5693183, -19588494}, {-8151699, -9117298, 9258947, 15060309, 24828599, -1024298, 18824775, 11154865, -26906427, 15012221}}, + {{14119739, 7823199, -16275881, -7624482, 11144011, -2875661, -20056080, -4229491, -32760678, 2590714}, {9627191, 18236503, -27236629, -25837616, -45444437, 26025595, -5995972, 13583987, 26988550, -24154834}, {26370245, 10789731, -6785238, -13517725, 4168988, -3492154, -27236508, -12641367, -21787846, 7435359}} + }, + { + {{4025709, -18443049, 63145583, -17093650, 9160084, 442019, 6137549, 11688790, 10446734, -5877762}, {51028153, 10088979, 266211, 8379088, 41412198, 15574635, 59882137, 9771596, -47033066, 26421194}, {-22143940, 6332934, -5899499, -7459829, 20257201, -2161124, -22839614, 7413369, 14836514, 667274}}, + {{-14940628, -25247842, 10939384, -8204221, -46631366, 10606092, 15321404, 23272801, 9968507, 17476099}, {9622502, -7713926, 40663578, -18208253, 8291926, -17699142, -21443082, -6369739, 8731231, 3075459}, {911575, -1965705, 32801069, 7303022, -24865207, -6586476, -21037828, -8619572, 8268268, 13003069}}, + {{13391403, -14369812, -8495941, 15348703, 14039596, 12429524, 41821521, -5658261, 13750930, 6438876}, {37821067, -12493324, -35374899, 11675763, -48025748, 19633964, 6958553, -12969327, 35409782, -8167538}, {30911389, -4773241, -7102624, 7733251, -9660818, 3164814, -26044459, -5006731, -14247956, -5637609}}, + {{26944116, 11925, 66230473, -13659283, -11712891, -1450033, 38104492, -4643346, -51938065, -1863542}, {26513594, 20634555, -317371, -1074059, -12289915, -7238977, 3578752, -23025196, 14392431, -12631060}, {19086246, 13108905, 4585208, 9845640, -30881832, -12875727, -17744269, -15873825, 2163716, -11296357}}, + {{-1519327, -8701848, -19900325, -19237335, 35270482, -4058364, -2760111, -9187123, -24809820, 958912}, {-60143087, 24434408, 13330213, 2757095, 8879892, 14250846, 11171953, 19899415, -37791526, 22278482}, {31761595, -7987220, 10232969, 804235, 29770030, 9696724, -14890810, -3285397, -18187339, -10613633}}, + {{-32730866, -17348548, -5919344, -20494304, 15333268, 28523996, 55878583, -28368677, 6837327, 4993611}, {30033270, -13705710, -5162882, 840858, 28865852, 357546, 582019, -4017921, 1358927, 8174059}, {21252600, 2681360, -17716283, -8252559, -16622936, -9188324, -1401976, -754088, -1405316, -15305444}}, + {{19061825, 16984239, -15705648, -5158012, 45632648, 9152108, -45407737, -24127941, 897835, -12082177}, {9835713, -5561447, 1267434, -23647200, 1842256, 21213416, -10356573, -6829705, 64476145, -683241}, {-30552595, -12160723, -26873350, 3292037, -20145367, -13037247, -31356772, 3087465, 27506284, 9790325}}, + {{31218109, 2219693, -17554694, -2249580, -18769049, -3212128, -16635537, 9637750, 25613573, -7514198}, {-29731409, -1525607, 34872882, 27080576, 14089863, 14087084, -12185371, -23852912, -20434919, 2201374}, {-5069914, 4236508, 20683731, 7163480, -25409383, 13489940, -25275733, 10045725, -24985967, -13203315}} + } + }; + const precomp_data_t c_point_H_plus_G_precomp_data = { + { + {{-39816155, -14164145, 48882322, 7837288, 41754222, -8201549, -4905830, -940314, 5566603, 23894046}, {-3897773, 9695913, 9748846, 7901230, -1867182, -15802569, 45602682, 28911996, 28118415, -8768894}, {-22093752, 3067055, 30439696, 178853, 18503999, 4759602, 2547356, 14224684, -11930853, 7527284}}, + {{-33178079, 17479951, -15720239, 7540167, 27425573, 2953492, -34953726, -22060024, -36629404, -11328152}, {21324973, -3140901, 44002477, -8150207, 9851945, 30239584, -9317524, 6239104, 3110932, -21123908}, {23176510, -3672222, -12879907, 10855153, 4567818, -2709871, 8880416, -8358471, -14822505, 6744257}}, + {{4781330, -10547915, 57841035, 13962885, 1005889, -17806800, 7849169, -1976802, 54527990, 11717841}, {60401008, -2322939, -7572909, 1160963, 48156737, -8617152, 44610211, -16172534, -9446496, 19859225}, {29596428, -841061, -7893253, -3338784, -254482, -5470475, -32104407, -9382379, -7944614, -8445992}}, + {{39674153, -20880417, -31299919, 7880190, 15754698, 11056602, 15516266, -30547630, -17858838, 10115578}, {4497415, -7215627, -35712505, -21138390, -36705192, -19073450, 2337440, 872088, 46466222, 8682426}, {-29955884, 11442916, 16603336, -7611518, 5660466, -10855859, 26643219, 16373229, -26939401, -1298463}}, + {{43102341, 18198569, 8522111, 5706359, 8916980, 12789951, -26578270, -3620357, -26589640, 926472}, {9883233, 269211, 12572191, -12735575, 22786780, -2406009, 19874534, 23449165, 33955000, 30091692}, {-24923472, 6151350, -20658077, 594681, 25606782, -6037728, 17807754, -15381768, -29259970, 14286158}}, + {{51826403, -20042320, 5147727, -3572212, 24208596, -11076997, -17339556, 20883653, 27109678, 27054645}, {-13082675, 8853666, 61177593, -25383676, -2370406, -14466031, -7691442, -8775889, 33066158, -559297}, {21403619, -1320936, 1360119, -8883150, 21544362, -2963323, -3310606, 16086066, -28510335, -8053339}}, + {{39056265, 8037988, 41799363, 9784428, 52925127, -18736311, 7924076, 3054646, 14375658, 20316097}, {-10245689, -2669280, -3665135, -21355352, -3715551, -5371903, -4893442, -29947104, -5453398, 7598109}, {30824562, 729643, 19143152, -3260694, 20969927, -5587726, 30493589, 1462502, 28653229, 14878396}}, + {{-14504849, -4563013, 4220720, -9490250, -20753614, 15257510, -28817611, -1960666, 26681323, -17931229}, {-2500401, -12353373, -8888886, -14805214, -39590484, -7403478, -1349549, -85204, 13251279, -13891541}, {6749103, -16059744, -17316796, 6901963, -5756718, 4914193, 13614189, 6932543, -16976821, 7805464}} + }, + { + {{-44275891, -10549189, -29633106, -1340455, -15599665, -7998887, -35451108, 13776858, -32587407, 18348606}, {-9395149, 15647601, -28188200, 31802895, -9180843, -24751947, -23861408, 382848, 32754567, 11525716}, {19941335, 10758860, 7228790, 12016419, 20288948, 5689631, 26475660, -4135779, 5184338, 15306891}}, + {{10755570, -8397137, 40506658, -11976361, 4026458, 7220523, -5929864, 30243879, 22426643, 10267958}, {28258108, -2037957, -22727494, -13664445, -57238946, 25895659, 15615216, -3005277, -36350911, 11364854}, {5370615, 13212887, 10228227, 6698108, -2642399, 2050167, 24589932, 730321, 20699130, -804432}}, + {{7855537, -1728788, -8172066, 7241596, 18927222, 14854403, -36749684, 12257355, 56266033, 12555330}, {-1908271, 21052618, -45686424, -7386012, -17039018, -10246239, 19254420, 3833491, -3814213, -7220692}, {13883675, 7156278, 16569944, 16588969, -26199383, 7401551, -14421464, 10408321, -17172928, 15458510}}, + {{17794920, 31469639, -30428873, -7218808, -723502, 2975322, 23234843, 2863881, 28870439, 13104642}, {-196758, 239089, 35995605, 7758340, 41156672, 20984780, 19101577, -23441029, 14306617, 411502}, {19726973, 11802972, 27683603, 12627856, 5217821, 6288537, 14447538, 7990474, -5564574, -2213531}}, + {{-23702731, 6702770, -15055475, 13293291, 11699010, -18178053, 697130, 3769109, -28255259, 6153291}, {-39579703, 23236612, -25625567, -4524603, -19531286, 4978935, 57018384, -595609, -2849043, 17575319}, {6905822, 11533546, 6577832, -89916, -32878805, 5774877, 16920332, -8161675, 25727859, -14748005}}, + {{-2955371, -3558440, -12188170, -14445359, -32360363, 7715772, -16250455, -12579521, -41679923, -16040535}, {-52567891, -1968260, 31681636, -170049, -8717115, 24856524, 46911047, 13924431, -23298237, 5893055}, {-32105925, -16746082, 13745662, -5439013, 7651536, -11363101, -18979155, 2062899, -29798386, -7471732}}, + {{-20573579, 14520367, -60191044, 9243789, 8326181, -7643250, 4690664, -3444268, -24227062, 11624492}, {-9281001, 15989647, 1359004, 10622121, -55808191, 23000254, -7565506, 23959584, -28258262, -7390124}, {29131250, 15551810, -30149942, 1993386, -16571959, -2899547, -15032089, 4422476, 11099219, -11684360}}, + {{16186045, -2013545, -53752884, 5434695, 34529660, -2391375, -25201828, -2112332, 7910643, 7519069}, {6164297, -21305655, -5276460, -22637987, -3412090, 2289719, 1541288, -26950718, 3180065, -7279669}, {7603051, 9278472, -10049272, 9382712, -7003090, -2295281, 10188592, 13241980, 31675094, 16318086}} + }, + { + {{2975510, -1577378, 22890889, -5670236, 461218, 8986275, -44510758, 4684468, 583866, 29578997}, {19723706, -22469934, -28100401, 23994004, 29345630, 15954823, -13556128, 9839972, -55632320, 1005363}, {12134884, -7584508, -21509432, 14429074, 27282079, -6602364, -29053434, -7441264, 24318575, -11506694}}, + {{1407898, 2582456, -4919586, -26454360, -7368007, -13719869, 60757731, -10808283, -41492701, 6629201}, {61057990, 29903098, 28430992, -4894826, -40460465, 9522447, 1443153, -6078853, -3098057, -3083809}, {-11163398, 2419037, 28832173, 889805, -26704627, 14084807, 17746839, -2772825, 19921864, -11161548}}, + {{-3962272, -3690118, -18061043, -5772127, -17503319, -16634144, 44538355, -16032582, -4398875, 6898215}, {31593788, -23527462, -48486767, 14759745, -14925507, -13602730, 11752611, -9655452, 2974399, 11968327}, {1969039, -3228099, -3003791, 16200162, -13377098, -258562, 13645098, -10481060, 5186361, 6385842}}, + {{-36235914, 8877168, 12072077, -17882844, -19808886, -18852943, 18265665, -27504581, -43276159, 14482117}, {6095148, -11723272, -43394993, 3953286, 24086676, -1638453, -48122799, 1634227, 2204931, 14373043}, {-20566259, -5480640, -2756642, 15726313, -29953128, -8188145, -32670951, -1309507, 7128752, -15681127}}, + {{-20107442, -11808548, -15656323, -12014820, -13493428, -5707496, -52054164, 6578313, -22285735, 20090720}, {-32212866, -1055690, -6777057, 7448460, 25835512, 24475010, -7334546, 24237757, -36771343, 8408984}, {-15713494, 7985225, -3569442, -1506701, 24625410, -1318351, -20059465, 4525794, 1689122, -1705793}}, + {{3122738, -10983934, -16969286, -8542449, 4121662, -185607, 13388420, 20588369, -1796272, 17334688}, {54996510, -1815770, 46604656, -13012427, -49071988, 13199547, 34978298, 5496051, -3518400, -14055130}, {10414456, -14616205, -19118516, -16447912, -18164989, 14150808, -17637886, -5247132, 29445603, -11448910}}, + {{12029006, -3257997, 43557227, -10814381, 13341517, 432465, -1549056, 17277135, -42831971, -25378562}, {-17258378, -6937139, 8136229, -2333299, -15880299, -12513035, -48841046, -12912639, 8346791, 7061462}, {4811171, -4798778, -9029413, -2806939, -17541829, -2631553, -8356050, 7470782, -3158007, -4732898}}, + {{-27857882, 4702807, -19403619, 15709479, 20626880, 4923387, 14211270, -12445725, -12348753, -21410306}, {9747986, 24912909, -10679843, -5528609, 37718652, -1581829, 18774428, -10987579, -52918005, 7024296}, {-29663347, 12694597, 14207632, 3295450, -5496877, 5123054, 26132781, -11491386, -15452594, 11868693}} + }, + { + {{47880066, 14225621, -14470245, -19705222, -46008472, 13221251, 15408768, 5643435, 28837478, 3855353}, {857820, -3301773, 41798831, -8303062, 386312, 818057, -6842152, -1911481, 22374950, -28291539}, {-31814060, 8064783, -17053164, -6176522, 19048354, -11591068, 7668908, 10258759, 1857924, 1592875}}, + {{-8354350, 13982902, 1438414, 3013202, 33012597, 26662689, 472999, -7510509, 12707279, 2935385}, {-44523142, -16191620, -19693918, 26866768, -9384271, 6719687, -35309813, 1501863, 19451035, 6808289}, {-17142771, 13261661, 13878175, -5224933, 13092929, 5712649, -24249045, -7621190, 22720777, -5735487}}, + {{14584926, 5035261, -48903167, 3873736, 14684796, -22599718, 6592752, -3579494, 41382834, 20929245}, {21955206, 12350013, 4054179, -1159310, -48935108, 7150278, -3074452, 20251724, -10661684, -4783395}, {-12038883, -14854984, -1653699, -9894098, 3332471, 12516008, -27467863, 16759479, 17054920, -1045585}}, + {{-371653, -21319317, 14269602, 14876936, 2675616, 20104303, 46577283, 15247014, 2295086, 19960666}, {-34337263, 9062359, 3605352, 3811574, -290942, 151793, 5609515, 17268538, -5824646, -1507552}, {31341569, -6150200, 30915203, -3934320, 9170042, -2821122, 19539775, -8309478, -21506835, 3909703}}, + {{32575469, 5038442, 5894533, -24684650, -26976210, -3130646, 35899912, -8306591, -19575522, -927242}, {30520527, 4298102, 60219981, -8778528, 31412296, 24862674, -23675544, 4980333, -2177014, -26498470}, {20799789, 10250199, -23357518, 5235379, -17318365, 4995373, 11351608, -14329977, -4241062, -7135437}}, + {{-33708961, -10681744, 44893908, 20160328, 42923179, 9915773, -3420761, 18596951, 11284167, -8998884}, {2582953, 8283502, 4386626, -1306842, 20441991, -4892387, 2690307, 12028025, -21980001, -5571110}, {11436030, 13706606, 18295930, -13040673, -11313853, 11794175, 12631614, 8169005, -18535511, -13157575}}, + {{-9640722, 6792220, -254348, -12924221, 24425860, 4517358, 1463652, -10259333, 22154576, -21700687}, {16193300, -20305974, 60516020, -2690805, 9602228, -5601208, 52465390, -1370049, -18119120, -1587787}, {-18665987, 8255087, 12358781, 13159454, 21161438, 15792077, 30147037, -16229979, -32698768, -14941592}}, + {{-2307405, 10485747, 39295370, 14588786, 4398246, 6429581, -1367673, -17148995, -1427005, 16592987}, {-36661597, -22159389, 20182562, 11367804, 50893914, -10502039, 54187961, -11518549, -15338969, 8686865}, {-589443, 10055237, 2248329, 1681864, -25869653, -10483390, 8141259, 9185076, -764620, -2255836}} + }, + { + {{-7539919, 9636200, -21714907, -6368333, -7235053, -6939034, -9118147, -14563464, -9413611, 19620509}, {-45327821, 4153668, -28809623, -4801677, -21486751, 2353782, 47659657, 5772650, -37372651, -13580107}, {31551118, 13663464, -32586548, -9442420, 1599988, 9648514, 7021663, 10037197, 8547400, -5396572}}, + {{7159452, 1840193, 25466750, 18577392, 835761, 7323218, -30678863, -16353979, -18852036, -7337690}, {-32831410, 18027379, 18863650, 8284076, -38140067, -7075396, -24839181, 2961457, 35059954, 14893170}, {-24266347, -5350595, -24950691, -10540916, -6804388, -13956470, -7127420, 8559388, -10225705, 2372921}}, + {{-13513356, -13649907, -6339001, -1958880, -48187167, 8902386, 962999, 7424926, -31340554, -22447536}, {-23638418, 17970353, -54753529, 24193844, 7095187, 21529604, -2360327, 10076102, 14010140, 8567408}, {-31310372, -9223279, -16586937, -13453731, 14498347, 233201, 27810972, 13029701, 402562, -3455197}}, + {{-27249316, -1605410, 34623441, 6711490, 36047504, 5231705, 40768761, -17656033, -55345257, -9075209}, {12561880, 15226052, -2767207, 21899734, -8226358, -22004263, -13717073, 5466303, -5911661, 5114417}, {8136691, 12887366, 29097493, -16010242, -18845685, -16525917, 31273501, 5649551, 25544463, 5891661}}, + {{-9060044, 28573534, 26621156, 2412287, 11736156, -21702233, 41606651, -11903065, -37425711, -4305523}, {-52689042, 923938, 26534790, -21929301, 9230164, 758897, 1252353, -18079999, -643561, -15073995}, {-11144596, -3685331, 28815967, -5860993, -15674460, 1972033, 25777812, -1617499, 32154038, -8896107}}, + {{-6369589, -13172710, -5064996, 9138800, -26749468, 11900879, -15940458, -2576560, -7092540, -25782458}, {-57529209, -10995646, -56002602, 16675466, 22787278, -18138335, -37305050, -19921114, 15505056, -7476256}, {20036634, -8236744, 9488775, 9980126, 793048, -5544256, 24326142, -16680515, -27516278, 5404821}}, + {{11502921, 11861465, 26708889, -25307943, 43650436, -16766722, 11011775, 21788652, 46378003, 11742133}, {-47650185, -6096437, 6293355, 1762141, 8158190, -10280788, 35269981, -366506, -4492163, -54793}, {19571938, -11208475, 12715447, 8032888, -18405626, -9156617, 24219268, 472527, -8931641, -16211728}}, + {{-8599983, 2034158, 19328980, 9714767, -17915523, 16006984, 14164091, -720137, 19355077, -10309490}, {39767111, -17528894, -1630748, 13701701, -44632761, 11807268, -28489629, -10680531, 322797, -14654952}, {1809044, 12210040, -32449423, -9338725, -7423952, 12752681, 26906835, -8734553, -8367622, 82184}} + }, + { + {{-47006746, 22052935, 20792602, -8280800, 32254004, 11436994, 17785759, -1221897, -13662270, -3275645}, {18913246, -3934333, -8493930, 5603482, -720236, 8682806, -9892239, -75935, 47506872, 28002705}, {-12998522, -13382572, -25058578, -8727237, 33120415, -9513563, -17530532, 8914472, -589545, 12119368}}, + {{-20528441, -22161340, -30056218, -15320984, 40597827, -5215401, -16411330, 5623363, 8146138, 4967917}, {-18880063, -7537208, -15812678, 8125220, -15761477, 4435839, -5843780, -11949479, -52544210, 103971}, {20876164, -5702948, -30661348, -15372457, -16354433, 12735128, -7683175, -1706780, 20482728, -12025587}}, + {{-15181362, -1738141, 2937403, -4560472, 56106319, 18388054, 17281731, 2547295, -20480012, -1402021}, {-13301360, -6911083, -50796187, -25175850, 9723393, -8085126, -12442115, -8939305, 259254, 11964369}, {-10278774, -8926581, 21910465, 11128139, -33177783, 15466487, 20599725, 13573408, 4036183, 4175976}}, + {{54200020, 12073598, -749739, -7578170, 12017807, 11479032, 18819357, -30580182, -5661613, 482835}, {1378798, 11508946, 15315091, 18385986, -17543837, -5127372, 41636169, -798590, 4491173, 8249327}, {-10980326, -11152026, 27249123, 5129660, -3354569, -12162018, 13624268, 10802616, -25244815, -7042942}}, + {{5380650, -2641214, -19286494, 21327095, -30667976, -20148346, -35733992, 3369526, -7982752, 10619641}, {-45099848, 28173840, -20372660, 6613511, 11561244, 5875282, 31187260, 4610810, -29858618, 16996395}, {-19519076, -11159398, 18325381, -2841346, 32378721, 8265003, -32477166, -6929808, 27632659, -1154477}}, + {{6952423, 28751626, -3627919, 7286683, 32291810, -2792450, 4091282, -7150922, 19624973, -5193059}, {-58036529, -3933022, 50972131, 10172373, -28197802, -11919806, 35212826, -10942488, 42827699, 15831257}, {4119541, 6283558, 29775101, 8468756, 22993602, -13511415, 16193943, 11355974, -13095932, -16702609}}, + {{36793192, 17715925, -47017796, -14058455, 14972505, 26066588, 28864773, 5891275, -8060731, 12830682}, {11152062, 14259313, 12115186, 19300717, 48065293, -1460298, -25375661, 19922469, 33108561, 3505536}, {11491384, 15053639, 21255018, -14953116, -18661055, -2213136, -16327369, -16397206, 17857063, -3455721}}, + {{-19201792, -21056533, -4688573, 24718809, -3249546, 9920935, 12519271, -4245354, -1652915, 10661070}, {35094748, -8177713, -37040773, 3836519, 39743782, 22508963, -54135633, 20126170, -50823579, -7794132}, {16323604, 15349402, -32076211, -4707988, -7798519, -3064483, -26758500, 13292075, 25656674, -9043825}} + }, + { + {{43734659, -5319012, 46016463, -1620988, -38496562, 87293, -42546871, -7604965, 578936, 4426260}, {-5432409, 13064322, -20467239, 22120972, -15091024, -26535371, 2635367, -24677553, -54376868, -19781556}, {14345465, 16270852, 4756840, 7458194, 33275228, 3859916, 9802211, -765685, 70576, -14370386}}, + {{16611858, -1910689, 14319970, -10912303, 5232448, -2539253, -14037507, -25466057, -13570421, -2411747}, {-37413772, 4902867, -52467614, 6283407, 16050762, -7675881, 41640783, 6681257, 337963, -14342581}, {32861921, 3390058, -18056251, 14576342, 31934267, 7199830, 28917854, 12944757, 17111743, 5007086}}, + {{-7500517, 21308112, -37722218, 8083693, -18833401, 29186607, -4472399, 12369414, -16608573, -2621474}, {24589151, -8107860, -24991284, -17719105, -23421711, -826369, -11449941, -10445110, 35787931, 3057602}, {-29008638, -11234989, -5718810, -1901776, 24867316, 16042440, 33300654, -6687520, -31368037, -8960341}}, + {{-23670453, -1093376, 18609580, 8122059, 47415668, 11784982, 4471102, 6501945, -54795554, -364561}, {39376025, -5880334, -23389712, 24428343, 10589228, 19695952, -27661262, 13470783, -5521988, 29658649}, {-26687343, 15201886, 118242, 3657794, -28872101, 5501148, -15305078, 16654470, -15261454, -14594552}}, + {{-13306269, 19947636, 8483811, -3190176, -23627707, 10252917, 14832587, 24759739, -902752, -1166842}, {-26114653, 11829916, -54505725, -28666150, -29923991, -16228737, -4727451, 5781843, 55410772, -4561886}, {-29735991, 11466236, -14569729, -11827406, -26512116, 6710111, -10274674, -14237170, -20461738, -16244003}}, + {{12625398, 20046721, 5286337, 7474914, -22825196, -6381699, 9714385, 16895522, -13126949, -14199931}, {-2031800, 9361451, 28810765, -18545230, 7579584, 16517267, 14150271, -11432708, -11386907, 12185845}, {29962090, 3436662, -30434232, 16542079, -15783147, 6389271, -8401182, 5098617, -451357, 15925153}}, + {{-21081701, -9429138, 18520545, -23679835, -16457908, 25085243, 1855293, -14824660, 27942702, 8972269}, {-45958849, -17252154, -36117755, -5614007, 2734706, -6273399, 52441231, -13591968, 8620728, 5175773}, {19264689, 1667404, 33205073, 3308919, 687683, -8250375, 13373288, -9785873, 11395092, -1751113}}, + {{-19999590, -20756181, 8948023, -22355120, 57822735, -6417901, 9163919, 16852846, 56150656, -23780885}, {-17273210, -3051139, -48089577, 2762258, 2931577, 23780341, 23017019, 10235004, -6633220, 4094699}, {-15471108, -7628914, -20513916, -5495033, 24194398, -10045738, 3339675, -6469880, -26817235, 170334}} + }, + { + {{11043804, -21056413, 25089102, -23689432, 8790566, 7233991, 44727817, -5513045, -24304116, -24807950}, {39999434, 887787, 23080950, 792782, -5434700, -25043299, 17882515, -15450801, -423426, -5918810}, {23824631, -5728349, 5017134, -6480680, -23176854, 15426646, 21535341, 13596483, -31731756, -9009266}}, + {{-27396310, -8333033, 10986646, 8586168, 6785995, -28090074, 7941057, -17083636, -27899235, 9838332}, {-37871958, 154117, -52690902, 13816960, 42499085, -4482764, 48719803, -3174796, 4349027, -12371940}, {-28501050, 1590284, -32590995, -15830730, -18209072, -10354716, 18729561, 2693146, -20269448, -9203605}}, + {{-5417941, -3424753, 30842445, 9195024, -12394505, -18152018, -11189800, -11080382, 8589175, -2910070}, {43086965, 25206781, -34785907, -22089246, 24552255, -4805866, -4482744, 18017836, -14735643, 13311078}, {-8935163, -6369419, -28359239, -11248624, 21311049, 1317697, -29891217, 4173532, -30402596, 15076650}}, + {{-12264026, 13499738, -554276, 7911328, 5642702, -4487235, -33195201, -7547462, -6794648, 23195101}, {-21962104, 18804840, -30339708, -4031892, 38225180, -14220233, -7777789, -19438232, 22781890, -547965}, {32870892, 12137760, 18144990, 6711236, 11978906, -8820990, -2304588, 3559244, -8510327, -13421304}}, + {{-52986775, 12866719, 1610794, 3617512, -30276811, -10032788, 32625752, -8521784, 36232382, 19481123}, {3030971, 379053, 25866748, 3490964, -30817835, 7579484, -22858980, 9847760, -2371614, -5099489}, {32600431, -16683718, 25469662, -7863878, 27145324, 2231208, -25947987, 8612277, 25004875, 8507401}}, + {{13550201, 20507378, -3075593, 29173187, -49171591, -9693568, -44839713, -660091, -14277642, 18757544}, {-50645363, 6332734, 34190113, 636645, 17696443, 8057372, 5049185, -22967915, -28892196, 10920130}, {841263, -5293490, 2054521, -16537763, -25582619, 14313554, 27411062, 3822201, -18603128, 8312231}}, + {{-22602757, 13740868, -7303800, 4602319, 30573397, -13242526, 11086875, 6457252, 45452323, 19929429}, {-23754957, -13960182, 51455444, -22458279, 33235925, -1672610, 32592089, -4573286, 11320673, 8405483}, {-23879553, -7888804, -29791171, -12847132, -1235076, -15092650, -21935205, 12760100, -29339533, 15761064}}, + {{-2694348, 5098757, -11181611, -17830607, 15473799, -6229150, -24574053, 10298157, -44445244, 1811460}, {23717824, 27608831, -6887543, -9211003, 10428489, -19796712, 11021297, -10556929, 2178676, -21845872}, {-19590486, -13933828, -5439581, 4275259, 2098080, -12142172, -18225325, 14993971, 5425290, -8733882}} + }, + { + {{11868497, -15697319, -34268477, 16386778, -26868445, 15273532, 1480123, -18429566, 19765721, 17394524}, {19027887, 7192035, 12175469, 12676252, -30507951, 11707640, -21602451, -1577106, 2601223, 15479076}, {-7311472, 11351662, -17020174, 1960486, 29137035, 10865402, 23151197, -8175138, -6541259, -3657642}}, + {{9066941, -7381651, 51291726, 6711314, -41686369, 26395419, -10311274, 2359341, 872108, -6244488}, {-48442999, 2273909, -2525474, 25866780, 422887, 3382637, 34569616, 29208299, 18670392, 6639296}, {-27264479, 3582609, -10865205, -9931850, -5815604, -7506492, 5258546, 9844697, 9620260, -16046213}}, + {{-45366823, -25595363, -14185658, 2792812, -1406255, -9514017, 13078107, 17920026, -9641979, -10451827}, {1673165, -4266617, 11678154, -16004648, -63153053, 15162283, -39261865, 5278734, -37064813, 308469}, {23216144, -11791662, 6983650, 16064509, -32439035, -4711682, -32554489, -7478003, 11386580, 2460998}}, + {{25014893, 1661827, 35291946, -8325231, 19066372, -7871500, 34292790, 14328673, -10766114, 202214}, {27860965, 11944471, 23517710, -12963093, 4143268, -7019080, -640732, 6818193, 3774858, 19112238}, {-5098815, 2127323, -15039286, 9136963, -28256147, 16187371, -32731642, 8523431, 25045644, 223176}}, + {{50664585, 9322598, 19045209, -9889331, 23897592, -1310554, -4326164, -3657302, 11756593, 12619930}, {14272493, 9445898, 21434933, -6904549, 22350086, 9627926, 39938834, -18462276, -17512323, -1432994}, {14976161, -6822416, -7305954, 10992127, -11702300, -13259011, -28504633, 4143217, 26906184, -10306442}}, + {{28675118, 730638, 50340525, 14203387, 46493654, 22076072, -33261142, 8962596, -19605777, 16890867}, {37699570, 14485336, -5370675, 5271311, 16688070, 4156724, -20296922, -22625348, 34914055, 1900223}, {6562372, -11538119, -5902312, 12288803, 17014998, -352611, -26944539, 8861346, 10220582, 1452785}}, + {{3737307, -18904342, 64597078, -14042352, 12310755, 25424280, -35654520, 23472428, -61527131, -7556604}, {-37953739, -3969890, 1324420, -12004366, 39682155, 6455782, 26173376, -8499360, -4027711, 14656856}, {-1493633, -9433218, 4574097, 11407729, 31951489, -9687820, -1960263, 8177264, -29685295, 8838512}}, + {{-9181421, 7414816, 52381403, 9121363, 2074896, -14432263, 36641428, 6525110, 5596258, -8764633}, {45933847, -4758718, -5001577, 18761461, 62010382, 11543699, 6422236, 16736246, 59245546, -9856947}, {-29095073, 11416823, -18243034, 5629155, 24543272, 10401618, 12511961, -7280966, -12730211, -708266}} + }, + { + {{4274524, 4043839, -3436567, -27481630, -12762020, 23378465, 19910257, 4913107, -28189976, -2860031}, {18406284, -14642887, -63449915, -863030, -285954, -9288393, 42341973, -12024559, -22407158, 9482419}, {-18058683, -8621771, 24921325, 5278095, 3129192, -2553350, -23858739, -12224329, -24340787, -4546840}}, + {{-5499935, -2106328, -12451912, 19452688, -54368327, -8220771, -28990438, 3834078, 479955, -3213376}, {-17012887, 4786820, -11197850, 10714672, -11240765, -20691279, -1522762, 10982182, -7089813, 7633296}, {-23325848, 1459410, 1522332, 9664337, -3801705, 1847048, -13410787, -6281860, 1562599, -15096582}}, + {{30622958, 24906198, -35101214, -11879242, -18715863, 9057270, 5075352, 21951583, 45884824, 2643432}, {13266016, 348498, -23380786, -16792532, 17571361, -14434194, 44313334, -4280113, 11549418, 12208036}, {26895749, -15969948, -30058895, 13648122, 28837164, -14314292, 22466429, 16445787, -15153187, -12487027}}, + {{-21674573, 11232028, -25758077, 12198258, -38742442, -12462435, 36857050, 3032813, -47633805, 4282955}, {24718159, -3746650, -40637029, -18179914, 27761490, -18098213, 15787118, -23735657, 2037029, 15964843}, {-27286718, -12408889, 24851666, 12931506, 8307759, -2266172, 12434919, 15016983, -23277661, 16245465}}, + {{-31447267, -5415111, 33056600, 6951713, -26536105, 7700093, -11835192, 22400862, 41776236, 856932}, {20376065, 4839581, -3655566, -15695319, -31026483, -6749275, -31021074, -518708, 25216662, 22944914}, {8360147, -14325725, -18313567, 16261547, -26556470, -6476300, 1647620, 14461306, 3301654, -9201704}}, + {{16173558, -22951298, -2997348, 13903933, 22219511, -10474787, 12085799, -10966125, -7555703, 25722726}, {27971794, 8240868, -14328426, 10062703, -36555115, 11719359, -32024967, 8420287, 11077871, 5865106}, {-18560176, -3802162, 28514586, -11754909, 10317955, 607211, 27209043, 5972680, 5193874, -7034813}}, + {{-11821884, -7952985, -33020217, -25097199, 31154469, 17429913, 59044666, -3824103, 27604607, -10355219}, {47307216, -22733273, -29410287, -1772129, -30735969, 10432159, 2786244, 15070221, -37362553, -4774799}, {-4242055, -9074276, -27644267, 6498676, -28316989, -11838829, 21733081, -4025959, -19805396, -5162801}}, + {{51842380, -29895254, 11656750, -12072397, -5593318, 21989962, 5965537, 11990104, 44857092, 11836311}, {-13322340, -2798438, 4498144, -21036269, -26363924, 866862, 33252693, -16927192, 11656052, 16144963}, {21364854, -1862192, 24090206, 2902059, 23631541, 1800706, -7273027, 6531510, -23867735, -14401077}} + }, + { + {{5865692, -10990278, -49548354, 771099, 17186560, 5335367, 10468747, 10163615, 52929227, 2171626}, {-10901652, 17180646, 157162, -25525593, -17572704, -20528723, 47051193, 8174325, -10136135, 6495104}, {-8204966, 8235740, -407041, -15919231, 18364222, 15026736, 18597875, -10166673, -9414578, -11757991}}, + {{-10620328, 1198843, -37929729, -11608122, 20480468, 27536757, 12170690, 7423691, 10301440, -12736492}, {43745252, -21035541, 3438449, 14565576, -42395858, 1092785, -30097654, -2539473, -9410188, 825662}, {-1324395, 13857709, 2453979, 9006577, -11123272, 4638946, 18392923, 16113861, -23790723, -4481210}}, + {{-57914452, 28683635, -24569693, 13929141, 7131270, -18012389, -13169297, -1418990, -12971680, 17334927}, {-8518276, 1776957, -16914507, 14556573, 24016058, 6122261, -46009447, -1300374, -10222214, -8793587}, {-27768700, -909734, -20564255, -15908800, -7521595, 6373943, 11064646, 1195344, -4531986, -4886072}}, + {{21647556, -3796541, -21502048, 880719, -342288, 2282331, -39115512, -20744592, -31100237, -24433937}, {-8160646, -13936417, 41711308, 31098987, 16658418, 6818397, -9007358, -11918838, -29796567, 176149}, {32238907, 5231486, 1497188, -4651881, 21946425, 5030819, 1264715, 14943645, 30894263, 1625632}}, + {{17203878, -4796080, -21130245, -4160173, 5606274, -29031362, 23204629, -25696419, 38432167, 9226813}, {-4668224, 21518930, -15908641, 7679225, -50575008, 3569644, 35259827, -7140159, -14278545, -14846537}, {-15203667, 2386472, -20251662, 9962415, -28531198, -5270844, -23223743, 11417386, -30217541, -14504578}}, + {{-11206718, 9200636, -22908572, 9460721, -2823776, 17033139, -54053169, 3319518, 12838480, 22750692}, {-9752604, 9190512, 38513758, -11442623, -58442626, 12761629, 4376113, 14118008, -15040304, 9091106}, {16752388, -16143747, 33314870, -14311799, 32157971, -7897476, 14140004, 8370204, -18523694, 483143}}, + {{22370069, -9339523, -18801952, -29694324, -58952488, 8784277, -10575482, 4180677, 9096253, -9393846}, {24595611, -22263643, -18300354, 3669876, -4929472, -235397, 53928782, -24964699, 33718097, -19141618}, {24428247, -871725, 10210264, 9478951, 3623055, -3814634, -7313353, -10162077, 17467920, 7478866}}, + {{-9283312, -26068376, -6092731, 20047102, 29778957, 12622472, -26158322, 493978, -3600563, -1191718}, {-33854016, -1622716, 13886351, 5847670, 17650007, 5431806, 36696916, 14118562, -19676177, 11832314}, {-16338391, 5600499, 21868803, -5014094, 32567511, -10507217, 24242605, -10006561, -3539820, 7939342}} + }, + { + {{22056877, -23746613, 32915302, -8097070, 60146192, -560866, 60093742, -9504884, -6423528, 26871254}, {-28561339, -1184089, 15977638, -5183824, 3976576, -29827192, -2534322, 9081748, 45910056, -2061508}, {-26351622, -5119641, -22244376, 15796890, -5024905, 303706, 28031488, 15272809, -31950268, 4197464}}, + {{5662611, 23128849, 38051423, -5439130, 36415774, 10980264, 8310415, -4728883, -47302572, 4451244}, {-55519269, 49313, 9999529, 10432862, 28963156, 12843400, 30216795, 18336573, -13517506, 27214170}, {-32914120, -11072305, -21846804, -10912675, -15300186, 3464788, 3448882, 4096485, 26830356, 10804921}}, + {{-228397, 18677807, 3996163, -5765357, -17982455, -8134509, -18461152, -3870005, -16042828, -1504049}, {-41679557, 5439403, 37914863, 25724453, -44473333, -15960701, 33616338, 23930503, -42049746, 14909589}, {-16078716, 865701, -1526166, -3350480, -27398086, -2860566, 9605139, -7499346, 367350, 5030116}}, + {{22675004, 1517635, 23537301, -28309720, -10539962, -17732259, 54022275, 1380666, -265430, 15507642}, {35604954, -13504165, -26826687, 4591566, -35333806, 1977687, 781185, 15763796, 25388976, 13991338}, {15460778, 16733299, 19344988, 14048475, 30225606, 8919546, -3966554, 10157665, -22964020, 2411969}}, + {{-16245774, 27498100, 12684623, 7625322, -42605118, 3193624, 37310834, 10322027, 30809245, 6704937}, {-28272380, 3735790, -12023325, 14649270, -6525718, -5995068, 12663382, -13284889, 9026309, 17946619}, {-23177053, 12058737, 27221295, -2377426, -18376458, 9422949, 24453601, 12458087, -27966925, 8914550}}, + {{-11908904, 877246, 5148687, 712427, -37230060, 18249745, 20813181, -13585843, 15887850, -1716780}, {-11069340, 4018956, -19254115, -7652235, 1185650, -10458653, 40775407, 10258635, 31033662, 4391874}, {-8268906, -3654045, -28095940, 6636281, 16194123, 7657250, -29860191, 15870904, 1972975, 1735469}}, + {{13273532, 10829905, 29379327, 9334401, 25713862, -10758552, 29273542, -2552977, -33752072, -256896}, {-47219880, -12738379, 18657909, 21589833, -988160, 144006, 14595866, -29760307, 12617774, 27841618}, {21876908, -13242878, 17288627, 4977951, 3533917, 6527972, -18397968, -2983052, 17126580, -7992068}}, + {{-22738888, -1506617, 13748129, 5285807, 40232065, -16963695, -1010856, -7160209, 5275429, -3360475}, {-23283294, 5480091, 47642641, -11895325, -19152455, -13686675, 25639596, -21424409, -55672117, -17385167}, {-19757089, -8408606, -14911817, 13535907, 32141588, 10641593, -22660401, 15848366, -3871962, -16717742}} + }, + { + {{32299526, 14010149, -17432650, 11192953, 15013299, -27188126, 5462092, 6624559, -31322253, 5319111}, {13542630, -6438957, -13530398, -1527729, -14524931, 5357968, -7648166, -3503027, 23511577, -12430839}, {20879803, -4712607, 14870949, 11273192, 25222438, -13559273, -3095352, 15381835, 8038196, -4967077}}, + {{57875636, 7026832, -5385325, -408641, 12233482, -11407251, 16097979, -28434484, 52893470, 4897165}, {5891070, 2492936, 37563627, -27745775, -21811416, -8708341, -39292411, 2632112, -5621344, 25833365}, {20666607, -3144579, 8036694, -6144155, -15823358, 13028530, 31388536, 8498975, -30673072, -13005232}}, + {{-32299419, -10517716, -49443845, 10885897, -60563720, -4503825, 28681110, -1287509, 4402368, 1347495}, {-2265851, 16901066, -17583997, 1273955, 4021950, -11807027, -18043134, -14360713, 51248848, 32163777}, {-23736727, -12930783, 3702641, -4265401, 9417206, -9972194, 7692344, -16235623, 31067762, 161254}}, + {{-10206081, -11559961, 793952, -4142645, -19651913, 6312231, -52760030, 25947542, 1025162, 4279591}, {16516157, 20806323, 60845594, 17589785, 33156225, -25053763, -7706302, -3152586, -33274614, -17612693}, {33494023, 7410590, -18701402, 6156442, 29227126, -11066669, -5746013, -4772912, 23521452, 5865860}}, + {{-6373298, -2417154, 10022351, -3426242, 15113772, -25001335, 38113349, -16915972, -12213262, -8974306}, {-54587852, 2532534, -26557371, 27694748, -15541534, 851563, 27927061, 2058506, -13496946, -21242092}, {-15691788, -2807083, 22073819, 15886978, 26165883, -16600654, 18375257, -14137950, 22379487, 618932}}, + {{-38532955, -975675, -38996694, 7824194, -31093477, -4019014, -22236522, 4774558, 54687979, 24033175}, {-248783, -5373335, 11054690, -20676618, 3856353, 26198340, -16948412, 26655852, -3924657, 7401867}, {8122203, 8304380, -7766078, 6670570, 1288859, 5431766, 25898492, 1928592, -27685506, 12421188}}, + {{13447626, -19058772, 11292036, -7681052, 28894196, 1453354, -23547996, -7697542, -24272981, 166285}, {-35806612, -12174128, 37881920, 20096248, -28320612, 24786884, -11801752, -24769450, 41109149, -11890645}, {-6174077, -7707778, -3861523, 14160188, 19056730, 6931147, -31011646, 3419044, 29894448, -9406799}}, + {{29777954, 25592649, -19209298, -15308765, -29195760, -13060489, -11993888, -1050799, -24769719, -11422860}, {-18699344, 7201511, -22867982, -9857825, 37612322, -4114883, 420142, 25709239, -42307665, 17970078}, {33313729, 15801707, -30212345, -9693203, 3419268, -1522298, -33446197, 14905997, 25587876, 14546747}} + }, + { + {{2798209, 15162277, -15684307, -4848309, 51519813, 12550851, 3378246, -14208963, 6379504, -19126213}, {48045213, 7344295, -45496227, 19454081, -6532983, -7006177, -9684552, 16904569, 40189328, 2692675}, {-24290205, -13822302, -16731339, -9196708, -10231625, -12475402, -3927078, -16145637, -26340719, -4923758}}, + {{-13039496, -10977593, 25286947, 11491589, 8276800, -28332148, 3261445, 20136297, -2721162, -6207702}, {-41819530, 12972479, -28605725, -2226919, 34883486, 3609596, -62887815, 13102923, -30434074, -14511876}, {-12017955, -6504858, -20792181, -13657198, 16210598, 13575295, -11699255, -3920091, -23451271, 11663395}}, + {{2448139, 8499647, 29232582, -4968985, -26238588, 1234082, -15273636, 6493604, 15215528, 34243}, {34654291, -6232523, -12466028, -13749033, -18095494, -4850258, 17014508, -862816, 5795906, 1346193}, {-2593676, -14695430, -17573850, -9364354, 12972475, 2750912, 20876789, -14491819, -11179005, 16692910}}, + {{-58215422, -10434322, -35418615, -23019613, 34157818, -4032813, 46756009, -14667443, 10820011, -25962072}, {911212, 15615834, -27683427, -1291661, 20149292, -3964483, 18302855, -9077593, 41450369, 1345878}, {-11506608, -920266, 19069735, 4877100, -14879476, -8212985, -20750288, 2110258, 25194250, -4793958}}, + {{30982165, 13182276, 1804145, 19165108, 3557553, -16004629, 25397760, 1860407, -11333198, 10921092}, {5027671, 2444414, -47256149, -4582924, 36860387, -10913313, 21051062, 474703, -47565962, -2916184}, {-28264421, 590343, 26675165, -4492599, 29616661, 2699360, 11900358, -6732605, 30546923, -4563008}}, + {{12936229, -1552598, -17694160, 22984065, -13555215, 6642616, -16856542, -8340473, 3038360, -15138845}, {-7372957, -28977422, 7334578, -2604645, -24938121, 9431038, -13358950, 17719871, -55448604, -13172419}, {28780855, -2011440, 10075099, -11361048, 2794942, -2710954, 8534199, 4760106, -27712482, 6458713}}, + {{-21083355, 3030110, 63096983, -4386925, -14310636, 6719788, -4636422, -21743059, 6194601, -1795854}, {-10819193, 9973112, 1884851, 262107, 19590488, 21248586, -45883418, -10873873, 288313, -23063750}, {-103962, 12079084, 12597255, 6824992, 15885472, -13668986, -2535647, 1226717, 7344363, -13634998}}, + {{4176437, 22729955, 17496502, -6849030, -34221611, -27806794, -14046608, -5108398, -20401601, 17504009}, {6244243, 6704419, -27025810, 11039886, -26009693, -2450896, 30647416, 13665916, -34776579, 6877025}, {-16064951, 1034624, -23160982, -15440085, -21717774, 1315083, 557758, 1360821, 2657758, -346509}} + }, + { + {{13575072, -19789355, -15499669, -27774828, -1573937, 19608228, 38837589, 7466530, 43596560, 17244295}, {41466462, -9380539, 13479671, -1611996, -39688031, -10402250, -11933573, -18192774, 3331120, -6785231}, {-685245, -13527226, 595337, -6824797, 13606588, -5948857, 21008141, -14434553, -11578884, -3503288}}, + {{-3792452, -4510799, 31359450, -2520482, 56370085, 2060123, -44350761, -5942082, 44210401, 11548167}, {33875256, -6837799, -34036404, 9731002, -10116281, 28503947, 3018095, 15729244, 16667291, 740075}, {-17064493, -956828, -28220343, -16697818, -3731639, -6827899, 30938545, 14039606, 32576944, -10347818}}, + {{10757077, 14795809, -3407355, -780345, 16283675, -5176350, -40163988, -28650767, -5493307, 2075772}, {-32342609, 4029633, -32995121, 16421377, -24072275, 17951028, -23139410, 4034865, 53224171, -17508228}, {-6732679, -15214583, -27085518, -8968614, 11755012, -1499677, 6585597, -6797409, 14527081, 315054}}, + {{27307543, -527023, -58871446, -10931824, 32029460, -20768624, 42545415, 22418653, -51258657, -6176237}, {-9637979, 25428695, -7638516, -3621772, -32093254, 10596574, 18521249, -1129577, -7781761, -6925725}, {-17340695, -14918561, -17238962, -3358619, -9271226, -2732075, 30094692, 206540, 8047861, -5583327}}, + {{-23296813, 5372514, -55447356, -25438752, -394468, -1422767, 12271280, -12717025, 43935041, 3178842}, {30686435, 12736214, -10409960, 2397260, 26737592, 1240199, 7221192, -15254327, -22198131, 12243948}, {32396051, 10530849, 8542907, -6234439, -33143475, 5195376, -24616744, 13069327, 19123269, 15103570}}, + {{-61599163, 10407914, 15146127, -9577140, 2850555, -11434349, -10341117, 11688165, 57222980, 7443309}, {-1959157, 4123922, 46859779, 8039580, -21208177, -18798009, -24182107, -2946369, 1732410, 25984845}, {25946003, -12168188, 2048333, -13538555, -17578310, 13342801, -20932457, 2885364, 29616721, 11594640}}, + {{-40904044, 2945685, 11087344, -6564107, -57015017, -7934886, -42681448, 6648344, -31265094, 21506383}, {-21986860, -20326005, -3353394, 15341865, -6188985, 24351388, -656416, -494508, -26351318, -2036887}, {18250574, -15295358, -11832137, -5452519, 27980331, 16723298, 1292225, -4636338, -13285349, -14831043}}, + {{-15822181, -8220514, 44676240, 4837785, -10965147, 20758580, -6087251, -4268667, 15695528, -33273123}, {27699263, -11559548, -1680314, 17010295, -19865797, 7432280, 1175039, -7527665, 2498720, 132583}, {-20662680, 3812012, 28215072, 9683375, -32934656, 5848009, -28282421, -6651754, 1742396, 10862429}} + }, + { + {{-22733894, 22365918, 34991744, 22930598, -19496866, -8163136, 30107089, 7907709, -14553008, -11632657}, {-37296292, -2003218, 24591582, 9095488, -47173448, 14774464, 3246025, -10677419, 2569096, 445185}, {-13942373, -3559994, -9371297, 1580480, -20158109, 8513092, 11163834, -9623612, 28591763, -13690156}}, + {{11703909, -2375544, -12981611, 28562070, 12367055, 6822582, 32478995, -28584327, 21619877, -9192478}, {-37995101, -3593230, 41950501, -1831386, -24598319, -9607356, -14181623, 3703567, 42309421, -7195304}, {23029114, 10927269, -16101987, -10277174, 15635784, 14878063, -23215498, -1109595, 2198987, 5853567}}, + {{-37129983, -6412591, -37361902, 1346509, 7007490, -9977950, -25107526, -27806347, -14051851, 14030690}, {-20788269, -19804041, 7748724, 9563555, -56756344, -6202546, -1035170, -3893167, -17621495, -2261696}, {-28906373, 204764, -21936639, -13331811, 3966595, -8657893, 18798011, 15222066, -3951168, 16033081}}, + {{-23835089, 14694641, -61354419, 5610348, -10283594, 10840185, 6713333, -4080751, -10670280, 2370248}, {21454405, 5960615, 2048703, 1217562, 24554212, 13565407, -47321821, 28902575, -13897714, 27306186}, {-6032661, -10676923, 27946394, 2598890, -22637840, 6652672, -29695474, 6675520, 16441846, 4656403}}, + {{-13451707, 4507055, 62188672, -7988103, -19447422, 720632, 19254914, 12569311, 6252001, 16384964}, {14786925, -14783207, 3749232, 9850861, -44938020, -5908734, 9804106, -639181, -20593585, -15057988}, {-7443582, -11232846, 4954094, -5823514, 16748077, 9380015, 5897105, -8290425, 5871898, 9086861}}, + {{-34382229, -5828752, 15152997, -11124460, -8252533, 4873628, -19056104, 10644378, -24535978, -12602029}, {-17990235, -16524194, -26248761, 8719524, -30352475, -2606228, 24376282, -12539724, 532544, -9905963}, {-26261900, 1594704, -30851260, -15733673, -16245265, -724673, -25937603, -3280158, 31051504, 13183415}}, + {{-4433901, 22898181, 4408403, 4089599, 7026019, 725982, -35998453, -16160374, -49882415, 21440714}, {-34658715, -5989601, -2370793, 12922491, -315799, 21918616, -25558631, -1306328, 1786989, -4463662}, {24299172, 6407606, 30243748, -12413076, 19777849, 4778790, 20007455, 11060481, 92567, 14380440}}, + {{-62546359, -1117901, -952074, 7995591, 27044812, 13813422, -518271, 14514359, -7559876, 20776990}, {4194309, -29001351, 29866184, -24269021, -15696020, 14141518, -62562609, -8282275, -2484076, 7273808}, {-17821991, 6257652, 29709259, -9550721, -16005147, -5755011, 16908019, -9094499, -5282110, -8106630}} + }, + { + {{28685451, -6107266, 30239148, 6290924, 30696512, -8147733, 2960158, -14334512, -38921075, 4626660}, {1583703, -12161614, 22432712, -21621714, 24630924, 6162155, 59141724, 5599546, -17405309, 22280348}, {-29844040, -471409, -10622236, 12210452, -8239642, -11983887, -15183804, 16381174, 17319255, -2956271}}, + {{-2403083, 12925626, -13099156, 28363373, -7421956, 16456989, 26157882, 7667907, -27281693, -9167492}, {-45717659, -15626026, 50173092, -3406701, -54970694, 7385663, 24757090, -18564339, -4645939, 21629820}, {-32751670, 10248246, -21066690, -3059537, 26806646, -2312121, -17653642, 1520921, -27460759, -12323097}}, + {{13248067, 6436040, 8030453, -25818031, 30780082, -1430948, 18201771, 8897427, 19847298, -2659562}, {50680655, 13582932, -17146553, 4912299, -2595212, -17399816, -10502859, -12069603, 9084258, -14719238}, {31515119, 2251073, 4922241, 2492364, 20234810, -2120720, -26567634, 1872447, -26158151, -3820091}}, + {{3059908, 10356510, 3160147, -5814463, 6619250, 6005354, -18146875, 28990675, 6485346, -3393885}, {-18912530, 22467822, -60653559, 1552123, 17365776, -24805772, -44753569, -2181397, 847216, 17829951}, {-24027306, 1499890, 29296657, -4767293, -11192239, -15482208, -30071603, -13224053, -21934731, 337399}}, + {{1216703, -5387360, 14421225, -353640, 13814558, 27034582, 38058105, -9449465, 11449174, -22314414}, {-24922703, -15978446, -42236369, -3997012, -34641380, -5774914, -20346071, 20193613, -40743840, 9848360}, {12833052, 5696999, -22504492, -7743199, -29120426, -2764382, 26734085, 12053780, 8854624, -14858885}}, + {{35510797, -981503, 14318929, -3469597, 10336566, 21370992, -973336, 1867849, -28297193, 7062219}, {16394267, 12877663, 26342859, 13428701, 10841234, 10087180, -2265170, 5788091, -35468571, 24964845}, {14425123, 3556895, -28505669, -11596774, -32205271, 14061926, 33096714, -9460010, -25504553, 1459596}}, + {{24576115, 22264595, -39113376, 12822398, -48871562, 7948464, 63116078, 7228755, -27405020, -53976}, {8086679, 8186447, 19157134, -8249296, 4699914, 14764776, -2002260, -11057409, 27716466, -16081150}, {-27050118, -3528220, -1516699, -2231374, -12636934, 9995609, 25685841, -4140179, -3409048, -15464812}}, + {{-7531403, 4325881, 7535396, 7859314, -22699673, 7976792, 2479226, -6835756, -32588365, -392602}, {-46120529, 9916327, 38374782, 21688084, -19401825, -12255854, -31333428, 18558666, -21135491, -6668554}, {13991326, 12860930, -4422015, 10881593, 32950975, -283682, -28450269, -16032545, 9672918, -11362754}} + }, + { + {{609922, -16247499, 14961059, -1570609, -28091802, 14169626, -41783295, -13089622, 4930102, -3436202}, {9329866, -657063, -44356797, -15301661, -29486294, -17703348, 8805283, -14270540, -20958948, -26960484}, {23477300, -12109362, 25444691, -7136047, 9244360, 3145110, 19327657, 9308319, 28572142, 1225335}}, + {{8267621, -4527619, -27664281, -19631026, 7103467, 8015983, 19980277, -20523192, -33106752, -9640324}, {-49140895, -14621999, 9804745, 11746362, 1328203, -7481863, -9767851, 340196, -4927892, -2341788}, {-30353118, 622051, 10357298, -11276182, 23732131, -4604752, 29769254, 15682613, 14502745, 1692468}}, + {{1260912, -5294878, -53574238, 1785181, -6140895, 7516954, 13950460, -12831935, -44549610, -21761599}, {-31177968, 8480756, -13273798, -10571863, 47258623, 20807548, -24434810, 16780381, 14669642, 8224809}, {28182450, -9865310, -18750048, 14220580, -31294501, -12254360, -24830749, 3333773, 16756756, 3674180}}, + {{-6402360, -6335805, -33097256, -9850907, -4824695, -21057881, -15064635, 4889122, -22240663, -13412349}, {-44163136, 17929609, -31558170, -18775313, 16737199, 11833309, 47647709, 17892042, 27454173, -11748923}, {7733705, 3101270, -7805155, -5082179, 27897611, -11801644, 12061037, 7405405, -16546491, 15403389}}, + {{-4492968, 343804, 38266516, 32477765, -25777001, 13550643, 46526645, 17121454, -14426206, 18420417}, {-46530416, 1424718, 24723148, -680817, -40884673, 8897391, -13370151, -15981258, 36955976, 8156639}, {-24543854, -15223067, -2543355, 16106116, -14644361, -11276692, -25446112, -3383546, 1372079, 9830245}}, + {{-45249865, 5860643, -511570, 1494755, -24871604, 13184267, -25232936, -3704812, 41046541, 15652109}, {-20701335, 2062533, 4978884, 611175, -30157770, -15586203, -7510502, -19563320, -13272327, 5150375}, {10708302, -3863498, -22395389, 16573914, -5145231, -4552434, -4603892, -8967772, -1517224, 10636936}}, + {{22812080, -18752417, 9910097, 1108862, -16257891, 1138559, 2414519, -13730584, -10249269, 2676014}, {-20435954, 11175275, 45231099, 6155242, -48353071, 24683369, -59216429, 17111970, -22023587, -19928584}, {25874111, 6383009, 13602754, -6088836, -20233593, -3580839, 27183994, -11837778, -29518672, -2860903}}, + {{-1681560, -11679105, 400217, -6168948, -46402196, 1534799, -6234380, -45604, -2757186, 31803865}, {-15876686, 10637109, 30465123, -25542824, 18668596, -820323, -39800218, -21603264, 54303356, -1363285}, {-17522273, -15566672, -29122873, 7399164, 33527165, 12928839, 5585868, -15504027, 31653797, 10489380}} + }, + { + {{-8372444, 7555339, 32540989, -19186451, -11202553, -27432492, -45917828, -10768103, 20962520, -11534894}, {19695734, 12580309, -11811267, 10021575, 46310557, -411332, 2870540, -525511, 22740298, 9835954}, {27255654, 7099090, 12404130, 13814764, -7475522, -13667972, -21749346, 14576154, 7990399, -12406876}}, + {{11527801, 11839779, 17463740, -12828497, -30323835, -533377, -18537666, -2971505, 33445637, 1378899}, {-5182347, 2305541, -43036482, -12755443, -19326901, -25584801, -46604822, 108557, -32639917, 21539705}, {9401944, 7738115, 3634928, -5218468, 1792182, 11012020, -10935528, 9848524, -8395638, 1752383}}, + {{20087513, -291352, 34200431, -9266428, 62742024, -11465814, 25160028, -23260583, 20949348, 4741970}, {-34742547, 4824060, -24760277, 15520282, -3746158, 9908304, -15131750, 615003, 23774668, -4622502}, {30152793, 14686972, 18175085, 7025501, -16572275, -10778346, -3777754, 1265518, 4148852, -13707789}}, + {{-38414435, -12792916, -2239329, -3207407, -20902781, -7236076, 20364640, 14570920, -21750082, -1957286}, {-26406891, 588662, 42602249, 18949875, 40283141, 8327480, 44288302, 11085620, -42944036, -24193688}, {24058929, -11521453, -8974101, 8545768, 7842586, 5283701, -5952655, -16759937, -28459199, 2855313}}, + {{-22950445, 2636586, 16485375, 23498857, -50586070, 8299269, 44530771, -1084345, -12093804, -12285062}, {26623543, -10037872, 25079369, 6181813, -10081082, 7047923, -8641075, -26766059, 52958854, 1962838}, {-14692059, 3189504, -1141773, -6869718, 16477874, -16186435, 10319878, -12263639, 27007849, -11168270}}, + {{1395398, -2560759, 19469476, 28776421, -10401013, 1426902, 43387733, -15775984, -2907552, -3878368}, {44130694, -18470819, -42832262, -1157721, -19297931, 27290380, 9680329, -14007508, -19301064, -25801940}, {-9077853, 12479035, 32279877, 309923, 32237763, 11557611, -14314225, -6638385, 21114797, -12559936}}, + {{-1074752, -12711000, 11779129, -6005334, 18492568, 813113, -23399152, -17827765, -27283475, 897128}, {-5877536, -19332004, -32558825, 21223296, 14993686, -13962833, -42176122, -1104083, 14232253, -15133784}, {-19690492, 6937960, 25377806, 9508659, -510153, -14981949, -9629935, -4642867, 28215996, 61378}}, + {{-2424643, -23482508, 17854580, -12384463, -6175769, -7029740, 2895954, 7260602, 4923635, -9163617}, {-22476207, 4360038, -10341294, -17982317, -3199499, 18985914, 1781084, -13251932, -19610353, -13719439}, {30725364, -2670803, 30379991, 6502287, -6324103, -13835465, -30857651, 11056502, -11206851, -11544011}} + }, + { + {{25613616, -3102602, 40789082, 15098034, -27085595, -28107115, -24729657, 9846294, 64147258, 8535304}, {5544284, -29420706, -847298, -12517760, 16311373, -2661037, -26206351, -19068264, 2059874, 8195880}, {6669623, 1911069, -1424926, -11047889, -1797036, 5077921, -10177871, 4954835, -17974230, -12151160}}, + {{53838367, 18498333, 29327101, -18307717, -27697332, -6262662, 18729755, 10337992, -6784427, -12669848}, {-219965, 10998769, -13624131, 12996865, -22399952, 23493860, 13600601, -18769408, 20883561, 20137308}, {21917704, 666621, 29983376, -12912559, 33297656, 14065983, -14663339, -13679339, 12578619, -16118527}}, + {{560628, 14919700, 1508980, -11236102, 48897615, 20442779, 3014560, -26431507, 44332294, 1132925}, {13641098, 7148772, 63423392, 2454340, 266701, -10477331, 53865232, 5770029, 14388618, -12499003}, {23680383, -9234375, 13985236, -6697353, 2164536, 4153861, 13315193, 15804309, 22736038, -14401730}}, + {{-28797906, 19629356, 1528610, -16221572, -40039242, -218904, 4026062, 24818856, -5842348, 2442806}, {-22117432, 4453156, -20160710, 6594242, -4416272, 32605326, -46568762, -4076794, 42785798, 27679198}, {17658618, -10828002, 21213762, 1082858, 5596600, 7970557, 10413717, 15361795, 30096544, -14984181}}, + {{-34398711, 13610827, -7533094, 18637497, 13228901, -15549551, 34454960, -931237, 37709517, -5866337}, {-10580883, 5781373, -16402464, -9730763, 52388739, 4648305, 16976166, -17304963, 13365317, 24556797}, {-23208171, -4866820, 9566555, -2385155, 32031436, -1912329, -26656342, -13720432, 29996919, -16622340}}, + {{-14044704, 20590387, -19224032, -15661458, -30514062, 19176348, 18002615, -9139157, -54872916, 4783343}, {8745298, 6103435, 16808486, -15382452, 6883638, 13991438, -710423, -22054081, 9614176, 10941823}, {-20054347, -1473522, -13963513, -12909374, 32183518, -9397961, -30746382, -12228468, 31752780, -11444156}}, + {{53597225, 11311815, 51366539, 4168341, 38588940, -9441254, 34224936, -4331012, -5898761, -15177316}, {11566971, -14572795, 864689, 11811969, -10947644, 22048946, -7055954, 17376260, -5170355, 3726178}, {18017909, 5290946, 4193366, -7542284, 23281477, -12847996, -27373724, 4478364, -27664855, -1638231}}, + {{6492510, -10992036, -17181759, 26181968, -13816983, -3239659, 5097351, 918347, -10497797, -18113476}, {-35106388, 398620, 34036107, 931208, -33293947, -8334349, -18454969, -26315265, 5152047, -8450474}, {-6825120, -5661866, 3152790, -334544, 30064065, -14377643, -32647844, 7261409, 21680638, -11642126}} + }, + { + {{-26325513, -8248593, -3247140, 1740121, -34992129, -18480334, -19932573, 27682074, -46819460, -12935819}, {4372323, -20195835, 48957234, 22171431, 21759893, 15021816, 20161859, -5774394, -6423072, 14280917}, {-2345355, 14800842, -33176513, -14576316, -6275749, -7130565, -22666781, -11553044, 20757373, 7638412}}, + {{18554129, 1883773, 33190000, -137057, -38265135, -2458605, 12151744, -3941042, -24904603, 5182536}, {-45627519, 18696043, 6833972, -16969839, -23385441, -10799057, 29598860, 16700748, 41400259, -22784054}, {-9975310, 9942494, 32932345, 9470829, -19659249, 8806378, -24570784, 14852161, 19807157, -9112620}}, + {{20728432, -2965451, -16983203, -8355403, 13568410, -19649207, -33100963, -9061445, 39853397, -17601764}, {33435384, 15050151, -2695531, -6769507, 34423744, -9209925, -23362771, 10679619, -10219535, 3020820}, {-24169278, 12088578, 30194499, -14423347, 4621968, -11420678, -12857712, 1445253, 2454940, -5098990}}, + {{-50090410, -11937497, 20023918, -28422725, -25901937, -4562103, 2957441, 9350542, 27011030, 22919199}, {-16855872, -14285699, 41271594, -4437213, 23047931, 24003335, -21274185, -3716982, -10501104, 1224083}, {31381937, -15006606, 22569079, 849892, 25067525, -12846614, 18279065, -2688830, 4086724, -11375950}}, + {{-25807098, 664214, -20940416, 16721299, -13781153, -9825407, -11144281, 7087253, 39991176, -4321267}, {35916106, -16130278, -45522856, 4299345, 49211559, -1431649, 19013381, -1997569, 7898424, 13808859}, {-21081302, 7761271, 14799146, 10140929, -25916611, 4883839, -30034870, -5553186, -14047385, 15516431}}, + {{27336411, 3025295, 4763606, -18353613, -22285434, -2393666, -10650120, -14195341, 1208838, 5305816}, {33041431, -3031923, -48542168, -8010493, 16840522, -17236746, -35808808, -9896367, 15521690, 5581358}, {12964476, 9619386, 7525095, -1197026, 6449927, -10883525, 30807774, 2498372, -21141039, -3450882}}, + {{-36131818, -1284028, 21128192, -906526, -25769228, 1583451, -4294356, -11463455, 7181513, 18882049}, {27034390, 23461406, 12012698, 30665976, -17137104, -28414025, -16095762, -16380803, -7340749, -8589025}, {-15942564, -583248, 4994353, 477050, -25858706, -323177, 22093563, 766157, -12827507, -6319082}}, + {{22634837, 17227779, 2060432, -16826865, -20349374, 5789274, -20032198, -5620537, -40330372, 9990778}, {31284447, -1278585, -40294954, -1499651, -43891760, 6715506, -19491732, 2135147, 22416580, 7682118}, {-2901436, -8239520, 27494476, 13096587, 23762647, -1548528, -30477045, 3457949, 10095228, -7581833}} + }, + { + {{2114197, 17030051, -13659256, 9852839, -7653641, -17120494, 26934226, -16806072, -36500363, -23965140}, {-60558843, 13901365, -20685490, -3222777, 57453737, 7790306, 3132824, -11661968, 7015193, -1481912}, {2606844, -15219131, -23863412, 5506284, -28216375, -11753603, 28396964, -2821608, -8177325, -5229292}}, + {{2117620, 5071400, -51371060, 8659595, -1555064, -9254065, -16793387, 867368, -30116922, -11099567}, {-3074486, 6051358, -4580212, 17909015, 62691798, 5707253, 39685481, -1564528, -8106780, -10769123}, {26393433, 477586, 21455749, -3024754, -23080611, -4445543, -22936291, -11700610, -13410903, 15714181}}, + {{-31064456, -423253, 17927519, -15078939, -3651989, -4604710, -55755692, -6380619, 23667075, 2254886}, {-8866532, 26907601, -38178645, 12541627, -41761655, 15894554, 6139818, -9980589, -32669393, -31037282}, {8331842, 12088797, 8743449, 5199715, 7827646, 14995800, 32818339, -15785319, 26039508, 8660820}}, + {{29608880, -25012307, -3741475, 2263012, 17390139, 14671399, -46672426, -2644670, 31072720, -16370835}, {31432406, -7112671, 11848109, 25118790, -13938283, 11538983, 4069966, -18394394, -5824836, -1329775}, {-14433949, 4946823, -7500924, 12196981, 13338029, -15298747, -7069294, 16291914, -14596651, -764794}}, + {{-47671656, 5321445, 25113508, 25839794, 11138831, 11243554, -7992278, -492744, 3259159, 21502307}, {7246326, 1660785, -3260474, 6454628, 32064949, 17015606, -18472972, 20915418, -54909651, -3050597}, {15768270, -10694330, -28616776, 8679482, 12703510, 16040531, -32739301, -11567793, 24758624, 9552392}}, + {{57612225, 17986091, 3746391, 10734441, 3986026, -21094603, 16387973, -12469457, 3881315, -9926314}, {-624623, 12461149, -51123123, -22504775, 37750130, -7879511, 11693933, -7847909, 4979163, -14061758}, {-9228097, -16612591, -30048092, 9179101, -1510092, -12371889, -10272294, -7719712, 8198600, 14178374}}, + {{-44524641, 11655384, -3094856, -4653367, 14629907, 28489197, 22967506, 12213495, -2529582, 1078481}, {6176435, -17402926, 3629314, 27064491, 4067273, -3887667, 40995892, 4419129, 20423036, -9367845}, {17891255, 8589105, -24215999, -14819511, 19880982, 780210, -33205145, 11448404, 22097349, -11182687}}, + {{-56614347, -11578188, 35985602, -7657125, -33304359, -28085372, -11902129, -10381139, 4829275, -5224705}, {7662417, 16677484, 3043718, 18325901, 32667751, 2300018, -47786427, 17253601, 24265597, -18169169}, {-18998173, 12084374, 14914736, 184926, 10136115, -7636021, -1182475, 2011448, -3200275, 16596418}} + }, + { + {{20417236, 3754420, -6738616, 8258483, 8799896, 13466324, -23880510, 11012604, 6303439, -3234445}, {-9662424, -26686038, -46906146, -11028221, -22584644, 1743532, 43009814, -13291636, -47986433, -18890135}, {-6481517, 4004191, 4493109, -5202130, -31648275, 11051930, 5985603, -13179900, -26804977, 6841092}}, + {{-33140236, -26703602, -466711, 995232, 13691879, -4875991, -4209980, 2211678, 12277522, 8419710}, {26163546, 5021636, -35722295, -20577268, -44821239, 955253, 8256638, -25191066, -4483980, 22437190}, {-26364811, 3746737, 29973408, -13605927, 15675876, 8003871, 11707655, -16697620, 12112406, 4013808}}, + {{27492119, -14475041, -15050357, 25726237, 20610151, -13989916, 8011822, -1373664, 23660358, -27162084}, {34860435, -14275633, -35512837, 1671599, -8790883, -17961386, -23719502, -10031868, 42881268, -4549920}, {29021594, -3019356, 8587009, 11384121, -25402734, -7392345, 32885066, 14460607, -15018066, -15719330}}, + {{-36428323, 10993200, -17511364, 9372077, 20074151, 9525006, 27348409, 459280, 3871179, -8165676}, {15159929, -14398564, -38057784, -17699073, -15046129, 20874698, -8384091, 21642740, 15388743, -6182942}, {6938581, 8822343, 8620932, -8578754, -4104627, -5936118, -26735367, 12738036, 13629323, 11082567}}, + {{-10094361, -334652, 38476983, 2790439, 27359870, 9552721, 32053453, -6969029, 10042131, 1926471}, {30282419, -2678756, -19246779, 1725181, 37410474, 20135333, 12145193, -21815855, 19828393, 20800757}, {26753059, -13933234, 27619188, -7497265, 16033163, 16756554, -22110989, 6046760, 4021520, -12705457}}, + {{-17531609, 15683192, -60939575, -3448475, 715976, 10128494, 2939400, 25784735, 58743432, -16073813}, {-20867029, 11543468, -2401509, -10757695, 63356468, -1332856, -35145770, -7583819, 2140192, 14736421}, {20912186, -9499909, 17368552, -5248439, 383852, 3792929, -15675370, -7000153, 25685400, -13601909}}, + {{1414967, 26315702, -47285501, -12511107, -26584273, -8841287, -11498324, 10640443, -24532611, -6408984}, {18127227, 864012, -9629079, 11593257, 1974271, -5312585, 39105750, 7314787, 42290595, -388650}, {24881185, 14073561, 4685989, 1030574, 5144912, -2519431, -20326615, 15917167, -4984945, -3376538}}, + {{-62565663, 4920478, -55376449, -476735, -43677535, 17959977, 38328264, -10344668, 505340, -28100303}, {3438657, -93716, 8832861, 1390381, 2767865, 13100345, -3166778, 17063164, 40430482, 3196597}, {-30623883, 6302481, -22871030, -1596089, -27318556, -1845828, -30934853, -11670445, -24178997, 2237082}} + }, + { + {{-42013187, -21787042, -1974859, 641794, -29012986, 27248518, -11318182, 5528619, 47218899, -27053971}, {21399495, -6961006, -60149823, -27990936, 32659538, 402218, -17546244, -17599875, 3654601, 2799325}, {25901287, -9761761, -3723331, -8371812, 25859324, 13536452, -18715963, -16042698, 17594096, 11317273}}, + {{-42888393, 19107059, -13724666, 2457030, 35585086, 15454849, 56449705, 6596061, -27137418, -10313846}, {-18245557, -12694977, 52885490, 17475442, -9942024, -4476971, -3203117, -553835, -15881918, -13413996}, {12202693, -12337785, -30153666, -4395318, 14717208, -4425600, -22858811, -13185192, -17959265, 2144141}}, + {{51166048, -26529493, 998246, -19904447, 21680565, 70271, 58588815, 11104313, -29340186, -15589375}, {10396306, 556339, -20794266, -10222229, 43439911, -19881575, -8125073, 409357, -29955322, -5006503}, {33021662, -1104036, -31710826, 8226104, -20213488, -1213314, 29757292, 12547987, -7586901, 2216753}}, + {{-35407447, 18766745, -29406085, 4524650, -19274474, -20474329, -29645035, 4173870, -18612774, -28994444}, {4417599, -13567597, -27595143, 24830672, 23713420, 11302197, -24087205, 21047428, 43127268, 2647518}, {-10840209, -4031615, 3434966, -2883654, -33078119, 11883954, -4958608, -3035636, 23436012, -4139629}}, + {{55573275, -10384260, 48760956, -8245044, 5563808, -3927548, -12376512, 10483595, 24339695, 24222716}, {3381031, -772374, -11089900, -13843410, -32834346, -23935396, 29059114, 5645517, -10519961, 3236912}, {23037092, -1287504, 7295737, -961721, -11545579, -14357320, -5928040, 12927381, 33019745, 7517994}}, + {{-10919893, 10029121, -1170858, 5096908, 22114728, 8472664, 15995883, -2832011, -13953384, -23651018}, {34866095, -1771857, 36174248, 2540622, -32624908, -6779600, -33549631, 3465737, -24182162, 4056752}, {12704410, 7507131, -7289543, 10523503, -22979044, 3716496, -608065, 11785705, 4833052, -12397016}}, + {{-20098856, -8357022, -13509875, -4260610, -1155839, -2460344, -11909914, 14519853, -11674164, -4932027}, {-20235794, 5667344, -34325855, -27044324, 34168809, 19411772, -31226346, -5984537, 11679534, -812723}, {-10928038, 3725640, 15839793, 2209351, 18379523, 16032103, 1913182, -15696614, -27517459, -8157489}}, + {{-18782125, -24814076, -3958506, 26630408, 60814430, 4813699, 33756661, 5374436, 27014220, -12974732}, {17864349, -8685810, -40310934, 2052652, 1728180, -23835879, 703879, 15354684, 29682008, 16487546}, {17771672, -11482859, -7287302, -11938074, -12767482, -8666772, -19744227, -7739340, 20155770, -3540752}} + }, + { + {{-20537140, -2325676, -18195382, 24196641, -15647052, 20118839, -12925105, 17045916, 34499709, -17229790}, {35193252, 8694668, 35544716, -7655657, 27470362, -3594335, -46317185, 10996548, 9029315, -12706320}, {13627845, -14179605, 27664073, -4176906, 30076695, -5368248, -28022384, 10437867, 31092096, -10165457}}, + {{26082898, 1481922, 42354473, 22859843, -47160656, -31990941, 22146898, -14550325, 13976901, 14484952}, {32189144, -8924380, -9072391, 4619295, 8692690, 1181533, -13742008, 8049019, 38048563, -13701850}, {-6553634, -7387076, 2142769, -1783714, -12658909, 4088377, -14531792, 15589041, 9532256, -5214258}}, + {{21903333, 835551, 25948411, 8087994, 10579336, -19159877, 10063391, 6406466, 26035008, 24825436}, {-7991019, 23450851, 28067991, 10971202, -44508446, -2071805, -26934681, -5349122, -31058556, 6922554}, {-23535575, 14721737, 19897836, 7195206, 18514260, 10267975, 32597365, 7146760, -26220125, -4181103}}, + {{-8377112, -15053012, 19701631, -1143892, 29173097, -7711884, 7533159, -11284451, 22602583, -202085}, {-12081374, 12320872, -18577273, -25481020, 6063795, -457184, 11528113, 6761257, 15950727, 2016225}, {-3488474, -1252458, 27598369, -9564249, -13868383, 12663504, 13034117, 10389639, 25008987, 12869544}}, + {{-41287488, 5097899, -8017582, 16515062, 4005319, 2886222, -26248725, 30756415, 37890545, -9382902}, {14169058, 21213397, -5825866, 2602682, 40886443, -27926390, -919315, 1053779, -14443655, -8976564}, {-26523777, 11005501, -13398213, -1504220, 17120379, -11293324, 4627812, -15843648, -13055828, 15956039}}, + {{2548227, -11481600, -17475494, -10395519, 12804828, 2200128, 681831, 22496890, -59662, -13031715}, {-57903567, 8975256, -42926640, 3285287, 32744596, -9503574, 28043407, -527888, -49147912, -10727719}, {9506135, -10079608, -27371911, -3187209, 31426795, -3119051, 12656925, -12472556, -19389021, -12220760}}, + {{25040145, 5375975, -16032779, -16207116, -24837545, 1229911, -18870216, -3502521, -38635521, -24186669}, {4129107, -9049199, -43495961, -4674306, 14771801, 26152529, 1639988, -22909721, -19916249, 5570799}, {7930351, 7168936, -18962536, 4388632, 6861069, 1314713, -11935473, -6148385, 6893105, -2679637}}, + {{14209111, -8618739, 10194979, 2677300, 4013085, 9775729, 19731499, -13248526, -13730102, 15670809}, {1951811, -16648029, 10124883, 23538690, 57732181, -151453, -17384431, 5916614, -42862646, -10821399}, {-12843967, -12783694, -5060981, 13040075, -3965076, -2110951, -32363179, -2348882, 19898655, -3575970}} + }, + { + {{-34792196, 10961077, 12194610, -4593557, -51395077, 10010208, -26461909, -1002357, 261319, -503468}, {-29207090, -6676381, -48195486, -25111299, -1638025, 11265984, -8328237, 211091, 34106289, 26184676}, {30472641, -2165883, 18114708, 3293995, -4965577, 4084296, 31866003, -7230542, -25605491, 8816749}}, + {{5482036, 9596271, -12015879, -12654964, -6454965, 3709767, 11700907, 2388819, -57663235, 3276276}, {-20962264, -9019427, 54613037, 12841154, -14598765, 5875969, -38133515, 22983389, 6067571, -7706478}, {14039908, 9441265, 24349126, -11164888, -25009241, 16168687, -29220409, 3453089, 20283883, -11622176}}, + {{-24958806, 7999411, 26453178, -8644238, 37004539, 9520148, -44953608, -4942104, -49827416, 6739321}, {-15417434, -22489529, 28384358, -8360578, -24069667, 21421860, -17147560, -8528850, 16955778, 1845317}, {18676342, 14475508, -25360785, -8450461, 5095309, 12998774, -8725611, -16378797, 17352997, -7873738}}, + {{6088013, 15443631, 15367919, 6931010, 7383773, -8971235, 3134230, -17993438, 19885092, -15431371}, {-36868691, 1848785, 28117399, -12178392, -32202919, -2935929, -41541808, -13740268, -1903224, 12010861}, {15872540, 8482255, 10321834, -9675351, -11648295, -7642890, 16801676, 10997144, -29109315, 5395913}}, + {{21122930, -14654623, -4691857, -20599888, -3407677, 8298546, 1212356, 20368845, 11864426, 17078944}, {-7942474, -3116257, -18091609, 10415574, 19535041, 18089154, -24275846, 1802933, 29309900, -14749954}, {-33017200, -10927095, -19262732, 8479894, -22891975, -15495620, -24826565, 173807, -28824337, 9766249}}, + {{10187499, -14842972, 1765958, 5454142, -29038474, -11108464, -7325191, -6006206, 3359839, 14414352}, {35404123, -1243790, 36161128, 23385616, -11058392, -1044806, 50151439, 13948196, 26832723, 7453256}, {-13954451, 5021979, 7140615, -11141845, 5062172, 9122582, -27422342, 11371205, -26697878, -7980757}}, + {{-15101525, 19083247, 49815512, 5467110, 55249963, 7815419, -22701226, 9352040, -17207788, -9327396}, {24432659, -3429041, -10078804, -23645764, 3705141, 7636697, -24328046, 3752550, -33924128, -10417608}, {4263947, -14573397, 1561691, -16719679, -15027272, 13811718, 7916120, 15642183, -12100015, -12542066}}, + {{-1246283, -16919000, 20714304, 9342413, 4463122, -3091715, -16615071, 8350186, 28517447, 7256289}, {-60583887, 10129604, 8033426, 12645057, 15784562, -24923815, -40527691, 2345010, -2630711, 5565399}, {24853847, -6571768, -4123529, 12035347, 27742746, 10789343, 21227012, 14204447, 26950712, 15226435}} + }, + { + {{38293607, 9950574, 34571061, 18019104, -4796135, -12903233, -37153980, 11988194, 64667371, -1295399}, {1990479, -3993934, 15302587, -13624854, -50925443, -10162423, 12470946, -12501532, -398257, -4518189}, {-2123361, 15868208, 20504658, -5640753, 12828365, 2917800, -23159772, 9610427, -22229642, 8514192}}, + {{60152501, -7881029, -5735493, 27067102, 15216094, -25578865, 5775396, -18282676, -32004183, 333751}, {-2942997, -19709343, 5657549, 5187848, -41462598, -1889377, 31388930, 12989898, -18862997, 17561703}, {27452835, 11888074, 2130182, -13375267, -27335132, 11090572, 26997919, -14726058, -6038282, 5670406}}, + {{24606109, -3086065, -6334722, -7104165, -17038207, 3899991, 43535930, -27376513, -14631009, -26472435}, {-41220877, 22579683, 1597526, -9250673, -29385377, -9619937, -22573078, 1989229, 44859531, 6507783}, {-15529106, 393113, -931832, -8044029, -4718990, 8311519, -30956863, -13990446, -1115870, -640824}}, + {{-18312096, 7296216, 29905169, 25918428, 1044356, 11106126, -52239421, 15937722, -22413453, 8019028}, {34783270, 17243468, -2583019, -6229442, 22256742, 11066256, 11271803, -12193662, 2341667, -11740674}, {23620188, 5155673, 28287869, -5403815, 27901784, 3248580, -11693777, -6246066, 2690945, -4535794}}, + {{-3476170, 25705465, -35582829, -6211080, 32037996, 19319806, -1946921, 2881239, 4200013, 24664725}, {-24648332, -2355153, -5164445, 1415306, -17921628, 5735806, -11414171, -28844433, -9840029, -1554479}, {29536729, 3727365, 30118034, -16717889, 9563888, -9113834, -19443307, -12170618, -2320751, -14161678}}, + {{-49927995, -23511266, 1925927, -22529664, 28821505, -8939245, -14236007, -8614804, 9368285, -8849337}, {-6508507, 5065926, -62306881, -7969506, 20657007, -9110349, -18390589, -8734012, -52065503, -6397031}, {-4258866, 12403757, 23357823, -5147989, 22816681, 14989671, -18261135, -12259319, -18169940, 15689278}}, + {{-43701663, 7343034, 35625243, 6830390, 38456241, 8090418, -39362684, 14665127, 42418672, -780303}, {-2622183, 20216964, 13038227, 8116138, 21533737, 12653508, -17065706, -15673089, -3998786, -30481879}, {-23923362, 4340854, 590054, -12912692, 8291014, -1995009, 16612887, -14602635, -5134320, -6609129}}, + {{-2605458, -10075893, -18084324, 1785292, -24201087, -7331775, -42147543, -1178129, 14910313, 18415851}, {-3772848, 7289091, 14209634, 26755102, 29108767, 19329837, 17330869, -28922531, -47107019, -797789}, {19507809, -5258985, 19827066, 9929560, -33064263, -11557847, 32396361, 9850512, 23796890, -1444503}} + }, + { + {{-12384446, -13010874, 2487059, 31217155, -13004356, 2408366, -27841844, -20200143, -16196, 8381494}, {-39680994, 4117412, -11547829, -64191, 18815740, 4549986, -1766722, -4552917, -6845154, 9783316}, {-29956699, -4572563, 6682169, 12636669, 17213151, 9006121, 29971302, -10155332, 1096947, 3628954}}, + {{-18465775, -908661, 49529146, 10305432, -258983, 23207363, -48359991, 18872011, -4327240, 7239294}, {11704483, 3567689, 6504514, -19537956, -25889227, 9574331, -9054889, -12073385, -52083106, -25638862}, {14856235, 11513568, 28357905, 15327185, -1082760, 14173294, -30704370, 11901690, 8802214, 16581834}}, + {{-9294664, -8457878, -10859921, 20428339, -15313257, -7900880, -4836246, 12327012, -23875432, 18148872}, {29748992, 19265676, 55897757, 2341831, -32343551, 16165530, 18983458, -10735336, -33163498, -11994620}, {31177644, -6686720, 4589526, -1943272, -31542249, -13403714, -16612505, -11535916, -16130625, 4101054}}, + {{-22368116, -3844438, -19803753, 1659525, -5314680, -33207352, -2393824, 158285, -22091012, 140342}, {21845392, 25861238, -3508139, -8460531, -52731176, -337492, 44029314, 11925833, -9152248, -3183260}, {-26957058, -985488, 11453566, 8162404, -9971724, 565243, -19106334, 15417138, 9570869, -8065373}}, + {{-7721498, -4576026, -49911119, 20372007, 20354437, 1785214, -18870524, 13216149, 13918268, -8338041}, {-18075312, 9107134, -13490015, 4262595, -3728271, -14273974, 27655182, 14282167, 18990264, -11873043}, {31949564, 7089028, 25036939, -147319, 6152506, -10917749, 21271289, 16352110, -4421421, 6096833}}, + {{-26160543, 23504438, 11550855, -22659236, 46630207, 24953409, -24064935, -2746233, 2457397, -8551569}, {-9276343, -6010072, -51234109, 6197754, 168167, 8495751, -8515229, -26660199, 44782121, -16745075}, {-23133267, -16088093, 32728011, 12088731, -22980897, 12361190, 13199668, 7106395, 16088520, -14360530}}, + {{11203394, 3535766, 494786, 2853581, 9470242, -10646902, -23262130, -3003340, -3438958, 4422278}, {-32520048, -15070518, 50782614, 606509, -34539328, -21730270, 26791576, 29915800, -1159434, -10942548}, {-26091274, -13738808, 26351380, -5292040, 8784328, -10413437, -17838113, -13270798, 32104096, -8195358}}, + {{-19763951, -493920, 37902700, -8894654, -21572, 9573680, -14380422, -5852103, -48784846, -2268320}, {-13451423, 8885698, -8613990, 14234224, -66053122, -1944250, -28789948, 10126155, 8041774, -8216666}, {-25625293, -12364030, -12897751, 15561517, -23966084, 15039628, 8398684, -12669672, 25537255, -3738530}} + }, + { + {{-26823707, -3014143, 9257839, 16598020, -57710506, 26340007, 14598539, -6911811, 8624957, -3355993}, {37578051, -27305543, 20671357, -16093098, 5470554, 7124597, -33166821, -19298833, 44351923, 3093751}, {5192241, 5198744, 8259336, 14807706, 16734428, -10213346, 12579450, 1529321, 3710929, -13803643}}, + {{32567887, -12778530, -4546434, -5195811, -23112588, -14382296, -2610796, 7243838, 6824785, 24853059}, {-33100475, 2101530, 14782812, -2946043, -13097786, -18547340, -147316, 4263580, 49118509, 389861}, {-26433271, 3095771, -21099841, 8183997, -17979696, 2375076, -6173115, 12351253, -15162325, -7325167}}, + {{-36410699, 7509499, -773676, 18481494, -1306270, 9379297, -7169729, 28985213, 23974182, -1469573}, {23013773, -2363861, 42337730, -14636146, -17262958, 212079, -47624395, 1262009, 2909484, -3851459}, {-26149346, -1598074, -31721571, 15768718, -21769911, 14908480, 23446540, -12658378, 16915236, -3638875}}, + {{-9573611, 4971503, -3191607, -11944444, -29560811, 11869309, -47019588, 4824066, 46060921, 8814279}, {4177875, -3528885, 43536831, 6554046, -5867355, 15354279, 11252984, 2571750, 365885, 9982789}, {-27327055, 5118536, -31003207, -2703988, -10913454, -6579013, -347619, -13536091, 22064770, 2451589}}, + {{-4054695, 5508150, 8968001, 15696040, 34336025, -19961059, 39155732, -7741309, 3460211, 8754601}, {53223993, -10795298, 1673849, 6566416, -25196301, -8107069, -15920352, 5890225, 30723453, -3973739}, {-10930190, -3718190, -24018573, -5446691, -27124800, -2428338, -6552058, 10097421, 32754393, -12001899}}, + {{9541613, 578230, 46189570, 932191, -39549476, 14125606, -20809415, 3664578, 38544816, -7737920}, {-7785869, 22461888, 17548446, -31568433, -25462556, 113852, -24901067, 10900994, -1525684, 10284652}, {12805753, -6731773, 28606412, -15976473, 17923858, 4215695, -8478244, 2410106, -5118417, 3095629}}, + {{-1274366, -14111579, -17609504, -9308071, -2709772, 20098094, 32833994, -8567754, 39391185, -13251562}, {49592320, 4207465, -29712732, 12885247, -27241144, 10683524, -7141288, -5135490, -25568193, -20093574}, {-8692174, -15973418, 14281508, -8382675, -477954, -9393444, -16847821, 547829, -822026, 6187183}}, + {{55926199, -13775110, -29489980, 8866140, 2339475, 3058935, 10330494, 239241, -12863051, 5699647}, {-10902873, 5615930, 28459160, -13948794, -14276655, 17635101, -4830130, 15571287, 41027545, -19163461}, {7107704, 4303869, 11655336, 14710427, 20216631, 8353283, 33184466, 1711678, -5172945, 11112386}} + }, + { + {{-21095760, 5299745, -27763118, 28284282, 1436142, -11502593, 36039271, -8549379, 14317211, 4479743}, {5683176, -14334649, -21838364, 4193246, 25608474, 16596289, -12362999, -4451691, -38177811, -9629351}, {-31491964, -9284285, -13811425, -16199088, 33353176, 13273993, 18365355, -11123036, -10830146, -1597417}}, + {{34402472, -3135277, 27771230, 22812093, 23940857, 11598071, -3989002, -5470641, 8010160, -10175848}, {-8288232, 10607321, -29598962, 6489101, 18323079, 19296159, 36126604, -4683323, 47574698, 12220272}, {16539663, -16433251, 28689171, 12952953, 22598174, 4283866, 32968775, -12075843, -33205368, 9921492}}, + {{28911702, -624890, -1956282, 20708125, -5990290, 10957759, 20918129, -11179075, -26234635, 19409040}, {-3987662, 25401092, -50912550, -9360127, 9291736, 19825745, 25396275, -3992341, -21209227, 5763050}, {-7167022, -11584585, -7333411, 8659035, -3813935, -2472291, -24501709, -582095, -31003960, -7572359}}, + {{7377972, -7045175, 3171818, 26600343, -21971503, -827928, 799562, 6807644, 12089895, -1568018}, {-26854334, 604743, -37384910, 6651275, 37667675, 5825320, 30304082, 16548576, 18929689, 6380490}, {-4734860, 2916604, 13659705, 1230109, 7914478, 1161122, 25569968, 16095238, -15211374, -12625431}}, + {{60046092, -19290031, 55644508, 5924598, -16766437, 3649303, 15210001, -17200016, 8334941, -17348311}, {3053696, -3308889, -1659352, -23119850, 48903761, 20154609, -2016783, -1501822, -13598205, 15227395}, {-14027328, 14143977, -29622540, 5698529, -17797829, 8965460, 24478568, 10860023, 6255778, 1962558}}, + {{12838367, 21455368, 12394529, -139996, -13218318, 14835646, 2847962, 1094168, -61604547, 23469499}, {2855951, 6031460, 45288055, 3797286, -51243370, -15934874, 19639606, -31254818, 5495231, 5512993}, {-18991821, 9505719, 20743211, -7202131, -2855225, -2478301, 29885329, 978005, 31385863, 4697927}}, + {{35701794, -24267613, 17101414, 12014107, 4146841, -12963378, 27534917, -23554339, -7899590, 16246191}, {-9676560, -3481087, -6536306, -3008555, -54980755, -20435504, -34010965, 7211889, -37950560, -9244615}, {-32523039, -14841927, 10221226, 14841350, -10266079, -5102634, 23372907, -5705056, -19578232, -8060045}}, + {{-7658070, -19432232, -47290862, 8957403, 17168605, 906858, -36808100, -6985063, -31491665, -14371382}, {-58222020, 5666018, 2688918, -3396193, 5751191, 12826358, -8403380, -25463309, -5058029, -6124326}, {-19076639, -15036080, 2429930, -11958307, 12461663, 5994178, 10138261, 6269717, -12097369, 7547950}} + }, + { + {{-46501177, -2125548, -9548106, -8843125, -2923066, 17176878, -30171081, -16913256, -39048947, -305231}, {15266631, -24114366, 27253976, 7266039, -54091222, 3501254, 15435497, 3471258, -25936019, 8170263}, {26834881, -6062492, -28449840, 3483898, -31136580, -9544420, -1756407, -10450795, -21653034, -8003913}}, + {{-37125907, -18209626, 42135247, 3809737, -16359931, -20806125, 23739718, 21900517, -29352752, 10613960}, {1860629, -4579294, -9973737, 3344677, -38038503, 8441211, -30132174, -950057, 9038008, 8935044}, {5979120, 13663981, 19260467, 15739069, 27378585, 1446046, -21112071, -4946305, 22988438, 684503}}, + {{-2821514, 906697, 24154172, 9182143, 54560520, 7609207, 8431926, 929296, 61087790, 1230495}, {63944476, -4178687, -22626644, -9457701, -8623058, -15014277, -55330302, -22871710, 2432744, -19211541}, {20709859, 8567199, 2865684, 12071011, 32610891, 11210795, -13386246, 7474652, -27491454, 11439199}}, + {{40618909, 2429404, 12141943, 2539210, 30163754, -14208132, 1444025, -2768015, -8060932, -6270219}, {-19029653, 7452358, 36903839, -18229978, 29530390, -1487086, -38416541, -2255473, 28777554, 6458181}, {-24736275, 12395257, -27149879, -12163758, 27353740, 3047870, -497024, 8252410, -1861756, 8325048}}, + {{-36754971, 15524492, -47907677, -1948229, 60658959, 18598121, 18387763, 611185, -41792300, -3677476}, {16737065, 305526, -12219471, 23726739, -5881191, -9681727, -23718217, 214461, 17177818, 26128170}, {-2349448, -3006891, -16439659, -2783518, 31486676, 3252129, -10712863, 14938612, 14702113, 13672012}}, + {{-11078323, -11838290, 4031, -3913152, -43826065, 21341690, 2790193, 6092619, 20805703, -23233766}, {-315631, -16147466, 45991095, 18206444, -2723379, -2056742, -41115611, 1257537, -37773205, -2067726}, {-12946980, 8349042, -2453180, 6392083, -23278159, 1324510, -6586009, -15419707, -4698574, 7511985}}, + {{-16694705, -11719309, 19858215, 4865671, -32480902, -8813778, 872249, 2334335, 14288878, 7189027}, {29113853, -18272411, 20500473, 18454115, 8794268, 19465256, -61828077, 730165, -45433566, 10039083}, {-27484780, -14872853, -23616577, 14291991, 23179101, 2019501, -19966087, 10999600, 32749372, 9970115}}, + {{3120511, 12269787, -3001538, 13290995, -1128459, -3481406, -6308853, 26046984, -5928423, -17110672}, {41139613, 13355719, 19291380, 3565697, 12270911, -17843794, 4235029, 6593636, -11185463, 6773264}, {5410979, -15251835, 21503951, -7887542, 2977573, -1161386, -3124857, 4720118, 11858001, 15384199}} + }, + { + {{25842592, 14593617, -19437269, -26592244, -6163586, 5373095, 17971662, -4789035, -16745698, 7068030}, {33768684, -8167397, -37168547, 63420, -44920202, 1433361, -23680212, -25269253, 19830680, -5240624}, {30461964, -5231669, -22849638, -14765530, -15189444, -16503368, 23230047, -14909056, -31679936, 644866}}, + {{8273882, 1137072, -17194898, -5578430, 26342019, -1090966, 16911388, 20207695, -3899499, -4290289}, {16643296, -31529108, -34850220, 12143484, -34461267, -3952664, -48204260, -7940513, -62326311, 23363653}, {7823844, 1044908, 9499386, -14637325, 31335916, 5619583, -23107982, 15533932, -14375910, -2155920}}, + {{24044439, 1439152, -58692596, -23133087, -41434693, 10688871, -45479206, 23405942, -12616434, -31798408}, {18159805, -13294066, -7075670, -5315801, 23470783, -14882841, 15090878, -5998356, 27399272, -77364}, {28684746, 5552489, 13110666, -9360878, 23897373, 4785350, 12631889, 10803881, 32275034, -6016527}}, + {{29274470, 10290674, -26252361, 27218709, -37048082, 1396228, 20172216, -15922336, 27285750, -26395538}, {-25287388, -15964396, 30064587, 3443053, -21460268, -14306662, -22954362, -3355594, 20342682, 419844}, {10786511, 8716378, -6325750, 2073134, 6445759, 6261624, 11360770, 2552677, -25621162, 12562267}}, + {{2387080, -11104386, -9798463, -22862391, -24757118, 2688514, 10978011, -9250992, -24706257, -30298702}, {13626152, 2590112, -19831931, 10156093, 8267612, -19284278, 10914457, -4827762, -7259217, 166518}, {18404147, -5172921, -10162167, 7964586, -29616364, -16556923, 14188521, -923817, -26394286, -11217322}}, + {{34295166, 5743559, -18395630, 7469162, -18857391, -2645298, 13980834, -26188707, 48951990, -5380091}, {-29630942, -26496615, 16671040, 3774880, 4578729, 27792736, -21803778, 6028099, -8320440, -1343449}, {-29007999, 2822961, -27850650, -6358270, -29504994, 14776822, -29783422, 5491385, -15122731, 16026941}}, + {{10454926, -14968006, -44739754, -11474677, -11318865, -6949916, -45687944, 22700739, 24453662, 19521493}, {14002326, 9863826, 15089352, -10779243, -10222377, 20896362, 13052866, -5438783, -10231186, 11334689}, {7410930, -14482625, -32716468, 8084678, -17291177, 4078433, -33186515, -8317799, 13550674, -3892341}}, + {{-35242978, 19954316, 54932693, 4828405, -43760401, 6985755, -845447, 23447781, 787324, 11746620}, {-11704610, -1037314, -849121, -5947239, 172063, 20938781, 19758853, -5602025, 56372880, 17452406}, {197997, -9955048, 23504559, 505454, -27257424, 6982508, 2410414, -6548151, -2163243, 9901807}} + } + }; + const precomp_data_t c_point_H_minus_G_precomp_data = { + { + {{-6101338, -6661723, 52466201, -2210993, 16947924, -6747813, -24932024, 17916559, -16983562, 8042810}, {-54955706, 22617141, 2814423, -28338455, 23705580, 7914563, -29397226, 7209197, -5399064, 7366774}, {2312352, -11391293, 18244857, 11704705, 3971365, 12980627, 17392726, 783360, 8460342, 15646137}}, + {{-20239555, 16082865, -5854372, 22689119, -7684622, 12313183, -12275638, -18070683, 4693680, -11046235}, {-17340869, -13616255, -5868684, -10034569, -15191572, 20137865, -20432096, 5217101, -29198262, -17197667}, {-13685239, 4994663, 25885257, 9060606, -4861059, -14098338, -30355925, 425817, 1219864, 5667302}}, + {{5991822, -22900537, -6527229, 23208262, -126517, 17458959, -22547298, -22409515, -40843093, 17103489}, {-16401884, -9000615, -32108929, 8000482, -36348053, 15767611, -33755660, 2466271, 19524833, -13710855}, {4596153, 864108, -26663913, -659755, 21662553, 1137542, 28544394, 11343556, -19996170, 9764152}}, + {{41479917, 6952184, -13202757, 6711746, 17108574, 7914425, 4831608, 3294066, 31787017, 16696458}, {-9912859, -21873314, 15974497, 17625586, 20721458, 25328353, -19083950, -29020540, -13141149, 1810816}, {23468401, 5254789, 29322678, -9793262, 27357687, 2411445, -31933501, 10461585, 16938452, 1175935}}, + {{24829240, -3415607, -11553057, 8637555, -21727752, 3944011, -21512010, 24623326, 2106329, 7397722}, {23165968, -18826827, -10267919, 23330437, 39673374, 25743475, -21908638, -8641762, 15992797, -23513728}, {-33263330, 4348463, -16739005, -12021537, 29127092, 15733434, -13569724, 9201179, -25105627, -8061119}}, + {{27567445, 25874627, 55288586, -17029271, 12554428, -16506064, -15001211, -12229245, 16957695, 4743941}, {-30012489, 1952641, -8591164, 4574331, -28105692, -11347574, 17638339, -15628181, -29278721, -25796869}, {28622941, -15482155, 16373432, -5796090, 31354806, 13291649, 11974248, 8564048, -2391125, -2058564}}, + {{-39990477, 28902297, 37601462, -15831416, 48058401, -17625888, 20067627, 4398, 1948666, 14493563}, {-9409557, -105773, -2776738, 4745850, -13838289, 10991370, -7785533, 15894196, -28376356, -8844791}, {5139613, -14511542, -16274525, -11962880, 22127615, -2586245, 25435983, 10515753, -31880884, 6339475}}, + {{-18563230, 820202, -160035, -474925, 185300, 26736048, 10555513, 3119407, -35591431, -17474400}, {27715556, -25786876, -53868953, -10536111, 40312998, -5838076, 16098811, -4768381, 24066977, -13251714}, {-14742388, -9988774, 28760055, -1137973, -17423163, 2820556, 13462902, -15063755, 2365930, 10207166}} + }, + { + {{-22120743, 8214777, -16537524, -13170506, -30367655, -3804888, 14277082, -7655723, -29891106, -3073435}, {9645547, -23046469, 45032692, -7413748, 25238101, 18015860, 23375640, 3930457, -14721544, -13063069}, {8892071, 10874043, 26183267, 11572119, -19978778, -6189764, 11165268, -13836282, 28945919, 12576697}}, + {{-43713126, 10624462, 2244625, -5556759, 25677104, -4558855, 15921880, -2953411, -10126390, -15025580}, {21154744, -8623864, 34292103, -3947205, 14634966, 9802863, 1030798, -21831087, -45813164, -6575692}, {-15858732, 13244353, -9311750, -16777004, -24476168, 6533093, -14726264, -1857811, -30842811, 14092289}}, + {{-20741142, -13333832, 27103343, 133627, 37750992, -3004882, 38886057, -29382432, 1034177, 11512600}, {-24347748, 3329888, 8876127, -22219603, -27419014, 25634800, 7617255, 2189800, 51893749, -5986452}, {-28491424, -15032272, 17877437, -14849685, 24733680, 12923188, -19810832, 15978551, 10922438, -7062212}}, + {{-26640111, -178237, -35738854, 21282776, -5490584, 25289123, -6794212, -26318179, -34919902, -11673855}, {-18238855, -20673019, 22503232, 4914042, 1855146, -6596791, -16049626, 851155, -21473438, 7239795}, {-13957512, -10845007, -9344893, 3930543, -27685800, 6937443, -23691600, -4918076, 32589247, 6455341}}, + {{16526111, -6392092, 1708620, 3103013, -10506175, -15044426, -3405340, 3390661, 9295024, 2063528}, {-49932405, 13823922, 23742874, 8829607, 14400923, -9972258, -41905254, 9219263, -35315460, 3521880}, {6238471, -10947822, -24612275, -3062096, -574262, 16197161, 18544232, 16526487, 6451418, 11587300}}, + {{-50698541, -6087676, -27232443, -12883517, 23198182, -4733605, 31122254, 7534375, 17334832, -2172862}, {2652287, -6328240, -16488621, 4399119, 35828600, -13855299, -6507372, 19854551, -11675082, 2715146}, {1779170, -11057330, -17013399, 10794427, -29670278, 5041182, 4162604, 4819058, -5876700, 5891788}}, + {{-20128844, 12960738, -26095675, 8724256, -21288208, 9502783, 29514068, -7023482, 8760189, -21777967}, {10315580, 7944400, 6193735, -2872928, -14712394, 16709417, -33625212, 16370780, 783701, -1285117}, {-14308805, 2475807, 21851135, -5618028, 14019294, -1367027, 29930296, -7504524, -22810989, -1325662}}, + {{3034705, -379052, 27627388, -29829746, 53617870, 8781049, 4100868, -3891310, 18918766, -1184752}, {34079955, -25432848, -24804370, -1454352, 4794280, -12552821, -27137072, 24569148, -21636950, 1993120}, {-3631411, -7915777, 6881202, 13646543, -17280490, -15203821, 6059144, -3096132, -7623624, -1486531}} + }, + { + {{-30794706, 4193518, -3100471, 16293049, -44803351, -14138044, -6883710, -13589283, -2137231, -22048690}, {-10704982, 3112646, -49264641, -12320505, -8473927, -7380064, -54108640, -4496501, 22032607, -7023850}, {32205918, -1999462, -31763801, -6635700, 1471421, -4013239, 11109037, 4381075, -30055289, 1647751}}, + {{963806, -129029, 24200205, 6647995, -9310093, 14434334, 21033793, 14209113, -8941803, 13304238}, {-42256054, -21328797, -1079861, 20566913, 54126569, -2594292, 15916909, -3625267, -24490541, -10323520}, {20035969, -10243999, -361060, 10756081, 3708164, -3820680, -24684404, 15141043, 6122086, 11727407}}, + {{-20761434, 20468957, 19441516, -4801237, -13285554, -2855042, 20509510, -8317203, -2231314, 14226324}, {3230036, 4083709, -20861872, 22688277, 26776420, -22898826, -16397120, -16389131, -16327352, 9745498}, {23055320, -1015854, -22173868, 11817687, 3875936, -5554632, 10818006, 11975513, -30064607, 5602738}}, + {{-3797584, 2143396, 41373422, 10088770, -4323111, -8006060, -28733171, 31937202, -15515802, -19245910}, {-18084114, -21375490, 21067414, 21399088, 41438069, 16598512, -10735599, 624980, 43989634, -8186604}, {19265941, -11752947, 13008137, -440499, -28197295, -8194060, -8167619, -5402200, -9371860, -1511455}}, + {{20014993, 3036485, -2411032, 5201030, 15452009, -11532833, -3762505, -8116517, 14198543, -9759075}, {33803163, -12092281, 51716774, 12265996, -6263457, 13381537, -57412117, -15468831, 17489717, 13992345}, {-7050586, -13229311, -14053896, -2607878, -30391729, 4333136, 20018106, 5769504, 16075790, -2822102}}, + {{-52894114, -15629487, -46141433, -6403030, -42466534, -25929688, 40568651, 4319114, 3029340, -1641405}, {-1351028, -1895103, -5958939, 9371256, 12742380, -7016350, -3107701, 22045356, 60038268, -15536511}, {-3641558, -15695305, 17320295, -8496472, 27104650, 633886, -16487319, 4002986, 29368940, 14253059}}, + {{-25329185, 6803809, 4972840, 27875024, -12209055, 9576734, 14785991, 21810088, 9438919, -18962595}, {19468239, -6004183, -20351276, -2692078, 33748531, 18594702, 31208815, 7746930, -25008727, -13861261}, {26935831, -9007108, 20829108, 10561049, 2588905, 5176098, 30880933, -10060792, 22768114, 2121024}}, + {{39565998, 849850, 7902098, -10429778, 55170890, 727178, 6039426, -13823556, -12125552, -1422093}, {-27479186, -3738654, -19540892, 8121694, -7717904, 26193154, -31340900, 12424846, -40892244, 2374969}, {10378627, 4280903, -20059863, 10785942, -3881646, -1484235, -11088665, -14432213, -9713771, 4940833}} + }, + { + {{1321341, 7822682, 30129669, 15003251, -34242353, -3199130, -38699977, 15818464, -25668076, -17890301}, {21893467, -10495072, -11393613, -8011643, -24395793, -8315754, -24636887, 2020314, 38141242, 11640697}, {537710, -985963, -20113460, 772213, -17074876, 6579162, -29261232, -277742, -13691266, 16596486}}, + {{-6575860, -11322994, 16005315, 25640240, -38363617, 12480731, -16895113, 6663001, 31273057, 26261951}, {-35662360, 21760402, 9794695, -5673532, -15607703, 14029503, -12256697, 18025009, -15179731, -2020021}, {16240855, 9341981, -22062926, 1032788, 32459121, -1346271, -5024171, 848026, 31529680, 14449571}}, + {{23589167, -3082355, -4158355, 25692800, -5440287, 14910648, -39128857, 8743929, 18404903, -1271302}, {-39982651, 7808109, 42406191, 204492, -56770365, 17067524, 16864465, 24295675, 7470461, -2966368}, {-769302, -10524785, -22960090, -3059387, 20456220, 2995609, -31691673, 12811332, -25375538, -6866131}}, + {{-5479409, 7184848, -61386185, -27165755, 12508891, -800753, -28294762, 2001146, -42658474, 15583920}, {10278091, 16087604, 3504711, 2627493, -30529291, 1044625, -20264556, -277244, 15718644, -14245200}, {-23585994, -5170531, 13605139, -6824381, -31877964, -14467529, 20989739, -1962312, -20651386, -4810754}}, + {{1663747, -10381012, 7061354, -2926878, 16643780, -13303228, -21701068, -5385587, -1005304, 2270822}, {9694317, -11897358, 16694536, -16421760, -22993144, 18408490, 29670560, -20192631, 23823048, -19855070}, {23765827, -2140427, 16895410, -10593501, 21772748, 1266351, 9253368, -7750571, 10654946, -11719271}}, + {{-5229250, -26563297, -19240791, 23303806, -18607470, 4765156, 22256589, -21365648, 19967362, 6617878}, {29082160, 4783087, -36336837, 8269700, -15340274, 25786716, -12018871, -10424922, -39427114, 16449334}, {-18458034, -13537141, 19169152, -13127868, 16016807, 940859, 4939512, -15032988, -26006392, -3762429}}, + {{-15120130, -7906905, -27001641, -8478349, 20297117, -9569850, -36779926, -7254406, 31942900, -976659}, {-25257406, 12042933, -37406413, 4868777, -6799057, -11952414, 26178830, -6802520, -11400198, 15407065}, {29101999, -16768541, -3466200, -3200415, -28041044, -5939374, -20439036, 8961453, 22139600, 2515024}}, + {{-13170662, -3120571, -30040295, 19550841, 20687868, -25764859, -7537027, 1396706, 10954150, -4426632}, {-26476568, -28220503, 30554065, -9938631, -25055028, 5360813, -36499451, -21577222, 2956918, -18505338}, {-31586365, 4019163, 20171651, 16446367, 6564339, 7881865, 17166893, -6973576, -8741426, 15217631}} + }, + { + {{37724191, 2128753, 40127511, -8621902, -11394166, -9978726, 23322676, -4342525, 24708417, 4155493}, {7564583, -28658637, -24011221, 11812306, -13125602, 807260, 25677764, 10254029, 34021623, -27174203}, {23158489, -14256612, 7239011, 13353059, 12116206, 7147839, 21636686, -7629531, 934063, -6360107}}, + {{15947591, 11065498, 47165515, -10874162, 4263318, -9309466, -10147489, -12632364, 12907733, 4889582}, {36916327, -22280792, 4329529, 22133766, -57566424, 21473618, -25502043, 5592570, 34395511, 20213400}, {32534470, 4744775, 13893135, 14635756, -8593258, -6280686, 19835917, 956060, -26940546, 3268553}}, + {{-14834121, 21275574, -27307203, 18073803, 33679433, -10892766, 16360541, -16737284, 21425539, -14175139}, {-38126757, -541986, 30356987, -10054699, 21323519, -5830432, 21313753, -6311744, 10248145, 8132563}, {-5708334, 9104274, 31813558, 7785104, -18336653, 6878670, 17404302, -5911886, -459625, -3610891}}, + {{20386923, -15677149, -12200355, -12784041, 47888652, -29759045, -7999005, 28411685, 29882388, 10794353}, {15693305, 7201225, 42110843, 20650073, -12074238, -369965, 27791119, -1255461, -8839378, 19477021}, {-1560321, -16752443, 19288819, 12537089, -9300441, 10089807, 16528900, -8449695, 6522695, -6565250}}, + {{3123481, -7047683, -34225299, -207468, -47673061, 3799009, -46924314, 2435848, -15840276, -16602601}, {-28759085, 12257437, -16055881, -28804748, 18334973, 28629045, 1515542, -22654612, -46605844, 11625777}, {-9916527, 10074067, 22878367, -4934849, 6894510, -15343499, 10761228, -15484688, 24914775, -9765601}}, + {{18494000, 27335693, -15198265, 13456320, -54433815, 19359117, 24303592, -2866310, 6218073, -2795545}, {-44583996, 3666011, 16986825, -17177156, 7779961, 2983503, -7723854, 18341634, 54958497, -17011269}, {-3049511, -3192827, 3697038, -15732998, 18333717, 14801153, 8967530, 307604, -28163105, 2934167}}, + {{21281758, -15806243, -14063749, -6126978, -2980791, 12388256, 58512170, 6028561, 37380758, 19708289}, {-17516074, 10109337, 33917323, -4860180, 11309595, 3509268, -5216114, -14479775, -9112088, 1307621}, {-28602911, -12769632, -9927277, 5377764, -18663180, -5109576, -2879888, 13866478, -2134299, -9309278}}, + {{-27219617, -8386696, -1756998, 11339489, -26522536, -491182, -52012366, -8811791, -231732, 10704184}, {18924945, 16353718, 24735484, 508745, -38110110, 32940662, 7594046, -8852717, -118966, 9806590}, {33106709, -14738830, -29721239, -10755676, 30395984, 6505380, 2577250, 7670846, -32171920, 13080748}} + }, + { + {{40538795, -4216279, -34572866, 7346784, -58158763, 3931894, -42144891, 13283221, 17300235, -6571408}, {-2489815, 28162463, 27387040, 22105246, -2372369, 10646282, -3434155, -18142427, 28619093, 21422272}, {-25111500, 3173572, -30905814, -10495414, 11698025, -13016057, 18734520, -802179, -7251386, 2117515}}, + {{42079065, 22103740, 11599837, -24909164, -3892297, 8461553, 44682053, 22776278, 4892668, 10481772}, {-15902141, -3914706, -16818939, -3786126, 46346375, 126419, -15906359, -6596048, 45009884, -5225704}, {22832941, 6653227, -23548897, 7600611, -22883790, 15730731, 11385385, 3236069, 14005890, -4631081}}, + {{-34671908, 2394114, -21140842, 4364765, -18714643, 14159622, -3566512, 8157898, 18324055, 22295943}, {-21201954, 12073618, 4148242, 19378675, -16364813, -2800964, -13005626, -8243080, 36311749, -9226055}, {-24556325, 12868514, -1657543, 1092057, -8011455, -2096939, 22210132, 12091612, -22782604, -10109916}}, + {{-28147016, 6703441, 3973677, -9623541, -16382462, 1667979, 3322106, 5854035, 36512345, -5400534}, {-443898, 21627577, 17566599, 18783545, 12847094, 14035793, 2960664, 13020009, -11549121, 2861778}, {-4522181, 11882774, 8475789, -14118257, -25417618, 7582031, 10885084, 15307303, 6828798, -9938396}}, + {{1291838, -30757626, 2745849, -12233840, 9638012, -16205526, -3794322, 22529482, 34743255, 20697921}, {7323886, -2031622, 1226007, 17838176, 8785098, 6351908, -34562784, -9215646, -19342019, 1557175}, {32667632, 7899099, 23830378, 2738684, -4038286, 3083299, -6230727, 14227100, -16910821, 11170159}}, + {{-50674843, 9630416, 21490359, -8922849, 22746412, -9227086, -4045943, 13530732, 2821767, -5361895}, {-1520365, -20515430, -12784209, -22859873, 14610844, -10143662, -44108161, 19218786, 55375617, 6555865}, {-12546186, 11588292, -21884389, 10163443, -25738849, 10366640, -776566, 12205382, 4642095, -972485}}, + {{-34675374, -269954, -25203603, -3175750, -39262251, 14563508, -40309164, -10560664, 46998209, -7880691}, {-23607712, -21981252, 37820109, -25583106, 26421879, 13459474, 16102520, 17199398, -11204903, -7709979}, {-33344548, -10610181, -32338187, 4502935, -21293101, -2739559, 31631278, 724711, 2055601, 15508788}}, + {{28807944, 23468451, 15536506, 4408442, -26621895, -23509414, 29527667, 9871672, 30198537, 1267620}, {-25869962, -5004855, -4272376, -10698046, -21064195, -7358662, -3226745, -722504, -11481489, -25363828}, {21625714, -909969, -14009617, 3749410, -8687689, 16017672, -27521046, -546939, 13129805, 5674757}} + }, + { + {{-20183821, 19532978, -32191009, -6156540, -37202121, -21409439, 44374168, 455503, -29190069, 5436715}, {-19993685, -237584, 4391783, 6025922, -12686313, -6184127, 12209294, -19390657, -37189161, -18447813}, {30056282, 9042644, -21846172, -947930, 13832123, -6723925, 24553441, -2250546, 31520440, 13124751}}, + {{54012931, 8747996, -7042666, 23882753, 21689448, -21244501, 9683790, -6643746, 26475259, -20112532}, {-9080279, 4590244, 58648868, 7181005, 12444242, -1045169, -6357594, -8370376, -29050935, -13160086}, {-23220929, 8551641, -18344564, -10860643, 5166534, 15227920, -14311635, 9346907, -27745370, -4242627}}, + {{6030328, -14326048, -14395069, -18988503, 2510641, 6568118, 20085405, 18264092, -7901093, 1331527}, {48201032, -11355804, 39104275, -9330837, -53756247, -22282096, 10606201, -5617870, -48235113, -12073137}, {30730367, 16552973, 955166, 7614078, -11766958, -2987945, 109054, 13883679, -4820682, 3232770}}, + {{35847261, 7893146, -4753404, 14715425, 5001162, -8483603, 9446375, 794052, -2238517, -19422030}, {-113825, -2023890, 47155862, -9008631, -33086870, -2992677, -55064941, -6656434, 56237155, 365374}, {-27132279, 6776707, 9606112, 12642639, -4958885, -2165454, 20090003, -12012175, 26849783, 9369239}}, + {{24498148, -68029, 32314769, 21871950, -1778691, 25867830, -38784775, -9779251, -37100537, -18380968}, {-26574082, -5857179, 11612663, 11177058, 16265295, -1980800, -24693427, -13974811, -9090895, 15015066}, {-12646670, -13544908, 14736317, -10408651, 29354900, 7546326, -5056778, -12160712, 14219988, 12020647}}, + {{2078977, 7756535, -2094336, 22250581, 38264716, 18702332, 35507824, -9746461, -45640296, -16787975}, {-63395, -15724695, 4917594, -7096055, -12544212, 12643738, 2129126, -1762963, -9689822, -13903891}, {12226091, -3745837, -24449171, 7138866, 10310764, 3478407, 24968873, 74508, -5893517, -8182326}}, + {{2474386, 19137005, 517900, -22293688, -35515458, -20683174, -10953486, -11862798, -13592164, 14998659}, {33158240, 5485931, -57096662, -5830178, -1484168, -6321034, 24526860, 1853740, 1713002, 781495}, {22150625, 16448009, 15541097, 13740537, -26397610, -2097295, -16644217, 14340770, 14497042, -1793232}}, + {{-20654129, -14872657, 45958603, 2546808, -1633955, -13389878, 4656838, 20420007, 46019738, 4764726}, {-2383585, -5472081, -4199067, -7444262, 16241707, 15511626, -41611650, -5660155, -20669084, 5701238}, {-957032, 14983808, 18341670, 14859549, 5760984, -11884467, -17939351, 10825550, 32732196, 9180328}} + }, + { + {{-15671227, 12842223, -46578346, 179553, -13722203, -4848162, 13283797, 17360002, 27616, -15380514}, {-45791795, -16228121, -17382166, -1905151, -44241699, 26894330, -7621401, -13387180, -51390268, -4641508}, {31574022, -951629, -10106442, -16591659, -14640758, -8789942, -16159450, -4494554, -10869913, 16717839}}, + {{36519535, -2061677, -3680068, -13614447, -7774275, 4403594, -53468676, -3096111, 30419643, 245891}, {-10761735, 26264941, 60870546, -5407247, -46979489, -1044766, 9445600, 8396857, -23854355, -10365889}, {21023294, 9978609, 6499153, -4862005, -8176891, 12085401, -10516889, -11285832, -606036, -2449999}}, + {{12479823, 2351623, 9251973, 2307144, -50997327, 9589083, 34956101, -17432615, 14290551, -25154724}, {14448917, -13177279, 53903265, 29505116, -1425903, 12157093, -1470743, -6334861, 42959535, -2396850}, {31161346, 10595307, -28610140, -848835, 10531704, -16436132, 22736169, 16667233, 20472468, 6175809}}, + {{-3147237, -9296413, -21260341, 12281885, 21515855, -14017069, -33563970, 3418846, 635705, 22095990}, {10546539, -16537939, 7724965, 4504747, -24072385, 7829417, -16843652, -5095778, 50390213, -2611288}, {-3980401, -8112514, -5173618, -10517685, -17223841, -5724252, -6688177, -6063807, 11816545, 16288045}}, + {{-15789337, 2788875, 40358750, -19893926, 1194945, 3868426, -41524624, 1897471, 15690471, -23343573}, {17397455, -25043369, 26080578, -1347894, 4544451, 17379882, -18410134, 18216929, 27018093, 1504693}, {-33377072, 14930193, -18958152, 146826, -3960760, -15963346, 7278738, 1221107, -15122463, -6044983}}, + {{21672262, -9863187, 33742395, -1311619, 11369404, 813149, 13860947, 8295531, 32642558, 13345380}, {-20280992, -9025217, 19703555, 15780543, 16216708, -13027053, -23028721, -9418037, 9617648, 11679344}, {28380250, 3967585, 16535461, 13619847, -4389541, -10046677, 23115554, -8322993, 9737103, 5407274}}, + {{-9582309, -3601605, 30404757, -13579377, -1385789, -3926919, 5824215, 20646794, -11241092, -14480467}, {33388693, 3833459, -8958705, 14331131, -60715931, -6494861, -37357921, -11047264, -9884794, -8874553}, {15135988, -10980931, -13349750, 11547314, 15189829, -9394623, 17645388, 2563198, -19348674, -12491350}}, + {{-52019408, -757959, 4357729, 14467913, -43421269, 18530286, -14445533, 15404627, 3559916, 1362776}, {-5145972, 23176057, 27491243, -5439415, 16179451, -6360704, 13700485, 8397943, -57288586, 11684958}, {17503686, 2541735, -23937769, 7155589, -15084486, -15742750, -16592, -265052, 26699193, 11820699}} + }, + { + {{-7344556, 14568660, -9287434, 8931746, -36763984, 23570463, -37008013, 1116413, 40616431, -94720}, {31610102, 4522094, -33374130, 13379140, 7360328, 7338337, 13607859, 29459031, -10585567, -28763936}, {-28270377, -14406710, -24751012, 3128366, -21126881, -9520388, -4374494, -10754448, -18452083, -11693577}}, + {{15394067, 1825726, -8734562, 12191035, -27304026, 12212917, 14551275, -1532335, -27285732, 25314605}, {-27910433, 10570206, -8709850, 14720953, 21963748, 11343969, 47180677, -7603861, 7933956, 5498311}, {28006027, -16151472, 13521442, 13243177, -529806, -16475123, -15274578, -8403326, -535931, -12600370}}, + {{-21625743, -26815416, 59945131, -3335279, -36794607, 16945693, -26388970, 8418032, -2776502, 21711883}, {7139017, 2567070, -6626235, 25992455, -16239273, -1402175, -2337384, 4391236, 13103206, -3416433}, {2462485, -8606454, 19628903, 6490117, -22774658, 6624825, -17127006, -3650734, 20524392, -3437325}}, + {{-53429272, 13875079, 26093790, 29354958, -11789948, -22938565, 19035002, -22915758, -8059486, -17995383}, {-6902074, -2129399, -36254496, -751884, 47716622, -9107675, 18577148, -1841492, 37832574, -11639429}, {25887122, -5820371, -23646576, -16091471, 23431591, 4391114, -27719401, 15537084, -19873079, -8508401}}, + {{-2317688, 7924430, -16990939, -2473366, -17981926, -9922110, -13416919, -1601779, 42558120, -26549126}, {-16199864, 8765112, 12953133, -4665338, -16355488, 21605980, -5709959, -1409723, -8933390, 1204012}, {28135877, 9205068, -24000920, 931630, -19560795, -739988, 5927878, -7368152, -15649425, 11646223}}, + {{9257311, 17876361, 28774520, 13645993, 28074009, 15984758, -61648790, 8268728, 42992812, -11630774}, {-45990987, -14354733, -20188398, 17827247, 1818379, 11194828, 3382554, -20347218, 18368342, 20135378}, {-2793074, -4852944, -26600001, -12448385, -33484513, 2696115, -27189303, 6765467, 23538784, 4165256}}, + {{7287098, -12926256, -45342968, 9718509, -10185494, -15236620, -10750624, -5972283, 21150789, 22474196}, {-29246526, -3192908, 3664230, 22597429, -46513944, -12414458, -28147984, 6283953, -24048835, 4227258}, {8360069, 16338978, 22519826, -260286, 6100160, -2406678, 21978122, -11580253, -7658037, 12005667}}, + {{-26068061, -2523003, -9439380, -17189516, 30990991, -8802709, -3578935, 4770212, 19147364, -17664828}, {19772521, 15129153, -15759600, -3497000, -21374223, -22095889, 28312339, 25466624, -65908, 12595568}, {-1122238, 2770614, -7412651, -12281534, -16654926, -1670658, 18067237, -13464010, -1833292, -7183382}} + }, + { + {{31381525, 7369560, 1973649, 7307845, 21541450, 16162690, -16259507, 9534176, -7691517, -14805525}, {8394915, 15348212, 48565281, 9225407, -38629408, 13209262, 16333445, 20342002, 46261201, 3539707}, {-18539019, 2106577, 9288885, 3325718, -263466, -14448806, -27788587, 4671734, -11848226, -8886225}}, + {{-300067, 22970948, -13975962, -5728090, 5140208, 9652038, 5155759, -21573460, 23663092, 2652448}, {35841085, 4407610, 33081538, -22133262, -28467234, -8281880, 44469699, -4934818, 30104160, -9208820}, {-19698986, 1335808, -21417594, 811874, -12814240, 16506262, 5879011, -311305, -18960987, 16364484}}, + {{-30111230, -7222663, -14683557, -17378652, 45350896, 7665112, -3057012, -5726529, 41332385, -16361164}, {-16070448, 14077903, -36081801, -12728696, 11713258, 24161708, -36999146, 7201523, 25424681, -10984438}, {-21882237, 13033240, -6629172, -7946221, 27705890, -2499569, 30322965, -10223164, -8591208, -2635625}}, + {{-52514684, 4053331, 4713098, -2944649, -29552992, 25610776, 25689684, -772588, -20956868, -4226923}, {1785260, 1400139, -33552198, 27751923, -7718692, -2472450, 10232018, 3864406, -34956572, -28898285}, {30136313, -3170020, -5895703, -4034764, -19409224, 13548140, 29154246, -7502233, 4297010, -12426185}}, + {{37285856, 6620401, 33032219, 12520925, -16731830, 18030763, -48730100, -15385640, 13422210, -30695821}, {-24896606, -2337679, 1514039, 10809135, -49006636, 3715431, -4467266, -59684, -38931554, 178377}, {30579906, -2804849, -14021137, 4914833, 19829198, -16417336, -14022916, 7709701, 10019045, 1326128}}, + {{15573024, 22077344, 40657518, 17428306, -32837137, -12312428, -1352150, -24427651, 13171649, 22861580}, {40345416, 10245140, -21686088, -11631184, -15294725, -6993572, 37932074, -5394379, -22015921, 2937354}, {12285896, 10015721, 11181068, -16075205, 25435143, -4993092, -7906923, -4104819, -33088426, 6911007}}, + {{-14288714, 24611891, -9318638, 18425515, -29551975, 32061897, 44501306, 9986976, -53007122, 16841307}, {-26203570, -209751, 55784778, -13989061, -24066219, 698831, 10463736, 12671504, 13180164, 5765713}, {14584465, -6840259, -20336593, -16089054, 14531784, -7914842, 7285215, 8297456, -499589, 12702118}}, + {{48080161, 8499401, 21375945, -5062693, 49962757, -8138420, -45926519, 11270415, 53591414, -8152215}, {8808527, 7201917, -22829747, 20035413, 16031651, -13250504, 2608313, 3594091, -9411994, -13650797}, {-21057039, 12514712, 24066971, -9909449, -23147245, -309497, 10289333, 16455742, -26715169, -12780043}} + }, + { + {{50850482, 2749855, 24073715, -23935977, 22552105, 4110591, 9903456, -18616850, 36277032, -21602916}, {-6475044, -5027387, -14000411, -4740205, -28020029, -10063133, -38361248, 3542210, 29120388, -7631060}, {130434, -9901027, 22113620, -5656710, -17048528, 4560621, -22498012, -4195487, 23698948, -530703}}, + {{-217036, -20099660, 8883879, -7740627, -28471174, -5096333, -24104800, -9237006, -23600083, 22889535}, {-40280378, -6603470, -7992535, 24243861, -17282752, -23756609, 25944016, -18416066, 210447, 4087533}, {546356, 4369567, 19111426, -13494740, -4310689, -2262866, 15867136, -4508329, -26759003, -872130}}, + {{-47143961, -2830753, -52476752, 4310356, 30932359, 26924585, -15333652, -1324616, -56713655, -5371453}, {15704297, 25068011, -10255402, -10403192, 32876973, 3434419, 31806200, 15557734, 8574335, -3041719}, {-30670366, -14649251, 20100519, -9873163, 13151223, -9463920, -19375915, 2292491, 18335487, 10612683}}, + {{4323708, 4632738, 34150237, -16521458, 35976929, 21966351, 43256286, 13665358, 47051586, -4020804}, {14793854, -27828124, -14220909, 3219190, 2870165, 8536493, -10242664, -6177318, 4770504, -3196018}, {32820291, 7385782, -191408, -2202015, -11385888, 9783485, -1357779, 4434160, 30737354, 5266517}}, + {{21255691, -722666, -43664660, 18487204, 8986992, -14480190, -8041651, -2496643, 22426536, -15482301}, {11038069, 25055488, 4226810, -4601668, 6350444, -5476734, -11004769, -114427, 9861282, -108863}, {-24293464, -8648141, 24285522, 8481277, -9855532, -16193435, -8778236, -6573546, -24555327, 2174770}}, + {{44243230, -6236312, 3130865, 9438300, -20293736, -2626002, -31544808, 50105, -43328493, -6894090}, {-21737236, -1879554, 10124873, -20228092, -20172110, 27483514, -10380300, 32545017, 13580881, 7835806}, {22813744, -6818496, 25498943, 7689915, -32235693, 4414276, 3546736, -1725664, 20537352, -14812348}}, + {{-39681599, -13027117, -10085298, 13899170, 22032372, -8387711, 4766332, 2845365, -43365804, -2206284}, {-12589561, -4412273, -26724102, 15852826, -23580010, -14272341, -55526656, 14560509, -12132536, 18706252}, {-17897852, 1457829, 7072841, -3312722, -8507461, -6932282, -14939438, -2267674, 8711246, -8911855}}, + {{-22882335, 16065570, 14994245, 4113494, 2866064, -25543377, 11353097, 8199010, 24012927, 766219}, {24431873, 3238284, -11830995, 3913078, 11527904, 5966513, 44574273, 17620630, -28724833, 27837069}, {13967849, -15046043, 22345380, -12767227, -19259529, 562705, -19403118, -5046868, -9526521, -12715162}} + }, + { + {{-39820767, 6776276, -23668008, -12048052, 33609065, -4271605, 2060600, 26138553, 46769322, 7119129}, {-7207495, 25887498, -4805744, 3343738, -10732775, 10373369, -62019564, 1532137, -18743706, 25642887}, {25409378, 12250175, 2070113, -15020952, 474928, -11107280, 3951694, -9152751, 30073579, -11343063}}, + {{12864865, -6802072, -16611084, -7905641, 26913129, -841686, -16861889, -17634633, -29923863, -3123800}, {43292161, 17555728, 14252832, -11427467, -2566889, -21070308, -20426205, -3683745, 10655581, 23131590}, {-6358451, -13293247, -1425317, 3877821, 17813511, 4309397, 10356114, 13699815, -3351785, -14081265}}, + {{9494470, -22287009, -16712259, 28478462, -37773704, -14779305, -16205871, 22921864, 24377294, 14569588}, {-22203858, 3292119, -28484341, -1204402, -25954842, -14338483, -26518921, 8973086, 23667804, -12320432}, {-23941480, 11267256, -7644860, 632755, -6937570, 10295099, -24515263, -12663303, 9447263, 4961601}}, + {{34074416, -12441443, 38319594, -5871650, 8169086, -16138764, -19288698, 9660786, -3136994, 1547067}, {-23372406, -8293177, 25635912, -11062256, -36804170, 4734560, -13498420, 16285644, -480032, 23593399}, {-25746855, 2587547, 23911025, -14346287, -6941211, -15706289, -12706124, 1198596, -15390273, -7900426}}, + {{-7398424, 3142689, 6236726, 19442358, -44839758, 22168913, 16575104, -21333845, 14955261, -7555418}, {-23408832, -18436287, 12792808, -13392254, 20435778, 3155259, -22477364, -1959705, -35280187, 3465296}, {1996299, 2009172, 14565758, 696622, 2249076, 2795060, 23765683, 14231066, 16843298, -3201933}}, + {{12517148, 2287125, 4019448, 251157, 25236885, 26586196, 22961137, 718639, -582588, 2265158}, {-5576116, 10007877, -2944188, -5960161, 14164159, -3845760, -30841917, -22076311, -106000, 6564564}, {26669805, -12541152, -3624879, 5120978, -17172980, -204965, -27288057, -12136365, 7621505, 7173844}}, + {{57209026, 15513145, 45703935, -3162825, 37406001, 3236942, -33788732, 20283729, 13807754, -4389031}, {5575802, -9126945, -18116241, 145459, 16114841, -28337650, 18192264, 10717423, -51631662, -1930275}, {12584317, -2295278, -11269350, 7421592, -9640278, 7435192, -7066145, 15599928, -28484532, -3282382}}, + {{47342509, 19856909, 31371440, -3945729, 62974096, 341200, 47491687, -15411774, 16189419, 1211487}, {11395021, -4007771, -28185832, -21541697, 2385406, 29678930, 15977397, -15178308, 41897595, -5069595}, {-19095124, 2768029, -30762992, 14184730, 4233096, -3769464, -25037804, 14705020, 3123388, 14530603}} + }, + { + {{-18525889, 17138373, 29042158, 14137769, -17372829, 8654497, 52390884, -10433960, -8524586, -27839513}, {-48485845, -6370071, -499592, -8462583, -20009811, -4454575, -1825914, -2193120, 26866342, -4141309}, {9722368, -7121433, 31113300, -10284803, -28346927, -8148277, 28156781, 7580576, -7239971, 8622867}}, + {{-37796726, -5204955, 21783385, 21641843, -109558, -27410069, -23732531, -11221930, -9989085, -11735135}, {-10819190, -14862615, 44752859, -3411779, 26968106, -5634653, -6702499, 664572, -16397797, -12579957}, {24917068, -7486329, -32783494, 388898, -1012434, -12839893, 6079384, -8542826, -12345333, 7946207}}, + {{-21647665, 23918503, -21508182, 8414467, 60647236, 792838, -31138855, 11016774, 30310668, 19414142}, {38099859, 9578003, 12500248, -14104581, 678886, -27321002, 25065611, -16505548, -2524442, 12319632}, {30086556, 830841, -3358317, 5150139, 32597201, -489067, 19457685, 2719442, -18387484, -6667758}}, + {{56130959, 14898690, -3884690, -23629271, -33522977, 11207766, -22627471, -17254133, 5539868, 29474487}, {-2134591, 1523912, -3554418, -2470559, -25991329, 3404402, -40720875, 4981355, -26095872, 164157}, {-16900663, 12194516, -5332114, 10032737, -5429007, 5684677, -20476671, -5058578, -22125616, -14310862}}, + {{-1783533, 20400492, -41881650, 24761328, -29290244, 7662499, 45790533, -14338779, 17617045, 9779659}, {-50286451, -12611450, 4495760, -7731898, -2047468, -13955469, 3663473, 4510295, 17451555, 16334987}, {-8124186, -3801254, 32046426, 14151697, -5576546, 109242, 28637198, -8022098, -25183720, 13356933}}, + {{-4034800, 21558875, 22914988, 11119515, -24683763, -2007230, -17896643, -6273340, 12994036, 2473578}, {-32758292, -11274547, -5844754, 10869667, 12221695, -21759088, -46953217, -25055634, -19125682, -29674312}, {5071020, 3877017, -8645050, -9596892, 17263025, -7197522, -28704943, 13832685, -8783218, 6413660}}, + {{14144390, 19181808, -25704298, 26818159, 28848665, 9345515, 23970260, 7911173, -11353037, -1819621}, {22822046, 12307254, 32047164, 4696707, 32187419, -8583427, -3915416, 9062451, -35815657, 10093493}, {28464880, 15785048, 17661023, -4005670, -25551887, 984698, -12251310, 3503149, 33055808, 8060338}}, + {{-33743123, -2916767, -4379, -2587098, -9879202, 1022641, 10599020, -13383434, 31845933, -1837512}, {-6930475, -29735353, -36952499, 25194324, 3669988, -9961461, -7151658, -14326802, 16528629, 7236584}, {15103232, -2015950, 31257417, 14072555, 32869846, 12299958, -18292988, 1026559, 8551780, 1635000}} + }, + { + {{-31662976, 8958841, -14654458, -4179414, -41574230, -17679439, -18937210, -9610204, 8647177, 22011503}, {8885704, -5344821, -22485940, -11968268, -23079344, -3704621, 27181962, 1086904, 24405269, -4137449}, {15891365, 7452623, 10460008, -14008611, -266460, 1031555, -4620742, 13018479, -29201294, 13834416}}, + {{34471598, 15278043, 43919973, 22012852, 44816636, -17757645, 29986028, -8440898, 28581512, -9359487}, {22656740, -13792385, 8041091, -9350418, 12598278, -14896685, 24204856, 21347788, 24714666, 8519359}, {-9501718, -14336701, -22953382, 4400117, -32090846, -6362084, 7552182, 2235220, 2612341, -1820301}}, + {{-28775543, -4358039, 26807764, 14705257, -43000127, 13329433, -14303645, -6766772, -18470575, 18625427}, {-18036555, -348937, 35310924, 8459859, 6029535, 17259535, 47823333, -18629930, -2830345, -9364869}, {-30456145, 9479301, 16063119, -3370909, -29004960, 2016638, -11533095, 5777110, 24940508, 15280863}}, + {{17557595, 16083579, 38585583, 6793806, -16690589, -18051590, 882379, 11436116, -11309232, -9679360}, {22166143, -1178217, 330723, -20645864, 10976369, 10372194, -17151687, -20427418, -27861530, -16817682}, {13508061, -3174824, -465059, -14284813, 26466556, -8807977, 24491526, -11922839, -1405911, -4327734}}, + {{10139163, -1900884, -58914887, 17907544, 6518674, -4644578, 12948627, -31837537, 27319758, 4062509}, {55457011, 9349254, -5426693, 8587368, -11558266, 50292, 4305177, 139543, 26008046, -10992799}, {18958788, 14819383, 30575075, -11168986, 19810082, 1314669, -31027712, -6897778, 17679746, -12225249}}, + {{20904177, -22631243, 34134169, 24044631, 21939305, 10340658, -20372174, -2602514, -14710351, -5004948}, {-44045525, -4481633, 12289611, -8760145, 17164799, 5452614, -25951722, -10567854, -12082659, -2748718}, {-2560181, -634447, -13608293, -31388, -31725070, -11295361, -9247745, 11888155, -7337341, 11831017}}, + {{10846006, -18090141, -38379545, -7386916, 19596799, 6029769, -4847312, 6770113, -24390465, 4341473}, {-27678342, 11755, 20278643, 20214922, 5822615, 17803117, -47977414, 6644473, 37867431, -15775441}, {-25880155, 13349044, -11867884, -12824451, 3220859, 3596583, 8678256, 11812352, 26829290, 8220258}}, + {{-4340162, 9536647, -21668847, 7979419, 294226, -5459876, -31663424, 289354, 15833344, -11719981}, {-52759734, -21859245, 35454203, 11753087, -3256380, -24551532, 21661116, 14282500, -39409088, 12242465}, {4494438, -9546037, -31946858, -13353048, 8384942, 6460545, -28378633, -10482028, 31520164, -16283970}} + }, + { + {{1823626, 164039, 6461336, 7798609, -31273028, 13541331, 6207654, 2325763, 27140802, 12383711}, {-3433076, 15948061, 53497752, 25704201, -32864044, 15711411, 24952554, 28036443, -22568840, 16780115}, {7184659, -6564327, -6516411, 10789908, 21629741, 6009096, -8582179, 15524312, 7161881, 10617461}}, + {{-19502308, 4005235, -28153157, 9404004, -22140058, 2561562, -8534572, -16868024, -2188013, -26341007}, {-22696148, -27364095, -34314189, 213302, 13489404, 1233746, -36406152, -1494354, -11798213, 5207823}, {10323777, -3403827, -19007544, 1513525, -25811617, 10650396, -21173598, 14688881, -21549067, 16012913}}, + {{-7849997, -3366236, 15310319, -15467523, -19141525, 1007081, 2087036, -18421124, 24050989, 4131757}, {-45336901, -27615724, -7398301, 12294815, -41100077, -27611265, -24797666, 6379018, -37086247, -26999935}, {-17750002, 13613060, -303811, 16168062, -4262376, -11068231, -22720502, -1951968, -16556703, 13583126}}, + {{18977855, 21759944, 12487308, 4100649, -13508850, -28364085, -7367638, 563382, 19742486, -22962575}, {42314517, -7937334, 44436998, -14352745, 51513304, 411635, 7127746, 22808726, 3689770, -3232419}, {7548212, -15674536, -2333, 15170591, 24564996, 4235775, 14899168, -8303579, -6717422, -13727730}}, + {{28113017, 479317, 4022895, -15473220, -2559427, 6950201, 52750440, 13519017, 17913462, -10143116}, {18220929, -18962957, -5140271, -6298306, -16543649, -7602787, 3539696, 2138217, -22059040, -1624534}, {-26189272, -14347880, 8062736, -11695287, 1388463, 3799049, 12425595, 12539193, -11388745, 11608334}}, + {{-41286948, 4869802, -39742514, 23662890, 4062368, -3738095, 2846143, 2153062, 10111519, -1799906}, {-25438954, -22814338, 5396684, 7621518, 53849136, -23716835, 8822111, 26421232, -47364075, -9801690}, {32789462, -11214154, 10420674, -3654170, -25703630, -16154276, -10601462, 10408728, 8736892, -13060362}}, + {{22634572, -3107544, 9830354, -8547906, -6162562, 27363909, -28750596, 5920635, 6567069, -25142374}, {-4839114, -2466208, -12650650, 8077202, 3556502, -4239449, -12150974, 23786971, -37764563, 2459454}, {10144581, 5240153, -14451382, 5965429, 11618438, 841827, 15281025, -1348268, -31508007, -7995501}}, + {{24758741, 16354783, -7366128, -13977677, -6445335, -2694037, 254410, -12497025, 23561941, 10993724}, {-12995879, 9724549, 23918628, 12056021, -44750009, -14132229, 24725978, -19259725, 40201583, -20874418}, {-13201520, 4302453, -15939827, 11311839, 33154413, -15348448, 18697942, 891386, -26950337, 6785366}} + }, + { + {{-11424236, -6308055, -2275825, -7778527, -3527645, 16629222, 26709899, 331681, -16208657, -24883803}, {-6254122, -9612153, -32896023, -17385797, 16373931, -4765142, 19791235, -2187747, 38237465, 620345}, {25059852, -3850968, -23204090, 9059955, 28643675, -6569464, 9635436, -15128183, -11160954, 3833112}}, + {{-38003765, 6153252, -2842076, -9731111, 4421241, -12184984, -37757271, 14429182, 20386613, 2049315}, {9469019, 10706068, -2113554, -12475299, 53586019, -474094, -10157103, -13966460, -30540057, -11472015}, {2455870, -4742727, 31902303, -4627546, -3277979, 8688119, -5883910, 16714116, -88784, -4308453}}, + {{-24239643, -12299051, -38353083, 5411710, -12876002, -4391588, -19321210, 949852, 38956437, -7354473}, {-14624107, 21205915, 4382713, -8746628, -8631424, -2062476, 1479778, -23225268, 6459693, -18321013}, {12521862, 2066705, 25392497, -13277316, 32548320, -2441127, 28468780, 10330770, -15270601, -7288882}}, + {{-35199004, 7886915, 31121378, 20825492, 31522816, -7723892, -1023394, 7264499, 22636567, 9524415}, {23905240, 14503887, -21443014, -5863770, 14920894, -17871760, 8180294, -17509853, 14188797, 4486217}, {10756438, -3911038, 5537383, 8842117, -20625762, -8763378, 10005140, 5719136, 2810700, 13392372}}, + {{-27941545, 27103969, 41576616, 23137423, -27766909, -24058602, 18990635, -4882828, -10791117, 1418526}, {-27948077, 2508871, 18632218, 10190327, 31271101, 7920476, 19303613, -4164096, -50561487, 6334902}, {-19248518, -14164021, 11281311, -12934077, -2937595, 9619497, 25103629, 13683159, -29223005, 16754133}}, + {{61250094, 5666997, -17554994, -9723180, 1792060, 23128892, -17863111, -9503155, -11440099, 8349519}, {1630604, -11699473, 7074740, -20998654, -61647292, -8501842, -7922013, 86401, -3454875, -5978241}, {-32533060, 2643395, -24933394, -5446718, 4658778, 9736946, -22895558, 13076296, -32217997, 3850312}}, + {{-40793207, 23131557, -58643230, 1453850, 18456888, -11681071, -11357218, 5934760, -15411101, -16603265}, {14291997, 10028183, -3522076, -19146146, -31657422, -11191445, 10113996, -13682306, -933881, 14158979}, {-20971877, -6015806, 32628147, 15387987, 24888678, 461773, -26446677, -3509034, 7501495, -15319879}}, + {{-10368704, 21074423, 62643283, 13992099, 56467685, 18782384, 12166517, 7409948, 40907504, -21429229}, {-45845424, 535989, -2371303, 19222689, 3245523, 11996814, -30575555, 12398712, -23739320, -4776379}, {2387154, -10664708, -15449141, 11069350, 20161808, -4565500, -19956162, -7030308, 25812806, -8047788}} + }, + { + {{-11393788, -31195641, 5914009, -8226580, -24992165, -13603463, -8419497, 9196904, 9942709, 17023821}, {380918, 2093827, -42908935, -13269472, -28502501, 13869739, -45706159, 18355538, 46404415, 6844933}, {-15657003, -2082160, -19313214, 10506720, 30813871, -3008467, 4864735, 10542907, 5146482, -16066099}}, + {{-26012206, 2440624, 34968934, 1674080, -12124996, 12254092, -35618687, 12993229, 52734543, -8754976}, {8363658, -22650692, 10471620, -19946100, 45702754, 6267052, 2816295, -2346457, 1012695, -21718010}, {4722214, 11565915, -29222713, -7632932, 14690342, -9309653, 9473536, 2287339, 5535428, 6082468}}, + {{37715665, -12032259, 17427076, -20118777, 619081, 1153738, 13837579, -9801709, -19023845, -1509944}, {25606015, 11917187, -31135502, -11291017, 50905807, -3420204, 49630657, 19991205, 38594971, -7151340}, {14797569, 7275261, -17622375, -12677304, 15863283, -4386891, -6821285, 1047435, 29221350, -12442876}}, + {{18223382, -5557019, -13941971, -270107, -6276162, -2649297, -25516399, -30398943, -30376112, 1934432}, {-24481222, 18332455, 42074839, 31113399, -50585006, 21419319, 31751971, 1604499, -31432334, 4012114}, {-5614394, 16118667, 17842984, 10154293, 7203392, -11760100, 12786533, 13539782, -11699136, 8069706}}, + {{-52415221, 11390392, 10634948, 5760017, 17503383, -19305298, 400282, 6562410, -45578538, 7471700}, {3785437, 9616354, 35505798, 5251077, -25848885, -8841316, 3089148, -18514060, 20029008, -18435942}, {837545, 6435504, 14517599, -2990881, 23535142, 10294946, -17303464, 1348860, -7846038, 12477368}}, + {{34024961, -19636451, -49400571, -440123, -13551236, -11721832, -24006897, -3642120, 6614492, 6991166}, {22424621, 13818795, 14059635, -19211115, -51683566, -11787346, 41264997, -16154432, 38529916, -8673210}, {-29242768, -7080381, 767860, -15762290, -13884415, -14008837, -8360107, 7262483, 29698713, 951923}}, + {{3993534, 11930001, 8116396, -13312413, -58362634, -23134275, 39248444, -1158132, -5010070, -9536476}, {46775790, -4717339, 8506206, 10843861, -4752500, -4112565, 7970818, -28209784, 1674628, 18226918}, {15014429, 7514026, 19143248, 3136851, 32633519, -3951912, 20990367, -1419185, 21553726, 12441390}}, + {{10478111, -23383406, -18952330, -167817, -19095938, -9134562, -30597693, -1530271, 7044267, 2592452}, {7133155, 5347562, -39013062, -18434567, -526094, 7129772, -575345, 5362853, 41758291, 2140598}, {-2947421, 15525486, -23996411, 6039451, 18811643, 13891367, 21702656, -11044360, 26127980, -13714955}} + }, + { + {{-2512461, -1372206, -35467931, -176266, 18461162, -1792418, 1287107, 8100825, -52504725, 24588235}, {-40949821, -1132156, 18799869, -1764834, -36085632, 610810, 2580243, -6649053, -12205113, 1062337}, {-22421880, 16776151, -26039760, -2906207, 11402611, -7283455, -29204913, 13188295, -1116466, -6742792}}, + {{-32390999, -14812052, 30933349, -7137404, -12995009, -10371462, -7075396, -17579330, -7884075, -9885737}, {23979633, 2778906, 20243223, -25070876, -11426251, 2381934, 20057128, 8148502, -49449311, 2906429}, {12643697, 12434471, -14574200, -14016002, -31206316, -13553402, 14367322, -4716995, -10905587, 1670326}}, + {{19026480, 23287111, 6272697, 27663013, 29247445, 7383421, 15703093, 4310091, -343132, -25508622}, {37550200, -6934929, 27827057, -4610215, -2745461, 17000769, -33562771, -2487325, -59541030, -2971006}, {17444074, -2714269, -30164474, 11479010, 17083699, -7174135, 15211210, 3716649, 1375112, -12633664}}, + {{-29695567, -19798119, 48199665, 6314768, -24908887, -16878777, -22312220, 21381561, -62609455, -4465042}, {18520321, -3430727, 7899957, 12334232, 10352651, -4728781, 36879380, 7591311, -1851449, -24330098}, {-9441852, 6514454, -2730097, 12017911, 23787864, -4685660, 27118696, 3902741, 32393460, -913193}}, + {{-680569, 27368161, 19897314, -4427070, 51833741, -5565835, -6494526, -14596372, -5717784, -5606705}, {-57689313, -129247, -28727214, -20715426, 10427619, -26237139, 59927698, 7945678, 19482960, -14914347}, {7639586, -10357575, 26177609, 13768483, 13693595, -9188690, -3274292, -6963965, -21719587, -7131527}}, + {{37990613, -4665460, -37182009, 7688230, -30857295, 16532957, 2229769, 8152048, 33472640, 22003191}, {15092871, -5593572, -26526525, -17792398, -26526325, -7720867, -49984255, 3017412, 30171526, 2377085}, {-3854974, -6002816, -14612785, -1109631, -11345964, 5854705, 26977843, -4913550, -28719386, -4944419}}, + {{26782420, -16703981, -32417800, 4779205, 35800529, -4923134, -22539402, -10875321, 5783305, -17221701}, {-19579296, 4797349, -33050308, 10979287, -5806745, 27289964, -8032346, 7722629, -33960437, 11392773}, {-28495461, -3191753, 30384833, 12690226, -32809025, -13118074, 20050301, -4432640, 23462068, -10746844}}, + {{-6192253, -3176327, 13759314, -11547622, 42355806, 5203471, 16835539, -18940708, -50799058, -19138803}, {21848409, -28044655, -11132206, 3173030, -23106916, 6377869, 13394871, 11254226, 13056196, 13282063}, {10903815, -318931, 20023736, -3062161, -33043718, -10483177, 13980354, 5850500, -3787447, 8279326}} + }, + { + {{-15332054, -3128134, 4217626, -23920213, -12813941, -8669465, 34295434, -4767981, -1921001, -12110719}, {-14316922, -7762186, -347748, -8317589, 30561813, -24326271, 7885374, -13156847, 42586295, -11598391}, {-5986075, 5716527, -21449148, 15827466, 10298570, 4796847, 26143678, -5517979, 26117337, 3215551}}, + {{-450797, -3960386, 4350998, 7511133, -19503884, 16372261, -24072091, 17323231, 252397, 24141690}, {29606469, -13112434, -30673940, 13445053, 10527018, -15896619, 2043099, -16095025, 2317389, -7701232}, {-21724989, -6843647, 5520708, -2804427, 30302861, 14193429, 31996951, -10764110, 18800609, -8435028}}, + {{-16092415, 4125816, -25947826, -5090834, 57798801, -15761098, -49435062, 22712141, 7198617, -8184157}, {7046437, 13066462, 19988158, 1668368, -5624737, -10781580, -6252040, -1293161, -36939853, -24156343}, {-15912134, 15554644, 20529504, -1964149, 25218951, -12492275, -2931377, 6809197, 32591275, 8141438}}, + {{43901294, 18638240, -17033266, -5068779, -27799472, -22140071, 44302090, 12820344, -10004646, 4899896}, {-19736902, 5738452, -9419198, -3263459, 17455508, -9670269, 18578554, 13440702, -54950948, -19629796}, {12087288, 9590630, -21952880, 14511399, 7160045, -8366025, -4259298, 15490224, -8111985, -14586351}}, + {{-7729310, -7411401, -18536796, -19063948, -50090493, -27466784, -12601316, -3337327, -32338683, -19832706}, {-55484508, -15637761, 28701456, -291864, 4782889, -549112, 54204536, 17511485, 14841627, 11131542}, {3482227, -4765013, 2128235, -5818091, 990479, 5647839, 1811126, -10065411, -10477514, -12719470}}, + {{-43296735, 22624866, -21885794, 13983934, -7585917, 979767, -31729817, 3092820, -11192523, 13045424}, {21936353, 3859126, 8674162, 14119524, -26036453, 3747117, -8540865, -92476, -7831533, 6148760}, {-28595098, -12010122, 9629784, 46145, 18039016, -6847849, -20262167, 11672034, 21004208, 10422611}}, + {{-42896688, -1926529, 48588324, -1156191, 38199580, -4254732, -45800601, -16745548, 5000677, -5591791}, {-4192014, 25615407, 10866648, -13427877, -24451378, -25657316, 2614871, 14762132, -48515979, -16992495}, {-7230360, 12536213, 3274484, 14850230, -28111654, -3879449, -14085489, 9446178, 3570569, 10000749}}, + {{26045226, 4594337, -40303866, 14329443, -39514437, -2022349, 33837398, 10307831, 4354304, 8921946}, {-7224138, 1431025, -13384774, 12191821, 11379371, 23560909, -27871846, -6722167, 17300704, 11717938}, {-19215969, 6010490, -31869912, 2483556, 6213569, -713937, 22848401, -11424117, -20172080, -11678587}} + }, + { + {{6607421, 12480494, 25428027, -18102165, -160701, -23724349, -5141897, -8553616, 28810543, 6922662}, {-39677521, 14421070, -18906753, 7702897, 5044227, 378013, 14146435, 9493068, -32891707, 10816192}, {-22673527, 10415048, -810235, 13256181, -3056072, 15894912, 12832664, -13856055, -22736135, -7124374}}, + {{24775529, 15012151, 15040989, 10514838, -20190653, 15618124, 21288611, -218153, -27800043, -26742}, {31379615, 5911423, -21178843, 20633530, -2440443, 10677890, 30938733, 25469277, 8553689, 9418830}, {-2752675, 9858208, 14285659, -10165248, 16638743, -9280038, 21498686, -7213728, 13108400, -5038892}}, + {{-9449484, -19316521, 4072499, 14995111, -9380605, 590509, 45719950, 14060381, -20627956, 6405383}, {-50875938, -8132887, -5088825, -1533161, -9897577, -15743051, -12171054, 11107961, 9598642, -12786005}, {24540837, -8914962, 13445348, -2226882, -12722019, 12245570, 3464372, 6923363, 23802564, -3354405}}, + {{12719393, 6186229, 3205364, -5309560, -18616217, -24988006, -4902262, 7772882, 1582263, 6479024}, {50382271, 8205633, -18040270, 5921760, 44849781, 4236674, 9646882, -17787846, -60502809, -25274328}, {-21870160, -8943416, -18857714, -13669387, 6581785, -8690535, 4610705, 7483982, 12708371, 5866112}}, + {{-3006154, -7557724, -22169959, -6284017, -10118629, 23728740, -12691610, 10394222, 691290, 13884352}, {10308096, -3147832, 1635715, 24866371, 32799905, 9767350, 43350518, 11620206, 61080638, -5279360}, {20773313, 6997282, -3809124, 12542279, 24703297, -8295618, 22040350, -6130895, -31020058, -8415480}}, + {{-26518614, -2719445, -22713946, -15613749, -27498654, -1251922, -52784874, 26006039, -1810392, -5264225}, {19526420, 9832513, 34645312, 10566587, -23229568, -24851960, 601760, -788989, -28878666, -17591219}, {-11194361, 9496633, 11574094, -15967320, 31868038, -2017814, -28314077, -5028405, 786536, -15233245}}, + {{21423278, 16274071, 7729969, 3728528, -49745765, -2189717, -9661071, -20965510, 27573690, -20056221}, {-39581388, -9448779, 45916493, -4188474, -7221443, 10078893, 40914437, -12218440, 31393268, 11136943}, {-19025067, -8937790, -1863238, -14696416, 13564285, -5096605, 29657450, 7256514, -16798239, -16552850}}, + {{-19847897, -5594469, 39344403, -4683436, -22625766, 23550447, -17378786, -334265, 37033298, -8633938}, {37873295, 21733533, -18576983, -24263718, 11311508, -2510227, -25489582, -11099607, -20215982, -23396432}, {31638938, 11266002, -14017046, 6454660, -3708082, 13857499, -29674180, 11217059, -9944124, 2404134}} + }, + { + {{-261678, -7849141, -34843012, -18330714, 12823110, -5409085, -637386, -3306802, -46619295, -3929080}, {-27165578, -24071059, 15212854, -8076208, -32981854, 4584589, 35033258, -27183974, 16211721, 14098878}, {-19944482, 9217160, 29166980, 10599437, 17168629, -9153918, 30127943, -5149380, 7115294, -15721402}}, + {{28718822, -14728241, 10922201, 5552845, -16998365, -8637291, -20572626, -23695944, 31266022, -15838481}, {19356870, 18101731, -22279113, 23485403, 34937339, -12195567, 18925240, -2534584, 24353654, 3022973}, {-8493708, -7900692, -31911097, 13374247, -31325809, -11138877, -29965332, 679570, -186672, 6927918}}, + {{-19371557, 6365963, -23021669, -12092535, -32190310, 23811729, -35212946, -6690732, -4425401, 1709924}, {-6912921, -23684853, 33021145, -9381373, 16503662, -6786035, 20300954, -2943916, 34176675, -14086980}, {-6568424, 13771726, 21857256, -14647726, 2979870, -507464, -4144029, 10367676, -9694929, 15963105}}, + {{-6504962, 3895999, 15330575, 6085731, -23338413, 7287105, 13358854, -21092609, 16274219, 17893318}, {-55096654, -28630821, -27498625, 10064439, -17110189, -5629883, 18381524, 12443615, -25787413, -5389020}, {-13562914, 125101, 10069578, -3267751, 15126173, 11128659, 28860725, -2220394, 31209598, 4741592}}, + {{-4171361, -16887831, -6824220, -3692201, -8714977, -3089811, 23584908, 8179016, 348585, 14700807}, {60333581, -4479775, 2964970, -22014545, -13655147, -8932453, 31945652, 19344532, 8315339, 9725067}, {-29492579, -11988190, 29868297, 15668335, 19515758, 5208175, 18570645, -12453448, -22651150, 12257559}}, + {{9297415, 1201627, 33167590, -396664, -35635797, 886522, 32001557, 6690554, -13391828, -7914547}, {-43738093, 30935445, 918928, 22105178, -4858945, 17798468, -11303337, 9751766, 29668922, 15368961}, {6349498, 6435647, -16762609, -871321, 24390394, -11228126, -27382581, 1428982, -29386922, 13093878}}, + {{57975408, -2027510, 45435287, -23089566, -16756208, -9193864, 14612730, -10391203, 12786762, 8187923}, {1469460, -15707970, 5635697, 8770840, -22627256, -11216978, -10949710, -20820501, -13492462, -15746741}, {-6035260, 8267404, 362534, 11537538, -29897307, 1151760, 11763092, -4363531, -13651065, -4561529}}, + {{28689216, 6409485, 12220204, -22516376, 5364707, 15733115, -6501438, -1478390, -23146730, 3734217}, {5664034, 10051653, -43413392, -6735256, -101135, -5681113, 38821030, -14021930, -17485088, 28200305}, {22221784, -15241964, 28292310, 10693661, 9115461, 4679508, 22886641, 10215724, -12891591, -2706350}} + }, + { + {{-11319013, 22092125, 6101371, -23112833, 4724792, -737430, -43154064, 8855918, 2368215, -14753784}, {13052289, -2211683, -17141905, 8918483, -47820468, -1104286, -6861658, -12957206, 46761279, -10669384}, {24527779, 9111443, -10606660, -6994118, 6360508, 8277150, -14301108, -5589450, 7995916, 2601089}}, + {{-20567677, 3869833, 22792031, 3877340, -5358238, -24675582, 2151592, 17806016, 8546022, 9282780}, {-1024971, -17593947, 4033769, 22284144, 52848512, 191028, -26685112, 2325830, 29271732, 269852}, {21914383, -8508981, 1584359, 9381216, 27077910, 9548224, 8083125, 9843874, 32662283, -6224944}}, + {{44977225, -17425911, -35662966, -11955772, -41081617, -5655595, -33889802, -11639581, 20559423, -12699812}, {18635889, 1717141, -743872, -21530196, -12575309, -21227371, -11961210, 7698111, 17344797, 5772870}, {31755093, 12835492, -28111039, -13882334, -6114100, 7804109, 27718359, -9748879, 26302609, 15894773}}, + {{-10479308, -30736552, 15655479, 18560091, -45784687, -1208851, -7464237, -5347583, 37602567, 3188747}, {-50795294, -362692, -25025471, 12626779, -9787325, 6479703, -42673855, 25275063, -21968891, -15939305}, {-14237323, -7667471, -2394791, 7563450, -28011184, 3757401, -13138955, -338927, -12550810, -4705688}}, + {{-997731, -11244355, 28307844, 31003171, -52648343, 13823368, -25119261, 195539, -22291166, -16449592}, {-54287065, -14202267, -4225368, -1386245, 7078343, -16715166, -25188893, -30908833, 8142782, 8193182}, {-31812856, -14454650, 21973231, -15942473, 13881138, -10421780, 29865093, 257485, 19188036, -2355462}}, + {{36607347, 2562141, -4061810, -8323178, 26030653, 19069729, -19911809, -973682, 28123549, 13069082}, {-29679391, 21962881, 33828672, 3669408, 32342651, -3428973, -38829285, 31897352, -9786281, 334240}, {-18958476, -9448616, 22047089, 14137801, 29557406, 13622841, 19309512, 1213569, -6970559, -14022250}}, + {{2567752, 30051368, -7869717, -30839292, -3346152, 14373100, -16374082, -8772262, 2390004, 10489445}, {-8168154, -940848, -56942419, 1855388, -10634282, -10061176, 50527334, -14943440, -42675052, 4945351}, {-2161578, -2129839, -24322080, 5238648, -1913956, -15052225, 13192063, 4524122, 27281408, -2567409}}, + {{5316974, -1652106, 23421334, 14286024, 5169539, -10278519, 7299556, -4916105, -11399259, -7995221}, {-56120566, -16699148, 35877614, 352134, 23842397, -18517099, -36670982, -16201841, 40381317, -14975627}, {20358374, -16032261, 21372886, 2229448, -12128163, 8384962, -20268879, 13945650, -11738322, -6352788}} + }, + { + {{48633486, -10216478, 12261071, 8645742, 7209828, 1201092, 19902952, 5679173, -12787484, 29787725}, {4237894, -8186226, -9620455, 10857166, 11357206, -21380442, -29207530, -5718719, -53691854, -3077103}, {-27312813, 15365228, -24022056, -4062791, -31056990, -1167716, 23863648, -4168917, 21152744, -7692607}}, + {{-4692465, -8612662, 25089518, -13362237, 17071702, 18545769, 3946832, -6215074, -23802544, -10377682}, {-23139891, -9823966, -4436690, 4520993, -42243454, -14678911, -14115386, -10878842, -35023202, 6505784}, {-7326378, -4764331, -16791732, 4328265, -24065452, -5898905, -15420255, 8536200, 739691, 13784933}}, + {{-45913725, 16629500, 13265621, -14270983, -4850195, 10441223, -21880345, 674614, 8141975, 21140875}, {-5917149, 6961978, 21961727, 7049701, -23105367, -10984291, 13950487, 7986758, 9038183, -12224179}, {11607489, -275019, 8794399, 1368189, 30180196, 11088225, 11603248, 211230, -26074831, -6437645}}, + {{-14554577, 9179014, 52781341, 376983, 1996737, 7973725, 3224830, 16479358, -58755195, 21010121}, {34578699, -7266060, 9081145, -12880641, -54401093, -25306157, -41468422, -15033426, 4654677, 10635069}, {-5205201, 7920985, 18658730, 9487273, 9049638, -11418646, 1721950, -8843881, 10455628, 12638026}}, + {{-31095281, -3649727, -10281050, -2192978, -46553189, 7366778, -21105682, 6603721, 4013012, -9486255}, {21994247, 22093215, 28324720, -20018730, 14962185, -25397368, 20088288, -1155741, -21152232, -9486345}, {29734196, 6899570, 22755892, 7095432, 29404584, -9982700, 6976163, -5933582, -8292488, -3951721}}, + {{-2823903, -10004932, -41642800, 17529940, -48438413, 16426593, -38347076, -10754706, 18529362, 1960110}, {-38993205, 23080306, 7715564, -5727918, 8703491, 13721445, -16103650, -4601126, -3222526, -10841104}, {22977101, -12797824, 18541274, -11855741, 4488929, 6624312, 15196080, 3421855, -15121122, -11941867}}, + {{-12279917, -11378351, -39458155, 10295352, -2381383, 1218040, 4250328, 1515750, -18043501, -8782361}, {8204255, -48669, -18012017, 3366462, -40211283, -12108228, 38487690, -24158700, 9375025, 20073937}, {-33211899, 878451, -13779691, 158784, 28571850, 3247815, -13420149, -9882438, 19630879, -9578616}}, + {{-1524162, 19359075, -54952182, 19936457, 29370414, -23041747, 18452380, -1682646, -45403846, -2872255}, {46482800, -9213111, -11326644, -10537127, 17886942, 3312703, 36280558, 31723292, 8754472, -10822831}, {29788745, -9578704, -32124397, -5237515, 13098731, 15495801, 9656793, 4992360, -31738654, -9173569}} + }, + { + {{-16278546, 7545261, -24908860, 10758830, 22765661, 8474008, 29761503, 8003328, -1616915, -18908405}, {17257026, -19687865, -10758910, -20875664, -19406683, 1562912, 7243455, 20839660, 5630677, -10593529}, {-17155060, -3795378, -12076573, -2699534, -31665702, -9435070, 4160877, 1277205, -11721623, 14441223}}, + {{-31270598, -12678036, 29863664, 6036798, 2800311, -8142142, -26282720, -9547816, 14026837, 15100824}, {-22366596, -1211390, -59216, -24784520, -28178807, 18056568, -817118, 12533760, 33355343, 7518302}, {-30983313, 6066747, 31034036, 15849538, -28343758, -9704223, -32559485, -3633862, 25842669, 9690479}}, + {{-8429032, 11392209, -1185641, -1949265, -9976804, 14945095, 41691304, -12416661, -33983295, -1832878}, {40970370, -18174883, -4320197, -24727969, -8030934, -17322773, -19795048, -9287653, 1741393, 21504952}, {-2612267, -14084516, 23371323, 14909696, -9777105, 8575292, -24712515, -1407767, 26673843, 13318593}}, + {{11258435, -3335510, -9378347, 9080874, -48037378, 1818100, -4673614, 13124593, -13445986, -19457862}, {-33282745, 23090950, 3670039, 15362154, 7785536, 5758718, 19067094, -8232413, 31123236, -10239406}, {31236959, -15451213, -13569986, 6863849, 1456103, 3255861, -1015217, -7348569, -10529144, -5973171}}, + {{-17355114, 6408303, -31757344, -21037718, -29332963, 265342, -3620892, -13917787, -12986841, 821907}, {-44193642, -4780261, -15560790, -10980740, -5301083, 16943326, 34038688, -18319439, 47714905, 9176477}, {-30408593, -13933451, 12540587, 10205245, -21156684, -2193434, -32644367, -2195594, -33227571, 1348962}}, + {{37300238, 13718999, -5440778, 23211687, -25434566, 16930020, 19002350, -11338408, -17165461, -1066853}, {-11256888, -14158089, 30550652, -496849, -10975066, -11590790, -30284342, -17105514, 36397093, 29841231}, {-3064649, 8804459, -25750541, -12180868, 22773076, -97238, -10307135, -4458757, 32735900, 5532092}}, + {{1532666, -13551228, 17062576, -6914464, -29699, -6163623, -32622423, 27358854, -23035478, -6675198}, {-65356094, 14641824, 39218996, -11105288, -5613813, 25527829, -12582169, 3931336, -42632342, -16488088}, {3310269, -2510089, -31795607, -3903471, 19216137, 9503161, -11692250, -2123365, -30741088, 1641923}}, + {{-10225624, -14754950, -40072478, -16547638, -19110590, -2092035, -21620770, 21427043, 3916097, -9477213}, {1447108, 2926094, -2949786, -4723118, 34413150, -6739645, -24584222, 6767619, 39145241, 10386667}, {-15561955, -16550369, 20291638, 10943916, -23414577, -6185458, 3379566, 16280619, 10525150, -13947491}} + }, + { + {{34658977, -16038847, -12802226, -13014151, 3247514, 4852077, 39865196, 10455200, 30045437, 16991276}, {24311145, -4913651, -45278920, -20411815, -25341898, -23925191, -24739212, 16469980, 16417381, 6451612}, {-16689431, -11998462, -9414744, -7261308, 6616461, -6574033, -16590968, 7616942, 19327058, -6851401}}, + {{-43347425, 11719412, 15552158, -24147106, -20651836, 9836617, 28125896, -28600360, 23325076, 11812607}, {-3508109, -10746900, 20787140, 8538944, 31980116, -17564519, -26852974, 4206554, -37601064, 18724725}, {4577393, -3230998, -154546, 11200325, 16900801, -13303198, 703161, 10326633, -9111559, 12622501}}, + {{-39725809, 13031525, -45619966, -1065900, 12977682, -26984824, 14396739, 23479074, 13854702, -7277246}, {-8666981, -9809045, -5828644, -1589910, -38666562, 2402226, -38187511, -2130616, -20658206, -18926322}, {3021153, 6293510, -12950698, -12635396, 22253895, -2704326, -4346713, -13545669, 16658927, 11656843}}, + {{-59858598, 14117142, -34942776, 13455194, -30347266, 12968167, -349016, -20272076, 1493980, -29128478}, {-311366, -13578650, -3624800, 17993138, 7052438, -14442621, -47595120, 8823830, 26377542, 423482}, {-15043195, 14759856, 12260841, -8268503, 11492641, 1734953, 8133531, -2641481, 19962273, -7414005}}, + {{-7319995, 14066561, 306018, -9411916, -9106104, 28412794, 4492154, 6686869, 2747033, -1712248}, {11409799, 15502609, -51140592, -10331378, -25666946, 4479790, 41995232, 3580355, 33962015, 21352220}, {12328954, 9749794, 28967140, -13246240, -21591005, 16352433, -32813092, -13950724, -2422183, -13272071}}, + {{-8704834, -13611958, -28725837, -5418165, -11662524, 1903780, 21191194, -19423669, 21840672, -4046432}, {33868948, -14602450, 17355767, -17469989, -9306120, 9991434, -36134744, -8906221, -14525880, 15878400}, {-2082348, 4968230, 867409, -14954533, 15018454, 16113129, -7179385, 15112575, 2207326, -2934540}}, + {{-950243, 765343, -17592467, 1469970, 3671602, 25269497, -19548977, 5934984, 27925413, 1252282}, {-24875987, -15215583, 2273293, -28049708, 34702386, -3402235, 45132453, 6703626, 25515525, 19721494}, {16396177, 8613584, -3757212, 2125711, 11975069, 2236439, -14826164, -10807755, 22775664, 6368252}}, + {{37631100, 11452175, 37996574, 28403091, 2042038, -25510785, -2244471, 20395577, -38771575, -21028519}, {-28395458, -15337803, 6533566, -949631, -32782254, -1683835, 12320247, 4327475, -20953713, 5677971}, {13046115, 9330037, -21424794, -1647804, -18873081, -10227439, -32108018, 5191824, -27460387, 4779906}} + }, + { + {{-13132390, 15900078, -35837620, 6138995, -16379525, 11099368, -30563068, -5811453, -22643042, 2789555}, {-17544404, -4350164, 17681678, 5542577, -10792183, -2960672, -22627138, -26233007, -42909694, -15508303}, {-18571556, -1708862, -11142004, 12397824, 16334994, -15561902, 10481689, 2473907, -23820826, -1317082}}, + {{-53900779, -11293054, -18662763, 19090140, -644060, -2518627, 8996174, 10536067, -19839854, -18190256}, {-1981303, -8058462, -22504681, 9193390, 16049798, -24235085, -51867624, -13768197, 29045932, 11552058}, {-17481070, -10146213, -2297259, -3142673, 12810526, -14280422, -4843334, -11927523, 24825679, -5561024}}, + {{15182206, -12852170, 4415707, -4284980, 1820581, 6208857, -22937108, 158677, -2418885, 15496217}, {-10640676, -13722574, -9233807, 1945194, 31321909, -27138585, -19043254, -11468265, 52878507, -15736175}, {-7942886, -14488153, -18458357, 13283736, -30617597, 8540108, 28634387, -16048077, 22446330, -9291456}}, + {{51951741, 1401316, 13819841, -10463224, 56112635, 5549412, 13922999, 7678647, -28351533, 12447598}, {-4586801, -19006962, 34850255, -22402400, 2533259, 20384162, -2311659, 10867869, 5705219, -20858768}, {-31191831, 1392011, -1145725, 13721318, 21857534, -12599402, -6210695, -4231569, -19891740, -7519416}}, + {{2370009, 20559918, 48498973, -4318784, -7398063, -3539373, -37041833, 12935251, -15719038, 607}, {45474899, 2381236, -873295, 17048136, 4009737, -9661675, -29179009, 16938359, -47207048, -14558157}, {-24091442, -10155633, 22844512, 10159654, 14068589, -2959969, 6159407, -5555702, 26419751, 13312649}}, + {{-5729427, 3619546, 26751877, -6582025, -18775514, -15859921, -39862434, -2934988, 4285811, 1198554}, {959289, 28703180, 4690625, -14221985, 40298260, 2933865, 25167294, 3749282, -60098589, -7448486}, {1425431, 11181969, -24988041, -16772793, -30681102, -1633118, -4588255, -490460, -17856864, -13059939}}, + {{12136150, 12152835, -8816684, 1269564, -21628783, -6466972, -17883602, -8157915, 4152133, -32374445}, {12546740, 11779659, 1422338, 20631740, -5537253, -4622706, 4551832, -6940805, 56184709, 904171}, {-28203630, 5856240, 23492855, 7672591, 26254943, 3206013, 24126176, 2480892, 6462164, 773285}}, + {{17058894, 12754689, 13661051, -16724573, -23285751, 12561383, 7477610, -4399654, -29734046, -4657536}, {-18579100, 4740393, 49935491, -14043397, 1785623, 5306303, 17241740, 24210984, 35074424, -14938694}, {26931965, -8440503, 22021231, -3228157, 23192224, -2082498, 31831419, 488532, 11056805, -4935150}} + }, + { + {{45685475, -8915848, 11706361, 26190642, -12915492, -10568751, 11413192, 22516022, 24402910, 19366350}, {-16280547, 14048926, 53355501, 203746, 3536470, 17310775, -25706326, 2965098, -23359130, -7019028}, {5219255, -13887489, 11530381, 8658685, -7970465, 2776178, 11655378, 8517982, 1942227, -2822448}}, + {{23273232, 6228496, 32138310, -3720228, 1034832, 8006940, 5760605, -1219334, 47209076, -1758613}, {28409420, -16146936, -12120684, -4267306, 62110870, 5712626, -23251639, -11075712, 15064378, 1888835}, {22925844, 13439451, 19978779, -11645437, -21236831, 12919717, 21475696, 5255011, -24111181, -1653030}}, + {{13889598, 6667069, 28886474, -8423735, 12627155, -22617676, 47396268, -11411299, 1419336, -6073487}, {-40253212, -12438049, 15138634, 3102653, -7839729, 6284108, 9544580, 13025665, 18218292, -9653413}, {-28548077, 6678572, -18967881, -12810072, -7223432, 14162449, 3655387, -5394146, -21806212, -16053453}}, + {{-20354796, 10453072, -5438313, -3955364, 21297494, -31107146, -8320689, 20633477, -26174801, -9330454}, {-16088198, 2892522, -20320971, -8698070, -29656494, 1606756, 58463095, -97109, 19616555, 18189512}, {27361092, 4322173, 12085912, -11381998, 18190737, 5708430, -26275044, 7165633, -9779984, -7005107}}, + {{21320473, 13996983, -57788174, 16914923, -10635504, 19089852, 7947688, -18038830, 17253651, 7317}, {18393349, 3176647, 769142, -1803903, 40651564, -12410346, -31852970, -8782034, -1992083, 8508993}, {-5374050, -7289834, -7153403, -2693727, 2148712, -13034476, 20610076, 8047910, 17892981, 10999419}}, + {{13571194, -3603298, -8872349, -2734879, -22504925, 11752829, -6842514, -13325989, -1741590, -11986556}, {-44576662, -17187304, -15291721, -8435243, 35874627, 6776207, -2055368, 1286983, 19340064, -18770834}, {-24330704, -8410612, -27321457, -15290306, -8779956, 12445176, 10359557, -1091854, -18442413, -7485155}}, + {{-17386538, 11979807, -46738526, 5048062, -54438144, 4405898, 15653779, -4176485, -19550053, 5427115}, {37242168, -114217, -13721474, 5045494, -11313016, 12872040, 26949855, 28864745, -39675857, 21523831}, {22507400, -8955250, 11955417, 3563585, -22259890, -11000825, 994347, -7600384, -5366041, 7044447}}, + {{-22194577, -27776645, 22482313, 12192501, -8553630, -13035554, 25200811, -15619470, 23778753, 27463106}, {-23566873, 2949467, 20829737, -6857829, -47006730, -3645552, -21517917, 5158284, -20183871, 4528420}, {-22090186, -2938287, -13033320, -16025050, -15959805, 2354862, -26621182, -7756844, -1196188, -11909316}} + }, + { + {{10370741, -5849955, 37123447, 18627351, -38720430, -5467337, -4646845, 282641, -16154810, -16954981}, {-25472479, -17218909, -29684541, 12586127, -18568342, 12085373, -7760527, -21475559, -13608206, 11699731}, {-25850627, 2849911, -22714356, 359324, -21369627, 11760766, 311767, -6363096, -20461078, 8200446}}, + {{51072371, -3885664, 24357186, 11765997, -31518666, -14327232, 26378127, -4529571, 4823539, -400306}, {-13132435, -19524316, -11075498, 15144095, 1386480, 7361216, 30733459, -16314427, 58072575, -26871542}, {-10685263, -12470842, 7658527, -873382, -17370174, -8328204, 24529973, 13255259, -13717250, -1145719}}, + {{-13155673, 15148313, -6237775, -8395215, -1364956, 12324015, 7578661, -7310534, 726779, -3892337}, {40017501, -1615435, -3576083, -12815803, 61932558, -10481385, 24841361, -22656372, -57273247, 135839}, {13130868, 7741076, -8053394, 5139371, 26669021, 10292387, -18188600, -4194478, -16156745, 2276057}}, + {{22695589, -9049988, -11216284, 18617738, -37469072, -4533426, -25210722, -1426655, -34085926, 7157229}, {-43379737, 13335278, -20074050, -12769148, -16636996, 14222596, -26473252, 18660333, -4677240, 24459041}, {3529739, 15115762, 2302159, -3601460, 24599977, 7260078, -23813764, 10706074, 23285160, -12260470}}, + {{1451402, -17978089, 4597652, -15136952, -24951520, 3349082, -31776203, -6166722, 16052817, 15578885}, {51786128, 9316193, 61979592, -10708090, 12271806, 7103764, 18545795, -9993308, -2886143, -6367303}, {13614916, 5454106, 18133988, 13974460, -16811344, 11294589, -18541412, 16215340, -15601800, 16352907}}, + {{6078819, -28262430, 1584794, -913250, -40032119, -11054435, 37478168, -14887045, 9851400, -9124994}, {-29383825, 846616, 19913242, -29348542, -4341087, 9879255, -13017782, 4141027, 56652888, 14154446}, {-21893532, 1751180, -22535928, -16418651, 1364239, 3379320, 31823798, -6441385, -16909191, -9631510}}, + {{-8798801, -17484910, -37085208, -4291375, -36708389, 405485, -3095693, -1897294, -15644675, 13201982}, {32174837, -12212012, 23906956, -9909357, -14878771, 16633681, 60281493, 4276490, -30821537, -2775138}, {-11837084, -5940846, 19286133, 12058815, 1577408, -10828924, 15301192, -16029574, 4699423, 15661197}}, + {{34815454, 28015558, 4984809, 23392680, 33677987, -19483212, -1801982, -21250999, -21444537, 27974827}, {9948478, -1836720, 7042909, -8912112, 17262215, 12098480, 51795848, 2711109, 40943719, -913629}, {-17613939, 8046125, 11877622, 7432861, 18881470, 12440012, 32878290, -16196398, -9439869, -1788868}} + }, + { + {{10205625, 18556565, 30374593, 5360360, -28809914, -6654000, -30267152, 20017871, 23439758, 19154333}, {-37791349, -2410869, -29226287, 23509664, 5889402, -20757308, 21603682, 1275863, -13216756, 7891299}, {29064179, -8479148, 15927568, 7407812, -27474199, 12419690, -19402948, 14555587, -4636876, 12854421}}, + {{35370478, 19649812, -37142240, -1339443, 12003445, -748041, 11921942, -8402832, -20024589, 10466678}, {-26687858, -13698008, 25888790, 28537401, 29009219, 6282429, -19372364, -4701276, 29500147, -21772314}, {-30155490, -1987836, -17629768, -7818777, 1199936, -9380234, 33257641, 6471997, 12280314, 10562436}}, + {{30242126, 3877144, -19160079, 13268125, -33233886, -27732747, 37329373, -1878923, -14981108, -11939081}, {23144988, -19625784, 19046919, -4606943, -19262334, 4435259, -29386565, 8342603, 32304512, 3926419}, {19740826, -14912918, 19841820, -1597371, 4000270, 3389137, 4304790, 8121605, -27599560, -9747665}}, + {{19955356, -11145715, 6723940, -9994548, -26447212, 16548776, 10204833, -13807843, -47500226, 4403134}, {-17432352, -4910523, 57888570, -7417520, 19158016, -8309066, -44266607, -12158363, -19278914, -11716194}, {-25096878, 15458827, -10969951, -146448, 30984047, -5646634, -31063597, -14068899, 31830986, 2482761}}, + {{34818770, 15336838, -10130245, -8925970, -12691036, 384437, 45736985, -155758, -36149061, 14027774}, {-4892, 7226782, -43149099, -8606054, -21859176, 4467743, -4065245, 31114504, -2394543, 6394198}, {-19454401, -8025470, 21005645, 935332, 4917028, 7033446, -4184343, -15083863, -30030715, 15685521}}, + {{37542805, 4271665, 2208642, 1857121, -3016247, -16972309, 57340351, -20309387, -11492591, -10203611}, {5201117, 19372089, -55047518, -17880649, 57292149, 3410863, -2501683, 10098047, 13523057, -19270659}, {-17011846, -7712403, -25913258, -15809123, -1872535, 5810276, 1015925, -5675459, 38638, -3671513}}, + {{3100286, -5837234, -23845272, 10938240, -20489584, 3639910, -9424498, 23060430, 43098682, -13308335}, {55720054, 20836422, -13256474, -6348632, -356440, 13207144, 19597314, -6777198, -19189604, -18200689}, {-364677, 2328345, -27523538, 15770527, -31973053, 8298802, -28499320, -11917079, 14607248, -9578452}}, + {{6756845, -8319734, -48155565, -12599467, 47322238, 3406568, 8817526, -22872889, 37772233, 1975826}, {-48809499, 19934514, 4820385, -6585299, 8591474, 27330954, -20068414, 5423895, -19754061, 3600822}, {-14438400, -8710252, 4397511, 13226636, -7622546, -15749654, 7487783, -6721987, 20749017, 8579430}} + }, + { + {{-13146224, -2954947, -19590290, 20584521, -35459163, 11484969, -17126902, -8893150, -22479218, 11943067}, {-19049940, 11536899, -35323094, 556155, 9444115, 17958867, 30448722, 15374052, 23740496, 21079421}, {-26898625, -6305106, 22653382, 7807030, 10193539, 13674411, -7048774, -7368330, -12087741, -2225551}}, + {{31867921, 10268601, 3589104, -10012663, 26122424, 3477368, 9206722, -4315560, 65626390, 5555194}, {18159207, 8603687, -6754636, -4993133, 10307820, -10460550, -14328676, 1941410, 753672, 6178}, {-30871685, 4971753, 7968986, 6377816, 24590769, -15347388, 4760760, 4938503, 15289388, 15153085}}, + {{-29833047, -22292033, -22437058, 10332517, -34915257, 5021570, 10011688, -7072021, -10336485, 6036439}, {23685721, -3613645, -40659620, -8299579, 23709783, 19982638, -32310986, 17866669, -5732883, 12210417}, {-23995707, -15472489, 7434900, 1921136, 11683526, 9881768, 3316359, -8282501, -3590943, 4763628}}, + {{-17136866, 4730105, 1340099, -6875053, 25920590, -6029800, -7897896, 7581765, -14118149, -614562}, {23844848, -8151697, -31350471, -5342619, -28146318, 6283042, 44335606, -6544861, -11177633, -2446974}, {-3964339, -3839709, -15556623, 9441366, 5019525, -8091531, 28857685, -15031226, 3636920, -13272435}}, + {{-17342167, -1799988, -2170322, 8552679, -10836031, 14275500, -48765297, -13025244, 34151360, -22381535}, {-9949023, 9538602, -15472544, -12370925, -7847713, 2368516, 1638365, -61652, -21123564, 2954541}, {9689996, 15184810, -29305262, 889957, 13792324, -3813673, -23916772, 9116177, 13239538, 14930571}}, + {{31398648, 516541, 53606342, 11861023, 12041363, -569634, 14181954, -13526625, 15261730, -4304743}, {-34431698, -6096219, -1188872, 4402503, -22779147, 24668920, -30651584, -13352147, -49236280, -3434639}, {-15604012, -5264712, -11285439, 11110692, -7419900, -1502294, 27919368, 15210720, 4352870, -8493384}}, + {{7880935, -26390635, 46079526, 2506887, 16984345, -24814996, 5237891, 17822620, 21752103, -26033559}, {-6190515, 5184159, 10181130, 10437621, 49407683, 6511732, -8233135, -12743142, -44107201, -1247359}, {-13491364, -6148630, -3221987, -15566188, 23146895, -11292831, 7819274, 15713104, 23517505, 16674487}}, + {{48428456, 4955956, -33767168, -23340410, -8662788, 12840906, -37340376, -14836638, -37267716, 3915624}, {18525716, 15497702, 4301192, -1953478, 31876770, -1131954, 28521674, 14010098, 4263976, 17623252}, {-26612028, -11434336, 14399011, 7727697, 21012650, 10977323, -22941610, 10192918, -14221003, 12258630}} + }, + { + {{18461603, 19334769, 41626573, 30794010, 2447121, 7050875, -12485913, 7215464, -2638972, 18431314}, {27439569, 14131655, -22466189, -1293104, -15246553, -25865639, 36203059, -10561582, -50671236, -1862930}, {-14225014, 8116107, -28215804, -9115491, 19533420, 4320566, 13478181, -1983082, 30167813, 8615589}}, + {{-6083862, -4200087, -43295848, -13943285, 776816, 3953840, 32847732, 10592737, -28337734, 5966991}, {-5647530, 5367613, 12475298, 15351869, -28056684, -5668070, 17921134, 13162707, 19185340, -22815747}, {-5613802, 13717358, -15598817, 1742192, -23583967, 7643889, -26953420, 15291792, 21698821, 6778229}}, + {{15529409, 17737558, 27589150, -13404401, 13434918, 15953748, -40577857, -18930872, -5940993, 18412185}, {15431317, -5038316, 4006854, -8721341, -24385588, -10054860, 22137441, -9813452, -23546035, 14254115}, {30382387, -3623060, -2962801, 4554754, 20603172, 14059127, -28685202, 9141484, -3849827, 10868327}}, + {{-14830708, 2899979, -32763136, -6755264, -8167621, -2496553, 4331022, 1064783, -7633743, -221036}, {44284226, -7062841, -1487288, 11592510, -56074797, 14818061, 44759376, -31782279, -23596513, -26061520}, {33088530, -10148397, 4662017, -5108256, 18148225, -5541506, -18654764, -5208915, 18019369, 15991016}}, + {{-1429469, -9581126, -302813, 26119688, -34154899, -23074232, -29836717, 31226655, -53723906, 26403907}, {47022657, 11267624, -56447379, -7088792, 32842011, 9713110, 29398155, 254627, 2432470, 4179577}, {-20692569, 9922705, -31906572, -9601808, -28142304, -12921421, -17914161, 1742332, -7859613, -6947127}}, + {{7986855, 17326819, 13578518, -200706, -47207399, -23181541, -43813273, 1845740, 8591475, -18210641}, {14271005, 9048027, 2140550, -27737820, -5252421, -4986805, 8682083, 22215462, -42218895, 8177129}, {12143199, 12169114, 5234082, 3227428, 10994855, 10993953, 11764913, 12616492, 683268, -1156488}}, + {{-28470508, 7642334, -13487543, -738157, -18930221, 30130757, 11554695, -21280161, -36627196, 23134539}, {112890, 9614314, 6856911, -10235405, 7361329, 421635, -11397375, -2121755, -20868284, -5212421}, {-15228284, 8267145, 5669929, 9640028, -917259, -8803923, -10942571, 5131020, 14128410, 7943530}}, + {{4583611, 16716097, -26997228, 8060844, 51908307, -13987189, 14269818, -16808042, 37942216, -2090590}, {-5027987, -9477151, -1394526, 25316732, -4975047, 2999255, 36547122, 4096572, 8115074, 30906874}, {28287543, 14133046, 1613100, -14164584, 23636363, 539921, 31097529, -2227320, 10335728, -10244474}} + }, + { + {{2895439, -30560411, -327139, 9675191, -15017358, 15835757, -1177063, -6745408, -23826127, -2439594}, {-60030525, -1507583, -24361893, 13997631, -1844748, -11342021, -26806363, 12267496, 26693091, -29998374}, {-13944340, 2977451, 19254875, -10656317, 9406954, 7268860, 2284270, 11952343, -9352332, -11814407}}, + {{-13000992, -18686758, 13475406, -20147895, 1593323, 15870377, -43782350, -6279630, 12071815, -21208679}, {49532208, 7264330, 38295652, -10551851, 52877285, 15613029, 9660816, 4307276, 34207995, -6039035}, {-9514134, 13690325, -33095814, -13410082, 25521150, -6940493, -22665108, 3311338, -28943807, -4614883}}, + {{58069710, 18929976, -11973308, 763240, 5244704, 3063245, 2034616, -14476405, 2869202, -14296406}, {3835584, -13870550, -35354044, -783914, -58099088, -22223657, -41269458, -18814237, -59367646, -8517344}, {-12958588, 8917584, -25298683, 15025459, -23309616, -3728746, 25229622, 14317972, 16318660, -4325041}}, + {{-15889803, -4035574, -16079905, -8415284, 29533240, 211888, -18626912, 2055459, 16607394, -27985702}, {40161533, -14516308, -36318099, 17884384, -17840614, -31484142, -25238516, 2119899, -5774124, -210654}, {7068417, -3254611, -27755301, 12521512, -27658780, -14245089, 26875648, -10638219, 13613282, -16016504}}, + {{-53004389, 22383610, -36057796, -12849854, 26615852, -2056503, -17151262, 18045970, 2945620, -3151953}, {7377715, -437098, -3002130, 4635002, 17766494, -27330215, -35491036, -8149012, -48581904, 1638527}, {-32193286, -9978043, -1419468, 1133310, -841762, 12456261, -1343545, 11949008, 21169603, 16313404}}, + {{16844907, 18476701, 13152707, 19998654, -8668918, -2993051, 1784707, -15774798, 11000621, -22750860}, {-10539685, 14655711, -21578269, -10650708, -7852222, -12944943, -16837235, -14380980, -54034761, 10124948}, {24701369, 7895900, -6682712, 2965095, 10724482, 5022449, 3296228, 4274525, 32055641, 13835830}}, + {{27170402, -16235602, 11716741, -10442355, 5352783, -1463503, -31357254, -21231204, 34820749, 4327579}, {-4596320, -264450, 1060311, -7855103, 11255889, 22437779, 22653770, -4793884, -25439297, -25824827}, {5194772, -11483286, -5013654, -8083761, -16992136, -3806751, -10109976, 4246728, 27365334, -286554}}, + {{10659177, -5655881, -6931258, -25775410, -18301523, 12858801, -1270020, -9363199, -31850180, -20743355}, {-54628161, 6255435, 52777798, -5472114, -19377665, -16320325, 20173754, -8442787, 32139964, 10336855}, {23911158, 15020529, -32222967, 812010, 30771383, -15992822, 4804002, 7159864, 23506724, -10668240}} + } + }; + + }; + + //const point_pc_t c_point_H2 {{ 1318371, 14804112, 12545972, -13482561, -12089798, -16020744, -21221907, -8410994, -33080606, 11275578, 3807637, 11185450, -23227561, -12892068, 1356866, -1025012, -8022738, -8139671, -20315029, -13916324, -6475650, -7025596, 12403179, -5139984, -12068178, 10445584, -14826705, -4927780, 13964546, 12525942, -2314107, -10566315, 32243863, 15603849, 5154154, 4276633, -20918372, -15718796, -26386151, 8434696 }}; + //const point_pc_t c_point_U {{ 30807552, 984924, 23426137, -5598760, 7545909, 16325843, 993742, 2594106, -31962071, -959867, 16454190, -4091093, 1197656, 13586872, -9269020, -14133290, 1869274, 13360979, -24627258, -10663086, 2212027, 1198856, 20515811, 15870563, -23833732, 9839517, -19416306, 11567295, -4212053, 348531, -2671541, 484270, -19128078, 1236698, -16002690, 9321345, 9776066, 10711838, 11187722, -16371275 }}; + //const point_pc_t c_point_X {{ 25635916, -5459446, 5768861, 5666160, -6357364, -12939311, 29490001, -4543704, -31266450, -2582476, 23705213, 9562626, -716512, 16560168, 7947407, 2039790, -2752711, 4742449, 3356761, 16338966, 17303421, -5790717, -5684800, 12062431, -3307947, 8139265, -26544839, 12058874, 3452748, 3359034, 26514848, -6060876, 31255039, 11154418, -21741975, -3782423, -19871841, 5729859, 21754676, -12454027 }}; + //const point_pc_t c_point_H_plus_G {{ 12291435, 3330843, -3390294, 13894858, -1099584, -6848191, 12040668, -15950068, -7494633, 12566672, -5526901, -16645799, -31081168, -1095427, -13082463, 4573480, -11255691, 4344628, 33477173, 11137213, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -6229107, -9324867, 558657, 6493750, 4895261, 12642545, 9549220, 696086, 21894285, -10521807 }}; + //const point_pc_t c_point_H_minus_G {{ -28347682, 3523701, -3380175, -14453727, 4238027, -6032522, 20235758, 4091609, 12557126, -8064113, 4212476, -13419094, -114185, -7650727, -24238, 16663404, 23676363, -6819610, 18286466, 8714527, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -20450317, 13815641, -11604061, -447489, 27380225, 9400847, -8551293, -1173627, -28110171, 14241295 }}; } // namespace crypto diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index a2681642..2f31c826 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -1,5 +1,5 @@ -// Copyright (c) 2020-2021 Zano Project -// Copyright (c) 2020-2021 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2020-2024 Zano Project +// Copyright (c) 2020-2024 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @@ -11,17 +11,45 @@ namespace crypto { + namespace mp = boost::multiprecision; + extern "C" { #include "crypto/crypto-ops.h" } // extern "C" - - // // Helpers // + // returns greatest k, s.t. n**k <= v + // tests in crypto_tests_range_proofs.h + constexpr uint64_t constexpr_floor_log_n(uint64_t v, uint64_t n) + { + return (v < n || n <= 1) ? 0 : constexpr_floor_log_n(v / n, n) + 1; + } + + // returns smallest k, s.t. v <= n**k + // tests in crypto_tests_range_proofs.h + constexpr uint64_t constexpr_ceil_log_n(uint64_t v, uint64_t n) + { + return (v <= 1 || n <= 1) ? 0 : constexpr_floor_log_n(v - 1, n) + 1; + } + + // returns smallest k, s.t. v <= 2**k + // tests in crypto_tests_range_proofs.h + constexpr uint64_t constexpr_ceil_log2(uint64_t v) + { + return constexpr_ceil_log_n(v, 2); + } + + // returns base ** k + constexpr uint64_t constexpr_pow(uint64_t k, uint64_t base) + { + return k == 0 ? 1 : base * constexpr_pow(k - 1, base); + } + + template std::string pod_to_hex_reversed(const pod_t &h) { @@ -30,7 +58,8 @@ namespace crypto size_t len = sizeof h; std::string s(len * 2, ' '); - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) + { s[2 * i] = hexmap[data[len - 1 - i] >> 4]; s[2 * i + 1] = hexmap[data[len - 1 - i] & 0x0F]; } @@ -46,7 +75,8 @@ namespace crypto size_t len = sizeof h; std::string s(len * 2, ' '); - for (size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) + { s[2 * i] = hexmap[data[i] >> 4]; s[2 * i + 1] = hexmap[data[i] & 0x0F]; } @@ -70,6 +100,22 @@ namespace crypto return ss.str(); } + template + std::string pod_to_comma_separated_chars(const pod_t &h) + { + std::stringstream ss; + ss << std::hex << std::setfill('0'); + size_t len = sizeof h; + const unsigned char* p = (const unsigned char*)&h; + for (size_t i = 0; i < len; ++i) + { + ss << "'\\x" << std::setw(2) << static_cast(p[i]) << "'"; + if (i + 1 != len) + ss << ", "; + } + return ss.str(); + } + template std::string pod_to_hex_comma_separated_uint64(const pod_t &h) { @@ -87,6 +133,22 @@ namespace crypto return ss.str(); } + template + std::string pod_to_comma_separated_int32(const pod_t &h) + { + static_assert((sizeof h) % 4 == 0, "size of h should be a multiple of 32 bit"); + size_t len = (sizeof h) / 4; + std::stringstream ss; + const int32_t* p = (const int32_t*)&h; + for (size_t i = 0; i < len; ++i) + { + ss << static_cast(p[i]); + if (i + 1 != len) + ss << ", "; + } + return ss.str(); + } + template bool parse_tpod_from_hex_string(const std::string& hex_str, t_pod_type& t_pod) { @@ -125,31 +187,28 @@ namespace crypto t_pod_type parse_tpod_from_hex_string(const std::string& hex_str) { t_pod_type t_pod = AUTO_VAL_INIT(t_pod); - parse_tpod_from_hex_string(hex_str, t_pod); + crypto::parse_tpod_from_hex_string(hex_str, t_pod); // using fully qualified name to avoid Argument-Dependent Lookup issues return t_pod; } // // scalar_t - holds a 256-bit scalar, normally in [0..L-1] // - struct alignas(32) scalar_t + struct /* TODO alignas(32) */ scalar_t { union { - uint64_t m_u64[4]; - unsigned char m_s[32]; + uint64_t m_u64[4]; + unsigned char m_s[32]; + crypto::secret_key m_sk; }; - scalar_t() - {} + scalar_t() = default; // won't check scalar range validity (< L) - scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) + constexpr scalar_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) noexcept + : m_u64{a0, a1, a2, a3} { - m_u64[0] = a0; - m_u64[1] = a1; - m_u64[2] = a2; - m_u64[3] = a3; } // won't check scalar range validity (< L) @@ -205,28 +264,22 @@ namespace crypto crypto::secret_key &as_secret_key() { - return *(crypto::secret_key*)&m_s[0]; + return m_sk; } const crypto::secret_key& as_secret_key() const { - return *(const crypto::secret_key*)&m_s[0]; + return m_sk; } operator crypto::secret_key() const { - crypto::secret_key result; - memcpy(result.data, &m_s, sizeof result.data); - return result; + return m_sk; } void from_secret_key(const crypto::secret_key& sk) { - uint64_t *p_sk64 = (uint64_t*)&sk; - m_u64[0] = p_sk64[0]; - m_u64[1] = p_sk64[1]; - m_u64[2] = p_sk64[2]; - m_u64[3] = p_sk64[3]; + m_sk = sk; // assuming secret key is correct (< L), so we don't need to call reduce here } @@ -315,6 +368,14 @@ namespace crypto return *this; } + scalar_t operator-() const + { + static unsigned char zero[32] = { 0 }; + scalar_t result; + sc_sub(&result.m_s[0], zero, &m_s[0]); + return result; + } + // returns this = a * b scalar_t& assign_mul(const scalar_t& a, const scalar_t& b) { @@ -325,7 +386,7 @@ namespace crypto /* I think it has bad symantic (operator-like), consider rename/reimplement -- sowle */ - // returns this * b + c + // returns c + this * b scalar_t muladd(const scalar_t& b, const scalar_t& c) const { scalar_t result; @@ -333,13 +394,20 @@ namespace crypto return result; } - // returns this = a * b + c + // returns this = c + a * b scalar_t& assign_muladd(const scalar_t& a, const scalar_t& b, const scalar_t& c) { sc_muladd(m_s, a.m_s, b.m_s, c.m_s); return *this; } + // returns this = c - a * b + scalar_t& assign_mulsub(const scalar_t& a, const scalar_t& b, const scalar_t& c) + { + sc_mulsub(m_s, a.m_s, b.m_s, c.m_s); + return *this; + } + scalar_t reciprocal() const { scalar_t result; @@ -449,6 +517,25 @@ namespace crypto m_u64[bit_index >> 6] &= ~(1ull << (bit_index & 63)); } + // the result is guaranteed to be within [ 0; 2 ^ bits_count ) + uint64_t get_bits(uint8_t bit_index_first, uint8_t bits_count) const + { + if (bits_count == 0 || bits_count > 64) + return 0; + uint8_t bits_count_m_1 = bits_count - 1; + unsigned int bit_index_last = bit_index_first + bits_count_m_1; + if (bit_index_last > 255) + bit_index_last = 255; + + uint64_t result = m_u64[bit_index_first >> 6] >> (bit_index_first & 63); + if (bits_count_m_1 > (bit_index_last & 63)) + result |= m_u64[bit_index_last >> 6] << (bits_count_m_1 - (bit_index_last & 63)); + + uint64_t result_mask = ((1ull << bits_count_m_1) - 1) << 1 | 1; // (just because 1ull << 64 in undefined behaviour, not a 0 as one would expect) + return result & result_mask; + } + + // does not reduce static scalar_t power_of_2(uint8_t exponent) { scalar_t result = 0; @@ -459,16 +546,20 @@ namespace crypto }; // struct scalar_t // - // Global constants + // Global constants (checked in crypto_constants) // - extern const scalar_t c_scalar_1; - extern const scalar_t c_scalar_L; - extern const scalar_t c_scalar_Lm1; - extern const scalar_t c_scalar_P; - extern const scalar_t c_scalar_Pm1; - extern const scalar_t c_scalar_256m1; - extern const scalar_t c_scalar_1div8; + static constexpr scalar_t c_scalar_0 = { 0, 0, 0, 0 }; + static constexpr scalar_t c_scalar_1 = { 1, 0, 0, 0 }; + static constexpr scalar_t c_scalar_2p64 = { 0, 1, 0, 0 }; + static constexpr scalar_t c_scalar_L = { 0x5812631a5cf5d3ed, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; + static constexpr scalar_t c_scalar_Lm1 = { 0x5812631a5cf5d3ec, 0x14def9dea2f79cd6, 0x0, 0x1000000000000000 }; + static constexpr scalar_t c_scalar_P = { 0xffffffffffffffed, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; + static constexpr scalar_t c_scalar_Pm1 = { 0xffffffffffffffec, 0xffffffffffffffff, 0xffffffffffffffff, 0x7fffffffffffffff }; + static constexpr scalar_t c_scalar_256m1 = { 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff }; + static constexpr scalar_t c_scalar_1div8 = { 0x6106e529e2dc2f79, 0x07d39db37d1cdad0, 0x0, 0x0600000000000000 }; + + static_assert(sizeof(scalar_t::m_sk) == sizeof(scalar_t::m_u64) && sizeof(scalar_t::m_u64) == sizeof(scalar_t::m_s), "size missmatch"); // // @@ -481,31 +572,26 @@ namespace crypto // with x = X / Z, y = Y / Z, x * y = T / Z. ge_p3 m_p3; - point_t() + point_t() = default; + + explicit point_t(const crypto::public_key& pk) // can throw std::runtime_error { + CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key"); } - explicit point_t(const crypto::public_key& pk) - { - if (!from_public_key(pk)) - zero(); - } - - point_t(const unsigned char(&v)[32]) + point_t(const unsigned char(&v)[32]) // can throw std::runtime_error { static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch"); - if (!from_public_key(*(const crypto::public_key*)v)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (char[32])"); } - point_t(const uint64_t(&v)[4]) + point_t(const uint64_t(&v)[4]) // can throw std::runtime_error { static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch"); - if (!from_public_key(*(const crypto::public_key*)v)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (uint64_t[4])"); } - point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) + point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) // can throw std::runtime_error { crypto::public_key pk; ((uint64_t*)&pk)[0] = a0; @@ -513,8 +599,7 @@ namespace crypto ((uint64_t*)&pk)[2] = a2; ((uint64_t*)&pk)[3] = a3; - if (!from_public_key(pk)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key (four uint64_t)"); } explicit point_t(tag_zero&&) @@ -522,6 +607,21 @@ namespace crypto zero(); } + explicit point_t(const key_image& ki) // can throw std::runtime_error + : point_t(static_cast(static_cast(ki))) + { + } + + explicit constexpr point_t(const int32_t(&v)[40]) noexcept + : m_p3{ + {v[ 0], v[ 1], v[ 2], v[ 3], v[ 4], v[ 5], v[ 6], v[ 7], v[ 8], v[9]}, + {v[10], v[11], v[12], v[13], v[14], v[15], v[16], v[17], v[18], v[19]}, + {v[20], v[21], v[22], v[23], v[24], v[25], v[26], v[27], v[28], v[29]}, + {v[30], v[31], v[32], v[33], v[34], v[35], v[36], v[37], v[38], v[39]} + } + { + } + // as we're using additive notation, zero means identity group element (EC point (0, 1)) here and after void zero() { @@ -530,9 +630,13 @@ namespace crypto bool is_zero() const { - // (0, 1) ~ (0, z, z, 0) + // (0, 1) ~ (0, z, z, 0) for any non-zero z https://www.rfc-editor.org/rfc/rfc8032#page-17 if (fe_isnonzero(m_p3.X) != 0) - return false; + return false; // x != 0 + if (fe_isnonzero(m_p3.Z) == 0) + return false; // z == 0 + if (fe_isnonzero(m_p3.T) != 0) + return false; // t != 0 fe y_minus_z; fe_sub(y_minus_z, m_p3.Y, m_p3.Z); return fe_isnonzero(y_minus_z) == 0; @@ -625,14 +729,15 @@ namespace crypto friend point_t operator*(const scalar_t& lhs, const point_t& rhs) { point_t result; - ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3); + //ge_scalarmult_p3(&result.m_p3, lhs.m_s, &rhs.m_p3); + ge_scalarmult_vartime_p3(&result.m_p3, lhs.m_s, &rhs.m_p3); return result; } point_t& operator*=(const scalar_t& rhs) { - // TODO: ge_scalarmult_vartime_p3 - ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3); + //ge_scalarmult_p3(&m_p3, rhs.m_s, &m_p3); + ge_scalarmult_vartime_p3(&m_p3, rhs.m_s, &m_p3); return *this; } @@ -641,7 +746,17 @@ namespace crypto point_t result; scalar_t reciprocal; sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]); - ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3); + //ge_scalarmult_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3); + ge_scalarmult_vartime_p3(&result.m_p3, &reciprocal.m_s[0], &lhs.m_p3); + return result; + } + + point_t operator-() const + { + point_t result = *this; + fe zero = {0}; + fe_sub(result.m_p3.Y, zero, result.m_p3.Y); + fe_sub(result.m_p3.Z, zero, result.m_p3.Z); return result; } @@ -651,6 +766,24 @@ namespace crypto return *this; } + point_t modify_mul_pow_2(size_t power) + { + if (power > 0) + { + ge_p1p1 p1; + ge_p2 p2; + ge_p3_to_p2(&p2, &m_p3); + for (size_t i = 1; i < power; ++i) + { + ge_p2_dbl(&p1, &p2); + ge_p1p1_to_p2(&p2, &p1); + } + ge_p2_dbl(&p1, &p2); + ge_p1p1_to_p3(&m_p3, &p1); + } + return *this; + } + // returns a * this + G point_t mul_plus_G(const scalar_t& a) const { @@ -678,6 +811,8 @@ namespace crypto friend bool operator==(const point_t& lhs, const point_t& rhs) { + // TODO: @#@# (performance) consider checking (lhs - rhs).is_zero() instead + // convert to xy form, then compare components (because (x, y, z, t) representation is not unique) fe lrecip, lx, ly; fe rrecip, rx, ry; @@ -696,12 +831,32 @@ namespace crypto return false; return true; - }; + } friend bool operator!=(const point_t& lhs, const point_t& rhs) { return !(lhs == rhs); - }; + } + + friend bool operator==(const point_t& lhs, const public_key& rhs) + { + return lhs.to_public_key() == rhs; + } + + friend bool operator!=(const point_t& lhs, const public_key& rhs) + { + return !(lhs == rhs); + } + + friend bool operator==(const public_key& lhs, const point_t& rhs) + { + return lhs == rhs.to_public_key(); + } + + friend bool operator!=(const public_key& lhs, const point_t& rhs) + { + return !(lhs == rhs); + } friend std::ostream& operator<<(std::ostream& ss, const point_t &v) { @@ -733,6 +888,11 @@ namespace crypto return pod_to_hex_comma_separated_uint64(pk); } + std::string to_comma_separated_int32_str() const + { + return pod_to_comma_separated_int32(m_p3); + } + }; // struct point_t @@ -741,16 +901,16 @@ namespace crypto // struct point_g_t : public point_t { - point_g_t() + explicit constexpr point_g_t(const int32_t(&v)[40]) noexcept + : point_t(v) { - scalar_t one(1); - ge_scalarmult_base(&m_p3, &one.m_s[0]); } friend point_t operator*(const scalar_t& lhs, const point_g_t&) { point_t result; - ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]); + //ge_scalarmult_base(&result.m_p3, &lhs.m_s[0]); + ge_scalarmult_base_vartime(&result.m_p3, &lhs.m_s[0]); return result; } @@ -759,7 +919,8 @@ namespace crypto point_t result; scalar_t reciprocal; sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]); - ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]); + //ge_scalarmult_base(&result.m_p3, &reciprocal.m_s[0]); + ge_scalarmult_base_vartime(&result.m_p3, &reciprocal.m_s[0]); return result; } @@ -768,6 +929,42 @@ namespace crypto }; // struct point_g_t + void construct_precomp_data(precomp_data_t precomp_data, const point_t& point); + + // + // point_pc_t -- point with 30kB of precomputed data, which make possible to do very fast single scalar multiplication + // + struct point_pc_t : public point_t + { + constexpr point_pc_t(const int32_t(&v)[40], const precomp_data_t* precomp_data_p) + : point_t(v) + , m_precomp_data_p(precomp_data_p) + { + //construct_precomp_data(m_precomp_data, *this); + } + + friend point_t operator*(const scalar_t& lhs, const point_pc_t& self) + { + point_t result; + ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &lhs.m_s[0]); + return result; + } + + friend point_t operator/(const point_pc_t& self, const scalar_t& rhs) + { + point_t result; + scalar_t reciprocal; + sc_invert(&reciprocal.m_s[0], &rhs.m_s[0]); + ge_scalarmult_precomp_vartime(&result.m_p3, *self.m_precomp_data_p, &reciprocal.m_s[0]); + return result; + } + + static_assert(sizeof(crypto::public_key) == 32, "size error"); + + const precomp_data_t* m_precomp_data_p; + }; // struct point_pc_t + + // // vector of scalars // @@ -845,8 +1042,11 @@ namespace crypto // zeroes all elements void zero() { + PUSH_GCC_WARNINGS + DISABLE_GCC_AND_CLANG_WARNING(class-memaccess) size_t size_bytes = sizeof(scalar_t) * size(); memset(data(), 0, size_bytes); + POP_GCC_WARNINGS } // invert all elements in-place efficiently: 4*N muptiplications + 1 inversion @@ -885,6 +1085,19 @@ namespace crypto scalar_t calc_hs() const; + void make_random() + { + for(size_t size = this->size(), i = 0; i < size; ++i) + at(i).make_random(); + } + + void resize_and_make_random(size_t size) + { + this->resize(size); + make_random(); + } + + }; // scalar_vec_t @@ -909,14 +1122,29 @@ namespace crypto // - // Global constants + // Global constants (checked in crypto_constants and crypto_generators_precomp tests) // - extern const point_g_t c_point_G; + namespace xdetails + { + extern const precomp_data_t c_point_H_precomp_data; + extern const precomp_data_t c_point_H2_precomp_data; + extern const precomp_data_t c_point_U_precomp_data; + extern const precomp_data_t c_point_X_precomp_data; + extern const precomp_data_t c_point_H_plus_G_precomp_data; + extern const precomp_data_t c_point_H_minus_G_precomp_data; + }; + + inline constexpr point_t c_point_0 {{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }}; + inline constexpr point_g_t c_point_G {{ 25485296, 5318399, 8791791, -8299916, -14349720, 6939349, -3324311, -7717049, 7287234, -6577708, -758052, -1832720, 13046421, -4857925, 6576754, 14371947, -13139572, 6845540, -2198883, -4003719, -947565, 6097708, -469190, 10704810, -8556274, -15589498, -16424464, -16608899, 14028613, -5004649, 6966464, -2456167, 7033433, 6781840, 28785542, 12262365, -2659449, 13959020, -21013759, -5262166 }}; + + inline constexpr point_pc_t c_point_H {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }, &xdetails::c_point_H_precomp_data }; + inline constexpr point_pc_t c_point_H2 {{ 1318371, 14804112, 12545972, -13482561, -12089798, -16020744, -21221907, -8410994, -33080606, 11275578, 3807637, 11185450, -23227561, -12892068, 1356866, -1025012, -8022738, -8139671, -20315029, -13916324, -6475650, -7025596, 12403179, -5139984, -12068178, 10445584, -14826705, -4927780, 13964546, 12525942, -2314107, -10566315, 32243863, 15603849, 5154154, 4276633, -20918372, -15718796, -26386151, 8434696 }, &xdetails::c_point_H2_precomp_data }; + inline constexpr point_pc_t c_point_U {{ 30807552, 984924, 23426137, -5598760, 7545909, 16325843, 993742, 2594106, -31962071, -959867, 16454190, -4091093, 1197656, 13586872, -9269020, -14133290, 1869274, 13360979, -24627258, -10663086, 2212027, 1198856, 20515811, 15870563, -23833732, 9839517, -19416306, 11567295, -4212053, 348531, -2671541, 484270, -19128078, 1236698, -16002690, 9321345, 9776066, 10711838, 11187722, -16371275 }, &xdetails::c_point_U_precomp_data }; + inline constexpr point_pc_t c_point_X {{ 25635916, -5459446, 5768861, 5666160, -6357364, -12939311, 29490001, -4543704, -31266450, -2582476, 23705213, 9562626, -716512, 16560168, 7947407, 2039790, -2752711, 4742449, 3356761, 16338966, 17303421, -5790717, -5684800, 12062431, -3307947, 8139265, -26544839, 12058874, 3452748, 3359034, 26514848, -6060876, 31255039, 11154418, -21741975, -3782423, -19871841, 5729859, 21754676, -12454027 }, &xdetails::c_point_X_precomp_data }; + inline constexpr point_pc_t c_point_H_plus_G {{ 12291435, 3330843, -3390294, 13894858, -1099584, -6848191, 12040668, -15950068, -7494633, 12566672, -5526901, -16645799, -31081168, -1095427, -13082463, 4573480, -11255691, 4344628, 33477173, 11137213, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -6229107, -9324867, 558657, 6493750, 4895261, 12642545, 9549220, 696086, 21894285, -10521807 }, &xdetails::c_point_H_plus_G_precomp_data }; + inline constexpr point_pc_t c_point_H_minus_G {{ -28347682, 3523701, -3380175, -14453727, 4238027, -6032522, 20235758, 4091609, 12557126, -8064113, 4212476, -13419094, -114185, -7650727, -24238, 16663404, 23676363, -6819610, 18286466, 8714527, -3837023, -12436594, -8471924, -814016, 10785607, 9492721, 10992667, 7406385, -5687296, -127915, -20450317, 13815641, -11604061, -447489, 27380225, 9400847, -8551293, -1173627, -28110171, 14241295 }, &xdetails::c_point_H_minus_G_precomp_data }; - extern const point_t c_point_H; - extern const point_t c_point_H2; - extern const point_t c_point_0; // // hash functions' helper @@ -938,11 +1166,17 @@ namespace crypto return scalar_t(crypto::cn_fast_hash(str.c_str(), str.size())); // will reduce mod L } + static hash h(const std::string& str) + { + return crypto::cn_fast_hash(str.c_str(), str.size()); + } + struct hs_t { - hs_t() + hs_t(size_t size_to_reserve = 0) { static_assert(sizeof(scalar_t) == sizeof(crypto::public_key), "unexpected size of data"); + m_elements.reserve(size_to_reserve); } void reserve(size_t elements_count) @@ -984,6 +1218,11 @@ namespace crypto m_elements.emplace_back(pk); } + void add_key_image(const crypto::key_image& ki) + { + m_elements.emplace_back(ki); + } + scalar_t& access_scalar(size_t index) { return m_elements[index].scalar; @@ -1012,6 +1251,16 @@ namespace crypto m_elements.emplace_back(key_image_array[i]); } + void add_hash(const hash& h) + { + m_elements.emplace_back(h); + } + + void add_32_chars(const char(&str32)[32]) + { + m_elements.emplace_back(str32); + } + scalar_t calc_hash(bool clear = true) { size_t data_size_bytes = m_elements.size() * sizeof(item_t); @@ -1022,6 +1271,16 @@ namespace crypto return scalar_t(hash); // this will reduce to L } + hash calc_hash_no_reduce(bool clear = true) + { + size_t data_size_bytes = m_elements.size() * sizeof(item_t); + hash result; + crypto::cn_fast_hash(m_elements.data(), data_size_bytes, result); + if (clear) + this->clear(); + return result; + } + void assign_calc_hash(scalar_t& result, bool clear = true) { static_assert(sizeof result == sizeof(crypto::hash), "size missmatch"); @@ -1038,17 +1297,24 @@ namespace crypto item_t(const scalar_t& scalar) : scalar(scalar) {} item_t(const crypto::public_key& pk) : pk(pk) {} item_t(const crypto::key_image& ki) : ki(ki) {} + item_t(const crypto::hash& h) : h(h) {} + item_t(const char(&str32)[32]) { memcpy(c, str32, sizeof c); } scalar_t scalar; crypto::public_key pk; crypto::key_image ki; + crypto::hash h; + char c[32]; }; + static_assert(sizeof(item_t::c) == sizeof(item_t::pk), "size missmatch"); + static_assert(sizeof(item_t::h) == sizeof(item_t::pk), "size missmatch"); + std::vector m_elements; }; static scalar_t hs(const scalar_t& s, const std::vector& ps0, const std::vector& ps1) { - hs_t hs_calculator; + hs_t hs_calculator(3); hs_calculator.add_scalar(s); hs_calculator.add_points_array(ps0); hs_calculator.add_points_array(ps1); @@ -1058,7 +1324,7 @@ namespace crypto static scalar_t hs(const crypto::hash& s, const std::vector& ps0, const std::vector& ps1) { static_assert(sizeof(crypto::hash) == sizeof(scalar_t), "size missmatch"); - hs_t hs_calculator; + hs_t hs_calculator(3); hs_calculator.add_scalar(*reinterpret_cast(&s)); hs_calculator.add_pub_keys_array(ps0); hs_calculator.add_key_images_array(ps1); @@ -1067,12 +1333,79 @@ namespace crypto static scalar_t hs(const std::vector& ps0, const std::vector& ps1) { - hs_t hs_calculator; + hs_t hs_calculator(2); hs_calculator.add_points_array(ps0); hs_calculator.add_points_array(ps1); return hs_calculator.calc_hash(); } + static scalar_t hs(const char(&str32)[32], const scalar_t& s) + { + hs_t hs_calculator(2); + hs_calculator.add_32_chars(str32); + hs_calculator.add_scalar(s); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const char(&str32)[32], const scalar_t& s, const crypto::public_key& pk) + { + hs_t hs_calculator(2); + hs_calculator.add_32_chars(str32); + hs_calculator.add_scalar(s); + hs_calculator.add_pub_key(pk); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const crypto::public_key& pk, const uint64_t i) + { + hs_t hs_calculator(2); + hs_calculator.add_pub_key(pk); + hs_calculator.add_scalar(scalar_t(i)); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const crypto::secret_key& sk, const uint64_t i) + { + hs_t hs_calculator(2); + hs_calculator.add_scalar(sk); + hs_calculator.add_scalar(scalar_t(i)); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const char(&str32)[32], const crypto::public_key& pk, const uint64_t i) + { + hs_t hs_calculator(3); + hs_calculator.add_32_chars(str32); + hs_calculator.add_pub_key(pk); + hs_calculator.add_scalar(scalar_t(i)); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const char(&str32)[32], const crypto::hash& h) + { + hs_t hs_calculator(2); + hs_calculator.add_32_chars(str32); + hs_calculator.add_hash(h); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const char(&str32)[32], const crypto::point_t& p) + { + hs_t hs_calculator(2); + hs_calculator.add_32_chars(str32); + hs_calculator.add_point(p); + return hs_calculator.calc_hash(); + } + + static scalar_t hs(const char(&str32)[32], const crypto::key_derivation& derivation, uint64_t index) + { + hs_t hs_calculator(3); + hs_calculator.add_32_chars(str32); + hs_calculator.add_pub_key(reinterpret_cast(derivation)); + hs_calculator.add_scalar(index); + return hs_calculator.calc_hash(); + } + static point_t hp(const point_t& p) { point_t result; @@ -1104,6 +1437,13 @@ namespace crypto return result; } + static point_t hp(const std::string& str) + { + point_t result; + ge_bytes_hash_to_ec(&result.m_p3, str.data(), str.size()); + return result; + } + }; // hash_helper_t struct @@ -1111,7 +1451,6 @@ namespace crypto { // hs won't touch memory if size is 0, so it's safe return hash_helper_t::hs(data(), sizeof(scalar_t) * size()); - } - + } } // namespace crypto diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index a1e0c64c..37701cd7 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2022 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -19,9 +19,9 @@ #include "hash.h" #if !defined(NDEBUG) -# define crypto_assert(expression) assert(expression) +# define crypto_assert(expression) assert(expression); CRYPTO_CHECK_AND_THROW_MES(expression, #expression) #else -# define crypto_assert(expression) ((void)0) +# define crypto_assert(expression) CRYPTO_CHECK_AND_THROW_MES(expression, #expression) #endif namespace crypto { @@ -187,7 +187,8 @@ namespace crypto { return true; } - static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { + void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) + { struct { key_derivation derivation; char output_index[(sizeof(size_t) * 8 + 6) / 7]; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 64df2444..160929f8 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -17,6 +17,9 @@ #include "hash.h" #include "warnings.h" +#define CRYPTO_STR_(X) #X +#define CRYPTO_STR(X) CRYPTO_STR_(X) +#define CRYPTO_CHECK_AND_THROW_MES(cond, msg) if (!(cond)) { throw std::runtime_error(msg " @ " __FILE__ ":" CRYPTO_STR(__LINE__)); } PUSH_GCC_WARNINGS DISABLE_CLANG_WARNING(unused-private-field) @@ -86,6 +89,8 @@ namespace crypto { friend bool secret_key_to_public_key(const secret_key &, public_key &); static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); + static void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &); + friend void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &); static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &); @@ -174,6 +179,10 @@ namespace crypto { inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) { return crypto_ops::generate_key_derivation(key1, key2, derivation); } + inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &result) { + crypto::crypto_ops::derivation_to_scalar(derivation, output_index, result); + } + inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key) { return crypto_ops::derive_public_key(derivation, output_index, base, derived_key); diff --git a/src/crypto/msm.cpp b/src/crypto/msm.cpp new file mode 100644 index 00000000..628d905a --- /dev/null +++ b/src/crypto/msm.cpp @@ -0,0 +1,25 @@ +// Copyright (c) 2023-2023 Zano Project +// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#include "epee/include/misc_log_ex.h" +//#include "zarcanum.h" +#include "msm.h" +//#include "../currency_core/crypto_config.h" // TODO: move it to the crypto +//#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto + +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + +namespace crypto +{ + + + +} // namespace crypto diff --git a/src/crypto/msm.h b/src/crypto/msm.h new file mode 100644 index 00000000..218b55f6 --- /dev/null +++ b/src/crypto/msm.h @@ -0,0 +1,173 @@ +// Copyright (c) 2023-2023 Zano Project (https://zano.org/) +// Copyright (c) 2023-2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +#pragma once + +// This file contains Multi-Scalar Multiplication routines + +#include "epee/include/misc_log_ex.h" +#include "crypto-sugar.h" + +namespace crypto +{ + + template + bool msm_and_check_zero_naive(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand) + { + CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized"); + CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized"); + + point_t result = summand; + + for (size_t i = 0; i < g_scalars.size(); ++i) + result += g_scalars[i] * CT::get_generator(false, i); + + for (size_t i = 0; i < h_scalars.size(); ++i) + result += h_scalars[i] * CT::get_generator(true, i); + + if (!result.is_zero()) + { + LOG_PRINT_L0("msm result is non zero: " << result); + return false; + } + return true; + } + + + // https://eprint.iacr.org/2022/999.pdf + // "Pippenger algorithm [1], and its variant that is widely used in the ZK space is called the bucket method" + template + bool msm_and_check_zero_pippenger_v3(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand, uint8_t c) + { + // TODO: with c = 8 and with direct access got much worse result than with c = 7 and get_bits() for N = 128..256, consider checking again for bigger datasets (N>256) + // TODO: consider preparing a cached generators' points + + CHECK_AND_ASSERT_MES(g_scalars.size() <= CT::c_bpp_mn_max, false, "g_scalars oversized"); + CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized"); + CHECK_AND_ASSERT_MES(c < 10, false, "c is too big"); + + size_t C = 1ull << c; + + // k_max * c + (c-1) >= max_bit_idx + // + // max_bit_idx - (c - 1) max_bit_idx - (c - 1) + (c - 1) max_bit_idx + // k_max = ceil ( --------------------- ) = floor ( ------------------------------ ) = floor ( ----------- ) + // c c c + const size_t b = 253; // the maximum number of bits in x https://eprint.iacr.org/2022/999.pdf TODO: we may also scan for maximum bit used in all the scalars if all the scalars are small + const size_t max_bit_idx = b - 1; + const size_t k_max = max_bit_idx / c; + const size_t K = k_max + 1; + + std::vector buckets(C * K); + std::vector buckets_inited(C * K); + std::vector Sk(K); + std::vector Sk_inited(K); + std::vector Gk(K); + std::vector Gk_inited(K); + + // first loop, calculate partial bucket sums + for (size_t n = 0; n < g_scalars.size(); ++n) + { + for (size_t k = 0; k < K; ++k) + { + uint64_t l = g_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1] + if (l != 0) + { + size_t bucket_id = l * K + k; + if (buckets_inited[bucket_id]) + buckets[bucket_id] += CT::get_generator(false, n); + else + { + buckets[bucket_id] = CT::get_generator(false, n); + buckets_inited[bucket_id] = true; + } + } + } + } + // still the first loop (continued) + for (size_t n = 0; n < h_scalars.size(); ++n) + { + for (size_t k = 0; k < K; ++k) + { + uint64_t l = h_scalars[n].get_bits((uint8_t)(k * c), c); // l in [0; 2^c-1] + if (l != 0) + { + size_t bucket_id = l * K + k; + if (buckets_inited[bucket_id]) + buckets[bucket_id] += CT::get_generator(true, n); + else + { + buckets[bucket_id] = CT::get_generator(true, n); + buckets_inited[bucket_id] = true; + } + } + } + } + + // the second loop + for (size_t l = C - 1; l > 0; --l) + { + for (size_t k = 0; k < K; ++k) + { + size_t bucket_id = l * K + k; + if (buckets_inited[bucket_id]) + { + if (Sk_inited[k]) + Sk[k] += buckets[bucket_id]; + else + { + Sk[k] = buckets[bucket_id]; + Sk_inited[k] = true; + } + } + + if (Sk_inited[k]) + { + if (Gk_inited[k]) + Gk[k] += Sk[k]; + else + { + Gk[k] = Sk[k]; + Gk_inited[k] = true; + } + } + } + } + + // the third loop: Horner’s rule + point_t result = Gk_inited[K - 1] ? Gk[K - 1] : c_point_0; + for (size_t k = K - 2; k != SIZE_MAX; --k) + { + result.modify_mul_pow_2(c); + if (Gk_inited[k]) + result += Gk[k]; + } + + result += summand; + + if (!result.is_zero()) + { + LOG_PRINT_L0("multiexp result is non zero: " << result); + return false; + } + + return true; + } + + + + + + // Just switcher + + template + bool msm_and_check_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand) + { + //return msm_and_check_zero_naive(g_scalars, h_scalars, summand); + return msm_and_check_zero_pippenger_v3(g_scalars, h_scalars, summand, 7); + } + + + +} // namespace crypto diff --git a/src/crypto/one_out_of_many_proofs.cpp b/src/crypto/one_out_of_many_proofs.cpp new file mode 100644 index 00000000..a30374c1 --- /dev/null +++ b/src/crypto/one_out_of_many_proofs.cpp @@ -0,0 +1,322 @@ +// Copyright (c) 2023 Zano Project +// Copyright (c) 2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#include "one_out_of_many_proofs.h" +#include "../currency_core/crypto_config.h" +#include "epee/include/misc_log_ex.h" + +//DISABLE_GCC_AND_CLANG_WARNING(unused-function) + +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + +namespace crypto +{ + static const size_t N_max = 256; + static const size_t mn_max = 16; + + const point_t& get_BGE_generator(size_t index, bool& ok) + { + static std::vector precalculated_generators; + if (precalculated_generators.empty()) + { + precalculated_generators.resize(mn_max * 2); + + scalar_t hash_buf[2] = { hash_helper_t::hs("Zano BGE generator"), 0 }; + + for(size_t i = 0; i < precalculated_generators.size(); ++i) + { + hash_buf[1].m_u64[0] = i; + precalculated_generators[i] = hash_helper_t::hp(&hash_buf, sizeof hash_buf); + } + } + + if (index >= mn_max * 2) + { + ok = false; + return c_point_0; + } + + ok = true; + return precalculated_generators[index]; + } + + + + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("generate_BGE_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool generate_BGE_proof(const hash& context_hash, const std::vector& ring, const scalar_t& secret, const size_t secret_index, BGE_proof& result, uint8_t* p_err /* = nullptr */) + { + static constexpr size_t n = 4; // TODO: @#@# move it out + + DBG_PRINT(" - - - generate_BGE_proof - - -"); + size_t ring_size = ring.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring_size > 0, 0); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(secret_index < ring_size, 1); + +#ifndef NDEBUG + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring[secret_index] == secret * crypto::c_point_X, 2); +#endif + + + const size_t m = std::max(static_cast(1), constexpr_ceil_log_n(ring_size, n)); + const size_t N = constexpr_pow(m, n); + const size_t mn = m * n; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(N <= N_max, 3); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(mn <= mn_max, 4); + + scalar_mat_t a_mat(mn); // m x n matrix + a_mat.zero(); + std::vector l_digits(m); // l => n-ary gidits + size_t l = secret_index; + for(size_t j = 0; j < m; ++j) + { + for(size_t i = n - 1; i != 0; --i) // [n - 1; 1] + { + a_mat(j, i).make_random(); + a_mat(j, 0) -= a_mat(j, i); // a[j; 0] = -sum( a[j; i] ), i in [1; n-1] + } + + size_t digit = l % n; // j-th digit of secret_index + l_digits[j] = digit; + l = l / n; + } + +#ifndef NDEBUG + for(size_t j = 0; j < m; ++j) + { + scalar_t a_sum{}; + for(size_t i = 0; i != n; ++i) + a_sum += a_mat(j, i); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(a_sum.is_zero(), 230); + } +#endif + + // + // coeffs calculation (naive implementation, consider optimization in future) + // + scalar_vec_t coeffs(N * m); // m x N matrix + coeffs.zero(); + for(size_t i = 0; i < N; ++i) + { + coeffs[i] = c_scalar_1; // first row is (1, ..., 1) + size_t i_tmp = i; + size_t m_bound = 1; + for(size_t j = 0; j < m; ++j) + { + size_t i_j = i_tmp % n; // j-th digit of i + i_tmp /= n; + + if (i_j == l_digits[j]) // true if j-th digits of i and l matches + { + scalar_t carry{}; + for(size_t k = 0; k < m_bound; ++k) + { + scalar_t old = coeffs[k * N + i]; + coeffs[k * N + i] *= a_mat(j, i_j); + coeffs[k * N + i] += carry; + carry = old; + } + if (m_bound < m) + coeffs[m_bound * N + i] += carry; + ++m_bound; + } + else + { + for(size_t k = 0; k < m_bound; ++k) + coeffs[k * N + i] *= a_mat(j, i_j); + } + } + } + + scalar_t r_A = scalar_t::random(); + scalar_t r_B = scalar_t::random(); + scalar_vec_t ro(m); + ro.make_random(); + + point_t A = c_point_0; + point_t B = c_point_0; + + result.Pk.clear(); + + bool r = false, r2 = false; + for(size_t j = 0; j < m; ++j) + { + for(size_t i = 0; i < n; ++i) + { + const point_t& gen_1 = get_BGE_generator((j * n + i) * 2 + 0, r); + const point_t& gen_2 = get_BGE_generator((j * n + i) * 2 + 1, r2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(r && r2, 5); + const scalar_t& a = a_mat(j, i); + A += a * gen_1 - a * a * gen_2; + if (l_digits[j] == i) + B += gen_1 - a * gen_2; + else + B += a * gen_2; + } + + point_t Pk = c_point_0; + for(size_t i = 0; i < ring_size; ++i) + Pk += coeffs[j * N + i] * ring[i]; + for(size_t i = ring_size; i < N; ++i) + Pk += coeffs[j * N + i] * ring[ring_size - 1]; + + Pk += ro[j] * c_point_X; + result.Pk.emplace_back(std::move((c_scalar_1div8 * Pk).to_public_key())); + } + + A += r_A * c_point_X; + result.A = (c_scalar_1div8 * A).to_public_key(); + B += r_B * c_point_X; + result.B = (c_scalar_1div8 * B).to_public_key(); + + hash_helper_t::hs_t hsc(1 + ring_size + 2 + m); + hsc.add_hash(context_hash); + for(auto& ring_el : ring) + hsc.add_point(c_scalar_1div8 * ring_el); + hsc.add_pub_key(result.A); + hsc.add_pub_key(result.B); + hsc.add_pub_keys_array(result.Pk); + scalar_t x = hsc.calc_hash(); + DBG_VAL_PRINT(x); + + result.f.resize(m * (n - 1)); + for(size_t j = 0; j < m; ++j) + { + for(size_t i = 1; i < n; ++i) + { + result.f[j * (n - 1) + i - 1] = a_mat(j, i); + if (l_digits[j] == i) + result.f[j * (n - 1) + i - 1] += x; + } + } + + result.y = r_A + x * r_B; + + result.z = 0; + scalar_t x_power = c_scalar_1; + for(size_t k = 0; k < m; ++k) + { + result.z -= x_power * ro[k]; + x_power *= x; + } + result.z += secret * x_power; + + return true; + } +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + //--------------------------------------------------------------- + + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("generate_BGE_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool verify_BGE_proof(const hash& context_hash, const std::vector& ring, const BGE_proof& sig, uint8_t* p_err /* = nullptr */) + { + static constexpr size_t n = 4; // TODO: @#@# move it out + + DBG_PRINT(" - - - verify_BGE_proof - - -"); + size_t ring_size = ring.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(ring_size > 0, 0); + + const size_t m = std::max(static_cast(1), constexpr_ceil_log_n(ring_size, n)); + const size_t N = constexpr_pow(m, n); + //const size_t mn = m * n; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.Pk.size() == m, 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.f.size() == m * (n - 1), 2); + + hash_helper_t::hs_t hsc(1 + ring_size + 2 + m); + hsc.add_hash(context_hash); + for(const public_key* ppk : ring) + hsc.add_pub_key(*ppk); + hsc.add_pub_key(sig.A); + hsc.add_pub_key(sig.B); + hsc.add_pub_keys_array(sig.Pk); + scalar_t x = hsc.calc_hash(); + DBG_VAL_PRINT(x); + + scalar_vec_t f0(m); // the first column f_{i,0} = x - sum{j=1}{n-1}( f_{i,j} ) + for(size_t j = 0; j < m; ++j) + { + f0[j] = x; + for(size_t i = 1; i < n; ++i) + f0[j] -= sig.f[j * (n - 1) + i - 1]; + } + + // + // 1 + // + point_t A = point_t(sig.A).modify_mul8(); + point_t B = point_t(sig.B).modify_mul8(); + + point_t Z = A + x * B; + + bool r = false, r2 = false; + for(size_t j = 0; j < m; ++j) + { + for(size_t i = 0; i < n; ++i) + { + const point_t& gen_1 = get_BGE_generator((j * n + i) * 2 + 0, r); + const point_t& gen_2 = get_BGE_generator((j * n + i) * 2 + 1, r2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(r && r2, 5); + const scalar_t& f_ji = (i == 0) ? f0[j] : sig.f[j * (n - 1) + i - 1]; + + Z -= f_ji * gen_1 + f_ji * (x - f_ji) * gen_2; + } + } + Z -= sig.y * c_point_X; + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(Z.is_zero(), 100); + + // + // 2 + // + scalar_vec_t p_vec(N); + for(size_t i = 0; i < N; ++i) + { + p_vec[i] = c_scalar_1; + size_t i_tmp = i; + for(size_t j = 0; j < m; ++j) + { + size_t i_j = i_tmp % n; // j-th digit of i + i_tmp /= n; + const scalar_t& f_jij = (i_j == 0) ? f0[j] : sig.f[j * (n - 1) + i_j - 1]; + p_vec[i] *= f_jij; + } + } + + for(size_t i = 0; i < ring_size; ++i) + Z += p_vec[i] * point_t(*ring[i]).modify_mul8(); + for(size_t i = ring_size; i < N; ++i) + Z += p_vec[i] * point_t(*ring[ring_size - 1]).modify_mul8(); + + scalar_t x_power = c_scalar_1; + for(size_t k = 0; k < m; ++k) + { + Z -= x_power * point_t(sig.Pk[k]).modify_mul8(); + x_power *= x; + } + + Z -= sig.z * c_point_X; + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(Z.is_zero(), 101); + + return true; + } + +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + +} // namespace crypto diff --git a/src/crypto/one_out_of_many_proofs.h b/src/crypto/one_out_of_many_proofs.h new file mode 100644 index 00000000..e8c3c860 --- /dev/null +++ b/src/crypto/one_out_of_many_proofs.h @@ -0,0 +1,47 @@ +// Copyright (c) 2023 Zano Project +// Copyright (c) 2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#pragma once +#include "crypto-sugar.h" + +namespace crypto +{ + // + // BGE stands for Bootle, Groth, Esgin + // + // This is a proof-of-concept implementation of a log-size one-out-of-many proof based on ideas and approaches by Bootle et al, Groth et al and Esgin et al + // + // https://eprint.iacr.org/2014/764 + // https://eprint.iacr.org/2015/643 + // https://eprint.iacr.org/2019/1287 + // + // Disclaimer: shouldn't be used in production code until the security proofs and the code are peer-reviewed. + // + + // m+2 group elements, m(n-1)+2 field elements. + // Assuming fixed n=4, m = log4(ring_sz) the size is (log4(ring_sz) + 2) group elements and (3*log4(ring_sz) + 2) or, in total, (4*log4(ring_sz) + 4) 32-bytes words + + // ring_sz = m (inputs number) + // sig_count = k (outputs number) + // thus: + // k * (log4(m) + 2) group elements and k * (3*log4(m) + 2) field elements + + struct BGE_proof + { + public_key A; // premultiplied by 1/8 + public_key B; // premultiplied by 1/8 + std::vector Pk; // premultiplied by 1/8, size = m + scalar_vec_t f; // size = m * (n - 1) + scalar_t y; + scalar_t z; + }; + + bool generate_BGE_proof(const hash& context_hash, const std::vector& ring, const scalar_t& secret, const size_t secret_index, BGE_proof& result, uint8_t* p_err = nullptr); + + + bool verify_BGE_proof(const hash& context_hash, const std::vector& ring, const BGE_proof& sig, uint8_t* p_err = nullptr); + + +} // namespace crypto diff --git a/src/crypto/range_proof_bpp.h b/src/crypto/range_proof_bpp.h index cd61ca85..db1ffa1a 100644 --- a/src/crypto/range_proof_bpp.h +++ b/src/crypto/range_proof_bpp.h @@ -23,18 +23,26 @@ namespace crypto scalar_t delta; }; -#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL -#define DBG_PRINT(x) std::cout << x << ENDL +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + template - bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr) + bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const std::vector& commitments_1div8, bpp_signature& sig, uint8_t* p_err = nullptr) { -#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ - if (p_err) { *p_err = err_code; } return false; } - + // Note: commitments_1div8 are supposed to be already calculated static_assert(CT::c_bpp_n <= 255, "too big N"); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size(), 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && values.size() == commitments_1div8.size(), 1); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3); const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size()); @@ -42,14 +50,14 @@ namespace crypto const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n; const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n; - // pre-multiply all output points by c_scalar_1div8 - // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) - - // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H - commitments.resize(values.size()); - for (size_t i = 0; i < values.size(); ++i) - CT::calc_pedersen_commitment(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]); - +#ifndef NDEBUG + for(size_t i = 0; i < values.size(); ++i) + { + point_t V{}; + CT::calc_pedersen_commitment(values[i], masks[i], V); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(point_t(*commitments_1div8[i]).modify_mul8() == V, 4); + } +#endif // s.a. BP+ paper, page 15, eq. 11 // decompose v into aL and aR: @@ -85,7 +93,7 @@ namespace crypto DBG_PRINT("initial transcript: " << e); hash_helper_t::hs_t hsc; - CT::update_transcript(hsc, e, commitments); + CT::update_transcript(hsc, e, commitments_1div8); // BP+ paper, page 15: The prover begins with sending A = g^aL h^aR h^alpha (group element) // so we calculate A0 = alpha * H + SUM(aL_i * G_i) + SUM(aR_i * H_i) @@ -96,7 +104,8 @@ namespace crypto for (size_t i = 0; i < c_bpp_mn; ++i) A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i); - // part of 1/8 defense scheme + // pre-multiply all output points by c_scalar_1div8 + // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) A0 *= c_scalar_1div8; A0.to_public_key(sig.A0); @@ -147,7 +156,7 @@ namespace crypto // aL_hat = aL - 1*z scalar_vec_t aLs_hat = aLs - z; - // aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) + // aR_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) scalar_vec_t aRs_hat = aRs + z; for (size_t i = 0; i < c_bpp_mn; ++i) aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i]; @@ -324,9 +333,27 @@ namespace crypto DBG_VAL_PRINT(sig.delta); return true; -#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE } // bpp_gen() + + // convenient overload for tests + template + bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& commitments_1div8_to_be_generated, uint8_t* p_err = nullptr) + { + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() == masks.size(), 91); + commitments_1div8_to_be_generated.resize(values.size()); + std::vector commitments_1div8(values.size()); + std::vector commitments_1div8_pointers(values.size()); + for(size_t i = 0; i < values.size(); ++i) + { + CT::calc_pedersen_commitment(c_scalar_1div8 * values[i], c_scalar_1div8 * masks[i], commitments_1div8_to_be_generated[i]); + commitments_1div8[i] = (commitments_1div8_to_be_generated[i]).to_public_key(); + commitments_1div8_pointers[i] = &commitments_1div8[i]; + } + return bpp_gen(values, masks, commitments_1div8_pointers, sig, p_err); + } +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + struct bpp_sig_commit_ref_t { @@ -335,7 +362,7 @@ namespace crypto , commitments(commitments) {} const bpp_signature& sig; - const std::vector& commitments; + const std::vector& commitments; // assumed to be premultiplied by 1/8 }; @@ -343,7 +370,7 @@ namespace crypto bool bpp_verify(const std::vector& sigs, uint8_t* p_err = nullptr) { #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . "); @@ -689,11 +716,14 @@ namespace crypto point_t GH_exponents = c_point_0; CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents); - bool result = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents); + bool result = msm_and_check_zero(g_scalars, h_scalars, summand + GH_exponents); if (result) DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL); return result; #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE } +#undef DBG_VAL_PRINT +#undef DBG_PRINT + } // namespace crypto diff --git a/src/crypto/range_proof_bppe.h b/src/crypto/range_proof_bppe.h index 7aaed80c..de786541 100644 --- a/src/crypto/range_proof_bppe.h +++ b/src/crypto/range_proof_bppe.h @@ -24,18 +24,25 @@ namespace crypto scalar_t delta_2; }; -#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL -#define DBG_PRINT(x) std::cout << x << ENDL +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + template - bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr) + bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, const std::vector& commitments_1div8, bppe_signature& sig, uint8_t* p_err = nullptr) { -#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ - if (p_err) { *p_err = err_code; } return false; } - + // Note: commitments_1div8 are supposed to be already calculated static_assert(CT::c_bpp_n <= 255, "too big N"); - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size(), 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size() && values.size() == commitments_1div8.size(), 1); CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced() && masks2.is_reduced(), 3); const size_t c_bpp_log2_m = constexpr_ceil_log2(values.size()); @@ -43,14 +50,14 @@ namespace crypto const size_t c_bpp_mn = c_bpp_m * CT::c_bpp_n; const size_t c_bpp_log2_mn = c_bpp_log2_m + CT::c_bpp_log2_n; - // pre-multiply all output points by c_scalar_1div8 - // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify()) - - // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2 - commitments.resize(values.size()); - for (size_t i = 0; i < values.size(); ++i) - CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments[i]); - +#ifndef NDEBUG + for(size_t i = 0; i < values.size(); ++i) + { + point_t V{}; + CT::calc_pedersen_commitment_2(values[i], masks[i], masks2[i], V); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(point_t(*commitments_1div8[i]).modify_mul8() == V, 4); + } +#endif // s.a. BP+ paper, page 15, eq. 11 // decompose v into aL and aR: @@ -86,7 +93,7 @@ namespace crypto DBG_PRINT("initial transcript: " << e); hash_helper_t::hs_t hsc; - CT::update_transcript(hsc, e, commitments); + CT::update_transcript(hsc, e, commitments_1div8); // Zarcanum paper, page 33, Fig. D.3: The prover chooses alpha_1, alpha_2 and computes A = g^aL h^aR h_1^alpha_1 h_2^alpha_2 // so we calculate A0 = alpha_1 * H + alpha_2 * H_2 + SUM(aL_i * G_i) + SUM(aR_i * H_i) @@ -149,7 +156,7 @@ namespace crypto // aL_hat = aL - 1*z scalar_vec_t aLs_hat = aLs - z; - // aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) + // aR_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3) scalar_vec_t aRs_hat = aRs + z; for (size_t i = 0; i < c_bpp_mn; ++i) aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i]; @@ -336,10 +343,28 @@ namespace crypto DBG_VAL_PRINT(sig.delta_2); return true; -#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE } // bppe_gen() + // convenient overload for tests + template + bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector& commitments_1div8_to_be_generated, uint8_t* p_err = nullptr) + { + // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2 + commitments_1div8_to_be_generated.resize(values.size()); + std::vector commitments_1div8(values.size()); + std::vector commitments_1div8_pointers(values.size()); + for (size_t i = 0; i < values.size(); ++i) + { + CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments_1div8_to_be_generated[i]); + commitments_1div8[i] = (commitments_1div8_to_be_generated[i]).to_public_key(); + commitments_1div8_pointers[i] = &commitments_1div8[i]; + } + return bppe_gen(values, masks, masks2, commitments_1div8_pointers, sig, p_err); + } + #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + struct bppe_sig_commit_ref_t { bppe_sig_commit_ref_t(const bppe_signature& sig, const std::vector& commitments) @@ -347,7 +372,7 @@ namespace crypto , commitments(commitments) {} const bppe_signature& sig; - const std::vector& commitments; + const std::vector& commitments; // assumed to be premultiplied by 1/8 }; @@ -355,7 +380,7 @@ namespace crypto bool bppe_verify(const std::vector& sigs, uint8_t* p_err = nullptr) { #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ - if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . "); @@ -709,11 +734,14 @@ namespace crypto point_t GH_exponents = c_point_0; CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents); - bool result = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents); + bool result = msm_and_check_zero(g_scalars, h_scalars, summand + GH_exponents); if (result) DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL); return result; #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE } +#undef DBG_VAL_PRINT +#undef DBG_PRINT + } // namespace crypto diff --git a/src/crypto/range_proofs.cpp b/src/crypto/range_proofs.cpp index 783a0c2b..fd14ec0f 100644 --- a/src/crypto/range_proofs.cpp +++ b/src/crypto/range_proofs.cpp @@ -6,4 +6,12 @@ namespace crypto { + // TODO @#@# redesign needed, consider changing to inline constexpr + const point_t& bpp_ct_generators_HGX::bpp_G = c_point_H; + const point_t& bpp_ct_generators_HGX::bpp_H = c_point_G; + const point_t& bpp_ct_generators_HGX::bpp_H2 = c_point_X; + + const point_t& bpp_ct_generators_UGX::bpp_G = c_point_U; + const point_t& bpp_ct_generators_UGX::bpp_H = c_point_G; + const point_t& bpp_ct_generators_UGX::bpp_H2 = c_point_X; } diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h index bcd03393..646f2908 100644 --- a/src/crypto/range_proofs.h +++ b/src/crypto/range_proofs.h @@ -1,5 +1,5 @@ -// Copyright (c) 2021-2022 Zano Project (https://zano.org/) -// Copyright (c) 2021-2022 sowle (val@zano.org, crypto.sowle@gmail.com) +// Copyright (c) 2021-2023 Zano Project (https://zano.org/) +// Copyright (c) 2021-2023 sowle (val@zano.org, crypto.sowle@gmail.com) // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once @@ -23,23 +23,6 @@ namespace crypto return result; } - - // returns greatest k, s.t. 2**k <= v - // tests in crypto_tests_range_proofs.h - constexpr size_t constexpr_floor_log2(size_t v) - { - return v <= 1 ? 0 : constexpr_floor_log2(v >> 1) + 1; - } - - // returns smallest k, s.t. v <= 2**k - // tests in crypto_tests_range_proofs.h - constexpr size_t constexpr_ceil_log2(size_t v) - { - return v <= 1 ? 0 : constexpr_floor_log2(v - 1) + 1; - } - - - // returns least significant bit uing de Bruijn sequence // http://graphics.stanford.edu/~seander/bithacks.html inline uint8_t calc_lsb_32(uint32_t v) @@ -56,8 +39,25 @@ namespace crypto //////////////////////////////////////// // crypto trait for Zano //////////////////////////////////////// - template - struct bpp_crypto_trait_zano + struct bpp_ct_generators_HGX + { + // NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp + static const point_t& bpp_G; + static const point_t& bpp_H; + static const point_t& bpp_H2; + }; + + struct bpp_ct_generators_UGX + { + // NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators in range_proofs.cpp + static const point_t& bpp_G; + static const point_t& bpp_H; + static const point_t& bpp_H2; + }; + + + template + struct bpp_crypto_trait_zano : gen_trait_t { static constexpr size_t c_bpp_n = N; // the upper bound for the witness's range static constexpr size_t c_bpp_values_max = values_max; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs @@ -66,12 +66,14 @@ namespace crypto static void calc_pedersen_commitment(const scalar_t& value, const scalar_t& mask, point_t& commitment) { - commitment = value * c_point_G + mask * c_point_H; + // commitment = value * bpp_G + mask * bpp_H + commitment = operator*(value, bpp_G) + mask * bpp_H; } static void calc_pedersen_commitment_2(const scalar_t& value, const scalar_t& mask1, const scalar_t& mask2, point_t& commitment) { - commitment = value * c_point_G + mask1 * c_point_H + mask2 * c_point_H2; + // commitment = value * bpp_G + mask1 * bpp_H * mask2 * bpp_H2 + commitment = operator*(value, bpp_G) + mask1 * bpp_H + mask2 * bpp_H2; } static const scalar_t& get_initial_transcript() @@ -88,7 +90,17 @@ namespace crypto e = hsc.calc_hash(); } + // assumes hsc is cleared + static void update_transcript(hash_helper_t::hs_t& hsc, scalar_t& e, const std::vector& pub_keys) + { + hsc.add_scalar(e); + for(auto p : pub_keys) + hsc.add_pub_key(*p); + e = hsc.calc_hash(); + } + // TODO: refactor with proper OOB handling + // TODO: @#@# add domain separation static const point_t& get_generator(bool select_H, size_t index) { if (index >= c_bpp_mn_max) @@ -116,42 +128,21 @@ namespace crypto return result; } - static const point_t& bpp_H; - static const point_t& bpp_H2; + using gen_trait_t::bpp_G; + using gen_trait_t::bpp_H; + using gen_trait_t::bpp_H2; }; // struct bpp_crypto_trait_zano - template - const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H; - template - const point_t& bpp_crypto_trait_zano::bpp_H2 = c_point_H2; + typedef bpp_crypto_trait_zano bpp_crypto_trait_ZC_out; - - // efficient multiexponentiation (naive stub implementation atm, TODO) - template - bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand) - { - CHECK_AND_ASSERT_MES(g_scalars.size() < CT::c_bpp_mn_max, false, "g_scalars oversized"); - CHECK_AND_ASSERT_MES(h_scalars.size() < CT::c_bpp_mn_max, false, "h_scalars oversized"); - - point_t result = summand; - - for (size_t i = 0; i < g_scalars.size(); ++i) - result += g_scalars[i] * CT::get_generator(false, i); - - for (size_t i = 0; i < h_scalars.size(); ++i) - result += h_scalars[i] * CT::get_generator(true, i); - - if (!result.is_zero()) - { - LOG_PRINT_L0("multiexp result is non zero: " << result); - return false; - } - return true; - } + typedef bpp_crypto_trait_zano bpp_crypto_trait_Zarcanum; } // namespace crypto +#include "epee/include/profile_tools.h" // <- remove this, sowle + +#include "msm.h" #include "range_proof_bpp.h" #include "range_proof_bppe.h" diff --git a/src/crypto/tree-hash.c b/src/crypto/tree-hash.c index 87423fb8..2909f319 100644 --- a/src/crypto/tree-hash.c +++ b/src/crypto/tree-hash.c @@ -8,7 +8,9 @@ #include #include "hash-ops.h" - +#ifdef _M_ARM64 + #include "malloc.h" +#endif void tree_hash(const char (*hashes)[HASH_SIZE], size_t count, char *root_hash) { assert(count > 0); if (count == 1) { diff --git a/src/crypto/zarcanum.cpp b/src/crypto/zarcanum.cpp new file mode 100644 index 00000000..e0b81f44 --- /dev/null +++ b/src/crypto/zarcanum.cpp @@ -0,0 +1,425 @@ +// Copyright (c) 2022-2023 Zano Project +// Copyright (c) 2022-2023 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +// Note: This file originates from tests/functional_tests/crypto_tests.cpp +#include "epee/include/misc_log_ex.h" +#include "zarcanum.h" +#include "range_proofs.h" +#include "../currency_core/crypto_config.h" // TODO: move it to the crypto +#include "../common/crypto_stream_operators.h" // TODO: move it to the crypto + +#if 0 +# define DBG_VAL_PRINT(x) std::cout << std::setw(30) << std::left << #x ": " << x << std::endl +# define DBG_PRINT(x) std::cout << x << std::endl +#else +# define DBG_VAL_PRINT(x) (void(0)) +# define DBG_PRINT(x) (void(0)) +#endif + +namespace crypto +{ + const scalar_t c_zarcanum_z_coeff_s = { 0, 1, 0, 0 }; // c_scalar_2p64 + const mp::uint256_t c_zarcanum_z_coeff_mp = c_zarcanum_z_coeff_s.as_boost_mp_type(); + + template + inline std::ostream &operator <<(std::ostream &o, const std::vector &v) + { + for(size_t i = 0, n = v.size(); i < n; ++i) + o << ENDL << " [" << std::setw(2) << i << "]: " << v[i]; + return o; + } + + mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty) + { + //LOG_PRINT_GREEN_L0(ENDL << "floor( l / (z * D) ) = " << c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty)); + return c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty); // == floor( l / (z * D) ) + } + + mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty) + { + //LOG_PRINT_GREEN_L0(ENDL << "z * floor( l / (z * D) ) = " << c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty))); + return c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * pos_difficulty)); // == z * floor( l / (z * D) ) + } + + bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q, + const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint512_t& rhs) + { + scalar_t lhs_s = scalar_t(kernel_hash) * (blinding_mask + secret_q + last_pow_block_id_hashed); // == h * (f + q + f') mod l + lhs = lhs_s.as_boost_mp_type(); + rhs = static_cast(z_l_div_z_D) * stake_amount; // == floor( l / (z * D) ) * z * a + + //LOG_PRINT_GREEN_L0(ENDL << + // "z_l_div_z_D = " << z_l_div_z_D << ENDL << + // "stake_amount = " << stake_amount << ENDL << + // "lhs = " << lhs << ENDL << + // "rhs = " << rhs); + + return lhs < rhs; // h * (f + q + f') mod l < floor( l / (z * D) ) * z * a + } + + #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, uint64_t stake_amount, + const scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& stake_out_amount_blinding_mask, const scalar_t& pseudo_out_amount_blinding_mask, + zarcanum_proof& result, uint8_t* p_err /* = nullptr */) + { + DBG_PRINT("zarcanum_generate_proof"); + const scalar_t a = stake_amount; + const scalar_t h = scalar_t(kernel_hash); + const scalar_t f_plus_q = stake_out_amount_blinding_mask + secret_q; + const scalar_t f_plus_q_plus_fp = f_plus_q + last_pow_block_id_hashed; + const scalar_t lhs = h * f_plus_q_plus_fp; // == h * (f + q + f') mod l + const mp::uint256_t d_mp = lhs.as_boost_mp_type() / (c_zarcanum_z_coeff_mp * stake_amount) + 1; + result.d = scalar_t(d_mp); + + const scalar_t dz = result.d * c_zarcanum_z_coeff_s; + + const scalar_t ba = dz * a - lhs; // b_a = dza - h(f + q + f') + + const scalar_t bf = dz * f_plus_q - h * a; // b_f = dz(f + q) - ha + + const scalar_t x0 = scalar_t::random(), x1 = scalar_t::random(), x2 = scalar_t::random(); + + const scalar_t bx = x2 - h * x1 + dz * x0; // b_x = x'' - hx' + dzx + + point_t C = x0 * c_point_X + a * c_point_H + f_plus_q * c_point_G; + point_t C_prime = x1 * c_point_X + f_plus_q * c_point_H + a * c_point_G; + point_t E = bx * c_point_X + ba * c_point_H + bf * c_point_G; + + result.C = (c_scalar_1div8 * C).to_public_key(); + result.C_prime = (c_scalar_1div8 * C_prime).to_public_key(); + result.E = (c_scalar_1div8 * E).to_public_key(); + + // three proofs with a shared Fiat-Shamir challenge c + // 1) linear composition proof for the fact, that C + C' = lin(X, H + G) = (x + x') X + (a + f + q) (H + G) + // 2) linear composition proof for the fact, that C - C' = lin(X, H - G) = (x - x') X + (a - f - q) (H - G) + // 3) Schnorr proof for the fact, that hC' - dzC + E + f'hH = lin(X) = x'' X + + point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H; + + DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz); + DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F); + + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + scalar_t r2 = scalar_t::random(); + scalar_t r3 = scalar_t::random(); + scalar_t r4 = scalar_t::random(); + + point_t R_01 = r0 * c_point_X + r1 * c_point_H_plus_G; + point_t R_23 = r2 * c_point_X + r3 * c_point_H_minus_G; + point_t R_4 = r4 * c_point_X; + + hash_helper_t::hs_t hash_calc(7); + hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH); + hash_calc.add_point(R_01); + hash_calc.add_point(R_23); + hash_calc.add_point(R_4); + hash_calc.add_point(C + C_prime); + hash_calc.add_point(C - C_prime); + hash_calc.add_point(F); + result.c = hash_calc.calc_hash(); + + result.y0 = r0 + result.c * (x0 + x1); // y_0 = r_0 + c (x + x') + result.y1 = r1 + result.c * (a + f_plus_q); // y_1 = r_1 + c (a + f + q) + result.y2 = r2 + result.c * (x0 - x1); // y_2 = r_2 + c (x - x') + result.y3 = r3 + result.c * (a - f_plus_q); // y_3 = r_3 + c (a - f - q) + result.y4 = r4 + result.c * x2; // y_4 = r_4 + c x'' + + // range proof for E + const scalar_vec_t values = { ba }; // H component + const scalar_vec_t masks = { bf }; // G component + const scalar_vec_t masks2 = { bx }; // X component + const std::vector E_1div8_vec_ptr = { &result.E }; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10); + + // = five-layers ring signature data outline = + // (j in [0, ring_size-1]) + // layer 0 ring + // A[j] ( = ring[j].stealth_address) + // layer 0 secret (with respect to G) + // secret_x + // layer 0 linkability + // stake_ki + // + // layer 1 ring + // ring[j].amount_commitment - pseudo_out_amount_commitment + // layer 1 secret (with respect to G) + // stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask ( = f_i - f'_i ) + // + // additional layer for confidential assets: + // + // layer 2 ring + // ring[j].blinded_asset_id - pseudo_out_blinded_asset_id + // layer 2 secret (with respect to X) + // -pseudo_out_asset_id_blinding_mask ( = -r'_i ) + // + // additional layers for Zarcanum: + // + // layer 3 ring + // C - A[j] - Q[j] + // layer 3 secret (with respect to X) + // x0 - a * stake_out_asset_id_blinding_mask ( = x - a * r_i ) + // + // layer 4 ring + // Q[j] + // layer 4 secret (with respect to G) + // secret_q + + // such pseudo_out_asset_id_blinding_mask effectively makes pseudo_out_blinded_asset_id == currency::native_coin_asset_id_pt == point_H + scalar_t pseudo_out_asset_id_blinding_mask = -stake_out_asset_id_blinding_mask; // T^p_i = T_i + (-r_i) * X = H + + point_t stake_out_asset_id = c_point_H + stake_out_asset_id_blinding_mask * c_point_X; // T_i = H + r_i * X + + point_t pseudo_out_amount_commitment = a * stake_out_asset_id + pseudo_out_amount_blinding_mask * c_point_G; // A^p_i = a_i * T_i + f'_i * G + result.pseudo_out_amount_commitment = (c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key(); + + TRY_ENTRY() + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXXG(m, ring, pseudo_out_amount_commitment, c_point_H, C, stake_ki, + secret_x, stake_out_amount_blinding_mask - pseudo_out_amount_blinding_mask, -pseudo_out_asset_id_blinding_mask, x0 - a * stake_out_asset_id_blinding_mask, secret_q, secret_index, + result.clsag_ggxxg), 20); + CATCH_ENTRY2(false); + + return true; + } + #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + + + #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("zarcanum_verify_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const mp::uint128_t& pos_difficulty, + const zarcanum_proof& sig, uint8_t* p_err /* = nullptr */) noexcept + { + TRY_ENTRY() + { + DBG_PRINT("zarcanum_verify_proof"); + //bool r = false; + + //std::cout << "===== zarcanum_verify_proof =====" << ENDL + // << "m: " << m << ENDL + // << "kernel_hash: " << kernel_hash << ENDL + // << "last_pow_block_id_hashed: " << last_pow_block_id_hashed << ENDL + // << "stake_ki: " << stake_ki << ENDL + // << "pos_difficulty: " << pos_difficulty << ENDL; + //size_t ii = 0; + //for(const auto& el : ring) + //{ + // std::cout << "[" << ii << "]" << ENDL + // << " amount_commitment: " << el.amount_commitment << ENDL + // << " blinded_asset_id: " << el.blinded_asset_id << ENDL + // << " concealing_point: " << el.concealing_point << ENDL + // << " stealth_address: " << el.stealth_address << ENDL; + //} + + // make sure 0 < d <= l / floor(z * D) + const mp::uint256_t l_div_z_D_mp = zarcanum_precalculate_l_div_z_D(pos_difficulty); + const scalar_t l_div_z_D(l_div_z_D_mp); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(!sig.d.is_zero() && sig.d < l_div_z_D, 2); + const scalar_t dz = sig.d * c_zarcanum_z_coeff_s; + + // calculate h + const scalar_t h = scalar_t(kernel_hash); + + // calculate F + point_t C_prime = point_t(sig.C_prime); + C_prime.modify_mul8(); + point_t C = point_t(sig.C); + C.modify_mul8(); + point_t E = point_t(sig.E); + E.modify_mul8(); + point_t F = h * C_prime - dz * C + E + last_pow_block_id_hashed * h * c_point_H; + + DBG_VAL_PRINT(h); DBG_VAL_PRINT(last_pow_block_id_hashed); DBG_VAL_PRINT(dz); + DBG_VAL_PRINT(C); DBG_VAL_PRINT(C_prime); DBG_VAL_PRINT(E); DBG_VAL_PRINT(F); + + // check three proofs with a shared Fiat-Shamir challenge c + point_t C_plus_C_prime = C + C_prime; + point_t C_minus_C_prime = C - C_prime; + hash_helper_t::hs_t hash_calc(7); + hash_calc.add_32_chars(CRYPTO_HDS_ZARCANUM_PROOF_HASH); + hash_calc.add_point(sig.y0 * c_point_X + sig.y1 * c_point_H_plus_G - sig.c * C_plus_C_prime); // y_0 * X + y1 (H + G) - c (C + C') + hash_calc.add_point(sig.y2 * c_point_X + sig.y3 * c_point_H_minus_G - sig.c * C_minus_C_prime); // y_2 * X + y3 (H - G) - c (C - C') + hash_calc.add_point(sig.y4 * c_point_X - sig.c * F); // y_4 * X - c * F + hash_calc.add_point(C_plus_C_prime); + hash_calc.add_point(C_minus_C_prime); + hash_calc.add_point(F); + scalar_t c_prime = hash_calc.calc_hash(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.c == c_prime, 3); + + // check extended range proof for E + std::vector E_for_range_proof = { point_t(sig.E) }; // consider changing to 8*sig.E to avoid additional conversion + std::vector range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) }; + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify(range_proofs), 10); + + static public_key native_coin_asset_id = (c_scalar_1div8 * c_point_H).to_public_key(); // consider making it less ugly -- sowle + + // check extended CLSAG-GGXG ring signature + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXXG(m, ring, sig.pseudo_out_amount_commitment, native_coin_asset_id, sig.C, stake_ki, sig.clsag_ggxxg), 1); + } + CATCH_ENTRY_CUSTOM2({if (p_err) *p_err = 100;}, false) + + return true; + } + + #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("generate_vector_UG_aggregation_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool generate_vector_UG_aggregation_proof(const hash& m, const scalar_vec_t& u_secrets, const scalar_vec_t& g_secrets0, const scalar_vec_t& g_secrets1, + const std::vector& amount_commitments, + const std::vector& amount_commitments_for_rp_aggregation, + const std::vector& blinded_asset_ids, + vector_UG_aggregation_proof& result, uint8_t* p_err /* = nullptr */) + { + // w - public random weighting factor + // proof of knowing e_j and y'' in zero knowledge in the following eq: + // E_j + w * E'_j = e_j * (T'_j + w * U) + (y_j + w * y'_j) * G + // where: + // e_j -- output's amount + // T'_j -- output's blinded asset tag + // E_j == e_j * T'_j + y_j * G -- output's amount commitments + // E'_j == e_j * U + y'_j * G -- additional commitment to the same amount for range proof aggregation + + // amount_commitments[j] + w * amount_commitments_for_rp_aggregation[j] + // == + // u_secrets[j] * (blinded_asset_ids[j] + w * U) + (g_secrets0[j] + w * g_secrets1[j]) * G + + const size_t n = u_secrets.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n != 0, 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == g_secrets0.size(), 2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == g_secrets1.size(), 3); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == amount_commitments.size(), 4); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == amount_commitments_for_rp_aggregation.size(), 5); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n == blinded_asset_ids.size(), 6); + + hash_helper_t::hs_t hash_calculator(1 + 3 * n); + hash_calculator.add_hash(m); + hash_calculator.add_points_array(amount_commitments); + hash_calculator.add_points_array(amount_commitments_for_rp_aggregation); + scalar_t w = hash_calculator.calc_hash(false); // don't clean the buffer + DBG_VAL_PRINT(w); + +#ifndef NDEBUG + for(size_t j = 0; j < n; ++j) + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(amount_commitments[j] + w * amount_commitments_for_rp_aggregation[j] == u_secrets[j] * (blinded_asset_ids[j] + w * c_point_U) + (g_secrets0[j] + w * g_secrets1[j]) * c_point_G, 20); +#endif + + result.amount_commitments_for_rp_aggregation.clear(); + result.y0s.clear(); + result.y1s.clear(); + + scalar_vec_t r0, r1; + r0.resize_and_make_random(n); + r1.resize_and_make_random(n); + + std::vector asset_tag_plus_U_vec(n); + for(size_t j = 0; j < n; ++j) + asset_tag_plus_U_vec[j] = blinded_asset_ids[j] + w * c_point_U; + + std::vector R(n); + for(size_t j = 0; j < n; ++j) + R[j].assign_mul_plus_G(r0[j], asset_tag_plus_U_vec[j], r1[j]); // R[j] = r0[j] * asset_tag_plus_U_vec[j] + r1[j] * G + + hash_calculator.add_points_array(R); + result.c = hash_calculator.calc_hash(); + + DBG_VAL_PRINT(asset_tag_plus_U_vec); DBG_VAL_PRINT(m); DBG_VAL_PRINT(amount_commitments); DBG_VAL_PRINT(amount_commitments_for_rp_aggregation); DBG_VAL_PRINT(R); + DBG_VAL_PRINT(result.c); + + for(size_t j = 0; j < n; ++j) + { + result.y0s.emplace_back(r0[j] - result.c * u_secrets[j]); + result.y1s.emplace_back(r1[j] - result.c * (g_secrets0[j] + w * g_secrets1[j])); + result.amount_commitments_for_rp_aggregation.emplace_back((c_scalar_1div8 * amount_commitments_for_rp_aggregation[j]).to_public_key()); + } + + return true; + } +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + +#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("verify_vector_UG_aggregation_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << (int)err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool verify_vector_UG_aggregation_proof(const hash& m, const std::vector amount_commitments_1div8, const std::vector blinded_asset_ids_1div8, + const vector_UG_aggregation_proof& sig, uint8_t* p_err /* = nullptr */) noexcept + { + TRY_ENTRY() + { + const size_t n = amount_commitments_1div8.size(); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(n > 0, 1); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(blinded_asset_ids_1div8.size() == n, 2); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.amount_commitments_for_rp_aggregation.size() == n, 3); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.y0s.size() == n, 4); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.y1s.size() == n, 5); + + hash_helper_t::hs_t hash_calculator(1 + 3 * n); + hash_calculator.add_hash(m); + DBG_VAL_PRINT(m); + + std::vector amount_commitments_pt; + for(size_t j = 0; j < n; ++j) + { + point_t A = point_t(*amount_commitments_1div8[j]).modify_mul8(); + hash_calculator.add_point(A); + amount_commitments_pt.emplace_back(A); + DBG_VAL_PRINT(A); + } + + std::vector amount_commitments_for_rp_aggregation_pt; + for(size_t j = 0; j < n; ++j) + { + point_t Arpa = point_t(sig.amount_commitments_for_rp_aggregation[j]).modify_mul8(); + hash_calculator.add_point(Arpa); // TODO @#@ performance: consider adding premultiplied by 1/8 points to the hash + amount_commitments_for_rp_aggregation_pt.emplace_back(Arpa); + DBG_VAL_PRINT(Arpa); + } + + scalar_t w = hash_calculator.calc_hash(false); // don't clear the buffer + DBG_VAL_PRINT(w); + + std::vector asset_tag_plus_U_vec(n); + for(size_t j = 0; j < n; ++j) + asset_tag_plus_U_vec[j] = point_t(*blinded_asset_ids_1div8[j]).modify_mul8() + w * c_point_U; + DBG_VAL_PRINT(asset_tag_plus_U_vec); + + for(size_t j = 0; j < n; ++j) + { + hash_calculator.add_pub_key(point_t( + sig.y0s[j] * asset_tag_plus_U_vec[j] + + sig.y1s[j] * c_point_G + + sig.c * (amount_commitments_pt[j] + w * amount_commitments_for_rp_aggregation_pt[j]) + ).to_public_key()); + DBG_VAL_PRINT(hash_calculator.m_elements.back().pk); + } + + scalar_t c = hash_calculator.calc_hash(); + DBG_VAL_PRINT(c); DBG_VAL_PRINT(sig.c); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.c == c, 0); + } + CATCH_ENTRY_CUSTOM2({if (p_err) *p_err = 100; }, false) + + return true; + } +#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE + + + +} // namespace crypto diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h new file mode 100644 index 00000000..3fe4b5c1 --- /dev/null +++ b/src/crypto/zarcanum.h @@ -0,0 +1,295 @@ +// Copyright (c) 2022-2024 Zano Project +// Copyright (c) 2022-2024 sowle (val@zano.org, crypto.sowle@gmail.com) +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +// Note: This file originates from tests/functional_tests/crypto_tests.cpp +#pragma once +#include "crypto-sugar.h" +#include "range_proofs.h" +#include "clsag.h" + +namespace crypto +{ + extern const mp::uint256_t c_zarcanum_z_coeff_mp; + extern const scalar_t c_zarcanum_z_coeff_s; + + mp::uint256_t zarcanum_precalculate_l_div_z_D(const mp::uint128_t& pos_difficulty); + mp::uint256_t zarcanum_precalculate_z_l_div_z_D(const mp::uint128_t& pos_difficulty); + + bool zarcanum_check_main_pos_inequality(const hash& kernel_hash, const scalar_t& blinding_mask, const scalar_t& secret_q, + const scalar_t& last_pow_block_id_hashed, const mp::uint256_t& z_l_div_z_D_, uint64_t stake_amount, mp::uint256_t& lhs, mp::uint512_t& rhs); + + + struct zarcanum_proof + { + scalar_t d = 0; + public_key C; // premultiplied by 1/8 + public_key C_prime; // premultiplied by 1/8 + public_key E; // premultiplied by 1/8 + + scalar_t c; // shared Fiat-Shamir challenge for the following three proofs + scalar_t y0; // 1st linear composition proof + scalar_t y1; // ( C + C' = lin(X, H + G) ) + scalar_t y2; // 2nd linear composition proof + scalar_t y3; // ( C - C' = lin(X, H - G) ) + scalar_t y4; // Schnorr proof (F = lin(X)) + + bppe_signature E_range_proof; + + public_key pseudo_out_amount_commitment; // premultiplied by 1/8 + CLSAG_GGXXG_signature clsag_ggxxg; + }; + + bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, uint64_t stake_amount, + const scalar_t& stake_out_asset_id_blinding_mask, const scalar_t& stake_out_amount_blinding_mask, const scalar_t& pseudo_out_amount_blinding_mask, + zarcanum_proof& result, uint8_t* p_err = nullptr); + + + bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const mp::uint128_t& pos_difficulty, + const zarcanum_proof& sig, uint8_t* p_err = nullptr) noexcept; + + + // TODO @#@#: make sure it is used, implement, then move it to an appropriate place + struct linear_composition_proof + { + scalar_t c; + scalar_t y0; + scalar_t y1; + }; + + enum generator_tag { gt_void = 0, gt_G = 1, gt_H = 2, gt_H2 = 3, gt_X = 4, gt_U = 5 }; + + template + bool generate_linear_composition_proof(const hash& m, const public_key& A, const scalar_t& secret_a, const scalar_t& secret_b, linear_composition_proof& result, uint8_t* p_err = nullptr) + { + // consider embedding generators' tags into random entropy to distinguish proofs made with different generators during verification + return false; + } + + template + bool verify_linear_composition_proof(const hash& m, const public_key& A, const linear_composition_proof& sig, uint8_t* p_err = nullptr) + { + return false; + } + + + struct generic_schnorr_sig + { + scalar_t c; + scalar_t y; + }; + + + template + inline bool generate_schnorr_sig_custom_generator(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result, const generator_t& g_point_g) + { +#ifndef NDEBUG + if (A != secret_a * g_point_g) + return false; +#endif + scalar_t r = scalar_t::random(); + point_t R = r * g_point_g; + hash_helper_t::hs_t hsc(3); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(R); + result.c = hsc.calc_hash(); + result.y.assign_mulsub(result.c, secret_a, r); // y = r - c * secret_a + return true; + } + + template + inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result); + + template<> + inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) + { + return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_G); + } + + template<> + inline bool generate_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result) + { + return generate_schnorr_sig_custom_generator(m, A, secret_a, result, c_point_X); + } + + inline bool generate_schnorr_sig(const hash& m, const public_key& A, const secret_key& secret_a, generic_schnorr_sig& result) + { + return generate_schnorr_sig(m, point_t(A), scalar_t(secret_a), result); + } + + + template + inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept; + + // TODO @#@# make optimized version inline bool verify_schnorr_sig(const hash& m, const point_t& A, const generic_schnorr_sig& sig) noexcept; + // and change check_tx_balance() accordingly + + template<> + inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y.is_reduced()) + return false; + hash_helper_t::hs_t hsc(3); + hsc.add_hash(m); + hsc.add_pub_key(A); + hsc.add_point(point_t(A).mul_plus_G(sig.c, sig.y)); // sig.y * G + sig.c * A + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + template<> + inline bool verify_schnorr_sig(const hash& m, const public_key& A, const generic_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y.is_reduced()) + return false; + hash_helper_t::hs_t hsc(3); + hsc.add_hash(m); + hsc.add_pub_key(A); + hsc.add_point(sig.y * c_point_X + sig.c * point_t(A)); + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + // -------------------------------------------- + + // multi-base Schnorr-like proof (two generators, two secrets, one Fiat-Shamir challenge) + struct generic_double_schnorr_sig + { + scalar_t c; + scalar_t y0; + scalar_t y1; + }; + + template + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result); + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_G || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_G; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template<> + inline bool generate_double_schnorr_sig(const hash& m, const point_t& A, const scalar_t& secret_a, const point_t& B, const scalar_t& secret_b, generic_double_schnorr_sig& result) + { +#ifndef NDEBUG + if (A != secret_a * c_point_X || B != secret_b * c_point_G) + return false; +#endif + scalar_t r0 = scalar_t::random(); + scalar_t r1 = scalar_t::random(); + point_t R0 = r0 * c_point_X; + point_t R1 = r1 * c_point_G; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_point(B); + hsc.add_point(R0); + hsc.add_point(R1); + result.c = hsc.calc_hash(); + result.y0.assign_mulsub(result.c, secret_a, r0); // y0 = r0 - c * secret_a + result.y1.assign_mulsub(result.c, secret_b, r1); // y1 = r1 - c * secret_b + return true; + } + + template + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept; + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(A.mul_plus_G(sig.c, sig.y0)); // sig.y0 * G + sig.c * A + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + template<> + inline bool verify_double_schnorr_sig(const hash& m, const point_t& A, const public_key& B, const generic_double_schnorr_sig& sig) noexcept + { + try + { + if (!sig.c.is_reduced() || !sig.y0.is_reduced() || !sig.y1.is_reduced()) + return false; + hash_helper_t::hs_t hsc(5); + hsc.add_hash(m); + hsc.add_point(A); + hsc.add_pub_key(B); + hsc.add_point(sig.y0 * c_point_X + sig.c * A); + hsc.add_point(point_t(B).mul_plus_G(sig.c, sig.y1)); // sig.y1 * G + sig.c * B + return sig.c == hsc.calc_hash(); + } + catch(...) + { + return false; + } + } + + + // TODO: improve this proof using random weightning factor + struct vector_UG_aggregation_proof + { + std::vector amount_commitments_for_rp_aggregation; // E' = e * U + y' * G, premultiplied by 1/8 + scalar_vec_t y0s; + scalar_vec_t y1s; + scalar_t c; // common challenge + }; + + bool generate_vector_UG_aggregation_proof(const hash& m, const scalar_vec_t& u_secrets, const scalar_vec_t& g_secrets0, const scalar_vec_t& g_secrets1, + const std::vector& amount_commitments, + const std::vector& amount_commitments_for_rp_aggregation, + const std::vector& blinded_asset_ids, + vector_UG_aggregation_proof& result, uint8_t* p_err = nullptr); + + bool verify_vector_UG_aggregation_proof(const hash& m, const std::vector amount_commitments_1div8, const std::vector blinded_asset_ids_1div8, + const vector_UG_aggregation_proof& sig, uint8_t* p_err = nullptr) noexcept; + + +} // namespace crypto \ No newline at end of file diff --git a/src/currency_core/bc_attachments_helpers_basic.h b/src/currency_core/bc_attachments_helpers_basic.h index 18a8e558..74039e9d 100644 --- a/src/currency_core/bc_attachments_helpers_basic.h +++ b/src/currency_core/bc_attachments_helpers_basic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -8,14 +8,54 @@ namespace bc_services { + template + struct is_boost_variant : std::false_type {}; + + template + struct is_boost_variant> : std::true_type {}; + + template + struct type_selector; + + template<> + struct type_selector + { + template + static const std::type_info& get_type(const t_type& t) + { + return t.type(); + } + template + static const t_return_type& get(const t_type& t) + { + return boost::get(t); + } + }; + + template<> + struct type_selector + { + template + static const std::type_info& get_type(const t_type& t) + { + return typeid(t); + } + template + static const t_return_type& get(const t_type& t) + { + return t; + } + }; + template bool get_first_service_attachment_by_id(const t_attachment_type_container_t& tx_items, const std::string& id, const std::string& instruction, currency::tx_service_attachment& res) { for (const auto& item : tx_items) { - if (item.type() == typeid(currency::tx_service_attachment)) + typedef type_selector::value> TS; + if (TS::get_type(item) == typeid(currency::tx_service_attachment)) { - const currency::tx_service_attachment& tsa = boost::get(item); + const currency::tx_service_attachment& tsa = TS::template get(item); if (tsa.service_id == id && tsa.instruction == instruction) { res = tsa; @@ -25,4 +65,5 @@ namespace bc_services } return false; } -} \ No newline at end of file + +} diff --git a/src/currency_core/bc_offers_serialization.h b/src/currency_core/bc_offers_serialization.h index cee1e274..f786133f 100644 --- a/src/currency_core/bc_offers_serialization.h +++ b/src/currency_core/bc_offers_serialization.h @@ -13,7 +13,7 @@ #include #include #include "common/unordered_containers_boost_serialization.h" -#include "common/crypto_boost_serialization.h" +#include "common/crypto_serialization.h" #include "offers_service_basics.h" #include "offers_services_helpers.h" diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index dd22e385..17ed1fbd 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -37,6 +37,8 @@ #include "tx_semantic_validation.h" #include "crypto/RIPEMD160_helper.h" #include "crypto/bitcoin/sha256_helper.h" +#include "crypto_config.h" + #undef LOG_DEFAULT_CHANNEL #define LOG_DEFAULT_CHANNEL "core" @@ -58,6 +60,7 @@ using namespace currency; #define BLOCKCHAIN_STORAGE_CONTAINER_ADDR_TO_ALIAS "addr_to_alias" #define BLOCKCHAIN_STORAGE_CONTAINER_TX_FEE_MEDIAN "median_fee2" #define BLOCKCHAIN_STORAGE_CONTAINER_GINDEX_INCS "gindex_increments" +#define BLOCKCHAIN_STORAGE_CONTAINER_ASSETS "assets" #define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_BLOCK_CUMUL_SZ_LIMIT 0 #define BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_PRUNED_RS_HEIGHT 1 @@ -67,15 +70,6 @@ using namespace currency; #define TARGETDATA_CACHE_SIZE DIFFICULTY_WINDOW + 10 -#ifndef TESTNET -#define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 57000 -#else -#define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 18000 -#endif -#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20 - - - DISABLE_VS_WARNINGS(4267) namespace @@ -94,6 +88,7 @@ blockchain_storage::blockchain_storage(tx_memory_pool& tx_pool) :m_db(nullptr, m m_db_multisig_outs(m_db), m_db_solo_options(m_db), m_db_aliases(m_db), + m_db_assets(m_db), m_db_addr_to_alias(m_db), m_read_lock(m_rw_lock), m_db_current_block_cumul_sz_limit(BLOCKCHAIN_STORAGE_OPTIONS_ID_CURRENT_BLOCK_CUMUL_SZ_LIMIT, m_db_solo_options), @@ -278,6 +273,8 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); res = m_db_aliases.init(BLOCKCHAIN_STORAGE_CONTAINER_ALIASES); CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); + res = m_db_assets.init(BLOCKCHAIN_STORAGE_CONTAINER_ASSETS); + CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); res = m_db_addr_to_alias.init(BLOCKCHAIN_STORAGE_CONTAINER_ADDR_TO_ALIAS); CHECK_AND_ASSERT_MES(res, false, "Unable to init db container"); res = m_db_per_block_gindex_incs.init(BLOCKCHAIN_STORAGE_CONTAINER_GINDEX_INCS); @@ -296,6 +293,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro m_db_multisig_outs.set_cache_size(cache_size); m_db_solo_options.set_cache_size(cache_size); m_db_aliases.set_cache_size(cache_size); + m_db_assets.set_cache_size(cache_size); m_db_addr_to_alias.set_cache_size(cache_size); } @@ -413,6 +411,7 @@ bool blockchain_storage::init(const std::string& config_folder, const boost::pro m_db_multisig_outs.deinit(); m_db_solo_options.deinit(); m_db_aliases.deinit(); + m_db_assets.deinit(); m_db_addr_to_alias.deinit(); m_db_per_block_gindex_incs.deinit(); m_db.close(); @@ -609,9 +608,10 @@ bool blockchain_storage::prune_ring_signatures_and_attachments(uint64_t height, "is mot equal to height = " << height << " in blockchain index, for block on height = " << height); transaction_chain_entry lolcal_chain_entry = *it; - signatures_pruned += lolcal_chain_entry.tx.signatures.size(); - attachments_pruned += lolcal_chain_entry.tx.attachment.size(); + signatures_pruned = lolcal_chain_entry.tx.signatures.size(); lolcal_chain_entry.tx.signatures.clear(); + + attachments_pruned += lolcal_chain_entry.tx.attachment.size(); lolcal_chain_entry.tx.attachment.clear(); //reassign to db @@ -658,6 +658,7 @@ bool blockchain_storage::clear() m_db_outputs.clear(); m_db_multisig_outs.clear(); m_db_aliases.clear(); + m_db_assets.clear(); m_db_addr_to_alias.clear(); m_db_per_block_gindex_incs.clear(); m_pos_targetdata_cache.clear(); @@ -707,26 +708,30 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans purge_transaction_visitor(blockchain_storage& bcs, key_images_container& spent_keys, bool strict_check): m_bcs(bcs), m_spent_keys(spent_keys), - m_strict_check(strict_check){} - - bool operator()(const txin_to_key& inp) const + m_strict_check(strict_check) + {} + bool process_input(const crypto::key_image& k_image, const std::vector& key_offsets, uint64_t amount) const { - bool r = m_spent_keys.erase_validate(inp.k_image); - CHECK_AND_ASSERT_MES( !(!r && m_strict_check), false, "purge_transaction_keyimages_from_blockchain: key image " << inp.k_image << " was not found"); + bool r = m_spent_keys.erase_validate(k_image); + CHECK_AND_ASSERT_MES(r || !m_strict_check, false, "purge_transaction_keyimages_from_blockchain: key image " << k_image << " was not found"); - if(inp.key_offsets.size() == 1) + if(key_offsets.size() == 1) { //direct spend detected - if(!m_bcs.update_spent_tx_flags_for_input(inp.amount, inp.key_offsets[0], false)) + if(!m_bcs.update_spent_tx_flags_for_input(amount, key_offsets[0], false)) { //internal error - LOG_PRINT_L0("Failed to update_spent_tx_flags_for_input"); + LOG_ERROR("update_spent_tx_flags_for_input failed"); return false; } } return true; } + bool operator()(const txin_to_key& inp) const + { + return process_input(inp.k_image, inp.key_offsets, inp.amount); + } bool operator()(const txin_gen& inp) const { return true; @@ -735,14 +740,18 @@ bool blockchain_storage::purge_transaction_keyimages_from_blockchain(const trans { if (!m_bcs.update_spent_tx_flags_for_input(inp.multisig_out_id, 0)) { - LOG_PRINT_L0("update_spent_tx_flags_for_input failed for multisig id " << inp.multisig_out_id << " amount: " << inp.amount); + LOG_ERROR("update_spent_tx_flags_for_input failed for multisig id " << inp.multisig_out_id << " amount: " << inp.amount); return false; } return true; } bool operator()(const txin_htlc& inp) const { - return this->operator()(static_cast(inp)); + return process_input(inp.k_image, inp.key_offsets, inp.amount); + } + bool operator()(const txin_zc_input& inp) const + { + return process_input(inp.k_image, inp.key_offsets, 0 /* amount */); } }; @@ -784,8 +793,8 @@ bool blockchain_storage::purge_transaction_from_blockchain(const crypto::hash& t CHECK_AND_ASSERT_MES_NO_RET(res, "pop_transaction_from_global_index failed for tx " << tx_id); bool res_erase = m_db_transactions.erase_validate(tx_id); CHECK_AND_ASSERT_MES_NO_RET(res_erase, "Failed to m_transactions.erase with id = " << tx_id); - - LOG_PRINT_L1("transaction " << tx_id << (added_to_the_pool ? " was removed from blockchain history -> to the pool" : " was removed from blockchain history")); + + LOG_PRINT_L1("transaction " << tx_id << " from block @ " << tx_res_ptr->m_keeper_block_height << (added_to_the_pool ? " was removed from blockchain history -> to the pool" : " was removed from blockchain history")); return res; } @@ -994,7 +1003,7 @@ bool blockchain_storage::rollback_blockchain_switching(std::list& CHECK_AND_ASSERT_MES(r && bvc.m_added_to_main_chain, false, "PANIC!!! failed to add (again) block while chain switching during the rollback!"); } - LOG_PRINT_L0("Rollback success."); + LOG_PRINT_L0("Rollback succeeded."); return true; } //------------------------------------------------------------------ @@ -1107,6 +1116,7 @@ bool blockchain_storage::switch_to_alternative_blockchain(alt_chain_type& alt_ch //when machine time was wrongly set for a few hours back, then blocks which was detached from main chain //couldn't be added as alternative due to timestamps validation(timestamps assumed as from future) //thanks @Gigabyted for reporting this problem + LOG_PRINT("REORGANIZE FAILED because ex-main block wasn't added as alt, but we pretend it was successfull (see also comments in sources)", LOG_LEVEL_0); break; } } @@ -1127,7 +1137,7 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con std::vector timestamps; std::vector commulative_difficulties; if (!m_db_blocks.size()) - return DIFFICULTY_STARTER; + return DIFFICULTY_POW_STARTER; //skip genesis timestamp TIME_MEASURE_START_PD(target_calculating_enum_blocks); CRITICAL_REGION_BEGIN(m_targetdata_cache_lock); @@ -1147,13 +1157,13 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional(bool pos) con wide_difficulty_type& dif = pos ? m_cached_next_pos_difficulty : m_cached_next_pow_difficulty; TIME_MEASURE_FINISH_PD(target_calculating_enum_blocks); TIME_MEASURE_START_PD(target_calculating_calc); - if (m_db_blocks.size() > m_core_runtime_config.hard_fork_01_starts_after_height) + if (m_core_runtime_config.is_hardfork_active_for_height(1, m_db_blocks.size())) { - dif = next_difficulty_2(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); + dif = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter); } else { - dif = next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); + dif = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter); } @@ -1168,7 +1178,7 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, co std::vector commulative_difficulties; size_t count = 0; if (!m_db_blocks.size()) - return DIFFICULTY_STARTER; + return DIFFICULTY_POW_STARTER; auto cb = [&](const block_extended_info& bei, bool is_main){ if (!bei.height) @@ -1186,10 +1196,10 @@ wide_difficulty_type blockchain_storage::get_next_diff_conditional2(bool pos, co enum_blockchain(cb, alt_chain, split_height); wide_difficulty_type diff = 0; - if(abei.height > m_core_runtime_config.hard_fork_01_starts_after_height) - diff = next_difficulty_2(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); + if(m_core_runtime_config.is_hardfork_active_for_height(1, abei.height)) + diff = next_difficulty_2(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter); else - diff = next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET : DIFFICULTY_POW_TARGET); + diff = next_difficulty_1(timestamps, commulative_difficulties, pos ? global_difficulty_pos_target : global_difficulty_pow_target, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter); return diff; } //------------------------------------------------------------------ @@ -1249,7 +1259,7 @@ wide_difficulty_type blockchain_storage::get_next_difficulty_for_alternative_cha commulative_difficulties.push_back(m_db_blocks[i]->cumulative_diff_precise); } - return next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET:DIFFICULTY_POW_TARGET); + return next_difficulty_1(timestamps, commulative_difficulties, pos ? DIFFICULTY_POS_TARGET:DIFFICULTY_POW_TARGET, pos ? global_difficulty_pos_starter : global_difficulty_pow_starter); } //------------------------------------------------------------------ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t height, bool pos) const @@ -1263,10 +1273,13 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t } if (pos) { - CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake transaction in the block has the wrong type"); + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name()); + else + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name()); } - if (height > m_core_runtime_config.hard_fork_01_starts_after_height) + if (m_core_runtime_config.is_hardfork_active_for_height(1, height)) { // new rules that allow different unlock time in coinbase outputs uint64_t max_unlock_time = 0; @@ -1286,7 +1299,8 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t bool r = get_tx_max_min_unlock_time(b.miner_tx, max_unlock_time, min_unlock_time); CHECK_AND_ASSERT_MES(r && max_unlock_time == min_unlock_time && min_unlock_time == height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW, false, - "coinbase transaction has wrong min_unlock_time: " << min_unlock_time << ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); + "coinbase transaction has wrong min_unlock_time: " << min_unlock_time << " or max_unlock_time: " << max_unlock_time << + ", expected: " << height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); } @@ -1297,7 +1311,19 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t return false; } - CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions."); + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms + { + CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions."); + CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 3, false, "coinbase transaction has incorrect number of proofs (" << b.miner_tx.proofs.size() << "), expected 3"); + CHECK_AND_ASSERT_MES(b.miner_tx.proofs[0].type() == typeid(zc_asset_surjection_proof), false, "coinbase transaction has incorrect type of proof #0 (expected: zc_asset_surjection_proof)"); + CHECK_AND_ASSERT_MES(b.miner_tx.proofs[1].type() == typeid(zc_outs_range_proof), false, "coinbase transaction has incorrect type of proof #1 (expected: zc_outs_range_proof)"); + CHECK_AND_ASSERT_MES(b.miner_tx.proofs[2].type() == typeid(zc_balance_proof), false, "coinbase transaction has incorrect type of proof #2 (expected: zc_balance_proof)"); + } + else + { + CHECK_AND_ASSERT_MES(b.miner_tx.attachment.empty(), false, "coinbase transaction has attachments; attachments are not allowed for coinbase transactions."); + CHECK_AND_ASSERT_MES(b.miner_tx.proofs.size() == 0, false, "pre-HF4 coinbase shoudn't have non-empty proofs containter"); + } return true; } @@ -1309,15 +1335,6 @@ bool blockchain_storage::validate_miner_transaction(const block& b, const boost::multiprecision::uint128_t& already_generated_coins) const { CRITICAL_REGION_LOCAL(m_read_lock); - //validate reward - uint64_t money_in_use = get_outs_money_amount(b.miner_tx); - - uint64_t pos_income = 0; - if (is_pos_block(b)) - { - CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "Wrong miner tx_in"); - pos_income = boost::get(b.miner_tx.vin[1]).amount; - } std::vector last_blocks_sizes; get_last_n_blocks_sizes(last_blocks_sizes, CURRENCY_REWARD_BLOCKS_WINDOW); @@ -1327,9 +1344,18 @@ bool blockchain_storage::validate_miner_transaction(const block& b, LOG_PRINT_L0("block size " << cumulative_block_size << " is bigger than allowed for this blockchain"); return false; } - if (base_reward + pos_income + fee < money_in_use) + + uint64_t block_reward = base_reward; + // before HF4: add tx fee to the block reward; after HF4: burn it + if (b.miner_tx.version < TRANSACTION_VERSION_POST_HF4) { - LOG_ERROR("coinbase transaction spend too much money (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + pos_income + fee) << "(" << print_money(base_reward) << "+" << print_money(pos_income) << "+" << print_money(fee) + block_reward += fee; + } + + crypto::hash tx_id_for_post_hf4_era = b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4 ? get_transaction_hash(b.miner_tx) : null_hash; + if (!check_tx_balance(b.miner_tx, tx_id_for_post_hf4_era, block_reward)) + { + LOG_ERROR("coinbase transaction balance check failed. Block reward is " << print_money_brief(block_reward) << "(" << print_money(base_reward) << "+" << print_money(fee) << ", blocks_size_median = " << blocks_size_median << ", cumulative_block_size = " << cumulative_block_size << ", fee = " << fee @@ -1338,17 +1364,13 @@ bool blockchain_storage::validate_miner_transaction(const block& b, LOG_PRINT_L0(currency::obj_to_json_str(b.miner_tx)); return false; } - if (base_reward + pos_income + fee != money_in_use) + + if (!verify_asset_surjection_proof(b.miner_tx, tx_id_for_post_hf4_era)) { - LOG_ERROR("coinbase transaction doesn't use full amount of block reward: spent: (" << print_money(money_in_use) << "). Block reward is " << print_money(base_reward + pos_income + fee) << "(" << print_money(base_reward) << "+" << print_money(pos_income) << "+" << print_money(fee) - << ", blocks_size_median = " << blocks_size_median - << ", cumulative_block_size = " << cumulative_block_size - << ", fee = " << fee - << ", already_generated_coins = " << already_generated_coins - << "), tx:"); - LOG_PRINT_L0(currency::obj_to_json_str(b.miner_tx)); + LOG_ERROR("asset surjection proof verification failed for miner tx"); return false; } + LOG_PRINT_MAGENTA("Mining tx verification ok, blocks_size_median = " << blocks_size_median, LOG_LEVEL_2); return true; } @@ -1385,24 +1407,25 @@ uint64_t blockchain_storage::get_current_comulative_blocksize_limit() const return m_db_current_block_cumul_sz_limit; } //------------------------------------------------------------------ -bool blockchain_storage::create_block_template(block& b, - const account_public_address& miner_address, +bool blockchain_storage::create_block_template(const account_public_address& miner_address, + const blobdata& ex_nonce, + block& b, wide_difficulty_type& diffic, - uint64_t& height, - const blobdata& ex_nonce) const + uint64_t& height) const { - return create_block_template(b, miner_address, miner_address, diffic, height, ex_nonce, false, pos_entry()); + return create_block_template(miner_address, miner_address, ex_nonce, false, pos_entry(), nullptr, b, diffic, height); } //------------------------------------------------------------------ -bool blockchain_storage::create_block_template(block& b, - const account_public_address& miner_address, +bool blockchain_storage::create_block_template(const account_public_address& miner_address, const account_public_address& stakeholder_address, - wide_difficulty_type& diffic, - uint64_t& height, - const blobdata& ex_nonce, - bool pos, + const blobdata& ex_nonce, + bool pos, const pos_entry& pe, - fill_block_template_func_t custom_fill_block_template_func /* = nullptr */) const + fill_block_template_func_t custom_fill_block_template_func, + block& b, + wide_difficulty_type& diffic, + uint64_t& height, + tx_generation_context* miner_tx_tgc_ptr /* = nullptr */) const { create_block_template_params params = AUTO_VAL_INIT(params); params.miner_address = miner_address; @@ -1413,9 +1436,12 @@ bool blockchain_storage::create_block_template(block& b, params.pcustom_fill_block_template_func = custom_fill_block_template_func; create_block_template_response resp = AUTO_VAL_INIT(resp); bool r = create_block_template(params, resp); + b = resp.b; diffic = resp.diffic; - height = resp.height; + height = resp.height; + if (miner_tx_tgc_ptr) + *miner_tx_tgc_ptr = resp.miner_tx_tgc; return r; } @@ -1425,7 +1451,8 @@ bool blockchain_storage::create_block_template(const create_block_template_param const account_public_address& stakeholder_address = params.stakeholder_address; const blobdata& ex_nonce = params.ex_nonce; bool pos = params.pos; - const pos_entry& pe = params.pe; + pos_entry pe = params.pe; + fill_block_template_func_t* pcustom_fill_block_template_func = params.pcustom_fill_block_template_func; uint64_t& height = resp.height; @@ -1436,13 +1463,19 @@ bool blockchain_storage::create_block_template(const create_block_template_param size_t median_size; boost::multiprecision::uint128_t already_generated_coins; CRITICAL_REGION_BEGIN(m_read_lock); + if (pe.g_index == WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED) + { + std::vector indexs; + if (!get_tx_outputs_gindexs(pe.tx_id, indexs) || pe.tx_out_index >= indexs.size()) + { + CHECK_AND_ASSERT_MES(false, false, "Failed to get_tx_outputs_gindexs() for tx_id " << pe.tx_id); + } + pe.g_index = indexs[pe.tx_out_index]; + } + + height = m_db_blocks.size(); - if(height <= m_core_runtime_config.hard_fork_01_starts_after_height) - b.major_version = BLOCK_MAJOR_VERSION_INITIAL; - else if(height <= m_core_runtime_config.hard_fork_03_starts_after_height) - b.major_version = HF1_BLOCK_MAJOR_VERSION; - else - b.major_version = CURRENT_BLOCK_MAJOR_VERSION; + b.major_version = m_core_runtime_config.hard_forks.get_block_major_version_by_height(height); b.minor_version = CURRENT_BLOCK_MINOR_VERSION; b.prev_id = get_top_block_id(); @@ -1478,6 +1511,8 @@ bool blockchain_storage::create_block_template(const create_block_template_param if (!block_filled) return false; + resp.txs_fee = fee; + /* instead of complicated two-phase template construction and adjustment of cumulative size with block reward we use CURRENCY_COINBASE_BLOB_RESERVED_SIZE as penalty-free coinbase transaction reservation. @@ -1487,10 +1522,15 @@ bool blockchain_storage::create_block_template(const create_block_template_param fee, miner_address, stakeholder_address, - b.miner_tx, ex_nonce, + b.miner_tx, + resp.block_reward_without_fee, + resp.block_reward, + get_tx_version(height, m_core_runtime_config.hard_forks), + ex_nonce, CURRENCY_MINER_TX_MAX_OUTS, pos, - pe); + pe, + &resp.miner_tx_tgc); CHECK_AND_ASSERT_MES(r, false, "Failed to construc miner tx, first chance"); uint64_t coinbase_size = get_object_blobsize(b.miner_tx); // "- 100" - to reserve room for PoS additions into miner tx @@ -1517,7 +1557,7 @@ bool blockchain_storage::print_transactions_statistics() const // { // total_full_blob += get_object_blobsize(tx_entry.second.tx); // transaction tx = tx_entry.second.tx; -// tx.signatures.clear(); +// signatures.clear(); // total_cropped_blob += get_object_blobsize(tx); // } // } @@ -1538,6 +1578,7 @@ void blockchain_storage::reset_db_cache() const m_db_solo_options.clear_cache(); m_db_multisig_outs.clear_cache(); m_db_aliases.clear_cache(); + m_db_assets.clear_cache(); m_db_addr_to_alias.clear_cache(); } @@ -1614,13 +1655,14 @@ bool blockchain_storage::purge_keyimage_from_big_heap(const crypto::key_image& k return true; } //------------------------------------------------------------------ -bool blockchain_storage::purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id) +bool blockchain_storage::purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& block_id) { if (is_pos_block(b)) { - CHECK_AND_ASSERT_MES(b.miner_tx.vin.size()>=2, false, "paranoid check failed"); - CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "paranoid type check failed"); - purge_keyimage_from_big_heap(boost::get(b.miner_tx.vin[1]).k_image, id); + CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 2, false, "paranoid check failed"); + crypto::key_image ki{}; + CHECK_AND_ASSERT_MES(get_key_image_from_txin_v(b.miner_tx.vin[1], ki), false, "cannot get key image from input #1"); + purge_keyimage_from_big_heap(ki, block_id); } for (auto tx_id : b.tx_hashes) { @@ -1632,10 +1674,9 @@ bool blockchain_storage::purge_altblock_keyimages_from_big_heap(const block& b, transaction& tx = *tx_ptr; for (size_t n = 0; n < tx.vin.size(); ++n) { - if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc)) - { - purge_keyimage_from_big_heap(get_to_key_input_from_txin_v(tx.vin[n]).k_image, id); - } + crypto::key_image ki = AUTO_VAL_INIT(ki); + if (get_key_image_from_txin_v(tx.vin[n], ki)) + purge_keyimage_from_big_heap(ki, block_id); } } return true; @@ -1774,9 +1815,16 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: //check if PoS block allowed on this height CHECK_AND_ASSERT_MES_CUSTOM(!(pos_block && abei.height < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block is not allowed on this height"); + // miner tx prevalidation (light checks) + if (!prevalidate_miner_transaction(b, abei.height, pos_block)) + { + LOG_PRINT_RED_L0("Alternative block " << id << " @ " << coinbase_height << "has invalid miner transaction."); + bvc.m_verification_failed = true; + return false; + } + // PoW / PoS validation (heavy checks) wide_difficulty_type current_diff = get_next_diff_conditional2(pos_block, alt_chain, connection_height, abei); - CHECK_AND_ASSERT_MES_CUSTOM(current_diff, false, bvc.m_verification_failed = true, "!!!!!!! DIFFICULTY OVERHEAD !!!!!!!"); crypto::hash proof_of_work = null_hash; @@ -1805,13 +1853,6 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: // } - if (!prevalidate_miner_transaction(b, abei.height, pos_block)) - { - LOG_PRINT_RED_L0("Block with id: " << string_tools::pod_to_hex(id) - << " (as alternative) have wrong miner transaction."); - bvc.m_verification_failed = true; - return false; - } std::unordered_set alt_block_keyimages; uint64_t ki_lookup_total = 0; if (!validate_alt_block_txs(b, id, alt_block_keyimages, abei, alt_chain, connection_height, ki_lookup_total)) @@ -1834,7 +1875,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: if (abei.height >= m_core_runtime_config.pos_minimum_heigh) cumulative_diff_delta = correct_difficulty_with_sequence_factor(sequence_factor, cumulative_diff_delta); - if (abei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && abei.height <= m_core_runtime_config.hard_fork_01_starts_after_height && pos_block && sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT) + if (abei.height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && !m_core_runtime_config.is_hardfork_active_for_height(1, abei.height) && pos_block && sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT) { LOG_PRINT_RED_L0("Alternative block " << id << " @ " << abei.height << " has too big sequence factor: " << sequence_factor << ", rejected"); bvc.m_verification_failed = true; @@ -1882,7 +1923,7 @@ bool blockchain_storage::handle_alternative_block(const block& b, const crypto:: << ENDL << "id:\t" << id << ENDL << "prev\t" << abei.bl.prev_id << ENDL << ss_pow_pos_info.str() - << ENDL << "HEIGHT " << abei.height << ", difficulty: " << abei.difficulty << ", cumul_diff_precise: " << abei.cumulative_diff_precise << ", cumul_diff_adj: " << abei.cumulative_diff_adjusted << " (current mainchain cumul_diff_adj: " << m_db_blocks.back()->cumulative_diff_adjusted << ", ki lookup total: " << ki_lookup_total <<")" + << ENDL << "HEIGHT " << abei.height << ", difficulty: " << abei.difficulty << ", cumul_diff_precise: " << abei.cumulative_diff_precise << ", cumul_diff_adj: " << abei.cumulative_diff_adjusted << ", txs: " << abei.bl.tx_hashes.size() << " (current mainchain cumul_diff_adj: " << m_db_blocks.back()->cumulative_diff_adjusted << ", total ki lookups: " << ki_lookup_total <<")" , LOG_LEVEL_0); if (is_reorganize_required(*m_db_blocks.back(), alt_chain, proof)) @@ -1959,9 +2000,9 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_ const block_extended_info& alt_chain_bei = alt_chain.back()->second; const block_extended_info& connection_point = alt_chain.front()->second; - if (connection_point.height <= m_core_runtime_config.hard_fork_01_starts_after_height) + if (!m_core_runtime_config.is_hardfork_active_for_height(1, connection_point.height)) { - //use pre-hard fork, old-style comparing + //use pre-hard fork #1, old-style comparing if (main_chain_bei.cumulative_diff_adjusted < alt_chain_bei.cumulative_diff_adjusted) return true; else if (main_chain_bei.cumulative_diff_adjusted > alt_chain_bei.cumulative_diff_adjusted) @@ -1980,7 +2021,7 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_ return true; } } - else if (alt_chain_bei.height > m_core_runtime_config.hard_fork_01_starts_after_height) + else if (m_core_runtime_config.is_hardfork_active_for_height(1, alt_chain_bei.height)) { //new rules, applied after HARD_FORK_1 //to learn this algo please read https://github.com/hyle-team/docs/blob/master/zano/PoS_Analysis_and_improvements_proposal.pdf @@ -2008,9 +2049,18 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_ wide_difficulty_type main_pow_diff_begin = get_last_alt_x_block_cumulative_precise_adj_difficulty(alt_chain_type(), connection_point.height - 1, false); main_cumul_diff.pow_diff = main_pow_diff_end - main_pow_diff_begin; - //TODO: measurement of precise cumulative difficult - boost::multiprecision::uint1024_t alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff); - boost::multiprecision::uint1024_t main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff); + boost::multiprecision::uint1024_t alt = 0; + boost::multiprecision::uint1024_t main = 0; + if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, alt_chain_bei.height)) + { + alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff); + main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff); + } + else + { + alt = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, alt_cumul_diff, main_cumul_diff); + main = get_a_to_b_relative_cumulative_difficulty(difficulty_pos_at_split_point, difficulty_pow_at_split_point, main_cumul_diff, alt_cumul_diff); + } LOG_PRINT_L1("[FORK_CHOICE]: " << ENDL << "difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL << "difficulty_pos_at_split_point:" << difficulty_pos_at_split_point << ENDL @@ -2027,6 +2077,21 @@ bool blockchain_storage::is_reorganize_required(const block_extended_info& main_ return false; else { + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + { + // prefer blocks with more summary fee(to motivate stakers include transactions) + + // since we don't have "summary block fee" field yet, we can use this_block_tx_fee_median multiplied to transactions + // count as an indirect measure of sumarry paid fee. If this approach won't be doing it's job it's subject + // to reconsider and introducing additional field in block_extended_info structure + + if (alt_chain_bei.this_block_tx_fee_median * alt_chain_bei.bl.tx_hashes.size() > + main_chain_bei.this_block_tx_fee_median * main_chain_bei.bl.tx_hashes.size()) + { + //with the rest equal, alt block has more fees in it, prefer it + return true; + } + } if (!is_pos_block(main_chain_bei.bl)) return false; // do not reorganize on the same cummul diff if it's a PoW block @@ -2465,53 +2530,78 @@ size_t blockchain_storage::get_alternative_blocks_count() const return m_alternative_chains.size(); } //------------------------------------------------------------------ -bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix) const +bool blockchain_storage::add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t g_index, uint64_t mix_count, + bool use_only_forced_to_mix, uint64_t height_upper_limit) const { CRITICAL_REGION_LOCAL(m_read_lock); - auto out_ptr = m_db_outputs.get_subitem(amount, i); + auto out_ptr = m_db_outputs.get_subitem(amount, g_index); auto tx_ptr = m_db_transactions.find(out_ptr->tx_id); - CHECK_AND_ASSERT_MES(tx_ptr, false, "internal error: transaction with id " << out_ptr->tx_id << ENDL << - ", used in mounts global index for amount=" << amount << ": i=" << i << "not found in transactions index"); + CHECK_AND_ASSERT_MES(tx_ptr, false, "internal error: transaction " << out_ptr->tx_id << " was not found in transaction DB, amount: " << print_money_brief(amount) << + ", g_index: " << g_index); CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_ptr->out_no, false, "internal error: in global outs index, transaction out index=" - << out_ptr->out_no << " more than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id); + << out_ptr->out_no << " is greater than transaction outputs = " << tx_ptr->tx.vout.size() << ", for tx id = " << out_ptr->tx_id); + + CHECK_AND_ASSERT_MES(amount != 0 || height_upper_limit != 0, false, "height_upper_limit must be nonzero for hidden amounts (amount = 0)"); + + if (height_upper_limit != 0 && tx_ptr->m_keeper_block_height > height_upper_limit) + return false; const transaction& tx = tx_ptr->tx; - if (tx.vout[out_ptr->out_no].target.type() == typeid(txout_htlc)) - { - //silently return false, it's ok - return false; - } - CHECK_AND_ASSERT_MES(tx.vout[out_ptr->out_no].target.type() == typeid(txout_to_key), false, "unknown tx out type"); - const txout_to_key& otk = boost::get(tx.vout[out_ptr->out_no].target); - - CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error"); - + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() == tx.vout.size(), false, "internal error: spent_flag.size()=" << tx_ptr->m_spent_flags.size() << ", tx.vout.size()=" << tx.vout.size()); + //do not use outputs that obviously spent for mixins if (tx_ptr->m_spent_flags[out_ptr->out_no]) return false; - - // do not use burned coins - if (otk.key == null_pkey) - return false; - + //check if transaction is unlocked if (!is_tx_spendtime_unlocked(get_tx_unlock_time(tx, out_ptr->out_no))) return false; - //use appropriate mix_attr out - uint8_t mix_attr = otk.mix_attr; + const tx_out_v& out_v = tx.vout[out_ptr->out_no]; - if(mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + // do not use burned coins + if (is_out_burned(out_v)) + return false; + + // check mix_attr + uint8_t mix_attr = CURRENCY_TO_KEY_OUT_RELAXED; + if (!get_mix_attr_from_tx_out_v(out_v, mix_attr)) + return false; // output has no mix_attr, skip it + if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) return false; //COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS call means that ring signature will have more than one entry. - else if(use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED) + else if (use_only_forced_to_mix && mix_attr == CURRENCY_TO_KEY_OUT_RELAXED) return false; //relaxed not allowed - else if(mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count) - return false;//mix_attr set to specific minimum, and mix_count is less then desired count + else if (mix_attr != CURRENCY_TO_KEY_OUT_RELAXED && mix_attr > mix_count) + return false; //mix_attr set to specific minimum, and mix_count is less then desired count + VARIANT_SWITCH_BEGIN(out_v); + VARIANT_CASE_CONST(tx_out_bare, o) + { + CHECK_AND_ASSERT_MES(amount != 0, false, "unexpected amount == 0 for tx_out_bare"); + if (o.target.type() == typeid(txout_htlc)) + { + //silently return false, it's ok + return false; + } + CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "unexpected out target type: " << o.target.type().name()); + const txout_to_key& otk = boost::get(o.target); + + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); + oen.global_amount_index = g_index; + oen.stealth_address = otk.key; + } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + { + CHECK_AND_ASSERT_MES(amount == 0, false, "unexpected amount != 0 for tx_out_zarcanum"); + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); + oen.global_amount_index = g_index; + oen.stealth_address = toz.stealth_address; + oen.amount_commitment = toz.amount_commitment; + oen.concealing_point = toz.concealing_point; + oen.blinded_asset_id = toz.blinded_asset_id; // TODO @#@# bad design, too much manual coping, consider redesign -- sowle + } + VARIANT_SWITCH_END(); - COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry& oen = *result_outs.outs.insert(result_outs.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry()); - oen.global_amount_index = i; - oen.out_key = otk.key; return true; } //------------------------------------------------------------------ @@ -2528,7 +2618,7 @@ size_t blockchain_storage::find_end_of_allowed_index(uint64_t amount) const --i; auto out_ptr = m_db_outputs.get_subitem(amount, i); auto tx_ptr = m_db_transactions.find(out_ptr->tx_id); - CHECK_AND_ASSERT_MES(tx_ptr, 0, "internal error: failed to find transaction from outputs index with tx_id=" << out_ptr->tx_id); + CHECK_AND_ASSERT_MES(tx_ptr, 0, "internal error: failed to find transaction from outputs index with tx_id=" << out_ptr->tx_id << ", amount: " << print_money_brief(amount)); if (tx_ptr->m_keeper_block_height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW <= get_current_blockchain_size()) return i+1; } while (i != 0); @@ -2538,7 +2628,10 @@ size_t blockchain_storage::find_end_of_allowed_index(uint64_t amount) const bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const { CRITICAL_REGION_LOCAL(m_read_lock); - BOOST_FOREACH(uint64_t amount, req.amounts) + LOG_PRINT_L3("[get_random_outs_for_amounts] amounts: " << req.amounts.size()); + std::map amounts_to_up_index_limit_cache; + + for(uint64_t amount : req.amounts) { COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount()); result_outs.amount = amount; @@ -2550,38 +2643,259 @@ bool blockchain_storage::get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDO } //it is not good idea to use top fresh outs, because it increases possibility of transaction canceling on split //lets find upper bound of not fresh outs - size_t up_index_limit = find_end_of_allowed_index(amount); + size_t up_index_limit = 0; + auto it_limit = amounts_to_up_index_limit_cache.find(amount); + if (it_limit == amounts_to_up_index_limit_cache.end()) + { + up_index_limit = find_end_of_allowed_index(amount); + amounts_to_up_index_limit_cache[up_index_limit]; + } + else + { + up_index_limit = it_limit->second; + } + CHECK_AND_ASSERT_MES(up_index_limit <= outs_container_size, false, "internal error: find_end_of_allowed_index returned wrong index=" << up_index_limit << ", with amount_outs.size = " << outs_container_size); - if (up_index_limit >= req.outs_count) + if (up_index_limit >= req.decoys_count) { std::set used; size_t try_count = 0; - for(uint64_t j = 0; j != req.outs_count && try_count < up_index_limit;) + for(uint64_t j = 0; j != req.decoys_count && try_count < up_index_limit;) { - size_t i = crypto::rand()%up_index_limit; - if(used.count(i)) + size_t g_index = crypto::rand() % up_index_limit; + if(used.count(g_index)) continue; - bool added = add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs); - used.insert(i); + bool added = add_out_to_get_random_outs(result_outs, amount, g_index, req.decoys_count, req.use_forced_mix_outs, req.height_upper_limit); + used.insert(g_index); if(added) ++j; ++try_count; } - if (result_outs.outs.size() < req.outs_count) + if (result_outs.outs.size() < req.decoys_count) { - LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.outs_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total"); + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0); } - }else + } + else { size_t added = 0; for (size_t i = 0; i != up_index_limit; i++) - added += add_out_to_get_random_outs(result_outs, amount, i, req.outs_count, req.use_forced_mix_outs) ? 1 : 0; - LOG_PRINT_RED_L0("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.outs_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs"); + added += add_out_to_get_random_outs(result_outs, amount, i, req.decoys_count, req.use_forced_mix_outs, req.height_upper_limit) ? 1 : 0; + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << req.decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs", LOG_LEVEL_0); } } return true; } //------------------------------------------------------------------ +bool blockchain_storage::get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +{ + size_t decoys_count = details.offsets.size(); + uint64_t amount = details.amount; + + uint64_t outs_container_size = m_db_outputs.get_item_size(details.amount); + if (!outs_container_size) + { + LOG_ERROR("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: not outs for amount " << amount << ", wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist"); + return false;//actually this is strange situation, wallet should use some real outs when it lookup for some mix, so, at least one out for this amount should exist + } + //it is not good idea to use top fresh outs, because it increases possibility of transaction canceling on split + //lets find upper bound of not fresh outs + size_t up_index_limit = 0; + auto it_limit = amounts_to_up_index_limit_cache.find(amount); + if (it_limit == amounts_to_up_index_limit_cache.end()) + { + up_index_limit = find_end_of_allowed_index(amount); + amounts_to_up_index_limit_cache[up_index_limit]; + } + else + { + up_index_limit = it_limit->second; + } + + CHECK_AND_ASSERT_MES(up_index_limit <= outs_container_size, false, "internal error: find_end_of_allowed_index returned wrong index=" << up_index_limit << ", with amount_outs.size = " << outs_container_size); + if (up_index_limit >= decoys_count) + { + std::set used; + used.insert(details.own_global_index); + for (uint64_t j = 0; j != decoys_count || used.size() >= up_index_limit;) + { + size_t g_index_initial = crypto::rand() % up_index_limit; + size_t g_index = g_index_initial; + //enumerate via whole loop from g_index to up_index_limit and then from 0 to g_index + while (true) + { + if (!used.count(g_index)) + break; + g_index++; + + if (g_index >= up_index_limit) + g_index = 0; + if (g_index == g_index_initial) + { + // we enumerated full circle and couldn't find needed amount of outs + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0); + return true; + } + } + + bool added = add_out_to_get_random_outs(result_outs, amount, g_index, decoys_count, req.use_forced_mix_outs, req.height_upper_limit); + used.insert(g_index); + if (added) + ++j; + } + if (result_outs.outs.size() < decoys_count) + { + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << result_outs.outs.size() << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total", LOG_LEVEL_0); + } + return true; + } + else + { + size_t added = 0; + for (size_t i = 0; i != up_index_limit; i++) + added += add_out_to_get_random_outs(result_outs, amount, i, decoys_count, req.use_forced_mix_outs, req.height_upper_limit) ? 1 : 0; + LOG_PRINT_YELLOW("Not enough inputs for amount " << print_money_brief(amount) << ", needed " << decoys_count << ", added " << added << " good outs from " << up_index_limit << " unlocked of " << outs_container_size << " total - respond with all good outs", LOG_LEVEL_0); + return true; + } +} +//------------------------------------------------------------------ +bool blockchain_storage::get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const +{ + std::set used; + used.insert(details.own_global_index); + for (auto offset : details.offsets) + { + + //perfectly we would need to find transaction's output on the given height, with the given probability + //of being coinbase(coinbase outputs should be included less in decoy selection algorithm) + bool is_coinbase = (crypto::rand() % 101) > req.coinbase_percents ? false : true; + + //TODO: Consider including PoW coinbase to transactions(does it needed?) + + // convert offset to estimated height + uint64_t estimated_h = this->get_current_blockchain_size() - 1 - offset; + //make sure it's after zc hardfork + if (estimated_h < m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]) + { + LOG_ERROR("Wrong estimated offset(" << offset << "), it hits zone before zarcanum hardfork"); + return false; + } + +#define TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN 10 + //try to find output around given H + std::vector selected_global_indexes; + auto process_tx = [&](const crypto::hash& tx_id) { + + auto tx_ptr = m_db_transactions.find(tx_id); + CHECK_AND_ASSERT_THROW_MES(tx_ptr, "internal error: tx_id " << tx_id << " around estimated_h = " << estimated_h << " not found in db"); + //go through tx outputs + for (size_t i = 0; i != tx_ptr->tx.vout.size(); i++) + { + if (tx_ptr->tx.vout[i].type() != typeid(tx_out_zarcanum)) + { + continue; + } + const tx_out_zarcanum& z_out = boost::get(tx_ptr->tx.vout[i]); + + // NOTE: second part of condition (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && ..) might be not accurate + // since the wallet might want to request more inputs then it planning to do mixins. For now let's keep it this way and fix + // it if we see the problems about it. + if (z_out.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX || (z_out.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND && z_out.mix_attr < details.offsets.size())) + { + continue; + } + + // skip spent outptus + if (tx_ptr->m_spent_flags[i]) + { + continue; + } + + if (used.find(tx_ptr->m_global_output_indexes[i]) != used.end()) + { + continue; + } + + // add output + // note: code that will process selected_global_indes will be revisiting transactions entries to obtain all + // needed data, that should work relatively effective because of on-top-of-db cache keep daya unserialized + selected_global_indexes.push_back(tx_ptr->m_global_output_indexes[i]); + } + + }; + + while (selected_global_indexes.size() < TARGET_RANDOM_OUTS_SELECTIOM_POOL_MIN) + { + auto block_ptr = m_db_blocks.get(estimated_h); + if (is_coinbase && is_pos_block(block_ptr->bl) ) + { + process_tx(get_transaction_hash(block_ptr->bl.miner_tx)); + } + else + { + //looking for regular output of regular transactions + for (auto tx_id : block_ptr->bl.tx_hashes) + { + process_tx(tx_id); + } + } + if(estimated_h) + estimated_h--; + else + { + //likely unusual situation when blocks enumerated all way back to genesis + //let's check if we have at least something + if (!selected_global_indexes.size()) + { + //need to regenerate offsets + return false; + } + } + } + + //pick up a random output from selected_global_indes + uint64_t global_index = selected_global_indexes[crypto::rand() % selected_global_indexes.size()]; + bool res = add_out_to_get_random_outs(result_outs, details.amount, global_index, details.offsets.size(), req.use_forced_mix_outs, req.height_upper_limit); + CHECK_AND_ASSERT_THROW_MES(res, "Failed to add_out_to_get_random_outs([" << global_index << "]) at postzarcanum era"); + used.insert(global_index); + } + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + LOG_PRINT_L3("[get_random_outs_for_amounts] amounts: " << req.amounts.size()); + std::map amounts_to_up_index_limit_cache; + uint64_t count_zarcanum_blocks = 0; + if(is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + count_zarcanum_blocks = this->get_current_blockchain_size() - m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[ZANO_HARDFORK_04_ZARCANUM]; + + + for (size_t i = 0; i != req.amounts.size(); i++) + { + uint64_t amount = req.amounts[i].amount; + //const std::vector& offsets = req.amounts[i].offsets; + COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs = *res.outs.insert(res.outs.end(), COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount()); + result_outs.amount = amount; + + bool r = false; + if (amount == 0 && count_zarcanum_blocks > 20000) + { + //zarcanum era inputs + r = get_target_outs_for_postzarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache); + } + else + { + //zarcanum era inputs + r = get_target_outs_for_amount_prezarcanum(req, req.amounts[i], result_outs, amounts_to_up_index_limit_cache); + } + if (!r) + return false; + } + return true; +} +//------------------------------------------------------------------ boost::multiprecision::uint128_t blockchain_storage::total_coins() const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -2609,6 +2923,9 @@ bool blockchain_storage::update_spent_tx_flags_for_input(uint64_t amount, const //------------------------------------------------------------------ bool blockchain_storage::update_spent_tx_flags_for_input(uint64_t amount, uint64_t global_index, bool spent) { + if (amount == 0) + return true; // fallback for hidden amounts + CRITICAL_REGION_LOCAL(m_read_lock); uint64_t outs_count = m_db_outputs.get_item_size(amount); CHECK_AND_ASSERT_MES(outs_count, false, "Amount " << amount << " have not found during update_spent_tx_flags_for_input()"); @@ -2758,7 +3075,7 @@ bool blockchain_storage::forecast_difficulty(std::vector= m_db_blocks.size() || start_index >= end_index) + { + //LOG_PRINT_L0("Wrong starter or end index set: start_index = " << start_index << ", end_index=" << end_index << ", expected max index " << m_db_blocks.size() - 1); + return true; + } + std::map summary; + + for (size_t i = start_index; i < m_db_blocks.size() && i < end_index; i++) + { + auto block_ptr = m_db_blocks[i]; + //only coin holders can vote + if(!is_pos_block(block_ptr->bl)) + continue; + r.total_pos_blocks++; + + extra_user_data eud = AUTO_VAL_INIT(eud); + if (!get_type_in_variant_container(block_ptr->bl.miner_tx.extra, eud)) + { + continue; + } + std::list> votes; + if (!currency::parse_vote(eud.buff, votes)) + { + continue; + } + for (const auto& v : votes) + { + if (v.second) + summary[v.first].yes++; + else + summary[v.first].no++; + } + } + for (const auto& s_entry : summary) + { + r.votes.push_back(s_entry.second); + r.votes.back().proposal_id = s_entry.first; + } + + return true; +} +//------------------------------------------------------------------ std::string blockchain_storage::get_blockchain_string(uint64_t start_index, uint64_t end_index) const { std::stringstream ss; @@ -2913,6 +3275,7 @@ void blockchain_storage::print_db_cache_perfeormance_data() const DB_CONTAINER_PERF_DATA_ENTRY(m_db_multisig_outs) << ENDL DB_CONTAINER_PERF_DATA_ENTRY(m_db_solo_options) << ENDL DB_CONTAINER_PERF_DATA_ENTRY(m_db_aliases) << ENDL + DB_CONTAINER_PERF_DATA_ENTRY(m_db_assets) << ENDL DB_CONTAINER_PERF_DATA_ENTRY(m_db_addr_to_alias) << ENDL //DB_CONTAINER_PERF_DATA_ENTRY(m_db_per_block_gindex_incs) << ENDL //DB_CONTAINER_PERF_DATA_ENTRY(m_tx_fee_median) << ENDL @@ -3012,10 +3375,16 @@ void blockchain_storage::print_blockchain_outs_stats() const if (!spent) ++stat.unspent; - if (!spent && p_tx->tx.vout[output_entry.out_no].target.type() == typeid(txout_to_key)) + if (!spent)// && p_tx->tx.vout[output_entry.out_no].target.type() == typeid(txout_to_key)) { - if (boost::get(p_tx->tx.vout[output_entry.out_no].target).mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) - ++stat.mixable; + VARIANT_SWITCH_BEGIN(p_tx->tx.vout[output_entry.out_no]); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_to_key) && boost::get(o.target).mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + ++stat.mixable; + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + if (toz.mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + ++stat.mixable; + VARIANT_SWITCH_END(); } return true; }; @@ -3170,7 +3539,7 @@ bool blockchain_storage::get_est_height_from_date(uint64_t date, uint64_t& res_h //we moved too much forward current_height_boundary = calculated_estimated_height; - CHECK_AND_ASSERT_MES(current_height_boundary > current_low_boundary, true, + CHECK_AND_ASSERT_MES(current_height_boundary >= current_low_boundary, true, "Internal error: current_hight_boundary(" << current_height_boundary << ") > current_low_boundary("<< current_low_boundary << ")"); uint64_t offset = (current_height_boundary - current_low_boundary)/2; if (offset <= 2) @@ -3188,7 +3557,7 @@ bool blockchain_storage::get_est_height_from_date(uint64_t date, uint64_t& res_h { //we too much in past current_low_boundary = calculated_estimated_height; - CHECK_AND_ASSERT_MES(current_height_boundary > current_low_boundary, true, + CHECK_AND_ASSERT_MES(current_height_boundary >= current_low_boundary, true, "Internal error: current_hight_boundary(" << current_height_boundary << ") > current_low_boundary(" << current_low_boundary << ")"); uint64_t offset = (current_height_boundary - current_low_boundary) / 2; if (offset <= 2) @@ -3326,30 +3695,38 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, block_verif bool blockchain_storage::push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes) { CRITICAL_REGION_LOCAL(m_read_lock); - size_t i = 0; - BOOST_FOREACH(const auto& ot, tx.vout) + size_t output_index = 0; + for(const auto& otv : tx.vout) { - if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) - { - m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, i)); - global_indexes.push_back(m_db_outputs.get_item_size(ot.amount) - 1); - if (ot.target.type() == typeid(txout_htlc) && !is_after_hardfork_3_zone()) + VARIANT_SWITCH_BEGIN(otv); + VARIANT_CASE_CONST(tx_out_bare, ot) + if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) { - LOG_ERROR("Error: Transaction with txout_htlc before is_after_hardfork_3_zone(before height " << m_core_runtime_config.hard_fork_03_starts_after_height <<")"); - return false; + m_db_outputs.push_back_item(ot.amount, global_output_entry::construct(tx_id, output_index)); + global_indexes.push_back(m_db_outputs.get_item_size(ot.amount) - 1); + + // TODO: CZ, consider removing this check + if (ot.target.type() == typeid(txout_htlc) && !is_hardfork_active(3)) + { + LOG_ERROR("Error: Transaction with txout_htlc before hardfork 3 (before height " << m_core_runtime_config.hard_forks.get_str_height_the_hardfork_active_after(3) << ")"); + return false; + } } - } - else if (ot.target.type() == typeid(txout_multisig)) - { - - crypto::hash multisig_out_id = get_multisig_out_id(tx, i); - CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); - CHECK_AND_ASSERT_MES(!m_db_multisig_outs.find(multisig_out_id), false, "Internal error: already have multisig_out_id " << multisig_out_id << "in multisig outs index"); - m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, i)); - global_indexes.push_back(0); // just stub to make other code easier - } - - ++i; + else if (ot.target.type() == typeid(txout_multisig)) + { + crypto::hash multisig_out_id = get_multisig_out_id(tx, output_index); + CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); + CHECK_AND_ASSERT_MES(!m_db_multisig_outs.find(multisig_out_id), false, "Internal error: already have multisig_out_id " << multisig_out_id << "in multisig outs index"); + m_db_multisig_outs.set(multisig_out_id, ms_output_entry::construct(tx_id, output_index)); + global_indexes.push_back(0); // just stub to make other code easier + } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + // TODO: CZ, consider using separate table for hidden amounts + m_db_outputs.push_back_item(0, global_output_entry::construct(tx_id, output_index)); + global_indexes.push_back(m_db_outputs.get_item_size(0) - 1); + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + ++output_index; } return true; } @@ -3376,13 +3753,20 @@ bool blockchain_storage::get_outs(uint64_t amount, std::list CHECK_AND_ASSERT_MES(tx_ptr, false, "transactions outs global index consistency broken: can't find tx " << out_entry_ptr->tx_id << " in DB, for amount: " << amount << ", gindex: " << i); CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() > out_entry_ptr->out_no, false, "transactions outs global index consistency broken: index in tx_outx == " << out_entry_ptr->out_no << " is greather than tx.vout size == " << tx_ptr->tx.vout.size() << ", for amount: " << amount << ", gindex: " << i); //CHECK_AND_ASSERT_MES(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key), false, "transactions outs global index consistency broken: out #" << out_entry_ptr->out_no << " in tx " << out_entry_ptr->tx_id << " has wrong type, for amount: " << amount << ", gindex: " << i); - if (tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_to_key)) - { - pkeys.push_back(boost::get(tx_ptr->tx.vout[out_entry_ptr->out_no].target).key); - }else if(tx_ptr->tx.vout[out_entry_ptr->out_no].target.type() == typeid(txout_htlc)) - { - pkeys.push_back(boost::get(tx_ptr->tx.vout[out_entry_ptr->out_no].target).pkey_redeem); - } + VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[out_entry_ptr->out_no]); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_to_key)) + { + pkeys.push_back(boost::get(o.target).key); + } + else if (o.target.type() == typeid(txout_htlc)) + { + pkeys.push_back(boost::get(o.target).pkey_redeem); + } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); } return true; @@ -3391,27 +3775,40 @@ bool blockchain_storage::get_outs(uint64_t amount, std::list bool blockchain_storage::pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id) { CRITICAL_REGION_LOCAL(m_read_lock); - size_t i = tx.vout.size()-1; - BOOST_REVERSE_FOREACH(const auto& ot, tx.vout) + + auto do_pop_output = [&](size_t i, uint64_t amount) -> bool { + uint64_t sz = m_db_outputs.get_item_size(amount); + CHECK_AND_ASSERT_MES(sz, false, "transactions outs global index: empty index for amount: " << amount); + auto back_item = m_db_outputs.get_subitem(amount, sz - 1); + CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch"); + CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch"); + m_db_outputs.pop_back_item(amount); + return true; + }; + + size_t i = tx.vout.size() - 1; + BOOST_REVERSE_FOREACH(const auto& otv, tx.vout) { - if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) - { - uint64_t sz= m_db_outputs.get_item_size(ot.amount); - CHECK_AND_ASSERT_MES(sz, false, "transactions outs global index: empty index for amount: " << ot.amount); - auto back_item = m_db_outputs.get_subitem(ot.amount, sz - 1); - CHECK_AND_ASSERT_MES(back_item->tx_id == tx_id, false, "transactions outs global index consistency broken: tx id missmatch"); - CHECK_AND_ASSERT_MES(back_item->out_no == i, false, "transactions outs global index consistency broken: in transaction index missmatch"); - m_db_outputs.pop_back_item(ot.amount); - //if (!it->second.size()) - // m_db_outputs.erase(it); - } - else if (ot.target.type() == typeid(txout_multisig)) - { - crypto::hash multisig_out_id = get_multisig_out_id(tx, i); - CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); - bool res = m_db_multisig_outs.erase_validate(multisig_out_id); - CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index"); - } + VARIANT_SWITCH_BEGIN(otv); + VARIANT_CASE_CONST(tx_out_bare, ot) + if (ot.target.type() == typeid(txout_to_key) || ot.target.type() == typeid(txout_htlc)) + { + if (!do_pop_output(i, ot.amount)) + return false; + } + else if (ot.target.type() == typeid(txout_multisig)) + { + crypto::hash multisig_out_id = get_multisig_out_id(tx, i); + CHECK_AND_ASSERT_MES(multisig_out_id != null_hash, false, "internal error during handling get_multisig_out_id() with tx id " << tx_id); + bool res = m_db_multisig_outs.erase_validate(multisig_out_id); + CHECK_AND_ASSERT_MES(res, false, "Internal error: multisig out not found, multisig_out_id " << multisig_out_id << "in multisig outs index"); + } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + // TODO: @#@# temporary comment this section and make a test for the corresponding bug + if (!do_pop_output(i, 0)) + return false; + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); --i; } return true; @@ -3427,6 +3824,14 @@ bool blockchain_storage::unprocess_blockchain_tx_extra(const transaction& tx) r = pop_alias_info(ei.m_alias); CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info"); } + + if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED) + { + crypto::public_key asset_id = currency::null_pkey; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ei.m_asset_operation, nullptr, &asset_id), false, "get_or_calculate_asset_id failed"); + r = pop_asset_info(asset_id); + CHECK_AND_ASSERT_MES(r, false, "failed to pop_alias_info"); + } return true; } //------------------------------------------------------------------ @@ -3451,6 +3856,27 @@ uint64_t blockchain_storage::get_aliases_count() const return m_db_aliases.size(); } //------------------------------------------------------------------ +bool blockchain_storage::get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& result) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + auto as_ptr = m_db_assets.find(asset_id); + if (as_ptr) + { + if (as_ptr->size()) + { + result = as_ptr->back().descriptor; + return true; + } + } + return false; +} +//------------------------------------------------------------------ +uint64_t blockchain_storage::get_assets_count() const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + return m_db_assets.size(); +} +//------------------------------------------------------------------ std::string blockchain_storage::get_alias_by_address(const account_public_address& addr)const { auto alias_ptr = m_db_addr_to_alias.find(addr); @@ -3462,6 +3888,17 @@ std::string blockchain_storage::get_alias_by_address(const account_public_addres return ""; } //------------------------------------------------------------------ +std::set blockchain_storage::get_aliases_by_address(const account_public_address& addr)const +{ + auto alias_ptr = m_db_addr_to_alias.find(addr); + if (alias_ptr && alias_ptr->size()) + { + return *(alias_ptr); + } + + return std::set(); +} +//------------------------------------------------------------------ bool blockchain_storage::pop_alias_info(const extra_alias_entry& ai) { CRITICAL_REGION_LOCAL(m_read_lock); @@ -3622,6 +4059,128 @@ bool blockchain_storage::put_alias_info(const transaction & tx, extra_alias_entr return true; } //------------------------------------------------------------------ +bool blockchain_storage::pop_asset_info(const crypto::public_key& asset_id) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + auto asset_history_ptr = m_db_assets.find(asset_id); + CHECK_AND_ASSERT_MES(asset_history_ptr && asset_history_ptr->size(), false, "empty name list in pop_asset_info"); + + assets_container::t_value_type local_asset_hist = *asset_history_ptr; + local_asset_hist.pop_back(); + if (local_asset_hist.size()) + m_db_assets.set(asset_id, local_asset_hist); + else + m_db_assets.erase(asset_id); + + LOG_PRINT_MAGENTA("[ASSET_POP]: " << asset_id << ": " << (!local_asset_hist.empty() ? "(prev)" : "(erased)"), LOG_LEVEL_1); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_ado_ownership(asset_op_verification_context& avc) +{ + asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); + bool r = get_type_in_variant_container(avc.tx.proofs, aoop); + CHECK_AND_ASSERT_MES(r, false, "Ownership validation failed - missing signature (asset_operation_ownership_proof)"); + + CHECK_AND_ASSERT_MES(avc.asset_op_history->size() != 0, false, "asset with id " << avc.asset_id << " has invalid history size() == 0"); + + crypto::public_key owner_key = avc.asset_op_history->back().descriptor.owner; + return crypto::verify_schnorr_sig(avc.tx_id, owner_key, aoop.gss); +} +//------------------------------------------------------------------ +bool blockchain_storage::put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado) +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + asset_op_verification_context avc = { tx, tx_id, ado }; + + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + + avc.asset_op_history = m_db_assets.find(avc.asset_id); + CHECK_AND_ASSERT_MES(!avc.asset_op_history, false, "asset with id " << avc.asset_id << " has already been registered"); + + avc.amount_to_validate = ado.descriptor.current_supply; + CHECK_AND_ASSERT_MES(validate_asset_operation_amount_commitment(avc), false, "asset operation validation failed!"); + + assets_container::t_value_type local_asset_history = AUTO_VAL_INIT(local_asset_history); + local_asset_history.push_back(ado); + m_db_assets.set(avc.asset_id, local_asset_history); + LOG_PRINT_MAGENTA("[ASSET_REGISTERED]: " << print_money_brief(ado.descriptor.current_supply, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + } + else + { + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(avc.ado, &avc.asset_id_pt, &avc.asset_id), false, "get_or_calculate_asset_id failed"); + avc.asset_op_history = m_db_assets.find(avc.asset_id); + + CHECK_AND_ASSERT_MES(avc.asset_op_history && avc.asset_op_history->size(), false, "asset with id " << avc.asset_id << " has not been registered"); + // check ownership permission + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE /*|| ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN*/) + { + bool r = validate_ado_ownership(avc); + CHECK_AND_ASSERT_MES(r, false, "Faild to validate ownership of asset_descriptor_operation, rejecting"); + } + + avc.amount_to_validate = 0; + bool need_to_validate_balance_proof = true; + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + //check that total current_supply haven't changed + CHECK_AND_ASSERT_MES(ado.descriptor.current_supply == avc.asset_op_history->back().descriptor.current_supply, false, "update operation attempted to change emission, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "update operation attempted to change fileds that shouldn't be modified, failed"); + need_to_validate_balance_proof = false; + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + CHECK_AND_ASSERT_MES(ado.descriptor.current_supply > avc.asset_op_history->back().descriptor.current_supply, false, "emit operation does not increase the current supply, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "emit operation is not allowed to update fields"); + CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == avc.asset_op_history->back().descriptor.meta_info, false, "emit operation is not allowed to update meta info"); + avc.amount_to_validate = ado.descriptor.current_supply - avc.asset_op_history->back().descriptor.current_supply; + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + CHECK_AND_ASSERT_MES(ado.descriptor.current_supply < avc.asset_op_history->back().descriptor.current_supply, false, "burn operation does not decrease the current supply, failed"); + CHECK_AND_ASSERT_MES(validate_ado_update_allowed(ado.descriptor, avc.asset_op_history->back().descriptor), false, "burn operation is not allowed to update fields"); + CHECK_AND_ASSERT_MES(ado.descriptor.meta_info == avc.asset_op_history->back().descriptor.meta_info, false, "burn operation is not allowed to update meta info"); + avc.amount_to_validate = avc.asset_op_history->back().descriptor.current_supply - ado.descriptor.current_supply; + } + else + { + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); + return false; + } + + if (need_to_validate_balance_proof) + { + bool r = validate_asset_operation_amount_commitment(avc); + CHECK_AND_ASSERT_MES(r, false, "Balance proof validation failed for asset_descriptor_operation"); + } + + assets_container::t_value_type local_asset_history = *avc.asset_op_history; + local_asset_history.push_back(ado); + m_db_assets.set(avc.asset_id, local_asset_history); + + switch(ado.operation_type) + { + case ASSET_DESCRIPTOR_OPERATION_UPDATE: + LOG_PRINT_MAGENTA("[ASSET_UPDATED]: " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_EMIT: + LOG_PRINT_MAGENTA("[ASSET_EMITTED]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: + LOG_PRINT_MAGENTA("[ASSET_BURNT]: " << print_money_brief(avc.amount_to_validate, ado.descriptor.decimal_point) << ", " << avc.asset_id << ": " << ado.descriptor.ticker << ", \"" << ado.descriptor.full_name << "\"", LOG_LEVEL_1); + break; + default: + LOG_ERROR("Unknown operation type: " << (int)ado.operation_type); + } + } + + return true; +} +//------------------------------------------------------------------ void blockchain_storage::set_event_handler(i_core_event_handler* event_handler) const { if (event_handler == nullptr) @@ -3644,26 +4203,12 @@ i_core_event_handler* blockchain_storage::get_event_handler() const //------------------------------------------------------------------ uint64_t blockchain_storage::validate_alias_reward(const transaction& tx, const std::string& alias) const { - - //validate alias coast uint64_t fee_for_alias = get_alias_coast(alias); - - //validate the price had been paid - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx); - - //@#@ - //work around for net 68's generation -#if CURRENCY_FORMATION_VERSION == 68 - if (alias == "bhrfrrrtret" && get_transaction_hash(tx) == epee::string_tools::parse_tpod_from_hex_string("760b85546678d2235a1843e18d8a016a2e4d9b8273cc4d7c09bebff1f6fa7eaf") ) - return true; - if (alias == "test-420" && get_transaction_hash(tx) == epee::string_tools::parse_tpod_from_hex_string("10f8a2539b2551bd0919bf7e3b1dfbae7553eca63e58cd2264ae60f90030edf8")) - return true; -#endif - - CHECK_AND_ASSERT_MES(found_alias_reward >= fee_for_alias, false, "registration of alias '" - << alias << "' goes with a reward of " << print_money(found_alias_reward) << " which is less than expected: " << print_money(fee_for_alias) - <<"(fee median: " << get_tx_fee_median() << ")" - << ", tx: " << get_transaction_hash(tx)); + uint64_t burnt_amount = 0; + CHECK_AND_ASSERT_MES(check_native_coins_amount_burnt_in_outs(tx, fee_for_alias, &burnt_amount), false, + "registration of alias '" << alias << "' failed due to incorrect reward; expected reward: " << print_money_brief(fee_for_alias) + << "; burnt amount: " << (tx.version <= TRANSACTION_VERSION_PRE_HF4 ? print_money_brief(burnt_amount) : std::string("hidden")) + << "; tx: " << get_transaction_hash(tx)); return true; } @@ -3706,7 +4251,7 @@ bool blockchain_storage::prevalidate_alias_info(const transaction& tx, const ext return true; } //------------------------------------------------------------------ -bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx) +bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id) { //check transaction extra tx_extra_info ei = AUTO_VAL_INIT(ei); @@ -3720,6 +4265,12 @@ bool blockchain_storage::process_blockchain_tx_extra(const transaction& tx) r = put_alias_info(tx, ei.m_alias); CHECK_AND_ASSERT_MES(r, false, "failed to put_alias_info"); } + if (ei.m_asset_operation.operation_type != ASSET_DESCRIPTOR_OPERATION_UNDEFINED) + { + r = put_asset_info(tx, tx_id, ei.m_asset_operation); + CHECK_AND_ASSERT_MES(r, false, "failed to put_asset_info"); + } + return true; } //------------------------------------------------------------------ @@ -3772,6 +4323,7 @@ uint64_t blockchain_storage::get_tx_fee_median() const //------------------------------------------------------------------ uint64_t blockchain_storage::get_alias_coast(const std::string& alias) const { + CRITICAL_REGION_LOCAL(m_read_lock); uint64_t median_fee = get_tx_fee_median(); //CHECK_AND_ASSERT_MES_NO_RET(median_fee, "can't calculate median"); @@ -3782,9 +4334,29 @@ uint64_t blockchain_storage::get_alias_coast(const std::string& alias) const return get_alias_coast_from_fee(alias, median_fee); } //------------------------------------------------------------------ +uint64_t blockchain_storage::get_tx_fee_window_value_median() const +{ + // calc it every time and cache it so it won't recalculated before next block + // it's effective because it's not affect sync time and needed only when node is synced + // and processing transactions + + misc_utils::median_helper mh; + for (uint64_t i = 0; i < CORE_FEE_BLOCKS_LOOKUP_WINDOW; i++) + { + uint64_t h = m_db_blocks.size() - 1 - i; + if (h >= m_db_blocks.size()) + break; + + auto block_ptr = m_db_blocks[h]; + CHECK_AND_ASSERT_THROW_MES(block_ptr, "Unexpected missing block " << h << " in get_tx_fee_window_value_median"); + mh.push_item(block_ptr->block_cumulative_size, 0); + } + + return (mh.get_median() + mh.get_avg())/2; +} +//------------------------------------------------------------------ bool blockchain_storage::unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp) { - size_t cnt_serv_attach = get_service_attachments_count_in_tx(tx); if (cnt_serv_attach == 0) return true; @@ -3816,19 +4388,18 @@ namespace currency const crypto::hash& m_tx_id; const crypto::hash& m_bl_id; const uint64_t m_bl_height; - uint64_t &m_mixins_count; - add_transaction_input_visitor(blockchain_storage& bcs, blockchain_storage::key_images_container& m_db_spent_keys, const crypto::hash& tx_id, const crypto::hash& bl_id, const uint64_t bl_height, uint64_t& mixins_count) : + uint64_t &m_max_mixins_count; + add_transaction_input_visitor(blockchain_storage& bcs, blockchain_storage::key_images_container& m_db_spent_keys, const crypto::hash& tx_id, const crypto::hash& bl_id, const uint64_t bl_height, uint64_t& max_mixins_count) : m_bcs(bcs), m_db_spent_keys(m_db_spent_keys), m_tx_id(tx_id), m_bl_id(bl_id), m_bl_height(bl_height), - m_mixins_count(mixins_count) + m_max_mixins_count(max_mixins_count) {} - bool operator()(const txin_to_key& in) const - { - const crypto::key_image& ki = in.k_image; + bool visit(uint64_t amount, const crypto::key_image& ki, const std::vector& key_offsets) const + { auto ki_ptr = m_db_spent_keys.get(ki); if (ki_ptr) { @@ -3838,27 +4409,27 @@ namespace currency } m_db_spent_keys.set(ki, m_bl_height); - if (in.key_offsets.size() == 1) + if (key_offsets.size() == 1) { //direct spend detected - if (!m_bcs.update_spent_tx_flags_for_input(in.amount, in.key_offsets[0], true)) + if (!m_bcs.update_spent_tx_flags_for_input(amount, key_offsets[0], true)) { //internal error LOG_PRINT_RED_L0("Failed to update_spent_tx_flags_for_input"); return false; } } - if (m_mixins_count < in.key_offsets.size()) - m_mixins_count = in.key_offsets.size(); + if (m_max_mixins_count < key_offsets.size()) + m_max_mixins_count = key_offsets.size(); return true; } + + bool operator()(const txin_to_key& in) const + { + return visit(in.amount, in.k_image, in.key_offsets); + } bool operator()(const txin_htlc& in) const { - if (!m_bcs.is_after_hardfork_3_zone()) - { - LOG_ERROR("Error: Transaction with txin_htlc before is_after_hardfork_3_zone(before height " << m_bcs.get_core_runtime_config().hard_fork_03_starts_after_height << ")"); - return false; - } return this->operator()(static_cast(in)); } bool operator()(const txin_gen& in) const { return true; } @@ -3873,6 +4444,10 @@ namespace currency } return true; } + bool operator()(const txin_zc_input& in) const + { + return visit(0, in.k_image, in.key_offsets); + } }; } @@ -3891,7 +4466,7 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(tx, tx_id, bl_height), false, "tx " << tx_id << ": hardfork-specific validation failed"); TIME_MEASURE_START_PD(tx_process_extra); - bool r = process_blockchain_tx_extra(tx); + bool r = process_blockchain_tx_extra(tx, tx_id); CHECK_AND_ASSERT_MES(r, false, "failed to process_blockchain_tx_extra"); TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_extra); @@ -3899,11 +4474,11 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const process_blockchain_tx_attachments(tx, bl_height, bl_id, timestamp); TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_attachment); - uint64_t mixins_count = 0; + uint64_t max_mixins_count = 0; TIME_MEASURE_START_PD(tx_process_inputs); for(const txin_v& in : tx.vin) { - if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height, mixins_count), in)) + if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height, max_mixins_count), in)) { LOG_ERROR("critical internal error: add_transaction_input_visitor failed. but key_images should be already checked"); purge_transaction_keyimages_from_blockchain(tx, false); @@ -3916,9 +4491,9 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const } } TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_inputs); - if (need_to_profile && mixins_count > 0) + if (need_to_profile && max_mixins_count > 0) { - m_performance_data.tx_mixin_count.push(mixins_count); + m_performance_data.tx_mixin_count.push(max_mixins_count); } //check if there is already transaction with this hash @@ -3935,6 +4510,9 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const return false; } TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_check_exist); + + // all check are ok, add tx to the database + TIME_MEASURE_START_PD(tx_push_global_index); transaction_chain_entry ch_e; ch_e.m_keeper_block_height = bl_height; @@ -3950,9 +4528,13 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_store_db); TIME_MEASURE_START_PD(tx_print_log); + static const std::string hidden("hidden"); LOG_PRINT_L1("Added tx to blockchain: " << tx_id << " via block at " << bl_height << " id " << print16(bl_id) - << ", ins: " << tx.vin.size() << ", outs: " << tx.vout.size() << ", outs sum: " << print_money_brief(get_outs_money_amount(tx)) << " (fee: " << (is_coinbase(tx) ? "0[coinbase]" : print_money_brief(get_tx_fee(tx))) << ")"); + << ", ins: " << tx.vin.size() << ", outs: " << tx.vout.size() + << ", outs sum: " << (tx.version > TRANSACTION_VERSION_PRE_HF4 ? hidden : print_money_brief(get_outs_money_amount(tx))) + << " (fee: " << (is_coinbase(tx) ? "0 [coinbase]" : print_money_brief(get_tx_fee(tx))) << ")"); TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_print_log); + //@#@ del me // LOG_PRINT_L0("APPEND_TX_TIME_INNER: " << m_performance_data.tx_append_rl_wait.get_last_val() // << " | " << m_performance_data.tx_append_is_expired.get_last_val() @@ -3987,7 +4569,7 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha CRITICAL_REGION_LOCAL(m_read_lock); bool res = check_tx_inputs(tx, tx_prefix_hash, max_used_block_height); if(!res) return false; - CHECK_AND_ASSERT_MES(max_used_block_height < m_db_blocks.size(), false, "internal error: max used block index=" << max_used_block_height << " is not less then blockchain size = " << m_db_blocks.size()); + CHECK_AND_ASSERT_MES(max_used_block_height < m_db_blocks.size(), false, "internal error: max used block index=" << max_used_block_height << " is not less than blockchain size = " << m_db_blocks.size()); get_block_hash(m_db_blocks[max_used_block_height]->bl, max_used_block_id); return true; } @@ -4086,7 +4668,7 @@ uint64_t blockchain_storage::tx_fee_median_for_height(uint64_t h)const //------------------------------------------------------------------ bool blockchain_storage::validate_all_aliases_for_new_median_mode() { - LOG_PRINT_L0("Started reinitialization of median fee..."); + LOG_PRINT_L0("Started reinitialization of median fee..."); math_helper::once_a_time_seconds<10> log_idle; uint64_t sz = m_db_blocks.size(); for (uint64_t i = 0; i != sz; i++) @@ -4109,12 +4691,12 @@ bool blockchain_storage::validate_all_aliases_for_new_median_mode() uint64_t fee_for_alias = get_alias_coast_from_fee(tei.m_alias.m_alias, median_fee); //validate the price had been paid - uint64_t found_alias_reward = get_amount_for_zero_pubkeys(tx_ptr->tx); - if (found_alias_reward < fee_for_alias) + uint64_t burnt_amount = 0; + if (!check_native_coins_amount_burnt_in_outs(tx_ptr->tx, fee_for_alias, &burnt_amount)) { - LOG_PRINT_RED_L0("[" << i << "]Found collision on alias: " << tei.m_alias.m_alias - << ", expected fee: " << print_money(fee_for_alias) << "(median:" << print_money(median_fee) << ")" - <<" found reward: " << print_money(found_alias_reward) <<". tx_id: " << tx_id); + LOG_PRINT_RED_L0("[" << i << "]Detected collision on alias: " << tei.m_alias.m_alias + << ", expected fee: " << print_money_brief(fee_for_alias) << " (median: " << print_money_brief(median_fee) << ")" + << " found reward: " << (tx_ptr->tx.version <= TRANSACTION_VERSION_PRE_HF4 ? print_money_brief(burnt_amount) : std::string("hidden")) << "; tx_id: " << tx_id); } } } @@ -4142,12 +4724,15 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const CHECK_AND_ASSERT_MES(tx_ptr->tx.vout.size() == tx_ptr->m_global_output_indexes.size(), false, "Internal error: output size missmatch"); for (uint64_t i = 0; i!= tx_ptr->tx.vout.size();i++) { - strm_tx << "[" << i << "]: " << print_money(tx_ptr->tx.vout[i].amount) << ENDL; - if (tx_ptr->tx.vout[i].target.type() != typeid(currency::txout_to_key)) - continue; - - usage_stat[tx_ptr->tx.vout[i].amount][tx_ptr->m_global_output_indexes[i]]; - + VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[i]); + VARIANT_CASE_CONST(tx_out_bare, o) + strm_tx << "[" << i << "]: " << print_money(o.amount) << ENDL; + if (o.target.type() != typeid(currency::txout_to_key)) + continue; + usage_stat[o.amount][tx_ptr->m_global_output_indexes[i]]; + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); } LOG_PRINT_L0("Lookup in all transactions...."); @@ -4199,14 +4784,44 @@ bool blockchain_storage::print_tx_outputs_lookup(const crypto::hash& tx_id)const return true; } //------------------------------------------------------------------ +bool check_tx_explicit_asset_id_rules(const transaction& tx, bool all_tx_ins_have_explicit_native_asset_ids) +{ + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + return true; + + // ( assuming that post-HF4 txs can only have tx_out_zarcanum outs ) + + bool r = false; + // if all tx inputs have explicit native asset id AND it does not emit a new asset THEN all outputs must have explicit asset id (native coin) + if (all_tx_ins_have_explicit_native_asset_ids && !is_asset_emitting_transaction(tx)) + { + for(size_t j = 0, k = tx.vout.size(); j < k; ++j) + { + r = crypto::point_t(boost::get(tx.vout[j]).blinded_asset_id).modify_mul8().to_public_key() == native_coin_asset_id; + CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has a non-explicit asset id in a tx where all inputs have an explicit native asset id"); + } + } + else // otherwise all outputs must have hidden asset id (unless they burn money by sending them to null pubkey) + { + for(size_t j = 0, k = tx.vout.size(); j < k; ++j) + { + const tx_out_zarcanum& zo = boost::get(tx.vout[j]); + r = zo.stealth_address == null_pkey || crypto::point_t(zo.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id; + CHECK_AND_ASSERT_MES(r, false, "output #" << j << " has an explicit asset id in a tx where not all inputs have an explicit native asset id"); + } + } + return true; +} +//------------------------------------------------------------------ bool blockchain_storage::have_tx_keyimges_as_spent(const transaction &tx) const { // check all tx's inputs for being already spent for (const txin_v& in : tx.vin) { - if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc)) + crypto::key_image ki = AUTO_VAL_INIT(ki); + if (get_key_image_from_txin_v(in, ki)) { - if (have_tx_keyimg_as_spent(get_to_key_input_from_txin_v(in).k_image)) + if (have_tx_keyimg_as_spent(ki)) { return true; } @@ -4238,70 +4853,77 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha { size_t sig_index = 0; max_used_block_height = 0; - - std::vector sig_stub; - const std::vector* psig = &sig_stub; + bool all_tx_ins_have_explicit_native_asset_ids = true; + + auto local_check_key_image = [&](const crypto::key_image& ki) -> bool + { + TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); + if (have_tx_keyimg_as_spent(ki)) + { + LOG_ERROR("Key image was already spent in blockchain: " << string_tools::pod_to_hex(ki) << " for input #" << sig_index << " tx: " << tx_prefix_hash); + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); + return true; + }; TIME_MEASURE_START_PD(tx_check_inputs_loop); for(const auto& txin : tx.vin) { - if (!m_is_in_checkpoint_zone) + VARIANT_SWITCH_BEGIN(txin); + VARIANT_CASE_CONST(txin_to_key, in_to_key) { - CHECK_AND_ASSERT_MES(sig_index < tx.signatures.size(), false, "Wrong transaction: missing signature entry for input #" << sig_index << " tx: " << tx_prefix_hash); - psig = &tx.signatures[sig_index]; - } - - if (txin.type() == typeid(txin_to_key)) - { - const txin_to_key& in_to_key = boost::get(txin); - CHECK_AND_ASSERT_MES(in_to_key.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash); - TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); - if (have_tx_keyimg_as_spent(in_to_key.k_image)) - { - LOG_ERROR("Key image was already spent in blockchain: " << string_tools::pod_to_hex(in_to_key.k_image) << " for input #" << sig_index << " tx: " << tx_prefix_hash); + if (!local_check_key_image(in_to_key.k_image)) return false; - } - TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); + uint64_t max_unlock_time = 0; - if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, *psig, max_used_block_height, max_unlock_time)) + if (!check_tx_input(tx, sig_index, in_to_key, tx_prefix_hash, max_used_block_height, max_unlock_time)) { LOG_ERROR("Failed to validate input #" << sig_index << " tx: " << tx_prefix_hash); return false; } } - else if (txin.type() == typeid(txin_multisig)) + VARIANT_CASE_CONST(txin_multisig, in_ms) { - const txin_multisig& in_ms = boost::get(txin); - if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, *psig, max_used_block_height)) + if (!check_tx_input(tx, sig_index, in_ms, tx_prefix_hash, max_used_block_height)) { LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << in_ms.multisig_out_id << ") in tx: " << tx_prefix_hash); return false; } } - else if (txin.type() == typeid(txin_htlc)) + VARIANT_CASE_CONST(txin_htlc, in_htlc) { - if (!is_after_hardfork_3_zone()) + if (!is_hardfork_active(3)) // @#@ CZ, consider removing this to validate_tx_for_hardfork_specific_terms { - LOG_ERROR("Error: Transaction with txin_htlc before is_after_hardfork_3_zone(before height " << m_core_runtime_config.hard_fork_03_starts_after_height << ")"); + LOG_ERROR("Error: Transaction with txin_htlc before hardfork 3 (before height " << m_core_runtime_config.hard_forks.get_str_height_the_hardfork_active_after(3) << ")"); return false; } - const txin_htlc& in_htlc = boost::get(txin); CHECK_AND_ASSERT_MES(in_htlc.key_offsets.size(), false, "Empty in_to_key.key_offsets for input #" << sig_index << " tx: " << tx_prefix_hash); - TIME_MEASURE_START_PD(tx_check_inputs_loop_kimage_check); - if (have_tx_keyimg_as_spent(in_htlc.k_image)) - { - LOG_ERROR("Key image was already spent in blockchain: " << string_tools::pod_to_hex(in_htlc.k_image) << " for input #" << sig_index << " tx: " << tx_prefix_hash); + if (!local_check_key_image(in_htlc.k_image)) return false; - } - TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_kimage_check); - if (!check_tx_input(tx, sig_index, in_htlc, tx_prefix_hash, *psig, max_used_block_height)) + + if (!check_tx_input(tx, sig_index, in_htlc, tx_prefix_hash, max_used_block_height)) { - LOG_ERROR("Failed to validate multisig input #" << sig_index << " (ms out id: " << obj_to_json_str(in_htlc) << ") in tx: " << tx_prefix_hash); + LOG_ERROR("Failed to validate htlc input #" << sig_index << " in tx: " << tx_prefix_hash << ", htlc json: " << ENDL << obj_to_json_str(in_htlc)); return false; } } + VARIANT_CASE_CONST(txin_zc_input, in_zc) + { + if (!local_check_key_image(in_zc.k_image)) + return false; + + if (!check_tx_input(tx, sig_index, in_zc, tx_prefix_hash, max_used_block_height, all_tx_ins_have_explicit_native_asset_ids)) + { + LOG_ERROR("Failed to validate zc input #" << sig_index << " in tx: " << tx_prefix_hash); + return false; + } + } + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); + sig_index++; } TIME_MEASURE_FINISH_PD(tx_check_inputs_loop); @@ -4315,6 +4937,8 @@ bool blockchain_storage::check_tx_inputs(const transaction& tx, const crypto::ha bool r = validate_attachment_info(tx.extra, tx.attachment, false); CHECK_AND_ASSERT_MES(r, false, "Failed to validate attachments in tx " << tx_prefix_hash << ": incorrect extra_attachment_info in tx.extra"); } + + CHECK_AND_ASSERT_MES(check_tx_explicit_asset_id_rules(tx, all_tx_ins_have_explicit_native_asset_ids), false, "tx does not comply with explicit asset id rules"); } TIME_MEASURE_FINISH_PD(tx_check_inputs_attachment_check); return true; @@ -4325,7 +4949,7 @@ bool blockchain_storage::is_tx_spendtime_unlocked(uint64_t unlock_time) const return currency::is_tx_spendtime_unlocked(unlock_time, get_current_blockchain_size(), m_core_runtime_config.get_core_time()); } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4345,7 +4969,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, for (auto& ptr : output_keys) output_keys_ptrs.push_back(&ptr); - return check_input_signature(tx, in_index, txin, tx_prefix_hash, sig, output_keys_ptrs); + return check_input_signature(tx, in_index, txin, tx_prefix_hash, output_keys_ptrs); } //---------------------------------------------------------------- struct outputs_visitor @@ -4354,6 +4978,7 @@ struct outputs_visitor blockchain_storage::scan_for_keys_context& m_scan_context; const blockchain_storage& m_bch; uint64_t& m_source_max_unlock_time_for_pos_coinbase; + outputs_visitor(std::vector& results_collector, const blockchain_storage& bch, uint64_t& source_max_unlock_time_for_pos_coinbase, @@ -4363,12 +4988,13 @@ struct outputs_visitor , m_source_max_unlock_time_for_pos_coinbase(source_max_unlock_time_for_pos_coinbase) , m_scan_context(scan_context) {} - bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out& out, uint64_t out_i) + + bool handle_output(const transaction& source_tx, const transaction& validated_tx, const tx_out_v& out_v, uint64_t out_i) { //check tx unlock time uint64_t source_out_unlock_time = get_tx_unlock_time(source_tx, out_i); //let coinbase sources for PoS block to have locked inputs, the outputs supposed to be locked same way, except the reward - if (is_coinbase(validated_tx) && is_pos_block(validated_tx)) + if (is_coinbase(validated_tx) && is_pos_miner_tx(validated_tx)) // @#@ consider changing to one call to is_pos_coinbase() { CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(source_out_unlock_time), false, "source output #" << out_i << " is locked by time, not by height, which is not allowed for PoS coinbase"); if (source_out_unlock_time > m_source_max_unlock_time_for_pos_coinbase) @@ -4378,33 +5004,27 @@ struct outputs_visitor { if (!m_bch.is_tx_spendtime_unlocked(source_out_unlock_time)) { - LOG_PRINT_L0("One of outputs for one of inputs have wrong tx.unlock_time = " << get_tx_unlock_time(source_tx, out_i)); + uint64_t limit = source_out_unlock_time < CURRENCY_MAX_BLOCK_NUMBER ? m_bch.get_current_blockchain_size() - 1 + CURRENCY_LOCKED_TX_ALLOWED_DELTA_BLOCKS : m_bch.get_core_runtime_config().get_core_time() + CURRENCY_LOCKED_TX_ALLOWED_DELTA_SECONDS; + LOG_PRINT_L0("An output has unlock time value of " << get_tx_unlock_time(source_tx, out_i) << " while the current limit is " << limit); return false; } } - if (out.target.type() == typeid(txout_to_key)) - { - crypto::public_key pk = boost::get(out.target).key; - m_results_collector.push_back(pk); - } - else if (out.target.type() == typeid(txout_htlc)) - { - m_scan_context.htlc_outs.push_back(boost::get(out.target)); - crypto::public_key pk = null_pkey; - if (m_scan_context.htlc_is_expired) - { - pk = boost::get(out.target).pkey_refund; - } - else - { - pk = boost::get(out.target).pkey_redeem; - } - m_results_collector.push_back(pk); - }else - { - LOG_PRINT_L0("Output have wrong type id, which=" << out.target.which()); - return false; - } + + VARIANT_SWITCH_BEGIN(out_v) + VARIANT_CASE_CONST(tx_out_bare, out) + VARIANT_SWITCH_BEGIN(out.target) + VARIANT_CASE_CONST(txout_to_key, out_tk) + m_results_collector.push_back(out_tk.key); + VARIANT_CASE_CONST(txout_htlc, out_htlc) + m_scan_context.htlc_outs.push_back(out_htlc); + m_results_collector.push_back(m_scan_context.htlc_is_expired ? out_htlc.pkey_refund : out_htlc.pkey_redeem); + VARIANT_CASE_OTHER() + LOG_PRINT_L0("Output has wrong target type id: " << out.target.which()); + return false; + VARIANT_SWITCH_END() + VARIANT_CASE_CONST(tx_out_zarcanum, out_zc) + m_scan_context.zc_outs.push_back(out_zc); + VARIANT_SWITCH_END() return true; } @@ -4432,7 +5052,7 @@ bool blockchain_storage::get_output_keys_for_input_with_checks(const transaction //------------------------------------------------------------------ // Note: this function can be used for checking to_key inputs against either main chain or alt chain, that's why it has output_keys_ptrs parameter // Doesn't check spent flags, the caller must check it. -bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const +bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& output_keys_ptrs) const { if (txin.key_offsets.size() != output_keys_ptrs.size()) { @@ -4440,7 +5060,7 @@ bool blockchain_storage::check_input_signature(const transaction& tx, size_t in_ return false; } - return check_input_signature(tx, in_index, /*txin.key_offsets,*/ txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, sig, output_keys_ptrs); + return check_input_signature(tx, in_index, /*txin.key_offsets,*/ txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, output_keys_ptrs); } //------------------------------------------------------------------ bool blockchain_storage::check_input_signature(const transaction& tx, @@ -4449,7 +5069,6 @@ bool blockchain_storage::check_input_signature(const transaction& tx, const crypto::key_image& in_k_image, const std::vector& in_etc_details, const crypto::hash& tx_prefix_hash, - const std::vector& sig, const std::vector& output_keys_ptrs) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4459,6 +5078,19 @@ bool blockchain_storage::check_input_signature(const transaction& tx, if(m_is_in_checkpoint_zone) return true; + uint64_t actual_sig_index = in_index; + if (is_pos_coinbase(tx)) + { + actual_sig_index = 0; + } + + + + CHECK_AND_ASSERT_MES(tx.signatures.size() > actual_sig_index, false, "Failed to check s.size(){" << tx.signatures.size() << "} > actual_sig_index {" << actual_sig_index << "}" ); + + CHECK_AND_ASSERT_MES(tx.signatures[actual_sig_index].type() == typeid(NLSAG_sig), false, "Unexpected type of sig in check_input_signature: " << tx.signatures[actual_sig_index].type().name()); + const std::vector& sig = boost::get(tx.signatures[actual_sig_index]).s; + if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) { // check attachments, mentioned directly in this input @@ -4507,7 +5139,7 @@ bool blockchain_storage::check_input_signature(const transaction& tx, //------------------------------------------------------------------ // Note: this function doesn't check spent flags by design (to be able to use either for main chain and alt chains). // The caller MUST check spent flags. -bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const transaction& source_tx, size_t out_n) const +bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const transaction& source_tx, size_t out_n) const { #define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, "ms input check failed: ms_id: " << txin.multisig_out_id << ", input #" << in_index << " in tx " << tx_prefix_hash << ", refers to ms output #" << out_n << " in source tx " << get_transaction_hash(source_tx) << ENDL << msg) CRITICAL_REGION_LOCAL(m_read_lock); @@ -4516,7 +5148,9 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, LOC_CHK(is_tx_spendtime_unlocked(unlock_time), "Source transaction is LOCKED! unlock_time: " << unlock_time << ", now is " << m_core_runtime_config.get_core_time() << ", blockchain size is " << get_current_blockchain_size()); LOC_CHK(source_tx.vout.size() > out_n, "internal error: out_n==" << out_n << " is out-of-bounds of source_tx.vout, size=" << source_tx.vout.size()); - const tx_out& source_tx_out = source_tx.vout[out_n]; + LOC_CHK(source_tx.vout[out_n].type() == typeid(tx_out_bare), "internal error: out_n==" << out_n << " has unexpected type: " << source_tx.vout[out_n].type().name()); + + const tx_out_bare& source_tx_out = boost::get(source_tx.vout[out_n]); const txout_multisig& source_ms_out_target = boost::get(source_tx_out.target); LOC_CHK(txin.sigs_count == source_ms_out_target.minimum_sigs, @@ -4543,56 +5177,71 @@ bool blockchain_storage::check_ms_input(const transaction& tx, size_t in_index, // make sure normal tx does not have extra_attachment_info in etc_details LOC_CHK(!have_type_in_variant_container(txin.etc_details), "Incorrect using of extra_attachment_info in etc_details in input #" << in_index << " for tx " << tx_prefix_hash); } - - LOC_CHK(tx.signatures.size() > in_index, "ms input index is out of signatures container bounds, tx.signatures.size() = " << tx.signatures.size()); - const std::vector& input_signatures = tx.signatures[in_index]; - - size_t expected_signatures_count = txin.sigs_count; bool need_to_check_extra_sign = false; - if (get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE && in_index == tx.vin.size() - 1) // last input in TX_FLAG_SIGNATURE_MODE_SEPARATE must contain one more signature to ensure that tx was completed by an authorized subject - { - expected_signatures_count++; - need_to_check_extra_sign = true; - } - LOC_CHK(expected_signatures_count == input_signatures.size(), "Invalid input's signatures count: " << input_signatures.size() << ", expected: " << expected_signatures_count); + LOC_CHK(tx.signatures.size() > in_index, "ms input index is out of signatures container bounds, signatures.size() = " << tx.signatures.size()); - crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, in_index, tx_prefix_hash); - LOC_CHK(tx_hash_for_signature != null_hash, "prepare_prefix_hash_for_sign failed"); + //@#@ + VARIANT_SWITCH_BEGIN(tx.signatures[in_index]); + VARIANT_CASE_CONST(void_sig, v); + VARIANT_CASE_CONST(NLSAG_sig, sig) + { + const std::vector& input_signatures = sig.s; - LOC_CHK(txin.sigs_count <= source_ms_out_target.keys.size(), "source tx invariant failed: ms output's minimum sigs == ms input's sigs_count (" << txin.sigs_count << ") is GREATHER than keys.size() = " << source_ms_out_target.keys.size()); // NOTE: sig_count == minimum_sigs as checked above - size_t out_key_index = 0; // index in source_ms_out_target.keys - for (size_t i = 0; i != txin.sigs_count; /* nothing */) - { - // if we run out of keys for this signature, then it's invalid signature - LOC_CHK(out_key_index < source_ms_out_target.keys.size(), "invalid signature #" << i << ": " << input_signatures[i]); - - // check signature #i against ms output key #out_key_index - if (crypto::check_signature(tx_hash_for_signature, source_ms_out_target.keys[out_key_index], input_signatures[i])) + size_t expected_signatures_count = txin.sigs_count; + if (get_tx_flags(tx)&TX_FLAG_SIGNATURE_MODE_SEPARATE && in_index == tx.vin.size() - 1) // last input in TX_FLAG_SIGNATURE_MODE_SEPARATE must contain one more signature to ensure that tx was completed by an authorized subject { - // match: go for the next signature and the next key - i++; - out_key_index++; + expected_signatures_count++; + need_to_check_extra_sign = true; } - else + + LOC_CHK(expected_signatures_count == input_signatures.size(), "Invalid input's signatures count: " << input_signatures.size() << ", expected: " << expected_signatures_count); + + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, in_index, tx_prefix_hash); + LOC_CHK(tx_hash_for_signature != null_hash, "prepare_prefix_hash_for_sign failed"); + + LOC_CHK(txin.sigs_count <= source_ms_out_target.keys.size(), "source tx invariant failed: ms output's minimum sigs == ms input's sigs_count (" << txin.sigs_count << ") is GREATHER than keys.size() = " << source_ms_out_target.keys.size()); // NOTE: sig_count == minimum_sigs as checked above + size_t out_key_index = 0; // index in source_ms_out_target.keys + for (size_t i = 0; i != txin.sigs_count; /* nothing */) { - // missmatch: go for the next key for this signature - out_key_index++; + // if we run out of keys for this signature, then it's invalid signature + LOC_CHK(out_key_index < source_ms_out_target.keys.size(), "invalid signature #" << i << ": " << input_signatures[i]); + + // check signature #i against ms output key #out_key_index + if (crypto::check_signature(tx_hash_for_signature, source_ms_out_target.keys[out_key_index], input_signatures[i])) + { + // match: go for the next signature and the next key + i++; + out_key_index++; + } + else + { + // missmatch: go for the next key for this signature + out_key_index++; + } + } + + if (need_to_check_extra_sign) + { + //here we check extra signature to validate that transaction was finilized by authorized subject + bool r = crypto::check_signature(tx_prefix_hash, get_tx_pub_key_from_extra(tx), input_signatures.back()); + LOC_CHK(r, "failed to check extra signature for last out with TX_FLAG_SIGNATURE_MODE_SEPARATE"); } } - if (need_to_check_extra_sign) - { - //here we check extra signature to validate that transaction was finilized by authorized subject - bool r = crypto::check_signature(tx_prefix_hash, get_tx_pub_key_from_extra(tx), tx.signatures[in_index].back()); - LOC_CHK(r, "failed to check extra signature for last out with TX_FLAG_SIGNATURE_MODE_SEPARATE"); - } + VARIANT_CASE_CONST(ZC_sig, s); + //@#@ + //TODO: don't forget about need_to_check_extra_sign + VARIANT_SWITCH_END(); + + + return true; #undef LOC_CHK } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height) const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height) const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4609,11 +5258,12 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, auto source_tx_ptr = m_db_transactions.find(source_tx_id); LOC_CHK(source_tx_ptr, "Can't find source transaction"); LOC_CHK(source_tx_ptr->tx.vout.size() > n, "ms output index is incorrect, source tx's vout size is " << source_tx_ptr->tx.vout.size()); - LOC_CHK(source_tx_ptr->tx.vout[n].target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected"); + LOC_CHK(source_tx_ptr->tx.vout[n].type() == typeid(tx_out_bare), "internal error: out_n==" << n << " has unexpected type: " << source_tx_ptr->tx.vout[n].type().name()); + LOC_CHK(boost::get(source_tx_ptr->tx.vout[n]).target.type() == typeid(txout_multisig), "ms output has wrong type, txout_multisig expected"); LOC_CHK(source_tx_ptr->m_spent_flags.size() > n, "Internal error, m_spent_flags size (" << source_tx_ptr->m_spent_flags.size() << ") less then expected, n: " << n); LOC_CHK(source_tx_ptr->m_spent_flags[n] == false, "Internal error, ms output is already spent"); // should never happen as multisig_ptr->spent_height is checked above - if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, sig, source_tx_ptr->tx, n)) + if (!check_ms_input(tx, in_index, txin, tx_prefix_hash, source_tx_ptr->tx, n)) return false; max_related_block_height = source_tx_ptr->m_keeper_block_height; @@ -4622,7 +5272,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, #undef LOC_CHK } //------------------------------------------------------------------ -bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height)const +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const { CRITICAL_REGION_LOCAL(m_read_lock); @@ -4633,7 +5283,7 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, uint64_t source_max_unlock_time_for_pos_coinbase_dummy = AUTO_VAL_INIT(source_max_unlock_time_for_pos_coinbase_dummy); if (!get_output_keys_for_input_with_checks(tx, txin, output_keys, max_related_block_height, source_max_unlock_time_for_pos_coinbase_dummy, scan_contex)) { - LOG_PRINT_L0("Failed to get output keys for input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")"); + LOG_PRINT_L0("Failed to get output keys for htlc input #" << in_index << " (amount = " << print_money(txin.amount) << ", key_offset.size = " << txin.key_offsets.size() << ")"); return false; } @@ -4659,7 +5309,6 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, //TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_ch_in_get_keys_loop); - std::vector output_keys_ptrs; output_keys_ptrs.reserve(output_keys.size()); @@ -4668,7 +5317,62 @@ bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, CHECK_AND_ASSERT_THROW_MES(output_keys_ptrs.size() == 1, "Internal error: output_keys_ptrs.size() is not equal 1 for HTLC"); - return check_input_signature(tx, in_index, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, sig, output_keys_ptrs); + + return check_input_signature(tx, in_index, txin.amount, txin.k_image, txin.etc_details, tx_prefix_hash, output_keys_ptrs); +} +//------------------------------------------------------------------ +bool blockchain_storage::check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, + uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const +{ + CRITICAL_REGION_LOCAL(m_read_lock); + + // we need a list this input is referring to + // and make sure that all of them are good (i.e. check 1) source tx unlock time validity; 2) mixin restrictions; 3) general gindex/ref_by_id corectness) + // get_output_keys_for_input_with_checks is used for that + // + std::vector dummy_output_keys; // won't be used + uint64_t dummy_source_max_unlock_time_for_pos_coinbase_dummy = 0; // won't be used + scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex); + + if (!get_output_keys_for_input_with_checks(tx, zc_in, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex)) + { + LOG_PRINT_L0("get_output_keys_for_input_with_checks failed for input #" << in_index << ", key_offset.size = " << zc_in.key_offsets.size() << ")"); + return false; + } + + if (m_is_in_checkpoint_zone) // TODO @#@# reconsider placement of this check + return true; + + // here we don't need to check zc_in.k_image validity because it is checked in verify_CLSAG_GG() + + CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == zc_in.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << zc_in.key_offsets.size() << " is expected."); + CHECK_AND_ASSERT_MES(in_index < tx.signatures.size(), false, "tx.signatures.size (" << tx.signatures.size() << ") is less than or equal to in_index (" << in_index << ")"); + // TODO: consider additional checks here + + // build a ring of references + vector ring; + ring.reserve(scan_contex.zc_outs.size()); + for(auto& zc_out : scan_contex.zc_outs) + { + ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.blinded_asset_id); + if (all_tx_ins_have_explicit_native_asset_ids && crypto::point_t(zc_out.blinded_asset_id).modify_mul8().to_public_key() != native_coin_asset_id) + all_tx_ins_have_explicit_native_asset_ids = false; + } + + // calculate corresponding tx prefix hash + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, in_index, tx_prefix_hash); + CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed"); + + const ZC_sig& sig = boost::get(tx.signatures[in_index]); + + //TIME_MEASURE_START_PD(tx_input_check_clsag_ggx); + + bool r = crypto::verify_CLSAG_GGX(tx_hash_for_signature, ring, sig.pseudo_out_amount_commitment, sig.pseudo_out_blinded_asset_id, zc_in.k_image, sig.clsags_ggx); + CHECK_AND_ASSERT_MES(r, false, "verify_CLSAG_GGX failed"); + + //TIME_MEASURE_FINISH_PD(tx_input_check_clsag_ggx); + + return true; } //------------------------------------------------------------------ uint64_t blockchain_storage::get_adjusted_time() const @@ -4719,7 +5423,7 @@ bool blockchain_storage::check_block_timestamp_main(const block& b) const } if (is_pos_block(b) && b.timestamp > get_adjusted_time() + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) { - LOG_PRINT_L0("Timestamp of PoS block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + " + epee::misc_utils::get_time_interval_string(CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + ": " << get_adjusted_time() << " (" << b.timestamp - get_adjusted_time() << ")"); + LOG_PRINT_L0("Timestamp of PoS block with id: " << get_block_hash(b) << ", " << b.timestamp << ", bigger than adjusted time + " + epee::misc_utils::get_time_interval_string(CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT) + ": " << get_adjusted_time() + CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT << " (" << b.timestamp - get_adjusted_time() - CURRENCY_POS_BLOCK_FUTURE_TIME_LIMIT << ")"); return false; } @@ -4794,18 +5498,127 @@ std::shared_ptr blockchain_storage::find_key_imag } for (auto& in : tx_chain_entry->tx.vin) { - if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(in, k_image)) { - if (get_to_key_input_from_txin_v(in).k_image == ki) + if (k_image == ki) { - id_result = get_transaction_hash(tx_chain_entry->tx); + id_result = get_transaction_hash(tx_chain_entry->tx); // ??? @#@# why not just use tx_id ? return tx_chain_entry; } } } } + + // got here, but found nothing -- log such suspicious event + CHECK_AND_ASSERT_THROW_MES(block_entry != nullptr, "invalid block_entry"); + LOG_PRINT_YELLOW("find_key_image_and_related_tx: failed to find key image " << ki << " in block " << get_block_hash(block_entry->bl), LOG_LEVEL_1); + return std::shared_ptr(); } +//--------------------------------------------------------------- +bool blockchain_storage::fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short) const +{ + //tei.blob = tx_ptr->tx + tei.id = epee::string_tools::pod_to_hex(h); + if (!tei.blob_size) + tei.blob_size = get_object_blobsize(tx); + + tei.fee = get_tx_fee(tx); + tei.pub_key = epee::string_tools::pod_to_hex(get_tx_pub_key_from_extra(tx)); + tei.timestamp = timestamp; + tei.amount = get_outs_money_amount(tx); + + if (is_short) + return true; + + fill_tx_rpc_inputs(tei, tx); + fill_tx_rpc_outputs(tei, tx, ptce); + fill_tx_rpc_payload_items(tei.extra, tx.extra); + fill_tx_rpc_payload_items(tei.attachments, tx.attachment); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const +{ + + //handle inputs + for (auto in : tx.vin) + { + tei.ins.push_back(tx_in_rpc_entry()); + tx_in_rpc_entry& entry_to_fill = tei.ins.back(); + if (in.type() == typeid(txin_gen)) + { + entry_to_fill.amount = 0; + } + else if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input)) + { + //TODO: add htlc info + entry_to_fill.amount = get_amount_from_variant(in); + entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(get_key_image_from_txin_v(in)); + const std::vector& key_offsets = get_key_offsets_from_txin_v(in); + std::vector absolute_offsets = relative_output_offsets_to_absolute(key_offsets); + for (auto& ao : absolute_offsets) + { + entry_to_fill.global_indexes.push_back(0); + if (ao.type() == typeid(uint64_t)) + { + entry_to_fill.global_indexes.back() = boost::get(ao); + } + else if (ao.type() == typeid(ref_by_id)) + { + //disable for the reset at the moment + auto tx_ptr = get_tx_chain_entry(boost::get(ao).tx_id); + if (!tx_ptr || tx_ptr->m_global_output_indexes.size() <= boost::get(ao).n) + { + tei.ins.back().global_indexes.back() = std::numeric_limits::max(); + return false; + } + tei.ins.back().global_indexes.back() = tx_ptr->m_global_output_indexes[boost::get(ao).n]; + } + } + if (in.type() == typeid(txin_htlc)) + { + entry_to_fill.htlc_origin = epee::string_tools::buff_to_hex_nodelimer(boost::get(in).hltc_origin); + } + } + else if (in.type() == typeid(txin_multisig)) + { + txin_multisig& tms = boost::get(in); + entry_to_fill.amount = tms.amount; + entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(tms.multisig_out_id); + if (tx.signatures.size() >= tei.ins.size() && + tx.signatures[tei.ins.size() - 1].type() == typeid(NLSAG_sig)) + { + entry_to_fill.multisig_count = boost::get(tx.signatures[tei.ins.size() - 1]).s.size(); + } + } + + const std::vector& etc_options = get_txin_etc_options(in); + for (size_t i = 0; i < etc_options.size(); ++i) + { + std::stringstream ss; + if (etc_options[i].type() == typeid(signed_parts)) + { + const auto& sp = boost::get(etc_options[i]); + ss << "n_outs: " << sp.n_outs << ", n_extras: " << sp.n_extras; + entry_to_fill.etc_options.push_back(ss.str()); + } + else if (etc_options[i].type() == typeid(extra_attachment_info)) + { + const auto& eai = boost::get(etc_options[i]); + ss << "cnt: " << eai.cnt << ", sz: " << eai.sz << ", hsh: " << eai.hsh; + entry_to_fill.etc_options.push_back(ss.str()); + } + else + { + entry_to_fill.etc_options.push_back("unknown type"); + } + } + + } + return true; +} //------------------------------------------------------------------ bool blockchain_storage::prune_aged_alt_blocks() { @@ -4934,62 +5747,156 @@ bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transacti return validate_tx_for_hardfork_specific_terms(tx, tx_id, block_height); } //------------------------------------------------------------------ + +template +struct visitor_proxy : public boost::static_visitor +{ + const x_type* operator()(const x_type& v)const + { + return &v; + } + template + const x_type* operator()(const t_type& v)const { return nullptr; } +}; + + bool blockchain_storage::validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const { - auto is_allowed_before_hardfork2 = [&](const payload_items_v& el) -> bool - { - CHECK_AND_ASSERT_MES(el.type() != typeid(tx_payer), false, "tx " << tx_id << " contains tx_payer which is not allowed on height " << block_height); - CHECK_AND_ASSERT_MES(el.type() != typeid(tx_receiver), false, "tx " << tx_id << " contains tx_receiver which is not allowed on height " << block_height); - CHECK_AND_ASSERT_MES(el.type() != typeid(extra_alias_entry), false, "tx " << tx_id << " contains extra_alias_entry which is not allowed on height " << block_height); - return true; - }; + bool var_is_after_hardfork_1_zone = m_core_runtime_config.is_hardfork_active_for_height(1, block_height); + bool var_is_after_hardfork_2_zone = m_core_runtime_config.is_hardfork_active_for_height(2, block_height); + bool var_is_after_hardfork_3_zone = m_core_runtime_config.is_hardfork_active_for_height(3, block_height); + bool var_is_after_hardfork_4_zone = m_core_runtime_config.is_hardfork_active_for_height(4, block_height); - auto is_allowed_before_hardfork1 = [&](const payload_items_v& el) -> bool + auto is_allowed_before_hardfork1 = [&](const auto& el) -> bool { CHECK_AND_ASSERT_MES(el.type() != typeid(etc_tx_details_unlock_time2), false, "tx " << tx_id << " contains etc_tx_details_unlock_time2 which is not allowed on height " << block_height); return true; }; - bool var_is_after_hardfork_1_zone = is_after_hardfork_1_zone(block_height); - bool var_is_after_hardfork_2_zone = is_after_hardfork_2_zone(block_height); - bool var_is_after_hardfork_3_zone = is_after_hardfork_3_zone(block_height); + auto is_allowed_before_hardfork2 = [&](const auto& el) -> bool + { + CHECK_AND_ASSERT_MES(el.type() != typeid(tx_payer), false, "tx " << tx_id << " contains tx_payer which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(el.type() != typeid(tx_receiver), false, "tx " << tx_id << " contains tx_receiver which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(el.type() != typeid(extra_alias_entry), false, "tx " << tx_id << " contains extra_alias_entry which is not allowed on height " << block_height); + return true; + }; + + auto is_allowed_before_hardfork3 = [&](const auto& el) -> bool + { + CHECK_AND_ASSERT_MES(el.type() != typeid(txin_htlc), false, "tx " << tx_id << " contains txin_htlc which is not allowed on height " << block_height); + const tx_out_bare* pbare = boost::apply_visitor(visitor_proxy(), el); + if (pbare) + { + CHECK_AND_ASSERT_MES(pbare->target.type() != typeid(txout_htlc), false, "tx " << tx_id << " contains txout_htlc which is not allowed on height " << block_height); + } + return true; + }; + + auto is_allowed_before_hardfork4 = [&](const auto& el) -> bool + { + CHECK_AND_ASSERT_MES(el.type() != typeid(zarcanum_tx_data_v1), false, "tx " << tx_id << " contains zarcanum_tx_data_v1 which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(el.type() != typeid(txin_zc_input), false, "tx " << tx_id << " contains txin_zc_input which is not allowed on height " << block_height); + CHECK_AND_ASSERT_MES(el.type() != typeid(tx_out_zarcanum), false, "tx " << tx_id << " contains tx_out_zarcanum which is not allowed on height " << block_height); + return true; + }; + + auto is_allowed_after_hardfork4 = [&](const auto& el) -> bool + { + CHECK_AND_ASSERT_MES(el.type() != typeid(tx_out_bare), false, "tx " << tx_id << " contains tx_out_bare which is not allowed on height " << block_height); + return true; + }; //inputs - for (const auto in : tx.vin) + for (const auto& in : tx.vin) { - if (in.type() == typeid(txin_htlc)) - { - if (!var_is_after_hardfork_3_zone) - return false; - } + if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(in)) + return false; + if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(in)) + return false; + if (!var_is_after_hardfork_3_zone && !is_allowed_before_hardfork3(in)) + return false; + if (!var_is_after_hardfork_4_zone && !is_allowed_before_hardfork4(in)) + return false; + if (var_is_after_hardfork_4_zone && !is_allowed_after_hardfork4(in)) + return false; } //outputs - for (const auto out : tx.vout) + for (const auto& out : tx.vout) { - if (out.target.type() == typeid(txout_htlc)) - { - if (!var_is_after_hardfork_3_zone) - return false; - } + if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(out)) + return false; + if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(out)) + return false; + if (!var_is_after_hardfork_3_zone && !is_allowed_before_hardfork3(out)) + return false; + if (!var_is_after_hardfork_4_zone && !is_allowed_before_hardfork4(out)) + return false; + if (var_is_after_hardfork_4_zone && !is_allowed_after_hardfork4(out)) + return false; } + size_t count_ado = 0; //extra - for (const auto el : tx.extra) + for (const auto& el : tx.extra) { + if (el.type() == typeid(asset_descriptor_operation)) + count_ado++; if (!var_is_after_hardfork_1_zone && !is_allowed_before_hardfork1(el)) return false; if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(el)) return false; + if (!var_is_after_hardfork_4_zone && !is_allowed_before_hardfork4(el)) + return false; + if (var_is_after_hardfork_4_zone && !is_allowed_after_hardfork4(el)) + return false; } //attachments - for (const auto el : tx.attachment) + for (const auto& el : tx.attachment) { if (!var_is_after_hardfork_2_zone && !is_allowed_before_hardfork2(el)) return false; - } - + if (!var_is_after_hardfork_4_zone && !is_allowed_before_hardfork4(el)) + return false; + if (var_is_after_hardfork_4_zone && !is_allowed_after_hardfork4(el)) + return false; + } + + // TODO @#@# consider: 1) tx.proofs, 2) new proof data structures + + + if (var_is_after_hardfork_4_zone) + { + CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "HF4: tx with version " << tx.version << " is not allowed"); + + if (is_pos_miner_tx(tx)) + CHECK_AND_ASSERT_MES(tx.vout.size() == 1 || tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while 1 or >= " << CURRENCY_TX_MIN_ALLOWED_OUTS << " is expected for a PoS miner tx"); + else + CHECK_AND_ASSERT_MES(tx.vout.size() >= CURRENCY_TX_MIN_ALLOWED_OUTS, false, "HF4: tx.vout has " << tx.vout.size() << " element(s), while required minimum is " << CURRENCY_TX_MIN_ALLOWED_OUTS); + + if(!validate_inputs_sorting(tx)) + { + return false; + } + bool mode_separate = get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE? true:false; + if (is_coinbase(tx) && mode_separate) + { + LOG_ERROR("TX_FLAG_SIGNATURE_MODE_SEPARATE not allowed for coinbase tx"); + return false; + } + if (count_ado > 1) + { + LOG_ERROR("More then 1 asset_descriptor_operation not allowed in tx"); + return false; + } + if (mode_separate && count_ado > 0) + { + LOG_ERROR("asset_descriptor_operation not allowed in tx with TX_FLAG_SIGNATURE_MODE_SEPARATE"); + return false; + } + + } return true; } //------------------------------------------------------------------ @@ -5005,11 +5912,13 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio return true; } - CHECK_AND_ASSERT_MES(get_block_height(miner_tx) > m_core_runtime_config.hard_fork_01_starts_after_height, false, "error in block [" << get_block_height(miner_tx) << "] etc_tx_details_unlock_time2 can exist only after hard fork point : " << m_core_runtime_config.hard_fork_01_starts_after_height); + uint64_t block_height = get_block_height(miner_tx); + CHECK_AND_ASSERT_MES(m_core_runtime_config.is_hardfork_active_for_height(1, block_height), false, "error in block [" << block_height << "]: etc_tx_details_unlock_time was not found but etc_tx_details_unlock_time2 can exist only after hard fork 1 at height " << m_core_runtime_config.hard_forks.get_str_height_the_hardfork_active_after(1)); //etc_tx_details_unlock_time2 can be kept only after hard_fork_1 point etc_tx_details_unlock_time2 ut2 = AUTO_VAL_INIT(ut2); - get_type_in_variant_container(miner_tx.extra, ut2); + bool found = get_type_in_variant_container(miner_tx.extra, ut2); + CHECK_AND_ASSERT_MES(found, false, "etc_tx_details_unlock_time2 was not found in tx extra"); CHECK_AND_ASSERT_MES(ut2.unlock_time_array.size() == miner_tx.vout.size(), false, "ut2.unlock_time_array.size()<" << ut2.unlock_time_array.size() << "> != miner_tx.vout.size()<" << miner_tx.vout.size() << ">"); @@ -5020,7 +5929,14 @@ bool blockchain_storage::validate_pos_coinbase_outs_unlock_time(const transactio uint64_t unlock_value = ut2.unlock_time_array[i]; CHECK_AND_ASSERT_MES(should_unlock_value_be_treated_as_block_height(unlock_value), false, "output #" << i << " is locked by time, not buy height, which is not allowed for PoS coinbase"); if (unlock_value >= source_max_unlock_time) - amount_of_coins_in_unlock_in_range += miner_tx.vout[i].amount; + { + VARIANT_SWITCH_BEGIN(miner_tx.vout[i]); + VARIANT_CASE_CONST(tx_out_bare, o) + amount_of_coins_in_unlock_in_range += o.amount; + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); + } } if (amount_of_coins_in_unlock_in_range >= staked_amount) @@ -5034,7 +5950,7 @@ bool blockchain_storage::validate_pos_block(const block& b, wide_difficulty_type basic_diff, uint64_t& amount, wide_difficulty_type& final_diff, - crypto::hash& proof_hash, + crypto::hash& kernel_hash, const crypto::hash& id, bool for_altchain, const alt_chain_type& alt_chain, @@ -5047,90 +5963,163 @@ bool blockchain_storage::validate_pos_block(const block& b, //check timestamp CHECK_AND_ASSERT_MES(b.timestamp%POS_SCAN_STEP == 0, false, "wrong timestamp in PoS block(b.timestamp%POS_SCAN_STEP == 0), b.timestamp = " <(b.miner_tx.vin[1]); - if (!for_altchain && have_tx_keyimg_as_spent(in_to_key.k_image)) - { - LOG_PRINT_L0("Key image in coinstake already spent in blockchain: " << string_tools::pod_to_hex(in_to_key.k_image)); - return false; - } - - - // the following check is de-facto not applicable since 2021-10, but left intact to avoid consensus issues - // PoS blocks don't use etc_tx_time anymore to store actual timestamp; instead, they use tx_service_attachment in mining tx extra - uint64_t actual_ts = get_actual_timestamp(b); - if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) || - (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) - ) - { - LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAX_ACTUAL_TIMESTAMP_TO_MINED << " s."); - return false; - } - - //check kernel - stake_kernel sk = AUTO_VAL_INIT(sk); - - stake_modifier_type sm = AUTO_VAL_INIT(sm); - bool r = build_stake_modifier(sm, alt_chain, split_height); - CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier"); - amount = 0; - r = build_kernel(b, sk, amount, sm); - CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake"); - CHECK_AND_ASSERT_MES(amount!=0, false, "failed to build kernel_stake, amount == 0"); - - proof_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); - - LOG_PRINT_L2("STAKE KERNEL for bl ID: " << get_block_hash(b) << ENDL - << print_stake_kernel_info(sk) - << "amount: " << print_money(amount) << ENDL - << "kernel_hash: " << proof_hash); - - - final_diff = basic_diff / amount; - if (!check_hash(proof_hash, final_diff)) - { - LOG_ERROR("PoS difficulty check failed for block " << get_block_hash(b) << " @ HEIGHT " << get_block_height(b) << ":" << ENDL - << " basic_diff: " << basic_diff << ENDL - << " final_diff: " << final_diff << ENDL - << " amount: " << print_money_brief(amount) << ENDL - << " kernel_hash: " << proof_hash << ENDL - ); - return false; - } - - //validate signature - uint64_t max_related_block_height = 0; - const txin_to_key& coinstake_in = boost::get(b.miner_tx.vin[1]); - CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1, false, "PoS block's miner_tx has incorrect signatures size = " << b.miner_tx.signatures.size() << ", block_id = " << get_block_hash(b)); + CHECK_AND_ASSERT_MES(b.miner_tx.vin.size() == 2, false, "incorrect: miner_tx.vin.size() = " << b.miner_tx.vin.size()); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[0].type() == typeid(txin_gen), false, "incorrect input 0 type: " << b.miner_tx.vin[0].type().name()); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key) || b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name()); + const crypto::key_image& stake_key_image = get_key_image_from_txin_v(b.miner_tx.vin[1]); + //check keyimage if it's main chain candidate + TIME_MEASURE_START_PD(pos_validate_ki_search); if (!for_altchain) { - // Do coinstake input validation for main chain only. - // Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs() - uint64_t source_max_unlock_time_for_pos_coinbase = 0; - r = check_tx_input(b.miner_tx, 1, coinstake_in, id, b.miner_tx.signatures[0], max_related_block_height, source_max_unlock_time_for_pos_coinbase); - CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b)); + CHECK_AND_ASSERT_MES(!have_tx_keyimg_as_spent(stake_key_image), false, "stake key image has been already spent in blockchain: " << stake_key_image); + } + TIME_MEASURE_FINISH_PD(pos_validate_ki_search); - if (get_block_height(b) > m_core_runtime_config.hard_fork_01_starts_after_height) + if (!is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + { + // the following check is de-facto not applicable since 2021-10, but left intact to avoid consensus issues + // PoS blocks don't use etc_tx_time anymore to store actual timestamp; instead, they use tx_service_attachment in mining tx extra + // TODO: remove this entire section after HF4 -- sowle + uint64_t actual_ts = get_block_timestamp_from_miner_tx_extra(b); + if ((actual_ts > b.timestamp && actual_ts - b.timestamp > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) || + (actual_ts < b.timestamp && b.timestamp - actual_ts > POS_MAX_ACTUAL_TIMESTAMP_TO_MINED) + ) { - uint64_t last_pow_h = get_last_x_block_height(false); - CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")"); - //let's check that coinbase amount and unlock time - r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase); - CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b) - << "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase); - } - else - { - CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")"); + LOG_PRINT_L0("PoS block actual timestamp " << actual_ts << " differs from b.timestamp " << b.timestamp << " by " << ((int64_t)actual_ts - (int64_t)b.timestamp) << " s, it's more than allowed " << POS_MAX_ACTUAL_TIMESTAMP_TO_MINED << " s."); + return false; } } - uint64_t block_height = for_altchain ? split_height + alt_chain.size() : m_db_blocks.size(); - uint64_t coinstake_age = block_height - max_related_block_height - 1; + // build kernel and calculate hash + stake_kernel sk = AUTO_VAL_INIT(sk); + stake_modifier_type sm = AUTO_VAL_INIT(sm); + uint64_t last_pow_block_height = 0; + bool r = build_stake_modifier(sm, alt_chain, split_height, nullptr, &last_pow_block_height); + CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier"); + r = build_kernel(stake_key_image, sk, sm, b.timestamp); + CHECK_AND_ASSERT_MES(r, false, "failed to build kernel_stake"); + kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); - CHECK_AND_ASSERT_MES(coinstake_age >= m_core_runtime_config.min_coinstake_age, false, - "Coinstake age is: " << coinstake_age << " is less than minimum expected: " << m_core_runtime_config.min_coinstake_age); + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + { + CHECK_AND_ASSERT_MES(b.miner_tx.version > TRANSACTION_VERSION_PRE_HF4, false, "Zarcanum PoS: miner tx with version " << b.miner_tx.version << " is not allowed"); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name() << ", txin_zc_input expected"); + const txin_zc_input& stake_input = boost::get(b.miner_tx.vin[1]); + CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1, false, "incorrect number of stake input signatures: " << b.miner_tx.signatures.size()); + CHECK_AND_ASSERT_MES(b.miner_tx.signatures[0].type() == typeid(zarcanum_sig), false, "incorrect sig 0 type: " << b.miner_tx.signatures[0].type().name()); + + //std::stringstream ss; + if (!for_altchain) + { + TIME_MEASURE_START_PD(pos_validate_get_out_keys_for_inputs); + // do general input check for main chain blocks only + // TODO @#@#: txs in alternative PoS blocks (including miner_tx) must be validated by validate_alt_block_txs() + const zarcanum_sig& sig = boost::get(b.miner_tx.signatures[0]); + uint64_t max_related_block_height = 0; + std::vector dummy_output_keys; // won't be used + uint64_t dummy_source_max_unlock_time_for_pos_coinbase_dummy = 0; // won't be used + scan_for_keys_context scan_contex = AUTO_VAL_INIT(scan_contex); + r = get_output_keys_for_input_with_checks(b.miner_tx, stake_input, dummy_output_keys, max_related_block_height, dummy_source_max_unlock_time_for_pos_coinbase_dummy, scan_contex); + +//#define ADD_ITEM_TO_SS(item) ss << " " #item ": " << m_performance_data.item.get_last_val() << ENDL +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_get_item_size); +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop); +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_iteration); +// ss << " tx_check_inputs_loop_scan_outputkeys_loop_iteration (avg): " << m_performance_data.tx_check_inputs_loop_scan_outputkeys_loop_iteration.get_avg() << ENDL; +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_get_subitem); +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_find_tx); +// ADD_ITEM_TO_SS(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); +//#undef ADD_ITEM_TO_SS + + CHECK_AND_ASSERT_MES(r, false, "get_output_keys_for_input_with_checks failed for stake input"); + CHECK_AND_ASSERT_MES(scan_contex.zc_outs.size() == stake_input.key_offsets.size(), false, "incorrect number of referenced outputs found: " << scan_contex.zc_outs.size() << ", while " << stake_input.key_offsets.size() << " is expected."); + // make sure that all referring inputs are either older then, or the same age as, the most resent PoW block. + CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_block_height, false, "stake input refs' max related block height is " << max_related_block_height << " while last PoW block height is " << last_pow_block_height); + + TIME_MEASURE_FINISH_PD(pos_validate_get_out_keys_for_inputs); + + // build a ring of references + vector ring; + ring.reserve(scan_contex.zc_outs.size()); + for(auto& zc_out : scan_contex.zc_outs) + ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.blinded_asset_id, zc_out.concealing_point); + + crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id); + + uint8_t err = 0; + TIME_MEASURE_START_PD(pos_validate_zvp); + r = crypto::zarcanum_verify_proof(id, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, basic_diff, sig, &err); + TIME_MEASURE_FINISH_PD(pos_validate_zvp); + CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << (int)err); + //std::stringstream ss; + //std::cout << " validate_pos_block > get_output_keys_for_input_with_checks: " << ENDL << ss.str(); + } + + return true; + } + else + { + // old PoS non-hidden amount scheme + CHECK_AND_ASSERT_MES(b.miner_tx.version <= TRANSACTION_VERSION_PRE_HF4, false, "PoS miner tx has incorrect version: " << b.miner_tx.version); + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "incorrect input 1 type: " << b.miner_tx.vin[1].type().name() << ", txin_to_key expected"); + const txin_to_key& intk = boost::get(b.miner_tx.vin[1]); + amount = intk.amount; + + CHECK_AND_ASSERT_MES(intk.key_offsets.size(), false, "wrong miner transaction"); + + CHECK_AND_ASSERT_MES(amount!=0, false, "failed to build kernel_stake, amount == 0"); + + LOG_PRINT_L2("STAKE KERNEL for bl ID: " << get_block_hash(b) << ENDL + << print_stake_kernel_info(sk) + << "amount: " << print_money(amount) << ENDL + << "kernel_hash: " << kernel_hash); + + final_diff = basic_diff / amount; + if (!check_hash(kernel_hash, final_diff)) + { + LOG_ERROR("PoS difficulty check failed for block " << get_block_hash(b) << " @ HEIGHT " << get_block_height(b) << ":" << ENDL + << " basic_diff: " << basic_diff << ENDL + << " final_diff: " << final_diff << ENDL + << " amount: " << print_money_brief(amount) << ENDL + << " kernel_hash: " << kernel_hash << ENDL + ); + return false; + } + + //validate signature + uint64_t max_related_block_height = 0; + const txin_to_key& coinstake_in = boost::get(b.miner_tx.vin[1]); + + if (!for_altchain) + { + // Do coinstake input validation for main chain only. + // Txs in alternative PoS blocks (including miner_tx) are validated by validate_alt_block_txs() + uint64_t source_max_unlock_time_for_pos_coinbase = 0; + r = check_tx_input(b.miner_tx, 1, coinstake_in, id, max_related_block_height, source_max_unlock_time_for_pos_coinbase); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate coinstake input in miner tx, block_id = " << get_block_hash(b)); + + if (m_core_runtime_config.is_hardfork_active_for_height(1, get_block_height(b))) + { + uint64_t last_pow_h = get_last_x_block_height(false); + CHECK_AND_ASSERT_MES(max_related_block_height <= last_pow_h, false, "Failed to validate coinbase in PoS block, condition failed: max_related_block_height(" << max_related_block_height << ") <= last_pow_h(" << last_pow_h << ")"); + //let's check that coinbase amount and unlock time + r = validate_pos_coinbase_outs_unlock_time(b.miner_tx, coinstake_in.amount, source_max_unlock_time_for_pos_coinbase); + CHECK_AND_ASSERT_MES(r, false, "Failed to validate_pos_coinbase_outs_unlock_time() in miner tx, block_id = " << get_block_hash(b) + << "source_max_unlock_time_for_pos_coinbase=" << source_max_unlock_time_for_pos_coinbase); + } + else + { + CHECK_AND_ASSERT_MES(is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase), false, "Failed to validate coinbase in PoS block, condition failed: is_tx_spendtime_unlocked(source_max_unlock_time_for_pos_coinbase)(" << source_max_unlock_time_for_pos_coinbase << ")"); + } + } + + uint64_t block_height = for_altchain ? split_height + alt_chain.size() : m_db_blocks.size(); + uint64_t coinstake_age = block_height - max_related_block_height - 1; + + CHECK_AND_ASSERT_MES(coinstake_age >= m_core_runtime_config.min_coinstake_age, false, + "Coinstake age is: " << coinstake_age << " is less than minimum expected: " << m_core_runtime_config.min_coinstake_age); + } return true; } @@ -5279,24 +6268,72 @@ bool get_tx_from_cache(const crypto::hash& tx_id, transactions_map& tx_cache, tr return true; } //------------------------------------------------------------------ +bool blockchain_storage::collect_rangeproofs_data_from_tx(const transaction& tx, const crypto::hash& tx_id, std::vector& agregated_proofs) +{ + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + return true; + + size_t range_proofs_count = 0; + size_t out_index_offset = 0; //Consolidated Transactions have multiple zc_outs_range_proof entries + for (const auto& a : tx.proofs) + { + if (a.type() == typeid(zc_outs_range_proof)) + { + const zc_outs_range_proof& zcrp = boost::get(a); + + // validate aggregation proof + std::vector amount_commitment_ptrs_1div8, blinded_asset_id_ptrs_1div8; + for(size_t j = out_index_offset; j < tx.vout.size(); ++j) + { + CHECKED_GET_SPECIFIC_VARIANT(tx.vout[j], const tx_out_zarcanum, zcout, false); + amount_commitment_ptrs_1div8.push_back(&zcout.amount_commitment); + blinded_asset_id_ptrs_1div8.push_back(&zcout.blinded_asset_id); + } + uint8_t err = 0; + bool r = crypto::verify_vector_UG_aggregation_proof(tx_id, amount_commitment_ptrs_1div8, blinded_asset_id_ptrs_1div8, zcrp.aggregation_proof, &err); + CHECK_AND_ASSERT_MES(r, false, "verify_vector_UG_aggregation_proof failed with err code " << (int)err); + + + agregated_proofs.emplace_back(zcrp); + + // convert amount commitments for aggregation from public_key to point_t form + // TODO: consider refactoring this ugly code + for (uint8_t i = 0; i != zcrp.aggregation_proof.amount_commitments_for_rp_aggregation.size(); i++) + agregated_proofs.back().amount_commitments.emplace_back(zcrp.aggregation_proof.amount_commitments_for_rp_aggregation[i]); + + out_index_offset += zcrp.aggregation_proof.amount_commitments_for_rp_aggregation.size(); + range_proofs_count++; + } + } + CHECK_AND_ASSERT_MES(out_index_offset == tx.vout.size(), false, "range proof elements count doesn't match with outputs count: " << out_index_offset << " != " << tx.vout.size()); + CHECK_AND_ASSERT_MES(range_proofs_count > 0, false, "transaction " << get_transaction_hash(tx) << " doesn't have range proofs"); + CHECK_AND_ASSERT_MES(range_proofs_count == 1 || (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE), false, "transaction " << get_transaction_hash(tx) + << " doesn't have TX_FLAG_SIGNATURE_MODE_SEPARATE but has range_proofs_count = " << range_proofs_count); + + return true; +} + bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc) { TIME_MEASURE_START_PD_MS(block_processing_time_0_ms); CRITICAL_REGION_LOCAL(m_read_lock); TIME_MEASURE_START_PD(block_processing_time_1); + + uint64_t height = get_current_blockchain_size(); // height <-> block height correspondence is validated in prevalidate_miner_transaction() + if(bl.prev_id != get_top_block_id()) { - LOG_PRINT_L0("Block with id: " << id << ENDL - << "have wrong prev_id: " << bl.prev_id << ENDL + LOG_PRINT_L0("Block with id: " << id << " @ " << height << ENDL + << "has wrong prev_id: " << bl.prev_id << ENDL << "expected: " << get_top_block_id()); return false; } if(!check_block_timestamp_main(bl)) { - LOG_PRINT_L0("Block with id: " << id << ENDL - << "have invalid timestamp: " << bl.timestamp); - //add_block_as_invalid(bl, id);//do not add blocks to invalid storage befor proof of work check was passed + LOG_PRINT_L0("Block with id: " << id << " @ " << height << ENDL + << "has invalid timestamp: " << bl.timestamp); + // do not add this block to invalid block list prior to proof of work check bvc.m_verification_failed = true; return false; } @@ -5306,7 +6343,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt m_is_in_checkpoint_zone = true; if (!m_checkpoints.check_block(get_current_blockchain_size(), id)) { - LOG_ERROR("CHECKPOINT VALIDATION FAILED"); + LOG_ERROR("CHECKPOINT VALIDATION FAILED @ " << height); bvc.m_verification_failed = true; return false; } @@ -5315,17 +6352,24 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt m_is_in_checkpoint_zone = false; crypto::hash proof_hash = null_hash; - uint64_t pos_coinstake_amount = 0; + uint64_t pos_coinstake_amount = UINT64_MAX; wide_difficulty_type this_coin_diff = 0; bool is_pos_bl = is_pos_block(bl); //check if PoS allowed in this height CHECK_AND_ASSERT_MES_CUSTOM(!(is_pos_bl && m_db_blocks.size() < m_core_runtime_config.pos_minimum_heigh), false, bvc.m_verification_failed = true, "PoS block not allowed on height " << m_db_blocks.size()); + if (!prevalidate_miner_transaction(bl, m_db_blocks.size(), is_pos_bl)) + { + LOG_PRINT_L0("Block with id: " << id << " @ " << height << " failed to pass miner tx prevalidation"); + bvc.m_verification_failed = true; + return false; + } + //check proof of work TIME_MEASURE_START_PD(target_calculating_time_2); wide_difficulty_type current_diffic = get_next_diff_conditional(is_pos_bl); CHECK_AND_ASSERT_MES_CUSTOM(current_diffic, false, bvc.m_verification_failed = true, "!!!!!!!!! difficulty overhead !!!!!!!!!"); - TIME_MEASURE_FINISH_PD(target_calculating_time_2); + TIME_MEASURE_FINISH_PD(target_calculating_time_2); TIME_MEASURE_START_PD(longhash_calculating_time_3); if (is_pos_bl) @@ -5349,17 +6393,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt return false; } } - TIME_MEASURE_FINISH_PD(longhash_calculating_time_3); + TIME_MEASURE_FINISH_PD(longhash_calculating_time_3); size_t aliases_count_befor_block = m_db_aliases.size(); - if (!prevalidate_miner_transaction(bl, m_db_blocks.size(), is_pos_bl)) - { - LOG_PRINT_L0("Block with id: " << id - << " failed to pass prevalidation"); - bvc.m_verification_failed = true; - return false; - } size_t cumulative_block_size = 0; size_t coinbase_blob_size = get_object_blobsize(bl.miner_tx); @@ -5379,7 +6416,7 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt TIME_MEASURE_START_PD(all_txs_insert_time_5); if (!add_transaction_from_block(bl.miner_tx, get_transaction_hash(bl.miner_tx), id, get_current_blockchain_size(), get_block_datetime(bl))) { - LOG_PRINT_L0("Block with id: " << id << " failed to add transaction to blockchain storage"); + LOG_PRINT_L0("Block with id: " << id << " failed to add miner transaction to the blockchain storage"); bvc.m_verification_failed = true; return false; } @@ -5391,10 +6428,14 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt size_t tx_processed_count = 0; + size_t tx_total_inputs_count = 0; + uint64_t tx_total_inputs_processing_time = 0; uint64_t fee_summary = 0; uint64_t burned_coins = 0; std::list block_summary_kimages; + std::vector range_proofs_agregated; + for(const crypto::hash& tx_id : bl.tx_hashes) { transaction tx; @@ -5423,12 +6464,29 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt append_per_block_increments_for_tx(tx, gindices); - //If we under checkpoints, ring signatures should be pruned + //If we under checkpoints, attachments, ring signatures and proofs should be pruned if(m_is_in_checkpoint_zone) { - tx.signatures.clear(); tx.attachment.clear(); + tx.signatures.clear(); + tx.proofs.clear(); } + + //std::vector tx_outs_commitments; + if (!m_is_in_checkpoint_zone) + { + auto cleanup = [&](){ purge_block_data_from_blockchain(bl, tx_processed_count); bvc.m_verification_failed = true; }; + + CHECK_AND_ASSERT_MES_CUSTOM(collect_rangeproofs_data_from_tx(tx, tx_id, range_proofs_agregated), false, cleanup(), + "block " << id << ", tx " << tx_id << ": collect_rangeproofs_data_from_tx failed"); + + CHECK_AND_ASSERT_MES_CUSTOM(check_tx_balance(tx, tx_id), false, cleanup(), + "block " << id << ", tx " << tx_id << ": check_tx_balance failed"); + + CHECK_AND_ASSERT_MES_CUSTOM(verify_asset_surjection_proof(tx, tx_id), false, cleanup(), + "block " << id << ", tx " << tx_id << ": verify_asset_surjection_proof failed"); + } + TIME_MEASURE_START_PD(tx_add_one_tx_time); TIME_MEASURE_START_PD(tx_check_inputs_time); if(!check_tx_inputs(tx, tx_id)) @@ -5448,6 +6506,8 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt return false; } TIME_MEASURE_FINISH_PD(tx_check_inputs_time); + tx_total_inputs_processing_time += tx_check_inputs_time; + tx_total_inputs_count += tx.vin.size(); burned_coins += get_burned_amount(tx); TIME_MEASURE_START_PD(tx_prapare_append); @@ -5493,17 +6553,49 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt return false; } - uint64_t base_reward = 0; boost::multiprecision::uint128_t already_generated_coins = m_db_blocks.size() ? m_db_blocks.back()->already_generated_coins:0; - if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) + uint64_t base_reward = get_base_block_reward(is_pos_bl, already_generated_coins, height); + + if (!m_is_in_checkpoint_zone) { - LOG_PRINT_L0("Block with id: " << id - << " have wrong miner transaction"); - purge_block_data_from_blockchain(bl, tx_processed_count); - bvc.m_verification_failed = true; - return false; + // validate_miner_transaction will check balance proof and asset surjection proof + // and, as a side effect, it MAY recalculate base_reward, consider redisign, TODO -- sowle + TIME_MEASURE_START_PD(validate_miner_transaction_time); + if (!validate_miner_transaction(bl, cumulative_block_size, fee_summary, base_reward, already_generated_coins)) // TODO @#@# base_reward will be calculated once again, consider refactoring + { + LOG_PRINT_L0("Block with id: " << id + << " have wrong miner transaction"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(validate_miner_transaction_time); + + TIME_MEASURE_START_PD(collect_rangeproofs_data_from_tx_time); + if (!collect_rangeproofs_data_from_tx(bl.miner_tx, get_transaction_hash(bl.miner_tx), range_proofs_agregated)) + { + LOG_PRINT_L0("Block with id: " << id + << " have wrong miner tx, failed to collect_rangeproofs_data_from_tx()"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(collect_rangeproofs_data_from_tx_time); + + //validate range proofs + TIME_MEASURE_START_PD(verify_multiple_zc_outs_range_proofs_time); + if (!verify_multiple_zc_outs_range_proofs(range_proofs_agregated)) + { + LOG_PRINT_L0("Block with id: " << id + << " have failed to verify multiple rangeproofs"); + purge_block_data_from_blockchain(bl, tx_processed_count); + bvc.m_verification_failed = true; + return false; + } + TIME_MEASURE_FINISH_PD(verify_multiple_zc_outs_range_proofs_time); } + //fill block_extended_info block_extended_info bei = boost::value_initialized(); bei.bl = bl; @@ -5548,11 +6640,12 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt bvc.m_verification_failed = true; return false; } - - bei.cumulative_diff_adjusted += cumulative_diff_delta; + //this used only in pre-hardfork 1 + bei.cumulative_diff_adjusted += cumulative_diff_delta; ////////////////////////////////////////////////////////////////////////// // rebuild cumulative_diff_precise_adjusted for whole period + // cumulative_diff_precise_adjusted - native cumulative difficulty adjusted ONLY by sequence_factor wide_difficulty_type diff_precise_adj = correct_difficulty_with_sequence_factor(sequence_factor, current_diffic); bei.cumulative_diff_precise_adjusted = last_x_h ? m_db_blocks[last_x_h]->cumulative_diff_precise_adjusted + diff_precise_adj : diff_precise_adj; @@ -5567,6 +6660,10 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt return false; } bei.already_generated_coins = already_generated_coins - burned_coins + base_reward; + if (bei.bl.miner_tx.version >= TRANSACTION_VERSION_POST_HF4) + { + bei.already_generated_coins -= fee_summary; + } auto blocks_index_ptr = m_db_blocks_index.get(id); if (blocks_index_ptr) @@ -5617,13 +6714,21 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt TIME_MEASURE_FINISH_PD_MS(block_processing_time_0_ms); //print result - stringstream powpos_str_entry, timestamp_str_entry; + stringstream powpos_str_entry, timestamp_str_entry, pos_validation_str_entry; if (is_pos_bl) { // PoS int64_t actual_ts = get_block_datetime(bei.bl); // signed int is intentionally used here int64_t ts_diff = actual_ts - m_core_runtime_config.get_core_time(); - powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: " << print_money_brief(pos_coinstake_amount) << ", final_difficulty: " << this_coin_diff; + powpos_str_entry << "PoS:\t" << proof_hash << ", stake amount: "; + if (pos_coinstake_amount != UINT64_MAX) + { + powpos_str_entry << print_money_brief(pos_coinstake_amount); + powpos_str_entry << ", final_difficulty: " << this_coin_diff; + } + else + powpos_str_entry << "hidden"; timestamp_str_entry << ", actual ts: " << actual_ts << " (diff: " << std::showpos << ts_diff << "s) block ts: " << std::noshowpos << bei.bl.timestamp << " (shift: " << std::showpos << static_cast(bei.bl.timestamp) - actual_ts << ")"; + pos_validation_str_entry << "(" << m_performance_data.pos_validate_ki_search.get_last_val() << "/" << m_performance_data.pos_validate_get_out_keys_for_inputs.get_last_val() << "/" << m_performance_data.pos_validate_zvp.get_last_val() << ")"; } else { // PoW @@ -5638,18 +6743,41 @@ bool blockchain_storage::handle_block_to_main_chain(const block& bl, const crypt LOG_PRINT_L1("+++++ BLOCK SUCCESSFULLY ADDED " << (is_pos_bl ? "[PoS]" : "[PoW]") << "["<< static_cast(bei.bl.major_version) << "." << static_cast(bei.bl.minor_version) << "] "<< " Sq: " << sequence_factor << ENDL << "id:\t" << id << timestamp_str_entry.str() << ENDL << powpos_str_entry.str() - << ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_adj: " << bei.cumulative_diff_adjusted << " (+" << cumulative_diff_delta << ")" + << ENDL << "HEIGHT " << bei.height << ", difficulty: " << current_diffic << ", cumul_diff_precise: " << bei.cumulative_diff_precise << ", cumul_diff_precise_adj: " << bei.cumulative_diff_precise_adjusted << " (+" << cumulative_diff_delta << ")" << ENDL << "block reward: " << print_money_brief(base_reward + fee_summary) << " (" << print_money_brief(base_reward) << " + " << print_money_brief(fee_summary) << ")" << ", coinbase_blob_size: " << coinbase_blob_size << ", cumulative size: " << cumulative_block_size << ", tx_count: " << bei.bl.tx_hashes.size() << ", timing: " << block_processing_time_0_ms << "ms" << "(micrsec:" << block_processing_time_1 << "(" << target_calculating_time_2 << "(" << m_performance_data.target_calculating_enum_blocks.get_last_val() << "/" << m_performance_data.target_calculating_calc.get_last_val() << ")" - << "/" << longhash_calculating_time_3 + << "/" << longhash_calculating_time_3 << pos_validation_str_entry.str() << "/" << insert_time_4 << "/" << all_txs_insert_time_5 - << "/" << etc_stuff_6 + << "/" << etc_stuff_6 + << "/" << tx_total_inputs_processing_time << " of " << tx_total_inputs_count + << "/(" << m_performance_data.validate_miner_transaction_time.get_last_val() << "|" + << m_performance_data.collect_rangeproofs_data_from_tx_time.get_last_val() << "|" + << m_performance_data.verify_multiple_zc_outs_range_proofs_time.get_last_val() << "~" + << range_proofs_agregated.size() + << ")" << "))"); + { + static epee::math_helper::average blocks_processing_time_avg_pos, blocks_processing_time_avg_pow; + (is_pos_bl ? blocks_processing_time_avg_pos : blocks_processing_time_avg_pow).push(block_processing_time_0_ms); + + static std::deque blocks_processing_time_median_pos, blocks_processing_time_median_pow; + std::deque& d = (is_pos_bl ? blocks_processing_time_median_pos : blocks_processing_time_median_pow); + d.push_back(block_processing_time_0_ms); + if (d.size() > 200) + d.pop_front(); + + uint64_t median_pow = epee::misc_utils::median(blocks_processing_time_median_pow); + uint64_t median_pos = epee::misc_utils::median(blocks_processing_time_median_pos); + + LOG_PRINT_YELLOW("last 30 blocks of type processing time (ms): PoW: " << std::setw(3) << (uint64_t)blocks_processing_time_avg_pow.get_avg() << ", PoS: " << (uint64_t)blocks_processing_time_avg_pos.get_avg(), LOG_LEVEL_1); + LOG_PRINT_YELLOW("last 200 blocks of type processing time (median, ms): PoW: " << std::setw(3) << median_pow << ", PoS: " << median_pos, LOG_LEVEL_1); + } + on_block_added(bei, id, block_summary_kimages); bvc.m_added_to_main_chain = true; @@ -5739,61 +6867,46 @@ bool blockchain_storage::update_next_comulative_size_limit() return true; } //------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_1_zone()const +bool blockchain_storage::is_hardfork_active(size_t hardfork_id) const { - return is_after_hardfork_1_zone(m_db_blocks.size()); -} -//------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_1_zone(uint64_t height)const -{ - if (height > m_core_runtime_config.hard_fork_01_starts_after_height) - return true; - return false; -} -//------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_2_zone()const -{ - return is_after_hardfork_2_zone(m_db_blocks.size()); -} -//------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_3_zone()const -{ - return is_after_hardfork_3_zone(m_db_blocks.size()); -} -//------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_2_zone(uint64_t height)const -{ - if (height > m_core_runtime_config.hard_fork_02_starts_after_height) - return true; - return false; -} -//------------------------------------------------------------------ -bool blockchain_storage::is_after_hardfork_3_zone(uint64_t height)const -{ - if (height > m_core_runtime_config.hard_fork_03_starts_after_height) - return true; - return false; + return m_core_runtime_config.is_hardfork_active_for_height(hardfork_id, m_db_blocks.size()); // note using m_db_blocks.size() ( == top_block_height + 1 ) } //------------------------------------------------------------------ bool blockchain_storage::prevalidate_block(const block& bl) { + + uint64_t block_height = get_block_height(bl); + + //before hard_fork1 - if (bl.major_version == BLOCK_MAJOR_VERSION_INITIAL && get_block_height(bl) <= m_core_runtime_config.hard_fork_01_starts_after_height) + if (bl.major_version == BLOCK_MAJOR_VERSION_INITIAL && get_block_height(bl) <= m_core_runtime_config.hard_forks.m_height_the_hardfork_n_active_after[1]) return true; - - //after hard_fork1 and before hard_fork3 - if ( get_block_height(bl) > m_core_runtime_config.hard_fork_01_starts_after_height && - get_block_height(bl) <= m_core_runtime_config.hard_fork_03_starts_after_height - ) + // HF0 + if (!m_core_runtime_config.is_hardfork_active_for_height(1, block_height)) { - if (bl.major_version <= HF1_BLOCK_MAJOR_VERSION ) - return true; - else - return false; + // at HF0 we do not check block version + return true; } - //after hard_fork3 + // HF1, HF2 + if ( m_core_runtime_config.is_hardfork_active_for_height(1, block_height) && + !m_core_runtime_config.is_hardfork_active_for_height(3, block_height)) + { + CHECK_AND_ASSERT_MES(bl.major_version <= HF1_BLOCK_MAJOR_VERSION, false, "HF1/HF2, incorrect block major version: " << (int)bl.major_version); + return true; + } + + // HF3 and !HF4 + if (m_core_runtime_config.is_hardfork_active_for_height(3, block_height) && + !m_core_runtime_config.is_hardfork_active_for_height(4, block_height)) + { + CHECK_AND_ASSERT_MES(bl.major_version == HF3_BLOCK_MAJOR_VERSION, false, "HF3 incorrect block major version: " << (int)bl.major_version); + CHECK_AND_ASSERT_MES(bl.minor_version <= HF3_BLOCK_MINOR_VERSION, false, "HF3 incorrect block minor version: " << (int)bl.minor_version); + return true; + } + + // rule for unknown versions if (bl.major_version > CURRENT_BLOCK_MAJOR_VERSION) { LOG_ERROR("prevalidation failed for block " << get_block_hash(bl) << ": major block version " << static_cast(bl.major_version) << " is incorrect, " << CURRENT_BLOCK_MAJOR_VERSION << " is expected" << ENDL @@ -5992,10 +7105,12 @@ bool blockchain_storage::build_kernel(const block& bl, stake_kernel& kernel, uin CHECK_AND_ASSERT_MES(txin.key_offsets.size(), false, "wrong miner transaction"); amount = txin.amount; - return build_kernel(txin.amount, txin.k_image, kernel, stake_modifier, bl.timestamp); + return build_kernel(txin.k_image, kernel, stake_modifier, bl.timestamp); } //------------------------------------------------------------------ -bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain, uint64_t split_height, crypto::hash *p_last_block_hash /* = nullptr */) const +bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain, uint64_t split_height, + crypto::hash* p_last_block_hash /* = nullptr */, + uint64_t* p_last_pow_block_height /* = nullptr */ ) const { CRITICAL_REGION_LOCAL(m_read_lock); sm = stake_modifier_type(); @@ -6017,11 +7132,13 @@ bool blockchain_storage::build_stake_modifier(stake_modifier_type& sm, const alt if (p_last_block_hash != nullptr) *p_last_block_hash = get_block_hash(m_db_blocks.back()->bl); + if (p_last_pow_block_height != nullptr) + *p_last_pow_block_height = pbei_last_pow->height; + return true; } //------------------------------------------------------------------ -bool blockchain_storage::build_kernel(uint64_t amount, - const crypto::key_image& ki, +bool blockchain_storage::build_kernel(const crypto::key_image& ki, stake_kernel& kernel, const stake_modifier_type& stake_modifier, uint64_t timestamp)const @@ -6034,46 +7151,6 @@ bool blockchain_storage::build_kernel(uint64_t amount, return true; } //------------------------------------------------------------------ -bool blockchain_storage::scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp) const -{ - uint64_t timstamp_start = 0; - wide_difficulty_type basic_diff = 0; - CRITICAL_REGION_BEGIN(m_read_lock); - timstamp_start = m_db_blocks.back()->bl.timestamp; - basic_diff = get_next_diff_conditional(true); - CRITICAL_REGION_END(); - - stake_modifier_type sm = AUTO_VAL_INIT(sm); - bool r = build_stake_modifier(sm); - CHECK_AND_ASSERT_MES(r, false, "failed to build_stake_modifier"); - - for (size_t i = 0; i != sp.pos_entries.size(); i++) - { - stake_kernel sk = AUTO_VAL_INIT(sk); - build_kernel(sp.pos_entries[i].amount, sp.pos_entries[i].keyimage, sk, sm, 0); - - for (uint64_t ts = timstamp_start; ts < timstamp_start + POS_SCAN_WINDOW; ts++) - { - sk.block_timestamp = ts; - crypto::hash kernel_hash = crypto::cn_fast_hash(&sk, sizeof(sk)); - wide_difficulty_type this_coin_diff = basic_diff / sp.pos_entries[i].amount; - if (!check_hash(kernel_hash, this_coin_diff)) - continue; - else - { - //found kernel - LOG_PRINT_GREEN("Found kernel: amount=" << print_money(sp.pos_entries[i].amount) << ", key_image" << sp.pos_entries[i].keyimage, LOG_LEVEL_0); - rsp.index = i; - rsp.block_timestamp = ts; - rsp.status = API_RETURN_CODE_OK; - return true; - } - } - } - rsp.status = API_RETURN_CODE_NOT_FOUND; - return false; -} -//------------------------------------------------------------------ void blockchain_storage::set_core_runtime_config(const core_runtime_config& pc) const { m_core_runtime_config = pc; @@ -6226,12 +7303,11 @@ void blockchain_storage::calculate_local_gindex_lookup_table_for_height(uint64_t } //------------------------------------------------------------------ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, - std::unordered_set& collected_keyimages, + std::unordered_set& collected_keyimages, const txs_by_id_and_height_altchain& alt_chain_tx_ids, - const crypto::hash& bl_id, - const crypto::hash& input_tx_hash, + const crypto::hash& bl_id, + const crypto::hash& input_tx_hash, size_t input_index, - const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::unordered_set& alt_chain_block_ids, @@ -6266,27 +7342,30 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, CRITICAL_REGION_LOCAL(m_read_lock); bool r = false; - if (p_max_related_block_height != nullptr) - *p_max_related_block_height = 0; + uint64_t max_related_block_height = 0; CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size(), false, "invalid input index: " << input_index); + + const txin_v& input_v = input_tx.vin[input_index]; - const txin_to_key& input_to_key = get_to_key_input_from_txin_v(input_v); + const crypto::key_image& input_key_image = get_key_image_from_txin_v(input_v); + const std::vector& input_key_offsets = get_key_offsets_from_txin_v(input_v); + const uint64_t input_amount = get_amount_from_variant(input_v); // check case b1: key_image spent status in main chain, should be either non-spent or has spent height >= split_height - auto p = m_db_spent_keys.get(input_to_key.k_image); - CHECK_AND_ASSERT_MES(p == nullptr || *p >= split_height, false, "key image " << input_to_key.k_image << " has been already spent in main chain at height " << *p << ", split height: " << split_height); + auto p = m_db_spent_keys.get(input_key_image); + CHECK_AND_ASSERT_MES(p == nullptr || *p >= split_height, false, "key image " << input_key_image << " has been already spent in main chain at height " << *p << ", split height: " << split_height); TIME_MEASURE_START(ki_lookup_time); //check key_image in altchain //check among this alt block already collected key images first - if (collected_keyimages.find(input_to_key.k_image) != collected_keyimages.end()) + if (collected_keyimages.find(input_key_image) != collected_keyimages.end()) { // cases b2, b3 - LOG_ERROR("key image " << input_to_key.k_image << " already spent in this alt block"); + LOG_ERROR("key image " << input_key_image << " already spent in this alt block"); return false; } - auto ki_it = m_altblocks_keyimages.find(input_to_key.k_image); + auto ki_it = m_altblocks_keyimages.find(input_key_image); if (ki_it != m_altblocks_keyimages.end()) { //have some entry for this key image. Check if this key image belongs to this alt chain @@ -6296,18 +7375,18 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, if (alt_chain_block_ids.find(h) != alt_chain_block_ids.end()) { // cases b2, b3 - LOG_ERROR("key image " << input_to_key.k_image << " already spent in altchain"); + LOG_ERROR("key image " << input_key_image << " already spent in altchain"); return false; } } } //update altchain with key image - collected_keyimages.insert(input_to_key.k_image); + collected_keyimages.insert(input_key_image); TIME_MEASURE_FINISH(ki_lookup_time); ki_lookuptime = ki_lookup_time; - std::vector abs_key_offsets = relative_output_offsets_to_absolute(input_to_key.key_offsets); - CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input_to_key.key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input_to_key.key_offsets.size()==" << input_to_key.key_offsets.size()); + std::vector abs_key_offsets = relative_output_offsets_to_absolute(input_key_offsets); + CHECK_AND_ASSERT_MES(abs_key_offsets.size() > 0 && abs_key_offsets.size() == input_key_offsets.size(), false, "internal error: abs_key_offsets.size()==" << abs_key_offsets.size() << ", input_key_offsets.size()==" << input_key_offsets.size()); // eventually we should found all public keys for all outputs this input refers to, for checking ring signature std::vector pub_keys(abs_key_offsets.size(), null_pkey); @@ -6322,7 +7401,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, if (!alt_chain.empty()) { - auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input_to_key.amount); + auto abg_it = alt_chain.back()->second.gindex_lookup_table.find(input_amount); if (abg_it != alt_chain.back()->second.gindex_lookup_table.end()) { amount_touched_altchain = true; @@ -6332,13 +7411,13 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, else { //quite easy, - global_outs_for_amount = m_db_outputs.get_item_size(input_to_key.amount); + global_outs_for_amount = m_db_outputs.get_item_size(input_amount); } } else { //quite easy, - global_outs_for_amount = m_db_outputs.get_item_size(input_to_key.amount); + global_outs_for_amount = m_db_outputs.get_item_size(input_amount); } CHECK_AND_ASSERT_MES(pub_keys.size() == abs_key_offsets.size(), false, "pub_keys.size()==" << pub_keys.size() << " != abs_key_offsets.size()==" << abs_key_offsets.size()); // just a little bit of paranoia @@ -6356,7 +7435,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, { uint64_t offset_gindex = boost::get(off); CHECK_AND_ASSERT_MES(amount_touched_altchain || (offset_gindex < global_outs_for_amount), false, - "invalid global output index " << offset_gindex << " for amount=" << input_to_key.amount << + "invalid global output index " << offset_gindex << " for amount=" << input_amount << ", max is " << global_outs_for_amount << ", referred to by offset #" << pk_n << ", amount_touched_altchain = " << amount_touched_altchain); @@ -6365,7 +7444,7 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, bool found_the_key = false; for (auto alt_it = alt_chain.rbegin(); alt_it != alt_chain.rend(); alt_it++) { - auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input_to_key.amount); + auto it_aag = (*alt_it)->second.gindex_lookup_table.find(input_amount); if (it_aag == (*alt_it)->second.gindex_lookup_table.end()) { CHECK_AND_ASSERT_MES(alt_it != alt_chain.rbegin(), false, "internal error: was marked as amount_touched_altchain but unable to find on first entry"); @@ -6379,8 +7458,8 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, //TODO: At the moment we ignore check of mix_attr against mixing to simplify alt chain check, but in future consider it for stronger validation uint64_t local_offset = offset_gindex - it_aag->second; auto& alt_keys = (*alt_it)->second.outputs_pub_keys; - CHECK_AND_ASSERT_MES(local_offset < alt_keys[input_to_key.amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input_to_key.amount << " ].size()=" << alt_keys.size()); - const output_key_or_htlc_v& out_in_alt = alt_keys[input_to_key.amount][local_offset]; + CHECK_AND_ASSERT_MES(local_offset < alt_keys[input_amount].size(), false, "Internal error: local_offset=" << local_offset << " while alt_keys[" << input_amount << " ].size()=" << alt_keys.size()); + const output_key_or_htlc_v& out_in_alt = alt_keys[input_amount][local_offset]; /* here we do validation against compatibility of input and output type @@ -6417,8 +7496,8 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, continue; //otherwise lookup in main chain index } - auto p = m_db_outputs.get_subitem(input_to_key.amount, offset_gindex); - CHECK_AND_ASSERT_MES(p != nullptr, false, "global output was not found, amount: " << input_to_key.amount << ", gindex: " << offset_gindex << ", referred to by offset #" << pk_n); + auto p = m_db_outputs.get_subitem(input_amount, offset_gindex); + CHECK_AND_ASSERT_MES(p != nullptr, false, "global output was not found, amount: " << input_amount << ", gindex: " << offset_gindex << ", referred to by offset #" << pk_n); tx_id = p->tx_id; out_n = p->out_no; } @@ -6434,105 +7513,158 @@ bool blockchain_storage::validate_alt_block_input(const transaction& input_tx, uint64_t height_of_source_block = it->second.second; CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed"); - /* - here we do validation against compatibility of input and output type - - TxOutput | TxInput | Allowed - ---------------------------- - HTLC | HTLC | ONLY IF HTLC NOT EXPIRED - HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED - TO_KEY | HTLC | NOT - TO_KEY | TO_KEY | YES - */ - //source tx found in altchain CHECK_AND_ASSERT_MES(it->second.first.vout.size() > out_n, false, "Internal error: out_n(" << out_n << ") >= it->second.vout.size()(" << it->second.first.vout.size() << ")"); - txout_target_v out_target_v = it->second.first.vout[out_n].target; - bool r = is_output_allowed_for_input(out_target_v, input_v, height_of_current_alt_block - height_of_source_block); - CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); + VARIANT_SWITCH_BEGIN(it->second.first.vout[out_n]); + VARIANT_CASE_CONST(tx_out_bare, o) + { + /* + here we do validation against compatibility of input and output type + TxOutput | TxInput | Allowed + ---------------------------- + HTLC | HTLC | ONLY IF HTLC NOT EXPIRED + HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED + TO_KEY | HTLC | NOT + TO_KEY | TO_KEY | YES + */ + txout_target_v out_target_v = o.target; - if (out_target_v.type() == typeid(txout_htlc)) - { - //source is hltc out - const txout_htlc& htlc = boost::get(out_target_v); - bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true; - pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem; - pub_key_pointers.push_back(&pk); - continue; - } - else if (out_target_v.type() == typeid(txout_to_key)) - { - //source is to_key out - pk = boost::get(out_target_v).key; - pub_key_pointers.push_back(&pk); - continue; - } - else - { - ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name()); + bool r = is_output_allowed_for_input(out_target_v, input_v, height_of_current_alt_block - height_of_source_block); + CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); + if (out_target_v.type() == typeid(txout_htlc)) + { + //source is hltc out + const txout_htlc& htlc = boost::get(out_target_v); + bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true; + pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem; + pub_key_pointers.push_back(&pk); + continue; + } + else if (out_target_v.type() == typeid(txout_to_key)) + { + //source is to_key out + pk = boost::get(out_target_v).key; + pub_key_pointers.push_back(&pk); + continue; + } + else + { + ASSERT_MES_AND_THROW("Unexpected out type for tx_in in altblock: " << out_target_v.type().name()); + } } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); } } auto p = m_db_transactions.get(tx_id); CHECK_AND_ASSERT_MES(p != nullptr && out_n < p->tx.vout.size(), false, "can't find output #" << out_n << " for tx " << tx_id << " referred by offset #" << pk_n); - auto &t = p->tx.vout[out_n].target; - - /* - here we do validation against compatibility of input and output type - TxOutput | TxInput | Allowed - ---------------------------- - HTLC | HTLC | ONLY IF HTLC NOT EXPIRED - HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED - TO_KEY | HTLC | NOT - TO_KEY | TO_KEY | YES - */ - uint64_t height_of_source_block = p->m_keeper_block_height; - CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed"); - bool r = is_output_allowed_for_input(t, input_v, height_of_current_alt_block - height_of_source_block); - CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); - - if (t.type() == typeid(txout_to_key)) + VARIANT_SWITCH_BEGIN(p->tx.vout[out_n]); + VARIANT_CASE_CONST(tx_out_bare, o) { - const txout_to_key& out_tk = boost::get(t); - pk = out_tk.key; + auto &t = o.target; - bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(out_tk.mix_attr, abs_key_offsets.size() - 1); - CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size()); + /* + here we do validation against compatibility of input and output type + TxOutput | TxInput | Allowed + ---------------------------- + HTLC | HTLC | ONLY IF HTLC NOT EXPIRED + HTLC | TO_KEY | ONLY IF HTLC IS EXPIRED + TO_KEY | HTLC | NOT + TO_KEY | TO_KEY | YES + */ + uint64_t height_of_source_block = p->m_keeper_block_height; + CHECK_AND_ASSERT_MES(height_of_current_alt_block > height_of_source_block, false, "Intenral error: height_of_current_alt_block > height_of_source_block failed"); + bool r = is_output_allowed_for_input(t, input_v, height_of_current_alt_block - height_of_source_block); + CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); + + if (t.type() == typeid(txout_to_key)) + { + const txout_to_key& out_tk = boost::get(t); + pk = out_tk.key; + + bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(p->tx.version, out_tk.mix_attr, abs_key_offsets.size() - 1, this->get_core_runtime_config()); + CHECK_AND_ASSERT_MES(mixattr_ok, false, "input offset #" << pk_n << " violates mixin restrictions: mix_attr = " << static_cast(out_tk.mix_attr) << ", input's key_offsets.size = " << abs_key_offsets.size()); + + } + else if (t.type() == typeid(txout_htlc)) + { + const txout_htlc& htlc = boost::get(t); + bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true; + pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem; + } + + // case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid) + CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height); + + if (max_related_block_height < p->m_keeper_block_height) + max_related_block_height = p->m_keeper_block_height; + + // TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks() + // make sure it was actually found + + // let's disable this check due to missing equal check in main chain validation code + //TODO: implement more strict validation with next hard fork + //CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n); + pub_key_pointers.push_back(&pk); } - else if (t.type() == typeid(txout_htlc)) - { - const txout_htlc& htlc = boost::get(t); - bool htlc_expired = htlc.expiration > (height_of_current_alt_block - height_of_source_block) ? false : true; - pk = htlc_expired ? htlc.pkey_refund : htlc.pkey_redeem; - } - - // case b4 (make sure source tx in the main chain is preceding split point, otherwise this referece is invalid) - CHECK_AND_ASSERT_MES(p->m_keeper_block_height < split_height, false, "input offset #" << pk_n << " refers to main chain tx " << tx_id << " at height " << p->m_keeper_block_height << " while split height is " << split_height); - - if (p_max_related_block_height != nullptr && *p_max_related_block_height < p->m_keeper_block_height) - *p_max_related_block_height = p->m_keeper_block_height; - - // TODO: consider checking p->tx for unlock time validity as it's checked in get_output_keys_for_input_with_checks() - // make sure it was actually found - - // let's disable this check due to missing equal check in main chain validation code - //TODO: implement more strict validation with next hard fork - //CHECK_AND_ASSERT_MES(pk != null_pkey, false, "Can't determine output public key for offset " << pk_n << " in related tx: " << tx_id << ", out_n = " << out_n); - pub_key_pointers.push_back(&pk); + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); } + // @#@# TODO review the following checks! + // do input checks (attachment_info, ring signature and extra signature, etc.) - r = check_input_signature(input_tx, input_index, input_to_key, input_tx_hash, input_sigs, pub_key_pointers); - CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); + VARIANT_SWITCH_BEGIN(input_v); + VARIANT_CASE_CONST(txin_to_key, input_to_key) + r = check_input_signature(input_tx, input_index, input_to_key, input_tx_hash, pub_key_pointers); + CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); + VARIANT_CASE_CONST(txin_htlc, input_htlc); + r = check_input_signature(input_tx, input_index, input_htlc, input_tx_hash, pub_key_pointers); + CHECK_AND_ASSERT_MES(r, false, "to_key input validation failed"); + VARIANT_CASE_CONST(txin_zc_input, input_zc); + if (is_pos_miner_tx(input_tx)) + { + // TODO @#@# Special case: handling Zarcanum PoS block input + } + else + { + // TODO @#@# properly handle ZC inputs! check_tx_input below isn't working because of incorrectly assembled ring + /* + uint64_t max_related_block_height = 0; + bool all_tx_ins_have_explicit_asset_ids = true; // stub for now, TODO @#@# + r = check_tx_input(input_tx, input_index, input_zc, input_tx_hash, max_related_block_height, all_tx_ins_have_explicit_asset_ids); + CHECK_AND_ASSERT_MES(r, false, "check_tx_input failed"); + */ + } + VARIANT_CASE_OTHER() + LOG_ERROR("unexpected input type: " << input_v.type().name()); + return false; + VARIANT_SWITCH_END(); + + if (p_max_related_block_height != nullptr) + *p_max_related_block_height = max_related_block_height; + + uint64_t alt_bl_h = split_height + alt_chain.size() + 1; + if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, alt_bl_h)) + { + if (alt_bl_h - max_related_block_height < CURRENCY_HF4_MANDATORY_MIN_COINAGE) + { + LOG_ERROR("Coinage rule broken(altblock): h = " << alt_bl_h << ", max_related_block_height=" << max_related_block_height << ", tx: " << input_tx_hash); + return false; + } + } + + // TODO: consider checking input_tx for valid extra attachment info as it's checked in check_tx_inputs() - return true; } //------------------------------------------------------------------ @@ -6603,7 +7735,13 @@ bool blockchain_storage::is_output_allowed_for_input(const output_key_or_htlc_v& } } //------------------------------------------------------------------ -bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain) const +bool blockchain_storage::is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const +{ + CHECK_AND_ASSERT_MES(in_v.type() == typeid(txin_zc_input), false, "tx_out_zarcanum can only be referenced by txin_zc_input, not by " << in_v.type().name()); + return true; +} +//------------------------------------------------------------------ +bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, uint64_t split_height, const alt_chain_type& alt_chain) const { // Main and alt chain outline: // @@ -6632,8 +7770,8 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx CRITICAL_REGION_LOCAL(m_read_lock); bool r = false; - - CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size() && input_tx.vin[input_index].type() == typeid(txin_multisig), false, "invalid ms input index: " << input_index << " or type"); + CHECK_AND_ASSERT_MES(input_index < input_tx.vin.size() + && input_tx.vin[input_index].type() == typeid(txin_multisig), false, "invalid ms input index: " << input_index << " or type"); const txin_multisig& input = boost::get(input_tx.vin[input_index]); // check corresponding ms out in the main chain @@ -6650,7 +7788,7 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx if (p_source_tx->m_keeper_block_height < split_height) { // cases g1, g2 - return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, p_source_tx->tx, p->out_no); + return check_ms_input(input_tx, input_index, input, input_tx_hash, p_source_tx->tx, p->out_no); } // p_source_tx is above split_height in main chain B, so it can't be a source for this input @@ -6684,17 +7822,22 @@ bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx for (size_t out_n = 0; out_n < tx.vout.size(); ++out_n) { - const tx_out& out = tx.vout[out_n]; - if (out.target.type() == typeid(txout_multisig)) - { - const crypto::hash& ms_out_id = get_multisig_out_id(tx, out_n); - if (ms_out_id == input.multisig_out_id) + VARIANT_SWITCH_BEGIN(tx.vout[out_n]); + VARIANT_CASE_CONST(tx_out_bare, o) + const tx_out_bare& out = o; + if (out.target.type() == typeid(txout_multisig)) { - // cases g3, g4, g5 - output_found = true; - return check_ms_input(input_tx, input_index, input, input_tx_hash, input_sigs, tx, out_n); + const crypto::hash& ms_out_id = get_multisig_out_id(tx, out_n); + if (ms_out_id == input.multisig_out_id) + { + // cases g3, g4, g5 + output_found = true; + return check_ms_input(input_tx, input_index, input, input_tx_hash, tx, out_n); + } } - } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); } return true; }; @@ -6742,29 +7885,34 @@ bool blockchain_storage::get_transaction_from_pool_or_db(const crypto::hash& tx_ bool blockchain_storage::update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei) const { //add tx outputs to gindex_lookup_table - for (auto o : tx.vout) + for (auto ov : tx.vout) { - if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc)) - { - //LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0); - // first, look at local gindexes tables - if (abei.gindex_lookup_table.find(o.amount) == abei.gindex_lookup_table.end()) + VARIANT_SWITCH_BEGIN(ov); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc)) { - // amount was not found in altchain gindexes container, start indexing from current main chain gindex - abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount); - //LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0); + //LOG_PRINT_MAGENTA("ALT_OUT KEY ON H[" << abei.height << "] AMOUNT: " << o.amount, LOG_LEVEL_0); + // first, look at local gindexes tables + if (abei.gindex_lookup_table.find(o.amount) == abei.gindex_lookup_table.end()) + { + // amount was not found in altchain gindexes container, start indexing from current main chain gindex + abei.gindex_lookup_table[o.amount] = m_db_outputs.get_item_size(o.amount); + //LOG_PRINT_MAGENTA("FIRST TOUCH: size=" << abei.gindex_lookup_table[o.amount], LOG_LEVEL_0); + } + if (o.target.type() == typeid(txout_to_key)) + { + abei.outputs_pub_keys[o.amount].push_back(boost::get(o.target).key); + } + else + { + abei.outputs_pub_keys[o.amount].push_back(boost::get(o.target)); + } + + //TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation } - if (o.target.type() == typeid(txout_to_key)) - { - abei.outputs_pub_keys[o.amount].push_back(boost::get(o.target).key); - } - else - { - abei.outputs_pub_keys[o.amount].push_back(boost::get(o.target)); - } - - //TODO: At the moment we ignore check of mix_attr again mixing to simplify alt chain check, but in future consider it for stronger validation - } + VARIANT_CASE_CONST(tx_out_zarcanum, toz) + //@#@ + VARIANT_SWITCH_END(); } return true; } @@ -6813,12 +7961,15 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha if (is_pos_block(b)) { - // check PoS block miner tx in a special way - CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.vin.size() == 2, false, "invalid PoS block's miner_tx, signatures size = " << b.miner_tx.signatures.size() << ", miner_tx.vin.size() = " << b.miner_tx.vin.size()); uint64_t max_related_block_height = 0; uint64_t ki_lookup = 0; - r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, b.miner_tx.signatures[0], split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height); + + // check PoS block miner tx in a special way + CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && b.miner_tx.vin.size() == 2, false, "invalid PoS block's miner_tx, signatures size = " << b.miner_tx.signatures.size() << ", miner_tx.vin.size() = " << b.miner_tx.vin.size()); + + r = validate_alt_block_input(b.miner_tx, collected_keyimages, alt_chain_tx_ids, id, get_block_hash(b), 1, split_height, alt_chain, alt_chain_block_ids, ki_lookup, &max_related_block_height); CHECK_AND_ASSERT_MES(r, false, "miner tx " << get_transaction_hash(b.miner_tx) << ": validation failed"); + ki_lookup_time_total += ki_lookup; // check stake age uint64_t coinstake_age = height - max_related_block_height - 1; @@ -6829,6 +7980,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha CHECK_AND_ASSERT_MES(validate_tx_for_hardfork_specific_terms(b.miner_tx, null_hash, height), false, "miner tx hardfork-specific validation failed"); + std::vector fees; for (auto tx_id : b.tx_hashes) { std::shared_ptr tx_ptr; @@ -6838,19 +7990,23 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha CHECK_AND_ASSERT_MES(get_transaction_from_pool_or_db(tx_id, tx_ptr, split_height), false, "failed to get alt block tx " << tx_id << " with split_height == " << split_height); } const transaction& tx = it == abei.onboard_transactions.end() ? *tx_ptr : it->second; - CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: tx.signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size()); + + CHECK_AND_ASSERT_MES(tx.signatures.size() == tx.vin.size(), false, "invalid tx: signatures.size() == " << tx.signatures.size() << ", tx.vin.size() == " << tx.vin.size()); + + fees.push_back(get_tx_fee(tx)); + for (size_t n = 0; n < tx.vin.size(); ++n) { - if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc)) + if (tx.vin[n].type() == typeid(txin_to_key) || tx.vin[n].type() == typeid(txin_htlc) || tx.vin[n].type() == typeid(txin_zc_input)) { uint64_t ki_lookup = 0; - r = validate_alt_block_input(tx, collected_keyimages, alt_chain_tx_ids, id, tx_id, n, tx.signatures[n], split_height, alt_chain, alt_chain_block_ids, ki_lookup); + r = validate_alt_block_input(tx, collected_keyimages, alt_chain_tx_ids, id, tx_id, n, split_height, alt_chain, alt_chain_block_ids, ki_lookup); CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << ": validation failed"); ki_lookup_time_total += ki_lookup; } else if (tx.vin[n].type() == typeid(txin_multisig)) { - r = validate_alt_block_ms_input(tx, tx_id, n, tx.signatures[n], split_height, alt_chain); + r = validate_alt_block_ms_input(tx, tx_id, n, split_height, alt_chain); CHECK_AND_ASSERT_MES(r, false, "tx " << tx_id << ", input #" << n << " (multisig): validation failed"); } else if (tx.vin[n].type() == typeid(txin_gen)) @@ -6871,6 +8027,7 @@ bool blockchain_storage::validate_alt_block_txs(const block& b, const crypto::ha update_alt_out_indexes_for_tx_in_block(tx, abei); } + abei.this_block_tx_fee_median = epee::misc_utils::median(fees); return true; } diff --git a/src/currency_core/blockchain_storage.h b/src/currency_core/blockchain_storage.h index cad2ca91..5bf57ad4 100644 --- a/src/currency_core/blockchain_storage.h +++ b/src/currency_core/blockchain_storage.h @@ -39,7 +39,7 @@ #include "dispatch_core_events.h" #include "bc_attachments_service_manager.h" #include "common/median_db_cache.h" - +#include "common/variant_helper.h" MARK_AS_POD_C11(crypto::key_image); @@ -68,10 +68,20 @@ namespace currency epee::math_helper::average etc_stuff_6; epee::math_helper::average insert_time_4; epee::math_helper::average raise_block_core_event; + epee::math_helper::average validate_miner_transaction_time; + epee::math_helper::average collect_rangeproofs_data_from_tx_time; + epee::math_helper::average verify_multiple_zc_outs_range_proofs_time; + + //target_calculating_time_2 epee::math_helper::average target_calculating_enum_blocks; epee::math_helper::average target_calculating_calc; + //longhash_calculating_time_3 + epee::math_helper::average pos_validate_ki_search; + epee::math_helper::average pos_validate_get_out_keys_for_inputs; + epee::math_helper::average pos_validate_zvp; + //tx processing zone epee::math_helper::average tx_check_inputs_time; epee::math_helper::average tx_add_one_tx_time; @@ -139,6 +149,7 @@ namespace currency { bool htlc_is_expired; std::list htlc_outs; + std::list zc_outs; }; // == Output indexes local lookup table conception == @@ -239,11 +250,11 @@ namespace currency template - bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_to_key& tx_in_to_key, visitor_t& vis) + bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& in_v, visitor_t& vis) { scan_for_keys_context cntx_stub = AUTO_VAL_INIT(cntx_stub); uint64_t stub = 0; - return scan_outputkeys_for_indexes(validated_tx, tx_in_to_key, vis, stub, cntx_stub); + return scan_outputkeys_for_indexes(validated_tx, in_v, vis, stub, cntx_stub); } template bool scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& /*scan_context*/) const; @@ -259,8 +270,8 @@ namespace currency wide_difficulty_type get_cached_next_difficulty(bool pos) const; - bool create_block_template(block& b, const account_public_address& miner_address, const account_public_address& stakeholder_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func = nullptr) const; - bool create_block_template(block& b, const account_public_address& miner_address, wide_difficulty_type& di, uint64_t& height, const blobdata& ex_nonce) const; + bool create_block_template(const account_public_address& miner_address, const blobdata& ex_nonce, block& b, wide_difficulty_type& di, uint64_t& height) const; + bool create_block_template(const account_public_address& miner_address, const account_public_address& stakeholder_address, const blobdata& ex_nonce, bool pos, const pos_entry& pe, fill_block_template_func_t custom_fill_block_template_func, block& b, wide_difficulty_type& di, uint64_t& height, tx_generation_context* miner_tx_tgc_ptr = nullptr) const; bool create_block_template(const create_block_template_params& params, create_block_template_response& resp) const; bool have_block(const crypto::hash& id) const; @@ -275,10 +286,12 @@ namespace currency bool handle_get_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, NOTIFY_RESPONSE_GET_OBJECTS::request& rsp)const; bool handle_get_objects(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; bool get_random_outs_for_amounts(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res)const; + bool get_random_outs_for_amounts2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res)const; bool get_backward_blocks_sizes(size_t from_height, std::vector& sz, size_t count)const; bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector& indexs)const; bool get_alias_info(const std::string& alias, extra_alias_entry_base& info)const; std::string get_alias_by_address(const account_public_address& addr)const; + std::set get_aliases_by_address(const account_public_address& addr)const; template bool enumerate_aliases(cb_t cb) const; template @@ -286,25 +299,27 @@ namespace currency uint64_t get_aliases_count()const; uint64_t get_block_h_older_then(uint64_t timestamp) const; bool validate_tx_service_attachmens_in_services(const tx_service_attachment& a, size_t i, const transaction& tx)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height)const; - bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, uint64_t& max_related_block_height)const; + bool get_asset_info(const crypto::public_key& asset_id, asset_descriptor_base& info)const; + uint64_t get_assets_count() const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_htlc& txin, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height)const; + bool check_tx_input(const transaction& tx, size_t in_index, const txin_zc_input& zc_in, const crypto::hash& tx_prefix_hash, uint64_t& max_related_block_height, bool& all_tx_ins_have_explicit_native_asset_ids) const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height)const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash) const; bool check_tx_inputs(const transaction& tx, const crypto::hash& tx_prefix_hash, uint64_t& max_used_block_height, crypto::hash& max_used_block_id)const; - bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const transaction& source_tx, size_t out_n) const; + bool check_ms_input(const transaction& tx, size_t in_index, const txin_multisig& txin, const crypto::hash& tx_prefix_hash, const transaction& source_tx, size_t out_n) const; bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id, uint64_t block_height) const; bool validate_tx_for_hardfork_specific_terms(const transaction& tx, const crypto::hash& tx_id) const; bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase, scan_for_keys_context& scan_context) const; bool get_output_keys_for_input_with_checks(const transaction& tx, const txin_v& verified_input, std::vector& output_keys, uint64_t& max_related_block_height, uint64_t& source_max_unlock_time_for_pos_coinbase) const; - bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& sig, const std::vector& output_keys_ptrs) const; + bool check_input_signature(const transaction& tx, size_t in_index, const txin_to_key& txin, const crypto::hash& tx_prefix_hash, const std::vector& output_keys_ptrs) const; bool check_input_signature(const transaction& tx, size_t in_index, uint64_t in_amount, const crypto::key_image& k_image, const std::vector& in_etc_details, const crypto::hash& tx_prefix_hash, - const std::vector& sig, const std::vector& output_keys_ptrs) const; uint64_t get_current_comulative_blocksize_limit()const; @@ -315,6 +330,7 @@ namespace currency boost::multiprecision::uint128_t total_coins()const; bool is_pos_allowed()const; uint64_t get_tx_fee_median()const; + uint64_t get_tx_fee_window_value_median() const; uint64_t get_tx_expiration_median() const; uint64_t validate_alias_reward(const transaction& tx, const std::string& ai)const; void set_event_handler(i_core_event_handler* event_handler) const; @@ -328,6 +344,11 @@ namespace currency bool is_tx_expired(const transaction& tx) const; std::shared_ptr find_key_image_and_related_tx(const crypto::key_image& ki, crypto::hash& id_result) const; + // returns true as soon as the hardfork is active for the NEXT upcoming block (not for the top block in the blockchain storage) + bool is_hardfork_active(size_t hardfork_id) const; + bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx) const; + bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false) const; + wide_difficulty_type block_difficulty(size_t i)const; bool forecast_difficulty(std::vector> &out_height_2_diff_vector, bool pos) const; bool prune_aged_alt_blocks(); @@ -335,14 +356,12 @@ namespace currency bool check_keyimages(const std::list& images, std::list& images_stat)const;//true - unspent, false - spent bool build_kernel(const block& bl, stake_kernel& kernel, uint64_t& amount, const stake_modifier_type& stake_modifier)const; // --- PoS --- - bool build_kernel(uint64_t amount, - const crypto::key_image& ki, + bool build_kernel(const crypto::key_image& ki, stake_kernel& kernel, const stake_modifier_type& stake_modifier, - uint64_t timestamp)const; - bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash *p_last_block_hash = nullptr) const; + uint64_t timestamp) const; + bool build_stake_modifier(stake_modifier_type& sm, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0, crypto::hash* p_last_block_hash = nullptr, uint64_t* p_last_pow_block_height = nullptr) const; - bool scan_pos(const COMMAND_RPC_SCAN_POS::request& sp, COMMAND_RPC_SCAN_POS::response& rsp)const; bool validate_pos_coinbase_outs_unlock_time(const transaction& miner_tx, uint64_t staked_amount, uint64_t source_max_unlock_time)const; bool validate_pos_block(const block& b, const crypto::hash& id, bool for_altchain)const; bool validate_pos_block(const block& b, wide_difficulty_type basic_diff, const crypto::hash& id, bool for_altchain)const; @@ -350,7 +369,7 @@ namespace currency wide_difficulty_type basic_diff, uint64_t& amount, wide_difficulty_type& final_diff, - crypto::hash& proof_hash, + crypto::hash& kernel_hash, const crypto::hash& id, bool for_altchain, const alt_chain_type& alt_chain = alt_chain_type(), @@ -395,7 +414,7 @@ namespace currency missed_bs.push_back(bl_id); else { - CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << string_tools::pod_to_hex(bl_id) + CHECK_AND_ASSERT_MES(*block_ind_ptr < m_db_blocks.size(), false, "Internal error: bl_id=" << epst::pod_to_hex(bl_id) << " have index record with offset=" << *block_ind_ptr << ", bigger then m_db_blocks.size()=" << m_db_blocks.size()); blocks.push_back(m_db_blocks[*block_ind_ptr]->bl); } @@ -450,6 +469,7 @@ namespace currency void serialize(archive_t & ar, const unsigned int version); bool get_est_height_from_date(uint64_t date, uint64_t& res_h)const; + bool get_pos_votes(uint64_t start_h, uint64_t end_h, vote_results& r); //debug functions bool validate_blockchain_prev_links(size_t last_n_blocks_to_check = 10) const; @@ -486,6 +506,9 @@ namespace currency typedef tools::db::cached_key_value_accessor multisig_outs_container;// ms out id => ms_output_entry typedef tools::db::cached_key_value_accessor solo_options_container; typedef tools::db::basic_key_value_accessor per_block_gindex_increments_container; // height => [(amount, gindex_increment), ...] + + typedef tools::db::cached_key_value_accessor, true, false> assets_container; // TODO @#@# consider storing tx_id as well for reference -- sowle + //----------------------------------------- @@ -527,13 +550,14 @@ namespace currency address_to_aliases_container m_db_addr_to_alias; per_block_gindex_increments_container m_db_per_block_gindex_incs; + assets_container m_db_assets; - mutable critical_section m_invalid_blocks_lock; + mutable epee::critical_section m_invalid_blocks_lock; blocks_ext_by_hash m_invalid_blocks; // crypto::hash -> block_extended_info - mutable critical_section m_alternative_chains_lock; + mutable epee::critical_section m_alternative_chains_lock; alt_chain_container m_alternative_chains; // crypto::hash -> alt_block_extended_info std::unordered_map m_alternative_chains_txs; // tx_id -> how many alt blocks it related to (always >= 1) std::unordered_map> m_altblocks_keyimages; // key image -> list of alt blocks hashes where it appears in inputs @@ -557,7 +581,7 @@ namespace currency mutable wide_difficulty_type m_cached_next_pow_difficulty; mutable wide_difficulty_type m_cached_next_pos_difficulty; - mutable critical_section m_targetdata_cache_lock; + mutable epee::critical_section m_targetdata_cache_lock; mutable std::list > m_pos_targetdata_cache; mutable std::list > m_pow_targetdata_cache; //work like a cache to avoid recalculation on read operations @@ -567,8 +591,8 @@ namespace currency mutable std::atomic m_deinit_is_done; mutable uint64_t m_blockchain_launch_timestamp; - bool init_tx_fee_median(); - bool update_tx_fee_median(); + //bool init_tx_fee_median(); + //bool update_tx_fee_median(); void store_db_solo_options_values(); bool set_lost_tx_unmixable(); bool set_lost_tx_unmixable_for_height(uint64_t height); @@ -584,11 +608,12 @@ namespace currency wide_difficulty_type get_next_difficulty_for_alternative_chain(const alt_chain_type& alt_chain, block_extended_info& bei, bool pos) const; bool handle_block_to_main_chain(const block& bl, block_verification_context& bvc); bool handle_block_to_main_chain(const block& bl, const crypto::hash& id, block_verification_context& bvc); + bool collect_rangeproofs_data_from_tx(const transaction& tx, const crypto::hash& tx_id, std::vector& agregated_proofs); std::string print_alt_chain(alt_chain_type alt_chain); bool handle_alternative_block(const block& b, const crypto::hash& id, block_verification_context& bvc); bool is_reorganize_required(const block_extended_info& main_chain_bei, const alt_chain_type& alt_chain, const crypto::hash& proof_alt); wide_difficulty_type get_x_difficulty_after_height(uint64_t height, bool is_pos); - bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& id); + bool purge_keyimage_from_big_heap(const crypto::key_image& ki, const crypto::hash& block_id); bool purge_altblock_keyimages_from_big_heap(const block& b, const crypto::hash& id); bool append_altblock_keyimages_to_big_heap(const crypto::hash& block_id, const std::unordered_set& alt_block_keyimages); bool validate_alt_block_input(const transaction& input_tx, @@ -597,13 +622,17 @@ namespace currency const crypto::hash& bl_id, const crypto::hash& input_tx_hash, size_t input_index, - const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain, const std::unordered_set& alt_chain_block_ids, uint64_t& ki_lookuptime, uint64_t* p_max_related_block_height = nullptr) const; - bool validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const std::vector& input_sigs, uint64_t split_height, const alt_chain_type& alt_chain) const; + bool validate_alt_block_ms_input(const transaction& input_tx, + const crypto::hash& input_tx_hash, + size_t input_index, + //const signature_v& input_sigs,//const std::vector& input_sigs, + uint64_t split_height, + const alt_chain_type& alt_chain) const; bool validate_alt_block_txs(const block& b, const crypto::hash& id, std::unordered_set& collected_keyimages, alt_block_extended_info& abei, const alt_chain_type& alt_chain, uint64_t split_height, uint64_t& ki_lookup_time_total) const; bool update_alt_out_indexes_for_tx_in_block(const transaction& tx, alt_block_extended_info& abei)const; bool get_transaction_from_pool_or_db(const crypto::hash& tx_id, std::shared_ptr& tx_ptr, uint64_t min_allowed_block_height = 0) const; @@ -613,14 +642,15 @@ namespace currency bool add_transaction_from_block(const transaction& tx, const crypto::hash& tx_id, const crypto::hash& bl_id, uint64_t bl_height, uint64_t timestamp); bool push_transaction_to_global_outs_index(const transaction& tx, const crypto::hash& tx_id, std::vector& global_indexes); bool pop_transaction_from_global_index(const transaction& tx, const crypto::hash& tx_id); - bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false) const; + bool add_out_to_get_random_outs(COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, uint64_t amount, size_t i, uint64_t mix_count, bool use_only_forced_to_mix = false, uint64_t height_upper_limit = 0) const; + bool get_target_outs_for_amount_prezarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; + bool get_target_outs_for_postzarcanum(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::offsets_distribution& details, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount& result_outs, std::map& amounts_to_up_index_limit_cache) const; bool add_block_as_invalid(const block& bl, const crypto::hash& h); bool add_block_as_invalid(const block_extended_info& bei, const crypto::hash& h); size_t find_end_of_allowed_index(uint64_t amount)const; bool check_block_timestamp_main(const block& b)const; bool check_block_timestamp(std::vector timestamps, const block& b)const; std::vector get_last_n_blocks_timestamps(size_t n)const; - const std::vector& get_txin_etc_options(const txin_v& in)const; void on_block_added(const block_extended_info& bei, const crypto::hash& id, const std::list& bsk); void on_block_removed(const block_extended_info& bei); void update_targetdata_cache_on_block_added(const block_extended_info& bei); @@ -629,22 +659,26 @@ namespace currency uint64_t get_tx_fee_median_effective_index(uint64_t h) const; void on_abort_transaction(); void load_targetdata_cache(bool is_pos) const; + uint64_t get_adjusted_time()const; bool complete_timestamps_vector(uint64_t start_height, std::vector& timestamps); bool update_next_comulative_size_limit(); - bool process_blockchain_tx_extra(const transaction& tx); + bool process_blockchain_tx_extra(const transaction& tx, const crypto::hash& tx_id); bool unprocess_blockchain_tx_extra(const transaction& tx); bool process_blockchain_tx_attachments(const transaction& tx, uint64_t h, const crypto::hash& bl_id, uint64_t timestamp); bool unprocess_blockchain_tx_attachments(const transaction& tx, uint64_t h, uint64_t timestamp); + bool validate_ado_ownership(asset_op_verification_context& avc); bool pop_alias_info(const extra_alias_entry& ai); bool put_alias_info(const transaction& tx, extra_alias_entry& ai); + bool pop_asset_info(const crypto::public_key& asset_id); + bool put_asset_info(const transaction& tx, const crypto::hash& tx_id, const asset_descriptor_operation& ado); void fill_addr_to_alias_dict(); //bool resync_spent_tx_flags(); bool prune_ring_signatures_and_attachments_if_need(); bool prune_ring_signatures_and_attachments(uint64_t height, uint64_t& transactions_pruned, uint64_t& signatures_pruned, uint64_t& attachments_pruned); - // bool build_stake_modifier_for_alt(const alt_chain_type& alt_chain, stake_modifier_type& sm); + template bool enum_blockchain(visitor_t& v, const alt_chain_type& alt_chain = alt_chain_type(), uint64_t split_height = 0) const; bool update_spent_tx_flags_for_input(uint64_t amount, const txout_ref_v& o, bool spent); @@ -661,13 +695,7 @@ namespace currency bool is_output_allowed_for_input(const output_key_or_htlc_v& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const; bool is_output_allowed_for_input(const txout_to_key& out_v, const txin_v& in_v)const; bool is_output_allowed_for_input(const txout_htlc& out_v, const txin_v& in_v, uint64_t top_minus_source_height)const; - bool is_after_hardfork_1_zone()const; - bool is_after_hardfork_1_zone(uint64_t height)const; - bool is_after_hardfork_2_zone()const; - bool is_after_hardfork_2_zone(uint64_t height)const; - bool is_after_hardfork_3_zone()const; - bool is_after_hardfork_3_zone(uint64_t height)const; - + bool is_output_allowed_for_input(const tx_out_zarcanum& out, const txin_v& in_v) const; @@ -714,10 +742,10 @@ namespace currency template bool blockchain_storage::scan_outputkeys_for_indexes(const transaction &validated_tx, const txin_v& verified_input, visitor_t& vis, uint64_t& max_related_block_height, scan_for_keys_context& scan_context) const { - const txin_to_key& input_to_key = get_to_key_input_from_txin_v(verified_input); + bool hf4 = this->is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM); - uint64_t amount = input_to_key.amount; - const std::vector& key_offsets = input_to_key.key_offsets; + uint64_t amount = get_amount_from_variant(verified_input); + const std::vector& key_offsets = get_key_offsets_from_txin_v(verified_input); CRITICAL_REGION_LOCAL(m_read_lock); TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_get_item_size); @@ -731,7 +759,7 @@ namespace currency TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_relative_to_absolute); TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop); size_t output_index = 0; - for(const txout_ref_v& o : absolute_offsets) + for (const txout_ref_v& o : absolute_offsets) { crypto::hash tx_id = null_hash; size_t n = 0; @@ -756,7 +784,7 @@ namespace currency } TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_find_tx); auto tx_ptr = m_db_transactions.find(tx_id); - CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction id in output indexes: " << string_tools::pod_to_hex(tx_id)); + CHECK_AND_ASSERT_MES(tx_ptr, false, "Wrong transaction id in output indexes: " << epst::pod_to_hex(tx_id)); CHECK_AND_ASSERT_MES(n < tx_ptr->tx.vout.size(), false, "Wrong index in transaction outputs: " << n << ", expected less then " << tx_ptr->tx.vout.size()); //check mix_attr @@ -774,57 +802,109 @@ namespace currency TO_KEY | TO_KEY | YES */ - bool r = is_output_allowed_for_input(tx_ptr->tx.vout[n].target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height); - CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); - - if (tx_ptr->tx.vout[n].target.type() == typeid(txout_to_key)) + VARIANT_SWITCH_BEGIN(tx_ptr->tx.vout[n]); + VARIANT_CASE_CONST(tx_out_bare, o) { - CHECKED_GET_SPECIFIC_VARIANT(tx_ptr->tx.vout[n].target, const txout_to_key, outtk, false); - //fix for burned money - patch_out_if_needed(const_cast(outtk), tx_id, n); + bool r = is_output_allowed_for_input(o.target, verified_input, get_current_blockchain_size() - tx_ptr->m_keeper_block_height); + CHECK_AND_ASSERT_MES(r, false, "Input and output incompatible type"); - bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(outtk.mix_attr, key_offsets.size() - 1); - CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx output #" << output_index << " violates mixin restrictions: mix_attr = " << static_cast(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size()); - } - else if (tx_ptr->tx.vout[n].target.type() == typeid(txout_htlc)) - { - //check for spend flags - CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false, - "Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}"); - CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected"); - - const txout_htlc& htlc_out = boost::get(tx_ptr->tx.vout[n].target); - if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height) + if (o.target.type() == typeid(txout_to_key)) { - //HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input - scan_context.htlc_is_expired = false; - } - else - { - //HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input - scan_context.htlc_is_expired = true; - } - }else - { - LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << tx_ptr->tx.vout[n].target.type().name()); - return false; - } + CHECKED_GET_SPECIFIC_VARIANT(o.target, const txout_to_key, outtk, false); + //fix for burned money + patch_out_if_needed(const_cast(outtk), tx_id, n); + + bool mixattr_ok = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, outtk.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config()); + CHECK_AND_ASSERT_MES(mixattr_ok, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast(outtk.mix_attr) << ", key_offsets.size = " << key_offsets.size()); + if (hf4) + { + bool legit_output_key = validate_output_key_legit(outtk.key); + CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << outtk.key); + } + } + else if (o.target.type() == typeid(txout_htlc)) + { + //check for spend flags + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags.size() > n, false, + "Internal error: tx_ptr->m_spent_flags.size(){" << tx_ptr->m_spent_flags.size() << "} > n{" << n << "}"); + CHECK_AND_ASSERT_MES(tx_ptr->m_spent_flags[n] == false, false, "HTLC out already spent, double spent attempt detected"); + + const txout_htlc& htlc_out = boost::get(o.target); + if (htlc_out.expiration > get_current_blockchain_size() - tx_ptr->m_keeper_block_height) + { + //HTLC IS NOT expired, can be used ONLY by pkey_before_expiration and ONLY by HTLC input + scan_context.htlc_is_expired = false; + } + else + { + //HTLC IS expired, can be used ONLY by pkey_after_expiration and ONLY by to_key input + scan_context.htlc_is_expired = true; + } + if (hf4) + { + bool legit_output_key = validate_output_key_legit(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem); + CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << static_cast(scan_context.htlc_is_expired ? htlc_out.pkey_refund : htlc_out.pkey_redeem)); + } + + } + else + { + LOG_ERROR("[scan_outputkeys_for_indexes]: Wrong output type in : " << o.target.type().name()); + return false; + } + + TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + + if (!vis.handle_output(tx_ptr->tx, validated_tx, o, n)) + { + size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin(); + LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx)); + return false; + } + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + } + VARIANT_CASE_CONST(tx_out_zarcanum, out_zc) + bool r = is_output_allowed_for_input(out_zc, verified_input); + CHECK_AND_ASSERT_MES(r, false, "Input and output are incompatible"); + + r = is_mixattr_applicable_for_fake_outs_counter(tx_ptr->tx.version, out_zc.mix_attr, key_offsets.size() - 1, this->get_core_runtime_config()); + CHECK_AND_ASSERT_MES(r, false, "tx input ref #" << output_index << " violates mixin restrictions: tx.version = " << tx_ptr->tx.version << ", mix_attr = " << static_cast(out_zc.mix_attr) << ", key_offsets.size = " << key_offsets.size()); + + bool legit_output_key = validate_output_key_legit(out_zc.stealth_address); + CHECK_AND_ASSERT_MES(legit_output_key, false, "tx input ref #" << output_index << " violates public key restrictions: tx.version = " << tx_ptr->tx.version << ", outtk.key = " << out_zc.stealth_address); + - TIME_MEASURE_START_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); - if (!vis.handle_output(tx_ptr->tx, validated_tx, tx_ptr->tx.vout[n], n)) + if (!vis.handle_output(tx_ptr->tx, validated_tx, out_zc, n)) { - LOG_PRINT_L0("Failed to handle_output for output id = " << tx_id << ", no " << n); + size_t verified_input_index = std::find(validated_tx.vin.begin(), validated_tx.vin.end(), verified_input) - validated_tx.vin.begin(); + LOG_PRINT_RED_L0("handle_output failed for output #" << n << " in " << tx_id << " referenced by input #" << verified_input_index << " in tx " << get_transaction_hash(validated_tx)); return false; } TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop_handle_output); + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); - if (max_related_block_height < tx_ptr->m_keeper_block_height) - max_related_block_height = tx_ptr->m_keeper_block_height; - + + if (max_related_block_height < tx_ptr->m_keeper_block_height) + max_related_block_height = tx_ptr->m_keeper_block_height; + ++output_index; } + + if (m_core_runtime_config.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, this->get_current_blockchain_size())) + { + //with hard fork 4 make it network rule to have at least 10 confirmations + + if (this->get_current_blockchain_size() - max_related_block_height < CURRENCY_HF4_MANDATORY_MIN_COINAGE) + { + LOG_ERROR("Coinage rule broken(mainblock): h = " << this->get_current_blockchain_size() << ", max_related_block_height=" << max_related_block_height << ", tx: " << get_transaction_hash(validated_tx)); + return false; + } + } + + TIME_MEASURE_FINISH_PD(tx_check_inputs_loop_scan_outputkeys_loop); return true; } diff --git a/src/currency_core/blockchain_storage_basic.h b/src/currency_core/blockchain_storage_basic.h index 8a487003..27908fbf 100644 --- a/src/currency_core/blockchain_storage_basic.h +++ b/src/currency_core/blockchain_storage_basic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2023 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -19,6 +19,8 @@ #include "currency_basic.h" #include "difficulty.h" #include "currency_protocol/blobdatatype.h" +#include "currency_format_utils_transactions.h" // only for output_generation_context + namespace currency { @@ -46,9 +48,9 @@ namespace currency block bl; uint64_t height; uint64_t block_cumulative_size; - wide_difficulty_type cumulative_diff_adjusted; + wide_difficulty_type cumulative_diff_adjusted; // used only before hardfork 1 wide_difficulty_type cumulative_diff_precise; - wide_difficulty_type cumulative_diff_precise_adjusted; + wide_difficulty_type cumulative_diff_precise_adjusted; //used after hardfork 1 (cumulative difficulty adjusted only by sequence factor) wide_difficulty_type difficulty; boost::multiprecision::uint128_t already_generated_coins; crypto::hash stake_hash; //TODO: unused field for PoW blocks, subject for refactoring @@ -144,6 +146,10 @@ namespace currency block b; wide_difficulty_type diffic; uint64_t height; + tx_generation_context miner_tx_tgc; // bad design, a lot of copying, consider redesign -- sowle + uint64_t block_reward_without_fee; + uint64_t block_reward; // == block_reward_without_fee + txs_fee if fees are given to the miner, OR block_reward_without_fee if fees are burnt + uint64_t txs_fee; // sum of transactions' fee if any }; typedef std::unordered_map transactions_map; @@ -154,6 +160,28 @@ namespace currency transactions_map onboard_transactions; }; + struct vote_on_proposal + { + std::string proposal_id; + uint64_t yes; + uint64_t no; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(proposal_id) + KV_SERIALIZE(yes) + KV_SERIALIZE(no) + END_KV_SERIALIZE_MAP() + }; -} \ No newline at end of file + struct vote_results + { + uint64_t total_pos_blocks; //total pos blocks in a given range + std::list votes; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total_pos_blocks) + KV_SERIALIZE(votes) + END_KV_SERIALIZE_MAP() + }; + +} // namespace currency diff --git a/src/currency_core/core_runtime_config.h b/src/currency_core/core_runtime_config.h index a2bbe84d..f970e144 100644 --- a/src/currency_core/core_runtime_config.h +++ b/src/currency_core/core_runtime_config.h @@ -5,13 +5,97 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #pragma once +#include "boost/serialization/array.hpp" #include "misc_language.h" #include "string_tools.h" namespace currency { + struct hard_forks_descriptor + { + constexpr static size_t m_total_count = ZANO_HARDFORKS_TOTAL; + std::array m_height_the_hardfork_n_active_after; + + hard_forks_descriptor() + { + clear(); + } + + void clear() + { + m_height_the_hardfork_n_active_after.fill(CURRENCY_MAX_BLOCK_NUMBER); + } + + void set_hardfork_height(size_t hardfork_id, uint64_t height_the_hardfork_is_active_after) + { + CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id); + m_height_the_hardfork_n_active_after[hardfork_id] = height_the_hardfork_is_active_after; + + // set all unset previous hardforks to this height + for(size_t hid = hardfork_id - 1; hid + 1 != 0; --hid) + { + if (m_height_the_hardfork_n_active_after[hid] == CURRENCY_MAX_BLOCK_NUMBER) + m_height_the_hardfork_n_active_after[hid] = height_the_hardfork_is_active_after; + } + } + + bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const + { + if (hardfork_id == 0) + return true; // hardfork #0 is a special case that is considered always active + CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id); + return height > m_height_the_hardfork_n_active_after[hardfork_id]; + } + + std::string get_str_height_the_hardfork_active_after(size_t hardfork_id) const + { + if (hardfork_id == 0) + return "0"; // hardfork #0 is a special case that is considered always active + CHECK_AND_ASSERT_THROW_MES(hardfork_id < m_total_count, "invalid hardfork id: " << hardfork_id); + return epee::string_tools::num_to_string_fast(m_height_the_hardfork_n_active_after[hardfork_id]); + } + + size_t get_the_most_recent_hardfork_id_for_height(uint64_t height) const + { + for(size_t hid = m_total_count - 1; hid != 0; --hid) // 0 is not including + { + if(is_hardfork_active_for_height(hid, height)) + return hid; + } + return 0; + } + + uint8_t get_block_major_version_by_height(uint64_t height) const + { + if (!this->is_hardfork_active_for_height(1, height)) + return BLOCK_MAJOR_VERSION_INITIAL; + else if (!this->is_hardfork_active_for_height(3, height)) + return HF1_BLOCK_MAJOR_VERSION; + else if (!this->is_hardfork_active_for_height(4, height)) + return HF3_BLOCK_MAJOR_VERSION; + else + return CURRENT_BLOCK_MAJOR_VERSION; + } + + uint8_t get_block_minor_version_by_height(uint64_t height) const + { + return HF3_BLOCK_MINOR_VERSION; + } + + bool operator==(const hard_forks_descriptor& rhs) const + { + return m_height_the_hardfork_n_active_after == rhs.m_height_the_hardfork_n_active_after; + } + + bool operator!=(const hard_forks_descriptor& rhs) const + { + return ! operator==(rhs); + } + }; + + typedef uint64_t (*core_time_func_t)(); - + struct core_runtime_config { uint64_t min_coinstake_age; @@ -21,21 +105,13 @@ namespace currency uint64_t max_alt_blocks; crypto::public_key alias_validation_pubkey; core_time_func_t get_core_time; + uint64_t hf4_minimum_mixins; - uint64_t hard_fork_01_starts_after_height; - uint64_t hard_fork_02_starts_after_height; - uint64_t hard_fork_03_starts_after_height; + hard_forks_descriptor hard_forks; bool is_hardfork_active_for_height(size_t hardfork_id, uint64_t height) const { - switch (hardfork_id) - { - case 0: return true; - case 1: return height > hard_fork_01_starts_after_height; - case 2: return height > hard_fork_02_starts_after_height; - case 3: return height > hard_fork_03_starts_after_height; - default: return false; - } + return hard_forks.is_hardfork_active_for_height(hardfork_id, height); } static uint64_t _default_core_time_function() @@ -52,10 +128,13 @@ namespace currency pc.tx_pool_min_fee = TX_MINIMUM_FEE; pc.tx_default_fee = TX_DEFAULT_FEE; pc.max_alt_blocks = CURRENCY_ALT_BLOCK_MAX_COUNT; + pc.hf4_minimum_mixins = CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE; - pc.hard_fork_01_starts_after_height = ZANO_HARDFORK_01_AFTER_HEIGHT; - pc.hard_fork_02_starts_after_height = ZANO_HARDFORK_02_AFTER_HEIGHT; - pc.hard_fork_03_starts_after_height = ZANO_HARDFORK_03_AFTER_HEIGHT; + // TODO: refactor the following + pc.hard_forks.set_hardfork_height(1, ZANO_HARDFORK_01_AFTER_HEIGHT); + pc.hard_forks.set_hardfork_height(2, ZANO_HARDFORK_02_AFTER_HEIGHT); + pc.hard_forks.set_hardfork_height(3, ZANO_HARDFORK_03_AFTER_HEIGHT); + pc.hard_forks.set_hardfork_height(4, ZANO_HARDFORK_04_AFTER_HEIGHT); pc.get_core_time = &core_runtime_config::_default_core_time_function; bool r = epee::string_tools::hex_to_pod(ALIAS_SHORT_NAMES_VALIDATION_PUB_KEY, pc.alias_validation_pubkey); diff --git a/src/currency_core/crypto_config.h b/src/currency_core/crypto_config.h new file mode 100644 index 00000000..648550bc --- /dev/null +++ b/src/currency_core/crypto_config.h @@ -0,0 +1,43 @@ +// Copyright (c) 2022-2023 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#pragma once + +// hash domain separation strings, 32 bytes long (31 chars + \0) +// + +#define CRYPTO_HDS_OUT_AMOUNT_MASK "ZANO_HDS_OUT_AMOUNT_MASK_______" +#define CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK "ZANO_HDS_OUT_AMOUNT_BLIND_MASK_" +#define CRYPTO_HDS_OUT_ASSET_BLINDING_MASK "ZANO_HDS_OUT_ASSET_BLIND_MASK__" +#define CRYPTO_HDS_OUT_CONCEALING_POINT "ZANO_HDS_OUT_CONCEALING_POINT__" + +#define CRYPTO_HDS_CLSAG_GG_LAYER_0 "ZANO_HDS_CLSAG_GG_LAYER_ZERO___" +#define CRYPTO_HDS_CLSAG_GG_LAYER_1 "ZANO_HDS_CLSAG_GG_LAYER_ONE____" +#define CRYPTO_HDS_CLSAG_GG_CHALLENGE "ZANO_HDS_CLSAG_GG_CHALLENGE____" + +#define CRYPTO_HDS_CLSAG_GGX_LAYER_0 "ZANO_HDS_CLSAG_GGX_LAYER_ZERO__" +#define CRYPTO_HDS_CLSAG_GGX_LAYER_1 "ZANO_HDS_CLSAG_GGX_LAYER_ONE___" +#define CRYPTO_HDS_CLSAG_GGX_LAYER_2 "ZANO_HDS_CLSAG_GGX_LAYER_TWO___" +#define CRYPTO_HDS_CLSAG_GGX_CHALLENGE "ZANO_HDS_CLSAG_GGX_CHALLENGE___" + +#define CRYPTO_HDS_CLSAG_GGXG_LAYER_0 "ZANO_HDS_CLSAG_GGXG_LAYER_ZERO_" +#define CRYPTO_HDS_CLSAG_GGXG_LAYER_1 "ZANO_HDS_CLSAG_GGXG_LAYER_ONE__" +#define CRYPTO_HDS_CLSAG_GGXG_LAYER_2 "ZANO_HDS_CLSAG_GGXG_LAYER_TWO__" +#define CRYPTO_HDS_CLSAG_GGXG_LAYER_3 "ZANO_HDS_CLSAG_GGXG_LAYER_THREE" +#define CRYPTO_HDS_CLSAG_GGXG_CHALLENGE "ZANO_HDS_CLSAG_GGXG_CHALLENGE__" + +#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_0 "ZANO_HDS_CLSAG_GGXXG_LAYER_ZERO" +#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_1 "ZANO_HDS_CLSAG_GGXXG_LAYER_ONE_" +#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_2 "ZANO_HDS_CLSAG_GGXXG_LAYER_TWO_" +#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_3 "ZANO_HDS_CLSAG_GGXXG_LAYER_3___" +#define CRYPTO_HDS_CLSAG_GGXXG_LAYER_4 "ZANO_HDS_CLSAG_GGXXG_LAYER_FOUR" +#define CRYPTO_HDS_CLSAG_GGXXG_CHALLENGE "ZANO_HDS_CLSAG_GGXXG_CHALLENGE_" + +#define CRYPTO_HDS_ZARCANUM_LAST_POW_HASH "ZANO_HDS_ZARCANUM_LAST_POW_HASH" +#define CRYPTO_HDS_ZARCANUM_PROOF_HASH "ZANO_HDS_ZARCANUM_PROOF_HASH___" + +#define CRYPTO_HDS_ASSET_CONTROL_KEY "ZANO_HDS_ASSET_CONTROL_KEY_____" +#define CRYPTO_HDS_ASSET_CONTROL_ABM "ZANO_HDS_ASSET_CONTROL_ABM_____" +#define CRYPTO_HDS_ASSET_ID "ZANO_HDS_ASSET_ID______________" +#define CRYPTO_HDS_DETERMINISTIC_TX_KEY "ZANO_HDS_DETERMINISTIC_TX_KEY__" diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index dc973a66..b5aa7fab 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2014-2015 The Boolberry developers @@ -26,10 +26,11 @@ #include "include_base_utils.h" #include "serialization/binary_archive.h" -#include "serialization/crypto.h" +#include "common/crypto_serialization.h" #include "serialization/stl_containers.h" #include "serialization/serialization.h" #include "serialization/variant.h" +#include "serialization/boost_types.h" #include "serialization/json_archive.h" #include "serialization/debug_archive.h" #include "serialization/keyvalue_serialization.h" // epee key-value serialization @@ -37,9 +38,12 @@ #include "currency_config.h" #include "crypto/crypto.h" #include "crypto/hash.h" +#include "crypto/range_proofs.h" +#include "crypto/zarcanum.h" #include "misc_language.h" #include "block_flags.h" #include "etc_custom_serialization.h" +#include "difficulty.h" namespace currency { @@ -53,6 +57,16 @@ namespace currency const static crypto::hash gdefault_genesis = epee::string_tools::hex_to_pod("CC608F59F8080E2FBFE3C8C80EB6E6A953D47CF2D6AEBD345BADA3A1CAB99852"); + // Using C++17 extended aggregate initialization (P0017R1). C++17, finally! -- sowle + const static crypto::public_key native_coin_asset_id = {{'\xd6', '\x32', '\x9b', '\x5b', '\x1f', '\x7c', '\x08', '\x05', '\xb5', '\xc3', '\x45', '\xf4', '\x95', '\x75', '\x54', '\x00', '\x2a', '\x2f', '\x55', '\x78', '\x45', '\xf6', '\x4d', '\x76', '\x45', '\xda', '\xe0', '\xe0', '\x51', '\xa6', '\x49', '\x8a'}}; // == crypto::c_point_H, checked in crypto_constants + const static crypto::public_key native_coin_asset_id_1div8 = {{'\x74', '\xc3', '\x2d', '\x3e', '\xaa', '\xfa', '\xfc', '\x62', '\x3b', '\xf4', '\x83', '\xe8', '\x58', '\xd4', '\x2e', '\x8b', '\xf4', '\xec', '\x7d', '\xf0', '\x64', '\xad', '\xa2', '\xe3', '\x49', '\x34', '\x46', '\x9c', '\xff', '\x6b', '\x62', '\x68'}}; // == 1/8 * crypto::c_point_H, checked in crypto_constants + const static crypto::point_t native_coin_asset_id_pt {{ 20574939, 16670001, -29137604, 14614582, 24883426, 3503293, 2667523, 420631, 2267646, -4769165, -11764015, -12206428, -14187565, -2328122, -16242653, -788308, -12595746, -8251557, -10110987, 853396, -4982135, 6035602, -21214320, 16156349, 977218, 2807645, 31002271, 5694305, -16054128, 5644146, -15047429, -568775, -22568195, -8089957, -27721961, -10101877, -29459620, -13359100, -31515170, -6994674 }}; // c_point_H + + const static wide_difficulty_type global_difficulty_pow_starter = DIFFICULTY_POW_STARTER; + const static wide_difficulty_type global_difficulty_pos_starter = DIFFICULTY_POS_STARTER; + const static uint64_t global_difficulty_pos_target = DIFFICULTY_POS_TARGET; + const static uint64_t global_difficulty_pow_target = DIFFICULTY_POW_TARGET; + typedef std::string payment_id_t; @@ -208,16 +222,21 @@ namespace currency typedef boost::variant txin_etc_details_v; - struct txin_to_key + + struct referring_input + { + std::vector key_offsets; + }; + + struct txin_to_key : public referring_input { uint64_t amount; - std::vector key_offsets; crypto::key_image k_image; // double spending protection - std::vector etc_details; //this flag used when TX_FLAG_SIGNATURE_MODE_SEPARATE flag is set, point to which amount of outputs(starting from zero) used in signature + std::vector etc_details; // see also TX_FLAG_SIGNATURE_MODE_SEPARATE BEGIN_SERIALIZE_OBJECT() VARINT_FIELD(amount) - FIELD(key_offsets) + FIELD(key_offsets) // from referring_input FIELD(k_image) FIELD(etc_details) END_SERIALIZE() @@ -247,6 +266,7 @@ namespace currency END_SERIALIZE() }; + struct txout_multisig { uint32_t minimum_sigs; @@ -277,12 +297,10 @@ namespace currency END_SERIALIZE() }; - typedef boost::variant txin_v; - typedef boost::variant txout_target_v; //typedef std::pair out_t; - struct tx_out + struct tx_out_bare { uint64_t amount; txout_target_v target; @@ -294,6 +312,192 @@ namespace currency }; + ///////////////////////////////////////////////////////////////////////////// + // Zarcanum structures + // + + struct txin_zc_input : public referring_input + { + txin_zc_input() {} + // Boost's Assignable concept + txin_zc_input(const txin_zc_input&) = default; + txin_zc_input& operator=(const txin_zc_input&)= default; + + crypto::key_image k_image; + std::vector etc_details; + + + BEGIN_SERIALIZE_OBJECT() + FIELD(key_offsets) // referring_input + FIELD(k_image) + FIELD(etc_details) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(key_offsets) // referring_input + BOOST_SERIALIZE(k_image) + BOOST_SERIALIZE(etc_details) + END_BOOST_SERIALIZATION() + }; + + struct tx_out_zarcanum + { + tx_out_zarcanum() {} + + // Boost's Assignable concept + tx_out_zarcanum(const tx_out_zarcanum&) = default; + tx_out_zarcanum& operator=(const tx_out_zarcanum&) = default; + + crypto::public_key stealth_address; + crypto::public_key concealing_point; // group element Q, see also Zarcanum paper, premultiplied by 1/8 + crypto::public_key amount_commitment; // premultiplied by 1/8 + crypto::public_key blinded_asset_id; // group element T, premultiplied by 1/8 + uint64_t encrypted_amount = 0; + uint8_t mix_attr = 0; + + BEGIN_SERIALIZE_OBJECT() + FIELD(stealth_address) + FIELD(concealing_point) + FIELD(amount_commitment) + FIELD(blinded_asset_id) + FIELD(encrypted_amount) + FIELD(mix_attr) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(stealth_address) + BOOST_SERIALIZE(concealing_point) + BOOST_SERIALIZE(amount_commitment) + BOOST_SERIALIZE(blinded_asset_id) + BOOST_SERIALIZE(encrypted_amount) + BOOST_SERIALIZE(mix_attr) + END_BOOST_SERIALIZATION() + }; + + struct zarcanum_tx_data_v1 + { + uint64_t fee; + + BEGIN_SERIALIZE_OBJECT() + FIELD(fee) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(fee) + END_BOOST_SERIALIZATION() + }; + + struct zc_asset_surjection_proof + { + std::vector bge_proofs; // one per output, non-aggregated version of Groth-Bootle-Esgin yet, need to be upgraded later -- sowle + + BEGIN_SERIALIZE_OBJECT() + FIELD(bge_proofs) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(bge_proofs) + END_BOOST_SERIALIZATION() + }; + + // non-consoditated txs must have one of this objects in the attachments (elements count == vout.size()) + // consolidated -- one pre consolidated part (sum(elements count) == vout.size()) + struct zc_outs_range_proof + { + crypto::bpp_signature_serialized bpp; // for commitments in form: amount * U + mask * G + crypto::vector_UG_aggregation_proof_serialized aggregation_proof; // E'_j = e_j * U + y'_j * G + vector Shnorr + + BEGIN_SERIALIZE_OBJECT() + FIELD(bpp) + FIELD(aggregation_proof) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(bpp) + BOOST_SERIALIZE(aggregation_proof) + END_BOOST_SERIALIZATION() + }; + + // Zarcanum-aware CLSAG signature (one per ZC input) + struct ZC_sig + { + crypto::public_key pseudo_out_amount_commitment = null_pkey; // premultiplied by 1/8 + crypto::public_key pseudo_out_blinded_asset_id = null_pkey; // premultiplied by 1/8 + crypto::CLSAG_GGX_signature_serialized clsags_ggx; + + BEGIN_SERIALIZE_OBJECT() + FIELD(pseudo_out_amount_commitment) + FIELD(pseudo_out_blinded_asset_id) + FIELD(clsags_ggx) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(pseudo_out_amount_commitment) + BOOST_SERIALIZE(pseudo_out_blinded_asset_id) + BOOST_SERIALIZE(clsags_ggx) + END_BOOST_SERIALIZATION() + }; + + // First part of a double Schnorr proof: + // 1) for txs without ZC inputs: proves that balance point = lin(G) (cancels out G component of outputs' amount commitments, asset tags assumed to be H (native coin) and non-blinded) + // 2) for txs with ZC inputs: proves that balance point = lin(X) (cancels out X component of blinded asset tags within amount commitments for both outputs and inputs (pseudo outs)) + // Second part: + // proof of knowing transaction secret key (with respect to G) + struct zc_balance_proof + { + crypto::generic_double_schnorr_sig_s dss; + + BEGIN_SERIALIZE_OBJECT() + FIELD(dss) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(dss) + END_BOOST_SERIALIZATION() + }; + + + struct zarcanum_sig : public crypto::zarcanum_proof + { + BEGIN_SERIALIZE_OBJECT() + FIELD(d) + FIELD(C) + FIELD(C_prime); + FIELD(E); + FIELD(c); + FIELD(y0); + FIELD(y1); + FIELD(y2); + FIELD(y3); + FIELD(y4); + FIELD_N("E_range_proof", (crypto::bppe_signature_serialized&)E_range_proof); + FIELD(pseudo_out_amount_commitment); + FIELD_N("clsag_ggxxg", (crypto::CLSAG_GGXXG_signature_serialized&)clsag_ggxxg); + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(d) + BOOST_SERIALIZE(C) + BOOST_SERIALIZE(C_prime); + BOOST_SERIALIZE(E); + BOOST_SERIALIZE(c); + BOOST_SERIALIZE(y0); + BOOST_SERIALIZE(y1); + BOOST_SERIALIZE(y2); + BOOST_SERIALIZE(y3); + BOOST_SERIALIZE(y4); + BOOST_SERIALIZE((crypto::bppe_signature_serialized&)E_range_proof); + BOOST_SERIALIZE(pseudo_out_amount_commitment); + BOOST_SERIALIZE((crypto::CLSAG_GGXXG_signature_serialized&)clsag_ggxxg); + END_BOOST_SERIALIZATION() + }; + +//#pragma pack(pop) + + typedef boost::variant txin_v; + + typedef boost::variant tx_out_v; + struct tx_comment { @@ -470,8 +674,7 @@ namespace currency extra_alias_entry(const extra_alias_entry_old& old) : extra_alias_entry_base(old) , m_alias(old.m_alias) - { - } + {} std::string m_alias; @@ -493,6 +696,142 @@ namespace currency }; + struct asset_descriptor_base + { + uint64_t total_max_supply = 0; + uint64_t current_supply = 0; + uint8_t decimal_point = 12; + std::string ticker; + std::string full_name; + std::string meta_info; + crypto::public_key owner = currency::null_pkey; // consider premultipling by 1/8 + bool hidden_supply = false; + uint8_t version = 0; + + BEGIN_VERSIONED_SERIALIZE(0, version) + FIELD(total_max_supply) + FIELD(current_supply) + FIELD(decimal_point) + FIELD(ticker) + FIELD(full_name) + FIELD(meta_info) + FIELD(owner) + FIELD(hidden_supply) + END_SERIALIZE() + + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(total_max_supply) + BOOST_SERIALIZE(current_supply) + BOOST_SERIALIZE(decimal_point) + BOOST_SERIALIZE(ticker) + BOOST_SERIALIZE(full_name) + BOOST_SERIALIZE(meta_info) + BOOST_SERIALIZE(owner) + BOOST_SERIALIZE(hidden_supply) + END_BOOST_SERIALIZATION() + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(total_max_supply) + KV_SERIALIZE(current_supply) + KV_SERIALIZE(decimal_point) + KV_SERIALIZE(ticker) + KV_SERIALIZE(full_name) + KV_SERIALIZE(meta_info) + KV_SERIALIZE_POD_AS_HEX_STRING(owner) + KV_SERIALIZE(hidden_supply) + END_KV_SERIALIZE_MAP() + }; + + + struct asset_descriptor_with_id: public asset_descriptor_base + { + crypto::public_key asset_id = currency::null_pkey; + + /* + BEGIN_VERSIONED_SERIALIZE() + FIELD(*static_cast(this)) + FIELD(asset_id) + END_SERIALIZE() + */ + + BEGIN_KV_SERIALIZE_MAP() + KV_CHAIN_BASE(asset_descriptor_base) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + }; + + +#define ASSET_DESCRIPTOR_OPERATION_UNDEFINED 0 +#define ASSET_DESCRIPTOR_OPERATION_REGISTER 1 +#define ASSET_DESCRIPTOR_OPERATION_EMIT 2 +#define ASSET_DESCRIPTOR_OPERATION_UPDATE 3 +#define ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN 4 + +#define ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER 1 + + struct asset_descriptor_operation + { + uint8_t operation_type = ASSET_DESCRIPTOR_OPERATION_UNDEFINED; + asset_descriptor_base descriptor; + crypto::public_key amount_commitment; // premultiplied by 1/8 + boost::optional opt_asset_id; // target asset_id - for update/emit + uint8_t verion = ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER; + + BEGIN_VERSIONED_SERIALIZE(ASSET_DESCRIPTOR_OPERATION_STRUCTURE_VER, verion) + FIELD(operation_type) + FIELD(descriptor) + FIELD(amount_commitment) + END_VERSION_UNDER(1) + FIELD(opt_asset_id) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(operation_type) + BOOST_SERIALIZE(descriptor) + BOOST_SERIALIZE(amount_commitment) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(opt_asset_id) + END_BOOST_SERIALIZATION() + }; + + struct asset_operation_proof + { + // linear composition proof for the fact amount_commitment = lin(asset_id, G) + boost::optional opt_amount_commitment_composition_proof; // for hidden supply + boost::optional opt_amount_commitment_g_proof; // for non-hidden supply, proofs that amount_commitment - supply * asset_id = lin(G) + uint8_t version = 0; + + BEGIN_VERSIONED_SERIALIZE(0, version) + FIELD(opt_amount_commitment_composition_proof) + FIELD(opt_amount_commitment_g_proof) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(opt_amount_commitment_composition_proof) + BOOST_SERIALIZE(opt_amount_commitment_g_proof) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(version) + END_BOOST_SERIALIZATION() + }; + + + struct asset_operation_ownership_proof + { + crypto::generic_schnorr_sig_s gss; + uint8_t version = 0; + + BEGIN_VERSIONED_SERIALIZE(0, version) + FIELD(gss) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(gss) + BOOST_END_VERSION_UNDER(1) + BOOST_SERIALIZE(version) + END_BOOST_SERIALIZATION() + }; + struct extra_padding { @@ -558,10 +897,10 @@ namespace currency END_SERIALIZE() }; - typedef boost::mpl::vector21< + typedef boost::mpl::vector23< tx_service_attachment, tx_comment, tx_payer_old, tx_receiver_old, tx_derivation_hint, std::string, tx_crypto_checksum, etc_tx_time, etc_tx_details_unlock_time, etc_tx_details_expiration_time, etc_tx_details_flags, crypto::public_key, extra_attachment_info, extra_alias_entry_old, extra_user_data, extra_padding, etc_tx_flags16_t, etc_tx_details_unlock_time2, - tx_payer, tx_receiver, extra_alias_entry + tx_payer, tx_receiver, extra_alias_entry, zarcanum_tx_data_v1, asset_descriptor_operation > all_payload_types; typedef boost::make_variant_over::type payload_items_v; @@ -569,26 +908,57 @@ namespace currency typedef payload_items_v attachment_v; + + + //classic CryptoNote signature by Nicolas Van Saberhagen + struct NLSAG_sig + { + std::vector s; + + BEGIN_SERIALIZE_OBJECT() + FIELD(s) + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + BOOST_SERIALIZE(s) + END_BOOST_SERIALIZATION() + }; + + struct void_sig + { + //TODO: + BEGIN_SERIALIZE_OBJECT() + END_SERIALIZE() + + BEGIN_BOOST_SERIALIZATION() + END_BOOST_SERIALIZATION() + }; + + typedef boost::variant signature_v; + + typedef boost::variant proof_v; + + + //include backward compatibility defintions + #include "currency_basic_backward_comp.inl" + class transaction_prefix { public: - // tx version information - uint64_t version{}; - //extra - std::vector extra; + uint64_t version = 0; std::vector vin; - std::vector vout; + std::vector extra; + std::vector vout; BEGIN_SERIALIZE() VARINT_FIELD(version) + CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_prefix_v1) + CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_prefix_v1) if(CURRENT_TRANSACTION_VERSION < version) return false; FIELD(vin) - FIELD(vout) FIELD(extra) + FIELD(vout) END_SERIALIZE() - - protected: - transaction_prefix(){} }; /* @@ -604,55 +974,23 @@ namespace currency class transaction: public transaction_prefix { public: - std::vector > signatures; //count signatures always the same as inputs count std::vector attachment; - - transaction(); + std::vector signatures; + std::vector proofs; BEGIN_SERIALIZE_OBJECT() FIELDS(*static_cast(this)) - FIELD(signatures) + CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_v1) + CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_v1) FIELD(attachment) + FIELD(signatures) + FIELD(proofs) END_SERIALIZE() - - }; - inline - transaction::transaction() - { - version = 0; - vin.clear(); - vout.clear(); - extra.clear(); - signatures.clear(); - attachment.clear(); - - } - /* - inline - transaction::~transaction() - { - //set_null(); - } - - inline - void transaction::set_null() - { - version = 0; - unlock_time = 0; - vin.clear(); - vout.clear(); - extra.clear(); - signatures.clear(); - } - */ - - - /************************************************************************/ /* */ @@ -714,8 +1052,6 @@ namespace currency */ //------------------------------------------------------------------------------------------------------------------- - - #pragma pack(push, 1) struct stake_modifier_type { @@ -725,7 +1061,6 @@ namespace currency struct stake_kernel { - stake_modifier_type stake_modifier; uint64_t block_timestamp; //this block timestamp crypto::key_image kimage; @@ -735,22 +1070,45 @@ namespace currency struct pos_entry { uint64_t amount; - uint64_t index; + uint64_t g_index; // global output index. (could be WALLET_GLOBAL_OUTPUT_INDEX_UNDEFINED) crypto::key_image keyimage; uint64_t block_timestamp; uint64_t stake_unlock_time; + + crypto::hash tx_id; // stake output source tx id + uint64_t tx_out_index; // stake output local index in its tx + //not for serialization - uint64_t wallet_index; + + uint64_t wallet_index; // transfer id index BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) - KV_SERIALIZE(index) + KV_SERIALIZE(g_index) KV_SERIALIZE(stake_unlock_time) KV_SERIALIZE(block_timestamp) KV_SERIALIZE_VAL_POD_AS_BLOB_FORCE(keyimage) + KV_SERIALIZE(tx_id) + KV_SERIALIZE(tx_out_index) END_KV_SERIALIZE_MAP() }; + bool operator ==(const currency::transaction& a, const currency::transaction& b); + bool operator ==(const currency::block& a, const currency::block& b); + bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b); + bool operator ==(const currency::NLSAG_sig& a, const currency::NLSAG_sig& b); + bool operator ==(const currency::void_sig& a, const currency::void_sig& b); + bool operator ==(const currency::ZC_sig& a, const currency::ZC_sig& b); + bool operator ==(const currency::zarcanum_sig& a, const currency::zarcanum_sig& b); + bool operator ==(const currency::ref_by_id& a, const currency::ref_by_id& b); + + // TODO: REPLACE all of the following operators to "bool operator==(..) const = default" once we moved to C++20 -- sowle + bool operator ==(const currency::signed_parts& a, const currency::signed_parts& b); + bool operator ==(const currency::txin_gen& a, const currency::txin_gen& b); + bool operator ==(const currency::txin_to_key& a, const currency::txin_to_key& b); + bool operator ==(const currency::txin_multisig& a, const currency::txin_multisig& b); + bool operator ==(const currency::txin_htlc& a, const currency::txin_htlc& b); + bool operator ==(const currency::txin_zc_input& a, const currency::txin_zc_input& b); } // namespace currency POD_MAKE_HASHABLE(currency, account_public_address); @@ -763,6 +1121,10 @@ BLOB_SERIALIZER(currency::txout_to_key); VARIANT_TAG(json_archive, type_name, json_tag) +BOOST_CLASS_VERSION(currency::asset_descriptor_operation, 1); +BOOST_CLASS_VERSION(currency::asset_operation_proof, 1); +BOOST_CLASS_VERSION(currency::asset_operation_ownership_proof, 1); + // txin_v variant currency SET_VARIANT_TAGS(currency::txin_gen, 0, "gen"); @@ -814,6 +1176,27 @@ SET_VARIANT_TAGS(currency::extra_alias_entry, 33, "alias_entry2"); SET_VARIANT_TAGS(currency::txin_htlc, 34, "txin_htlc"); SET_VARIANT_TAGS(currency::txout_htlc, 35, "txout_htlc"); +SET_VARIANT_TAGS(currency::tx_out_bare, 36, "tx_out_bare"); + +// Zarcanum +SET_VARIANT_TAGS(currency::txin_zc_input, 37, "txin_zc_input"); +SET_VARIANT_TAGS(currency::tx_out_zarcanum, 38, "tx_out_zarcanum"); +SET_VARIANT_TAGS(currency::zarcanum_tx_data_v1, 39, "zarcanum_tx_data_v1"); +SET_VARIANT_TAGS(crypto::bpp_signature_serialized, 40, "bpp_signature_serialized"); +SET_VARIANT_TAGS(crypto::bppe_signature_serialized, 41, "bppe_signature_serialized"); +SET_VARIANT_TAGS(currency::NLSAG_sig, 42, "NLSAG_sig"); +SET_VARIANT_TAGS(currency::ZC_sig, 43, "ZC_sig"); +SET_VARIANT_TAGS(currency::void_sig, 44, "void_sig"); +SET_VARIANT_TAGS(currency::zarcanum_sig, 45, "zarcanum_sig"); +SET_VARIANT_TAGS(currency::zc_asset_surjection_proof, 46, "zc_asset_surjection_proof"); +SET_VARIANT_TAGS(currency::zc_outs_range_proof, 47, "zc_outs_range_proof"); +SET_VARIANT_TAGS(currency::zc_balance_proof, 48, "zc_balance_proof"); + +SET_VARIANT_TAGS(currency::asset_descriptor_operation, 49, "asset_descriptor_base"); +SET_VARIANT_TAGS(currency::asset_operation_proof, 50, "asset_operation_proof"); +SET_VARIANT_TAGS(currency::asset_operation_ownership_proof, 51, "asset_operation_ownership_proof"); + + #undef SET_VARIANT_TAGS diff --git a/src/currency_core/currency_basic_backward_comp.inl b/src/currency_core/currency_basic_backward_comp.inl new file mode 100644 index 00000000..7dffea0e --- /dev/null +++ b/src/currency_core/currency_basic_backward_comp.inl @@ -0,0 +1,118 @@ +// Copyright (c) 2014-2022 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + + + +class transaction_prefix_v1 +{ +public: + // tx version information + uint64_t version{}; + //extra + std::vector extra; + std::vector vin; + std::vector vout;//std::vector vout; + + BEGIN_SERIALIZE() + //VARINT_FIELD(version) <-- this already unserialized + if (TRANSACTION_VERSION_PRE_HF4 < version) return false; + FIELD(vin) + FIELD(vout) + FIELD(extra) + END_SERIALIZE() +}; +/* +class transaction_prefix_v1_full +{ +public: + // tx version information + uint64_t version{}; + //extra + std::vector extra; + std::vector vin; + std::vector vout;//std::vector vout; + + BEGIN_SERIALIZE() + VARINT_FIELD(version) + if (TRANSACTION_VERSION_PRE_HF4 < version) return false; + FIELD(vin) + FIELD(vout) + FIELD(extra) + END_SERIALIZE() +}; +*/ + +template +bool transition_convert(const transaction_prefix_current_t& from, transaction_prefix_v1& to) +{ + to.extra = from.extra; + to.vin = from.vin; + for (const auto& v : from.vout) + { + if (v.type() == typeid(tx_out_bare)) + { + to.vout.push_back(boost::get(v)); + } + else { + throw std::runtime_error("Unexpected type in tx_out_v"); + } + } + return true; +} +template +bool transition_convert(const transaction_prefix_v1& from, transaction_prefix_current_t& to) +{ + to.extra = from.extra; + to.vin = from.vin; + for (const auto& v : from.vout) + { + to.vout.push_back(v); + } + return true; +} + + + +class transaction_v1 +{ +public: + std::vector > signatures; //count signatures always the same as inputs count + std::vector attachment; + + BEGIN_SERIALIZE_OBJECT() + FIELD(signatures) + FIELD(attachment) + END_SERIALIZE() +}; + +template +bool transition_convert(const transaction_current_t& from, transaction_v1& to) +{ + to.attachment = from.attachment; + for (const auto& s : from.signatures) + { + if (s.type() == typeid(NLSAG_sig)) + { + to.signatures.push_back(boost::get(s).s); + } + else + { + throw std::runtime_error(std::string("Unexpected type in tx.signatures during transition_convert: ") + s.type().name()); + } + } + return true; +} + +template +bool transition_convert(const transaction_v1& from, transaction_current_t& to) +{ + // TODO: consider using move semantic for 'from' + to.attachment = from.attachment; + to.signatures.resize(from.signatures.size()); + for (size_t i = 0; i != from.signatures.size(); i++) + { + boost::get(to.signatures[i]).s = from.signatures[i]; + } + return true; +} diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index 96f95bdc..5d7c40f7 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -15,7 +15,7 @@ #include #include "currency_basic.h" #include "common/unordered_containers_boost_serialization.h" -#include "common/crypto_boost_serialization.h" +#include "common/crypto_serialization.h" #include "offers_services_helpers.h" #define CURRENT_BLOCK_ARCHIVE_VER 2 @@ -104,13 +104,22 @@ namespace boost } template - inline void serialize(Archive &a, currency::tx_out &x, const boost::serialization::version_type ver) + inline void serialize(Archive &a, currency::tx_out_bare &x, const boost::serialization::version_type ver) { a & x.amount; a & x.target; } - + template + inline void serialize(Archive &a, currency::tx_out_zarcanum &x, const boost::serialization::version_type ver) + { + a & x.stealth_address; + a & x.concealing_point; + a & x.amount_commitment; + a & x.blinded_asset_id; + a & x.encrypted_amount; + a & x.mix_attr; + } template inline void serialize(Archive &a, currency::tx_comment &x, const boost::serialization::version_type ver) diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h index 18e38c67..c1335126 100644 --- a/src/currency_core/currency_config.h +++ b/src/currency_core/currency_config.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2019 Zano Project +// Copyright (c) 2014-2024 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -10,7 +10,7 @@ #ifndef TESTNET #define CURRENCY_FORMATION_VERSION 84 #else -#define CURRENCY_FORMATION_VERSION 88 +#define CURRENCY_FORMATION_VERSION 97 #endif #define CURRENCY_GENESIS_NONCE (CURRENCY_FORMATION_VERSION + 101011010121) //bender's nightmare @@ -20,15 +20,25 @@ #define CURRENCY_MAX_BLOCK_NUMBER 500000000 #define CURRENCY_MAX_BLOCK_SIZE 500000000 // block header blob limit, never used! #define CURRENCY_TX_MAX_ALLOWED_OUTS 2000 +#define CURRENCY_TX_MIN_ALLOWED_OUTS 2 // effective starting HF4 Zarcanum #define CURRENCY_PUBLIC_ADDRESS_BASE58_PREFIX 0xc5 // addresses start with 'Zx' #define CURRENCY_PUBLIC_INTEG_ADDRESS_BASE58_PREFIX 0x3678 // integrated addresses start with 'iZ' #define CURRENCY_PUBLIC_INTEG_ADDRESS_V2_BASE58_PREFIX 0x36f8 // integrated addresses start with 'iZ' (new format) #define CURRENCY_PUBLIC_AUDITABLE_ADDRESS_BASE58_PREFIX 0x98c8 // auditable addresses start with 'aZx' #define CURRENCY_PUBLIC_AUDITABLE_INTEG_ADDRESS_BASE58_PREFIX 0x8a49 // auditable integrated addresses start with 'aiZX' #define CURRENCY_MINED_MONEY_UNLOCK_WINDOW 10 -#define CURRENT_TRANSACTION_VERSION 1 +#define CURRENT_TRANSACTION_VERSION 2 +#define TRANSACTION_VERSION_INITAL 0 +#define TRANSACTION_VERSION_PRE_HF4 1 +#define TRANSACTION_VERSION_POST_HF4 2 #define HF1_BLOCK_MAJOR_VERSION 1 -#define CURRENT_BLOCK_MAJOR_VERSION 2 +#define HF3_BLOCK_MAJOR_VERSION 2 +#define HF3_BLOCK_MINOR_VERSION 0 +#define CURRENT_BLOCK_MAJOR_VERSION 3 + +#define CURRENCY_DEFAULT_DECOY_SET_SIZE 10 +#define CURRENCY_HF4_MANDATORY_DECOY_SET_SIZE 15 +#define CURRENCY_HF4_MANDATORY_MIN_COINAGE 10 #define CURRENT_BLOCK_MINOR_VERSION 0 #define CURRENCY_BLOCK_FUTURE_TIME_LIMIT 60*60*2 @@ -58,8 +68,9 @@ #define WALLET_MAX_ALLOWED_OUTPUT_AMOUNT ((uint64_t)0xffffffffffffffffLL) #define CURRENCY_MINER_TX_MAX_OUTS CURRENCY_TX_MAX_ALLOWED_OUTS +#define CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP 3 -#define DIFFICULTY_STARTER 1 +#define DIFFICULTY_POW_STARTER 1 #define DIFFICULTY_POS_TARGET 120 // seconds #define DIFFICULTY_POW_TARGET 120 // seconds #define DIFFICULTY_TOTAL_TARGET ((DIFFICULTY_POS_TARGET + DIFFICULTY_POW_TARGET) / 4) @@ -104,6 +115,7 @@ #define STRATUM_DEFAULT_PORT 11777 #define P2P_NETWORK_ID_TESTNET_FLAG 0 #define P2P_MAINTAINERS_PUB_KEY "8f138bb73f6d663a3746a542770781a09579a7b84cb4125249e95530824ee607" +#define DIFFICULTY_POS_STARTER 1 #else #define P2P_DEFAULT_PORT (11112 + CURRENCY_FORMATION_VERSION) #define RPC_DEFAULT_PORT 12111 @@ -111,6 +123,7 @@ #define STRARUM_DEFAULT_PORT 51113 #define P2P_NETWORK_ID_TESTNET_FLAG 1 #define P2P_MAINTAINERS_PUB_KEY "aaa2d7aabc8d383fd53a3ae898697b28f236ceade6bafc1eecff413a6a02272a" +#define DIFFICULTY_POS_STARTER 1 #endif #define P2P_NETWORK_ID_VER (CURRENCY_FORMATION_VERSION+0) @@ -145,6 +158,15 @@ #define POS_WALLET_MINING_SCAN_INTERVAL POS_SCAN_STEP //seconds #define POS_MINIMUM_COINSTAKE_AGE 10 // blocks count +#ifndef TESTNET +# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 57000 +#else +# define BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION 18000 +#endif +#define BLOCK_POS_STRICT_SEQUENCE_LIMIT 20 // the highest allowed sequence factor for a PoS block (i.e., the max total number of sequential PoS blocks is BLOCK_POS_STRICT_SEQUENCE_LIMIT + 1) + + +#define CORE_FEE_BLOCKS_LOOKUP_WINDOW 60 //number of blocks used to check if transaction flow is big enought to rise default fee #define WALLET_FILE_SIGNATURE_OLD 0x1111012101101011LL // Bender's nightmare #define WALLET_FILE_SIGNATURE_V2 0x1111011201101011LL // another Bender's nightmare @@ -205,7 +227,7 @@ #define CURRENCY_POOLDATA_FOLDERNAME_PREFIX "poolstate_" #define CURRENCY_POOLDATA_FOLDERNAME_SUFFIX "_v1" #define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_PREFIX "blockchain_" -#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v1" +#define CURRENCY_BLOCKCHAINDATA_FOLDERNAME_SUFFIX "_v2" #define P2P_NET_DATA_FILENAME "p2pstate.bin" #define MINER_CONFIG_FILENAME "miner_conf.json" @@ -214,6 +236,7 @@ #define GUI_INTERNAL_CONFIG2 "gui_internal_config.json" #define GUI_IPC_MESSAGE_CHANNEL_NAME CURRENCY_NAME_BASE "_message_que" +#define CURRENCY_VOTING_CONFIG_DEFAULT_FILENAME "voting_config.json" #define CURRENT_TRANSACTION_CHAIN_ENTRY_ARCHIVE_VER 3 @@ -227,9 +250,11 @@ #define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin" #ifndef TESTNET -#define WALLET_FILE_SERIALIZATION_VERSION 153 +#define WALLET_FILE_SERIALIZATION_VERSION 162 +#define WALLET_FILE_LAST_SUPPORTED_VERSION 162 #else -#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+69) +#define WALLET_FILE_LAST_SUPPORTED_VERSION (CURRENCY_FORMATION_VERSION+76) +#define WALLET_FILE_SERIALIZATION_VERSION (CURRENCY_FORMATION_VERSION+76) #endif #define CURRENT_MEMPOOL_ARCHIVE_VER (CURRENCY_FORMATION_VERSION+31) @@ -239,19 +264,39 @@ #define BLOCK_MINOR_VERSION_GENESIS 0 #define BLOCK_MAJOR_VERSION_INITIAL 0 #ifndef TESTNET -#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 -#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 -#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 +#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624 // 2019-09-21 20:25:16 +#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999 // 2021-04-05 09:11:45 +#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577 // 2021-06-01 23:28:10 +#define ZANO_HARDFORK_04_AFTER_HEIGHT 2555000 // 2024-03-21 10:16:46 (expected) #else -#define ZANO_HARDFORK_01_AFTER_HEIGHT 1440 -#define ZANO_HARDFORK_02_AFTER_HEIGHT 1800 -#define ZANO_HARDFORK_03_AFTER_HEIGHT 1801 +/////// Zarcanum Testnet ////////////////////////////// +#define ZANO_HARDFORK_01_AFTER_HEIGHT 0 +#define ZANO_HARDFORK_02_AFTER_HEIGHT 0 +#define ZANO_HARDFORK_03_AFTER_HEIGHT 0 +#define ZANO_HARDFORK_04_AFTER_HEIGHT 2440 #endif +#define ZANO_HARDFORK_00_INITAL 0 +#define ZANO_HARDFORK_01 1 +#define ZANO_HARDFORK_02 2 +#define ZANO_HARDFORK_03 3 +#define ZANO_HARDFORK_04_ZARCANUM 4 +#define ZANO_HARDFORKS_TOTAL 5 + + static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit"); static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs"); -#define CURRENCY_RELAY_TXS_MAX_COUNT 5 \ No newline at end of file +#define CURRENCY_RELAY_TXS_MAX_COUNT 5 + +#ifndef TESTNET + #define WALLET_ASSETS_WHITELIST_URL "https://api.zano.org/assets_whitelist.json" +#else + #define WALLET_ASSETS_WHITELIST_URL "https://api.zano.org/assets_whitelist_testnet.json" +#endif + + +#define WALLET_ASSETS_WHITELIST_VALIDATION_PUBLIC_KEY "" //TODO@#@ \ No newline at end of file diff --git a/src/currency_core/currency_core.cpp b/src/currency_core/currency_core.cpp index fde150f9..876c2d17 100644 --- a/src/currency_core/currency_core.cpp +++ b/src/currency_core/currency_core.cpp @@ -76,7 +76,10 @@ namespace currency bool core::handle_command_line(const boost::program_options::variables_map& vm) { m_config_folder = command_line::get_arg(vm, command_line::arg_data_dir); - m_stop_after_height = static_cast(command_line::get_arg(vm, command_line::arg_stop_after_height)); + m_stop_after_height = 0; + if(command_line::has_arg(vm, command_line::arg_stop_after_height)) + m_stop_after_height = static_cast(command_line::get_arg(vm, command_line::arg_stop_after_height)); + if (m_stop_after_height != 0) { LOG_PRINT_YELLOW("Daemon will STOP after block " << m_stop_after_height, LOG_LEVEL_0); @@ -89,6 +92,11 @@ namespace currency return m_blockchain_storage.get_current_blockchain_size(); } //----------------------------------------------------------------------------------------------- + uint64_t core::get_current_tx_version() const + { + return get_tx_version(m_blockchain_storage.get_current_blockchain_size(), m_blockchain_storage.get_core_runtime_config().hard_forks); + } + //----------------------------------------------------------------------------------------------- uint64_t core::get_top_block_height() const { return m_blockchain_storage.get_top_block_height(); @@ -350,7 +358,7 @@ namespace currency //----------------------------------------------------------------------------------------------- bool core::get_block_template(block& b, const account_public_address& adr, const account_public_address& stakeholder_address, wide_difficulty_type& diffic, uint64_t& height, const blobdata& ex_nonce, bool pos, const pos_entry& pe) { - return m_blockchain_storage.create_block_template(b, adr, stakeholder_address, diffic, height, ex_nonce, pos, pe); + return m_blockchain_storage.create_block_template(adr, stakeholder_address, ex_nonce, pos, pe, nullptr, b, diffic, height); } //----------------------------------------------------------------------------------------------- bool core::get_block_template(const create_block_template_params& params, create_block_template_response& resp) @@ -511,12 +519,25 @@ namespace currency bool r = m_blockchain_storage.add_new_block(b, bvc); if (r && bvc.m_added_to_main_chain) { - h = get_block_height(b); - auto& crc = m_blockchain_storage.get_core_runtime_config(); - if (h == crc.hard_fork_01_starts_after_height + 1) - { LOG_PRINT_GREEN("Hardfork 1 activated at height " << h, LOG_LEVEL_0); } - else if (h == crc.hard_fork_02_starts_after_height + 1) - { LOG_PRINT_GREEN("Hardfork 2 activated at height " << h, LOG_LEVEL_0); } + uint64_t h = get_block_height(b); + if (h > 0) + { + auto& crc = m_blockchain_storage.get_core_runtime_config(); + size_t hardfork_id_for_prev_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h); + size_t hardfork_id_for_curr_block = crc.hard_forks.get_the_most_recent_hardfork_id_for_height(h + 1); + if (hardfork_id_for_prev_block != hardfork_id_for_curr_block) + { + LOG_PRINT_GREEN("Hardfork " << hardfork_id_for_curr_block << " has been activated after the block at height " << h, LOG_LEVEL_0); + } + } + + if (h == m_stop_after_height) + { + LOG_PRINT_YELLOW("Reached block " << h << ", the daemon will now stop as requested", LOG_LEVEL_0); + if (m_critical_error_handler) + return m_critical_error_handler->on_immediate_stop_requested(); + return false; + } } return r; } diff --git a/src/currency_core/currency_core.h b/src/currency_core/currency_core.h index 354fd772..feeca5f4 100644 --- a/src/currency_core/currency_core.h +++ b/src/currency_core/currency_core.h @@ -63,6 +63,7 @@ namespace currency bool set_genesis_block(const block& b); bool deinit(); uint64_t get_current_blockchain_size() const; + uint64_t get_current_tx_version() const; uint64_t get_top_block_height() const; std::string get_config_folder(); bool get_blockchain_top(uint64_t& heeight, crypto::hash& top_id) const; @@ -139,18 +140,18 @@ namespace currency tx_memory_pool m_mempool; i_currency_protocol* m_pprotocol; i_critical_error_handler* m_critical_error_handler; - critical_section m_incoming_tx_lock; + epee::critical_section m_incoming_tx_lock; miner m_miner; account_public_address m_miner_address; std::string m_config_folder; uint64_t m_stop_after_height; currency_protocol_stub m_protocol_stub; - math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval; - math_helper::once_a_time_seconds<60, true> m_check_free_space_interval; + epee::math_helper::once_a_time_seconds<60*60*12, false> m_prune_alt_blocks_interval; + epee::math_helper::once_a_time_seconds<60, true> m_check_free_space_interval; friend class tx_validate_inputs; std::atomic m_starter_message_showed; - critical_section m_blockchain_update_listeners_lock; + epee::critical_section m_blockchain_update_listeners_lock; std::vector m_blockchain_update_listeners; }; } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index 7019ce41..cef1dfcd 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2023 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -14,6 +14,7 @@ using namespace epee; #include "print_fixed_point_helper.h" #include "currency_format_utils.h" +#include "currency_format_utils_transactions.h" #include "serialization/binary_utils.h" #include "serialization/stl_containers.h" #include "currency_core/currency_config.h" @@ -31,6 +32,11 @@ using namespace epee; #include "genesis_acc.h" #include "common/mnemonic-encoding.h" #include "crypto/bitcoin/sha256_helper.h" +#include "crypto_config.h" +#include "wallet/wallet_debug_events_definitions.h" + + +#define DBG_VAL_PRINT(x) ((void)0) // LOG_PRINT_CYAN(std::setw(42) << std::left << #x ":" << x, LOG_LEVEL_0) namespace currency { @@ -41,30 +47,210 @@ namespace currency tx.extra.push_back(alinfo); return true; } - - //--------------------------------------------------------------- - /* - bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, - size_t current_block_size, - uint64_t fee, - const account_public_address &miner_address, - transaction& tx, - const blobdata& extra_nonce, - size_t max_outs) + //-------------------------------------------------------------------------------- + bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, tx_generation_context& ogc, zc_asset_surjection_proof& result) { + bool r = false; + size_t outs_count = ogc.blinded_asset_ids.size(); + CHECK_AND_ASSERT_MES(outs_count > 0, false, "blinded_asset_ids shouldn't be empty"); + CHECK_AND_ASSERT_MES(outs_count == ogc.asset_id_blinding_masks.size(), false, "asset_id_blinding_masks != outs_count"); - alias_info alias = AUTO_VAL_INIT(alias); - return construct_miner_tx(height, median_size, already_generated_coins, current_block_size, - fee, - miner_address, - tx, - extra_nonce, - max_outs, - alias, - false, - pos_entry()); - }*/ + size_t zc_ins_count = ogc.pseudo_outs_blinded_asset_ids.size(); + if (zc_ins_count == 0) + { + // if there's no ZC inputs all the outputs must be native coins with explicit asset ids + for(size_t j = 0; j < ogc.blinded_asset_ids.size(); ++j) + { + CHECK_AND_ASSERT_MES(ogc.blinded_asset_ids[j] == currency::native_coin_asset_id_pt, false, "no ZC ins: out #" << j << " has a non-explicit asset id"); + CHECK_AND_ASSERT_MES(ogc.asset_id_blinding_masks[j] == 0, false, "no ZC ins: out #" << j << " has non-zero asset id blinding mask"); + } + return true; + } + + // okay, have some ZC inputs + + CHECK_AND_ASSERT_MES(zc_ins_count == ogc.pseudo_outs_plus_real_out_blinding_masks.size(), false, "zc_ins_count != pseudo_outs_plus_real_out_blinding_masks"); + CHECK_AND_ASSERT_MES(zc_ins_count == ogc.real_zc_ins_asset_ids.size(), false, "zc_ins_count != real_zc_ins_asset_ids"); + + // ins + //ogc.pseudo_outs_blinded_asset_ids; // T^p_i = T_real + r'_i * X + //ogc.pseudo_outs_plus_real_out_blinding_masks; // r_pi + r'_j + + // outs + //ogc.blinded_asset_ids; // T'_j = H_j + s_j * X + //ogc.asset_id_blinding_masks; // s_j + + for(size_t j = 0; j < outs_count; ++j) + { + const crypto::public_key H = ogc.asset_ids[j].to_public_key(); + const crypto::point_t& T = ogc.blinded_asset_ids[j]; + + std::vector ring; + ring.reserve(zc_ins_count); + size_t secret_index = SIZE_MAX; + crypto::scalar_t secret = -ogc.asset_id_blinding_masks[j]; + + for(size_t i = 0; i < zc_ins_count; ++i) + { + ring.emplace_back(ogc.pseudo_outs_blinded_asset_ids[i] - T); + if (secret_index == SIZE_MAX && ogc.real_zc_ins_asset_ids[i] == H) + { + secret_index = i; + secret += ogc.pseudo_outs_plus_real_out_blinding_masks[secret_index]; + } + } + + // additional ring member for native coins in txs with non-zc inputs + if (has_non_zc_inputs) + { + ring.emplace_back(currency::native_coin_asset_id_pt - T); + if (secret_index == SIZE_MAX && H == native_coin_asset_id) + secret_index = ring.size() - 1; + } + + // additional ring member for asset emitting operation (which has asset operation commitment in the inputs part) + if (!ogc.ao_amount_blinding_mask.is_zero() && !ogc.ao_commitment_in_outputs) + { + ring.emplace_back(ogc.ao_asset_id_pt - T); + if (secret_index == SIZE_MAX && H == ogc.ao_asset_id) + secret_index = ring.size() - 1; + } + + CHECK_AND_ASSERT_MES(secret_index != SIZE_MAX, false, "out #" << j << ": can't find a corresponding asset id in inputs, asset id: " << H); + + result.bge_proofs.emplace_back(crypto::BGE_proof_s{}); + uint8_t err = 0; + r = crypto::generate_BGE_proof(context_hash, ring, secret, secret_index, result.bge_proofs.back(), &err); + CHECK_AND_ASSERT_MES(r, false, "out #" << j << ": generate_BGE_proof failed with err=" << (int)err); + } + + return true; + } + //-------------------------------------------------------------------------------- + bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id) + { + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + return true; + + size_t outs_count = tx.vout.size(); + + bool has_ZC_inputs = false; + bool has_non_ZC_inputs = false; + for(const auto& in : tx.vin) + { + if (in.type() == typeid(txin_zc_input)) + has_ZC_inputs = true; + else + has_non_ZC_inputs = true; + } + + if (!has_ZC_inputs) + { + // no ZC ins -- just make sure there's only native outputs with explicit asset ids + for(size_t j = 0; j < outs_count; ++j) + { + CHECK_AND_ASSERT_MES(boost::get(tx.vout[j]).blinded_asset_id == native_coin_asset_id_1div8, false, "output #" << j << " has a non explicitly native asset id"); + } + return true; + } + + // tx has ZC inputs + const zc_asset_surjection_proof& sig = get_type_in_variant_container_by_ref(tx.proofs); // order of proofs and uniqueness of zc_asset_surjection_proof should be check before on prevalidation + CHECK_AND_ASSERT_MES(sig.bge_proofs.size() == outs_count, false, "ASP count: " << sig.bge_proofs.size() << ", outputs: " << outs_count << " => missmatch"); + + // make a ring + std::vector pseudo_outs_blinded_asset_ids; + for(const auto& sig : tx.signatures) + { + if (sig.type() == typeid(ZC_sig)) + pseudo_outs_blinded_asset_ids.emplace_back(crypto::point_t(boost::get(sig).pseudo_out_blinded_asset_id).modify_mul8()); + } + if (has_non_ZC_inputs) + pseudo_outs_blinded_asset_ids.emplace_back(currency::native_coin_asset_id_pt); // additional ring member for txs with non-zc inputs + + asset_descriptor_operation ado{}; + if (is_asset_emitting_transaction(tx, &ado)) + { + crypto::point_t asset_id_pt{}; + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &asset_id_pt, nullptr), false, "get_or_calculate_asset_id failed"); // TODO @#@# expensive operation, consider caching + pseudo_outs_blinded_asset_ids.emplace_back(asset_id_pt); // additional ring member for asset emitting tx + } + + for(size_t j = 0; j < outs_count; ++j) + { + crypto::point_t blinded_asset_id(boost::get(tx.vout[j]).blinded_asset_id); + blinded_asset_id.modify_mul8(); + + // TODO @#@# remove this redundant conversion to pubkey and back + std::vector ring(pseudo_outs_blinded_asset_ids.size()); + std::vector ring_pointers(pseudo_outs_blinded_asset_ids.size()); + for(size_t i = 0, n = pseudo_outs_blinded_asset_ids.size(); i < n; ++i) + { + ring[i] = ((crypto::c_scalar_1div8 * (pseudo_outs_blinded_asset_ids[i] - blinded_asset_id)).to_public_key()); + ring_pointers[i] = &ring[i]; + } + + uint8_t err = 0; + CHECK_AND_ASSERT_MES(crypto::verify_BGE_proof(tx_id, ring_pointers, sig.bge_proofs[j], &err), false, "verify_BGE_proof failed, err = " << (int)err); + } + + return true; + } + //-------------------------------------------------------------------------------- + bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const tx_generation_context& outs_gen_context, + const std::vector& vouts, zc_outs_range_proof& result) + { + size_t outs_count = outs_gen_context.amounts.size(); + // TODO @#@# reconsider this check CHECK_AND_ASSERT_MES(gen_context.check_sizes(outs_count), false, ""); + CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, ""); + + // prepare data for aggregation proof + std::vector amount_commitments_for_rp_aggregation; // E' = amount * U + y' * G + crypto::scalar_vec_t y_primes; // y' + for (size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i) + { + crypto::scalar_t y_prime = crypto::scalar_t::random(); + amount_commitments_for_rp_aggregation.emplace_back(outs_gen_context.amounts[i] * crypto::c_point_U + y_prime * crypto::c_point_G); // E'_j = e_j * U + y'_j * G + y_primes.emplace_back(std::move(y_prime)); + } + + // aggregation proof + uint8_t err = 0; + bool r = crypto::generate_vector_UG_aggregation_proof(context_hash, outs_gen_context.amounts, outs_gen_context.amount_blinding_masks, y_primes, + outs_gen_context.amount_commitments, + amount_commitments_for_rp_aggregation, + outs_gen_context.blinded_asset_ids, result.aggregation_proof, &err); + CHECK_AND_ASSERT_MES(r, false, "generate_vector_UG_aggregation_proof failed with error " << (int)err); + + // aggregated range proof + std::vector commitments_1div8(result.aggregation_proof.amount_commitments_for_rp_aggregation.size()); + for(size_t i = 0, sz = result.aggregation_proof.amount_commitments_for_rp_aggregation.size(); i < sz; ++i) + commitments_1div8[i] = &result.aggregation_proof.amount_commitments_for_rp_aggregation[i]; + + err = 0; + r = crypto::bpp_gen(outs_gen_context.amounts, y_primes, commitments_1div8, result.bpp, &err); + CHECK_AND_ASSERT_MES(r, false, "bpp_gen failed with error " << (int)err); + + return true; + } //--------------------------------------------------------------- + bool verify_multiple_zc_outs_range_proofs(const std::vector& range_proofs) + { + if (range_proofs.empty()) + return true; + + std::vector sigs; + sigs.reserve(range_proofs.size()); + for(auto& el : range_proofs) + sigs.emplace_back(el.range_proof.bpp, el.amount_commitments); + + uint8_t err = 0; + bool r = crypto::bpp_verify(sigs, &err); + CHECK_AND_ASSERT_MES(r, false, "bpp_verify failed with error " << (int)err); + + return true; + } + //-------------------------------------------------------------------------------- wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff) { //delta=delta*(0.75^n) @@ -75,62 +261,76 @@ namespace currency return diff; } //------------------------------------------------------------------ - bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, - size_t current_block_size, - uint64_t fee, - const account_public_address &miner_address, - const account_public_address &stakeholder_address, - transaction& tx, - const blobdata& extra_nonce, - size_t max_outs, - bool pos, - const pos_entry& pe) + bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const tx_generation_context& ogc, uint64_t block_reward_for_miner_tx, currency::zc_balance_proof& proof) { - uint64_t block_reward = 0; - if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward, height)) - { - LOG_ERROR("Block is too big"); - return false; - } - block_reward += fee; - - std::vector out_amounts; - decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD, - [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, - [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); + CHECK_AND_ASSERT_MES(tx.version > TRANSACTION_VERSION_PRE_HF4, false, "unsupported tx.version: " << tx.version); + CHECK_AND_ASSERT_MES(count_type_in_variant_container(tx.proofs) == 0, false, "zc_balance_proof is already present"); + bool r = false; - CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); - while (max_outs < out_amounts.size()) + uint64_t bare_inputs_sum = block_reward_for_miner_tx; + size_t zc_inputs_count = 0; + for(auto& vin : tx.vin) { - out_amounts[out_amounts.size() - 2] += out_amounts.back(); - out_amounts.resize(out_amounts.size() - 1); + VARIANT_SWITCH_BEGIN(vin); + VARIANT_CASE_CONST(txin_to_key, tk) + bare_inputs_sum += tk.amount; + VARIANT_CASE_CONST(txin_htlc, foo); + CHECK_AND_ASSERT_MES(false, false, "unexpected txin_htlc input"); + VARIANT_CASE_CONST(txin_multisig, ms); + //bare_inputs_sum += ms.amount; + CHECK_AND_ASSERT_MES(false, false, "unexpected txin_multisig input"); // TODO @#@# check support for multisig inputs + VARIANT_CASE_CONST(txin_zc_input, foo); + ++zc_inputs_count; + VARIANT_SWITCH_END(); } + uint64_t fee = 0; + CHECK_AND_ASSERT_MES(get_tx_fee(tx, fee), false, "unable to get tx fee"); - std::vector destinations; - for (auto a : out_amounts) + if (zc_inputs_count == 0) { - tx_destination_entry de = AUTO_VAL_INIT(de); - de.addr.push_back(miner_address); - de.amount = a; - if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW) - { - //this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately - de.unlock_time = height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW; - } - destinations.push_back(de); + // no ZC inputs => all inputs are bare inputs; all outputs have explicit asset_id = native_coin_asset_id; in main balance equation we only need to cancel out G-component + CHECK_AND_ASSERT_MES(count_type_in_variant_container(tx.signatures) == 0, false, "ZC_sig is unexpected"); + CHECK_AND_ASSERT_MES(ogc.asset_id_blinding_mask_x_amount_sum.is_zero(), false, "it's expected that all asset ids for this tx are obvious and thus explicit"); // because this tx has no ZC inputs => all outs clearly have native asset id + CHECK_AND_ASSERT_MES(ogc.ao_amount_blinding_mask.is_zero(), false, "asset emmission is not allowed for txs without ZC inputs"); + + // (sum(bare inputs' amounts) - fee) * H + sum(pseudo out amount commitments) - sum(outputs' commitments) = lin(G) + + crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt - ogc.amount_commitments_sum; + crypto::scalar_t secret_x = -ogc.amount_blinding_masks_sum; +#ifndef NDEBUG + CHECK_AND_ASSERT_MES(commitment_to_zero == secret_x * crypto::c_point_G, false, "internal error: commitment_to_zero is malformed (G)"); +#endif + r = crypto::generate_double_schnorr_sig(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss); + CHECK_AND_ASSERT_MES(r, false, "generate_double_schnorr_sig (G, G) failed"); + } + else // i.e. zc_inputs_count != 0 + { + // there're ZC inputs => in main balance equation we only need to cancel out X-component, because G-component cancelled out by choosing blinding mask for the last pseudo out amount commitment + + crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt + ogc.pseudo_out_amount_commitments_sum + (ogc.ao_commitment_in_outputs ? -ogc.ao_amount_commitment : ogc.ao_amount_commitment) - ogc.amount_commitments_sum; + crypto::scalar_t secret_x = ogc.real_in_asset_id_blinding_mask_x_amount_sum - ogc.asset_id_blinding_mask_x_amount_sum; + + DBG_VAL_PRINT(bare_inputs_sum); + DBG_VAL_PRINT(fee); + DBG_VAL_PRINT(ogc.pseudo_out_amount_commitments_sum); + DBG_VAL_PRINT((int)ogc.ao_commitment_in_outputs); + DBG_VAL_PRINT(ogc.ao_amount_commitment); + DBG_VAL_PRINT(ogc.amount_commitments_sum); + DBG_VAL_PRINT(ogc.real_in_asset_id_blinding_mask_x_amount_sum); + DBG_VAL_PRINT(ogc.asset_id_blinding_mask_x_amount_sum); + DBG_VAL_PRINT(commitment_to_zero); + DBG_VAL_PRINT(secret_x); + +#ifndef NDEBUG + bool commitment_to_zero_is_sane = commitment_to_zero == secret_x * crypto::c_point_X; + CHECK_AND_ASSERT_MES(commitment_to_zero_is_sane, false, "internal error: commitment_to_zero is malformed (X)"); +#endif + r = crypto::generate_double_schnorr_sig(tx_id, commitment_to_zero, secret_x, ogc.tx_pub_key_p, ogc.tx_key.sec, proof.dss); + CHECK_AND_ASSERT_MES(r, false, "genergenerate_double_schnorr_sigate_schnorr_sig (X, G) failed"); } - if (pos) - { - uint64_t stake_lock_time = 0; - if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW) - stake_lock_time = pe.stake_unlock_time; - destinations.push_back(tx_destination_entry(pe.amount, stakeholder_address, stake_lock_time)); - } - - - return construct_miner_tx(height, median_size, already_generated_coins, current_block_size, fee, destinations, tx, extra_nonce, max_outs, pos, pe); + return true; } //------------------------------------------------------------------ bool apply_unlock_time(const std::vector& destinations, transaction& tx) @@ -153,25 +353,103 @@ namespace currency return true; } - //------------------------------------------------------------------ + //--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t current_block_size, uint64_t fee, - const std::vector& destinations, + const account_public_address &miner_address, + const account_public_address &stakeholder_address, transaction& tx, - const blobdata& extra_nonce, - size_t max_outs, - bool pos, - const pos_entry& pe) + uint64_t& block_reward_without_fee, + uint64_t& block_reward, + uint64_t tx_version, + const blobdata& extra_nonce /* = blobdata() */, + size_t max_outs /* = CURRENCY_MINER_TX_MAX_OUTS */, + bool pos /* = false */, + const pos_entry& pe /* = pos_entry() */, // only pe.stake_unlock_time and pe.stake_amount are used now, TODO: consider refactoring -- sowle + tx_generation_context* ogc_ptr /* = nullptr */, + const keypair* tx_one_time_key_to_use /* = nullptr */, + const std::vector& destinations_ /* = std::vector() */ + ) { + std::vector destinations = destinations_; + + bool r = false; + + if (!get_block_reward(pos, median_size, current_block_size, already_generated_coins, block_reward_without_fee, height)) + { + LOG_ERROR("Block is too big"); + return false; + } + + block_reward = block_reward_without_fee; + // before HF4: add tx fee to the block reward; after HF4: burn it + if (tx_version < TRANSACTION_VERSION_POST_HF4) + { + block_reward += fee; + } + + if (!destinations.size()) + { + // + // prepare destinations + // + // 1. split block_reward into out_amounts + std::vector out_amounts; + if (tx_version > TRANSACTION_VERSION_PRE_HF4) + { + // randomly split into CURRENCY_TX_MIN_ALLOWED_OUTS outputs for PoW block, or for PoS block only if the stakeholder address differs + // (otherwise for PoS miner tx there will be ONE output with amount = stake_amount + reward) + if (!pos || miner_address != stakeholder_address) + decompose_amount_randomly(block_reward, [&](uint64_t a) { out_amounts.push_back(a); }, CURRENCY_TX_MIN_ALLOWED_OUTS); + } + else + { + // non-hidden outs: split into digits + decompose_amount_into_digits(block_reward, DEFAULT_DUST_THRESHOLD, + [&out_amounts](uint64_t a_chunk) { out_amounts.push_back(a_chunk); }, + [&out_amounts](uint64_t a_dust) { out_amounts.push_back(a_dust); }); + CHECK_AND_ASSERT_MES(1 <= max_outs, false, "max_out must be non-zero"); + while (max_outs < out_amounts.size()) + { + out_amounts[out_amounts.size() - 2] += out_amounts.back(); + out_amounts.resize(out_amounts.size() - 1); + } + } + // 2. construct destinations using out_amounts + + for (auto a : out_amounts) + { + tx_destination_entry de = AUTO_VAL_INIT(de); + de.addr.push_back(miner_address); + de.amount = a; + de.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is + if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW) + { + //this means that block is creating after hardfork_1 and unlock_time is needed to set for every destination separately + de.unlock_time = height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW; + } + destinations.push_back(de); + } + } + + if (pos) + { + uint64_t stake_lock_time = 0; + if (pe.stake_unlock_time && pe.stake_unlock_time > height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW) + stake_lock_time = pe.stake_unlock_time; + uint64_t amount = destinations.empty() ? pe.amount + block_reward : pe.amount; // combine stake and reward into one output if no destinations were generated above + destinations.push_back(tx_destination_entry(amount, stakeholder_address, stake_lock_time)); + destinations.back().flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // don't use asset id blinding as it's obvious which asset it is + } + CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS || height == 0, false, "Too many outs (" << destinations.size() << ")! Miner tx can't be constructed."); + tx = AUTO_VAL_INIT_T(transaction); + tx.version = tx_version; - tx.vin.clear(); - tx.vout.clear(); - tx.extra.clear(); - - keypair txkey = keypair::generate(); - add_tx_pub_key_to_extra(tx, txkey.pub); + tx_generation_context tx_gen_context{}; + tx_gen_context.set_tx_key(tx_one_time_key_to_use ? *tx_one_time_key_to_use : keypair::generate()); + add_tx_pub_key_to_extra(tx, tx_gen_context.tx_key.pub); if (extra_nonce.size()) if (!add_tx_extra_userdata(tx, extra_nonce)) return false; @@ -181,43 +459,236 @@ namespace currency //we always add extra_padding with 2 bytes length to make possible for get_block_template to adjust cumulative size tx.extra.push_back(extra_padding()); + size_t zc_ins_count = 0; + // input #0: txin_gen txin_gen in; in.height = height; tx.vin.push_back(in); + // input #1: stake (for PoS blocks only) if (pos) { - txin_to_key posin; - posin.amount = pe.amount; - posin.key_offsets.push_back(pe.index); - posin.k_image = pe.keyimage; - tx.vin.push_back(posin); - //reserve place for ring signature - tx.signatures.resize(1); - tx.signatures[0].resize(posin.key_offsets.size()); + if (tx.version > TRANSACTION_VERSION_PRE_HF4 /* && stake is zarcanum */) + { + // just placeholders, they will be filled in wallet2::prepare_and_sign_pos_block() + tx.vin.emplace_back(std::move(txin_zc_input())); + tx.signatures.emplace_back(std::move(zarcanum_sig())); + ++zc_ins_count; + } + else + { + // old fashioned non-hidden amount direct spend PoS scheme + // just placeholders, they will be filled in wallet2::prepare_and_sign_pos_block() + tx.vin.emplace_back(std::move(txin_to_key())); + tx.signatures.emplace_back(std::move(NLSAG_sig())); + } } - uint64_t no = 0; + // fill outputs + tx_gen_context.resize(zc_ins_count, destinations.size()); // auxiliary data for each output + uint64_t output_index = 0; std::set deriv_cache; for (auto& d : destinations) { - bool r = construct_tx_out(d, txkey.sec, no, tx, deriv_cache, account_keys()); - CHECK_AND_ASSERT_MES(r, false, "Failed to contruct miner tx out"); - no++; + finalized_tx result = AUTO_VAL_INIT(result); + uint8_t tx_outs_attr = 0; + r = construct_tx_out(d, tx_gen_context.tx_key.sec, output_index, tx, deriv_cache, account_keys(), + tx_gen_context.asset_id_blinding_masks[output_index], tx_gen_context.amount_blinding_masks[output_index], + tx_gen_context.blinded_asset_ids[output_index], tx_gen_context.amount_commitments[output_index], result, tx_outs_attr); + CHECK_AND_ASSERT_MES(r, false, "construct_tx_out failed, output #" << output_index << ", amount: " << print_money_brief(d.amount)); + tx_gen_context.amounts[output_index] = d.amount; + tx_gen_context.asset_ids[output_index] = crypto::point_t(d.asset_id); + tx_gen_context.asset_id_blinding_mask_x_amount_sum += tx_gen_context.asset_id_blinding_masks[output_index] * d.amount; + tx_gen_context.amount_blinding_masks_sum += tx_gen_context.amount_blinding_masks[output_index]; + tx_gen_context.amount_commitments_sum += tx_gen_context.amount_commitments[output_index]; + ++output_index; } + if (tx.attachment.size()) + add_attachments_info_to_extra(tx.extra, tx.attachment); - tx.version = CURRENT_TRANSACTION_VERSION; if (!have_type_in_variant_container(tx.extra)) { //if stake unlock time was not set, then we can use simple "whole transaction" lock scheme set_tx_unlock_time(tx, height + CURRENCY_MINED_MONEY_UNLOCK_WINDOW); } - + + if (ogc_ptr) + *ogc_ptr = tx_gen_context; // TODO @#@# consider refactoring (a lot of copying) -- sowle + + + if (tx.version > TRANSACTION_VERSION_PRE_HF4 && !pos) + { + // This is for PoW blocks only, because PoS blocks proofs are handled in wallet2::prepare_and_sign_pos_block() due to the necessity of making Zarcanum proofs first + // + // tx hash should be sealed by now + crypto::hash tx_id = get_transaction_hash(tx); + + // asset surjection proof + currency::zc_asset_surjection_proof asp{}; + bool r = generate_asset_surjection_proof(tx_id, true, tx_gen_context, asp); + CHECK_AND_ASSERT_MES(r, false, "generete_asset_surjection_proof failed"); + tx.proofs.emplace_back(std::move(asp)); + + // range proofs + currency::zc_outs_range_proof range_proofs{}; + r = generate_zc_outs_range_proof(tx_id, 0, tx_gen_context, tx.vout, range_proofs); + CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); + tx.proofs.emplace_back(std::move(range_proofs)); + + // balance proof + currency::zc_balance_proof balance_proof{}; + r = generate_tx_balance_proof(tx, tx_id, tx_gen_context, block_reward, balance_proof); + CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed"); + tx.proofs.emplace_back(std::move(balance_proof)); + } + + + return true; } - //--------------------------------------------------------------- + //------------------------------------------------------------------ + bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx /* = 0 */) + { + // legacy checks for old fashioned tx with non-hidden amounts + CHECK_AND_ASSERT_MES(tx.version <= TRANSACTION_VERSION_PRE_HF4, false, "check_tx_bare_balance can't check post-HF4 txs"); + uint64_t bare_outputs_sum = get_outs_money_amount(tx); + uint64_t bare_inputs_sum = get_inputs_money_amount(tx); + + if (additional_inputs_amount_and_fees_for_mining_tx == 0) + { + // normal tx + CHECK_AND_ASSERT_MES(bare_inputs_sum >= bare_outputs_sum, false, "tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum) + << ") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")"); + } + else + { + // miner tx + CHECK_AND_ASSERT_MES(bare_inputs_sum + additional_inputs_amount_and_fees_for_mining_tx == bare_outputs_sum, false, + "tx balance error: the sum of inputs (" << print_money_brief(bare_inputs_sum) << + ") + additional inputs and fees (" << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx) << + ") is less than or equal to the sum of outputs (" << print_money_brief(bare_outputs_sum) << ")"); + } + return true; + } + //----------------------------------------------------------------------------------------------- + bool validate_asset_operation_amount_commitment(asset_op_verification_context& context) + { + CHECK_AND_ASSERT_MES(count_type_in_variant_container(context.tx.proofs) == 1, false, "asset_operation_proof not present or present more than once"); + const asset_operation_proof& aop = get_type_in_variant_container_by_ref(context.tx.proofs); + + if (context.ado.descriptor.hidden_supply) + { + CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_composition_proof.has_value(), false, "opt_amount_commitment_composition_proof is absent"); + // TODO @#@# if asset is hidden -- check composition proof + return false; + } + else + { + // make sure that amount commitment corresponds to opt_amount_commitment_g_proof + CHECK_AND_ASSERT_MES(aop.opt_amount_commitment_g_proof.has_value(), false, "opt_amount_commitment_g_proof is absent"); + crypto::point_t A = crypto::point_t(context.ado.amount_commitment).modify_mul8() - context.amount_to_validate * context.asset_id_pt; + + bool r = crypto::check_signature(context.tx_id, A.to_public_key(), aop.opt_amount_commitment_g_proof.get()); + CHECK_AND_ASSERT_MES(r, false, "opt_amount_commitment_g_proof check failed"); + } + + return true; + } + //------------------------------------------------------------------ + bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx /* = 0 */) + { + if (tx.version > TRANSACTION_VERSION_PRE_HF4) + { + zc_balance_proof balance_proof = AUTO_VAL_INIT(balance_proof); + bool r = get_type_in_variant_container(tx.proofs, balance_proof); + CHECK_AND_ASSERT_MES(r, false, "zc_balance_proof is missing in tx proofs"); + + crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); + + size_t zc_inputs_count = 0; + uint64_t bare_inputs_sum = additional_inputs_amount_and_fees_for_mining_tx; + for(auto& vin : tx.vin) + { + VARIANT_SWITCH_BEGIN(vin); + VARIANT_CASE_CONST(txin_to_key, tk) + bare_inputs_sum += tk.amount; + VARIANT_CASE_CONST(txin_htlc, htlc); + bare_inputs_sum += htlc.amount; + VARIANT_CASE_CONST(txin_multisig, ms); + bare_inputs_sum += ms.amount; + VARIANT_CASE_CONST(txin_zc_input, foo); + ++zc_inputs_count; + VARIANT_SWITCH_END(); + } + + crypto::point_t outs_commitments_sum = crypto::c_point_0; // TODO: consider adding additional commitments / spends / burns here + for(auto& vout : tx.vout) + { + CHECK_AND_ASSERT_MES(vout.type() == typeid(tx_out_zarcanum), false, "unexpected type in outs: " << vout.type().name()); + const tx_out_zarcanum& ozc = boost::get(vout); + outs_commitments_sum += crypto::point_t(ozc.amount_commitment); // amount_commitment premultiplied by 1/8 + } + + uint64_t fee = 0; + CHECK_AND_ASSERT_MES(get_tx_fee(tx, fee) || additional_inputs_amount_and_fees_for_mining_tx > 0, false, "unable to get fee for a non-mining tx"); + + CHECK_AND_ASSERT_MES(additional_inputs_amount_and_fees_for_mining_tx == 0 || fee == 0, false, "invalid tx: fee = " << print_money_brief(fee) << + ", additional inputs + fees = " << print_money_brief(additional_inputs_amount_and_fees_for_mining_tx)); + + crypto::point_t sum_of_pseudo_out_amount_commitments = crypto::c_point_0; + // take into account generated/burnt assets + asset_descriptor_operation ado = AUTO_VAL_INIT(ado); + if (get_type_in_variant_container(tx.extra, ado)) + { + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + // amount_commitment supposed to be validated earlier in validate_asset_operation_amount_commitment() + sum_of_pseudo_out_amount_commitments += crypto::point_t(ado.amount_commitment); // *1/8 + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + outs_commitments_sum += crypto::point_t(ado.amount_commitment); // *1/8 + } + } + size_t zc_sigs_count = 0; + for(auto& sig_v : tx.signatures) + { + VARIANT_SWITCH_BEGIN(sig_v); + VARIANT_CASE_CONST(ZC_sig, zc_sig); + sum_of_pseudo_out_amount_commitments += crypto::point_t(zc_sig.pseudo_out_amount_commitment); // *1/8 + ++zc_sigs_count; + VARIANT_CASE_CONST(zarcanum_sig, sig); + sum_of_pseudo_out_amount_commitments += crypto::point_t(sig.pseudo_out_amount_commitment); // *1/8 + ++zc_sigs_count; + VARIANT_SWITCH_END(); + } + + outs_commitments_sum.modify_mul8(); + sum_of_pseudo_out_amount_commitments.modify_mul8(); + + // (sum(bare inputs' amounts) - fee) * H + sum(pseudo outs commitments for ZC inputs) - sum(outputs' commitments) = lin(X) OR = lin(G) + crypto::point_t commitment_to_zero = (crypto::scalar_t(bare_inputs_sum) - crypto::scalar_t(fee)) * currency::native_coin_asset_id_pt + sum_of_pseudo_out_amount_commitments - outs_commitments_sum; + + CHECK_AND_ASSERT_MES(zc_inputs_count == zc_sigs_count, false, "zc inputs count (" << zc_inputs_count << ") and zc sigs count (" << zc_sigs_count << ") missmatch"); + if (zc_inputs_count > 0) + { + r = crypto::verify_double_schnorr_sig(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss); + CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (X, G) is invalid"); + } + else + { + r = crypto::verify_double_schnorr_sig(tx_id, commitment_to_zero, tx_pub_key, balance_proof.dss); + CHECK_AND_ASSERT_MES(r, false, "verify_double_schnorr_sig (G, G) is invalid"); + } + return true; + } + + // pre-HF4 txs + return check_tx_bare_balance(tx, additional_inputs_amount_and_fees_for_mining_tx); + } + //------------------------------------------------------------------ bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral) { crypto::key_derivation recv_derivation = AUTO_VAL_INIT(recv_derivation); @@ -265,14 +736,24 @@ namespace currency return total; } //--------------------------------------------------------------- - bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_outputs_count) + bool is_mixattr_applicable_for_fake_outs_counter(uint64_t out_tx_version, uint8_t mix_attr, uint64_t fake_outputs_count, const core_runtime_config& rtc) { - if (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) - return fake_outputs_count + 1 >= mix_attr; - else if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) - return fake_outputs_count == 0; + if (out_tx_version >= TRANSACTION_VERSION_POST_HF4) + { + if (mix_attr != CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + return fake_outputs_count >= rtc.hf4_minimum_mixins; + else + return fake_outputs_count == 0; // CURRENCY_TO_KEY_OUT_FORCED_NO_MIX + } else - return true; + { + if (mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) + return fake_outputs_count + 1 >= mix_attr; + else if (mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + return fake_outputs_count == 0; + else + return true; + } } //--------------------------------------------------------------- bool parse_amount(uint64_t& amount, const std::string& str_amount_) @@ -353,31 +834,51 @@ namespace currency std::string print_stake_kernel_info(const stake_kernel& sk) { std::stringstream ss; - ss << "block_timestamp: " << sk.block_timestamp << ENDL - << "kimage: " << sk.kimage << ENDL - << "stake_modifier.last_pos_kernel_id: " << sk.stake_modifier.last_pos_kernel_id << ENDL - << "stake_modifier.last_pow_id: " << sk.stake_modifier.last_pow_id << ENDL; + ss << "block timestamp: " << sk.block_timestamp << ENDL + << "key image: " << sk.kimage << ENDL + << "sm.last_pos_kernel_id: " << sk.stake_modifier.last_pos_kernel_id << ENDL + << "sm.last_pow_id: " << sk.stake_modifier.last_pow_id << ENDL; return ss.str(); } //--------------------------------------------------------------- - bool get_tx_fee(const transaction& tx, uint64_t & fee) + bool get_tx_fee(const transaction& tx, uint64_t& fee) { fee = 0; if (is_coinbase(tx)) return true; - uint64_t amount_in = 0; - uint64_t amount_out = get_outs_money_amount(tx); - - BOOST_FOREACH(auto& in, tx.vin) + + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) { - amount_in += get_amount_from_variant(in); + // all amounts are open: fee = sum(outputs) - sum(inputs) + + uint64_t amount_in = 0; + uint64_t amount_out = get_outs_money_amount(tx); + + for(auto& in : tx.vin) + amount_in += get_amount_from_variant(in); + + CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spends (" << print_money_brief(amount_in) << ") more than it has (" << print_money_brief(amount_out) << ")"); + fee = amount_in - amount_out; + return true; } + // tx.version > TRANSACTION_VERSION_PRE_HF4 + // all amounts are hidden with Pedersen commitments + // therefore fee should be explicitly stated in the extra + auto cb = [&](const zarcanum_tx_data_v1& ztd) -> bool { + fee += ztd.fee; + return true; // continue + }; + + bool r = process_type_in_variant_container(tx.extra, cb, false); + + if (!r) + { + fee = 0; + return false; + } - - CHECK_AND_ASSERT_MES(amount_in >= amount_out, false, "transaction spend (" << amount_in << ") more than it has (" << amount_out << ")"); - fee = amount_in - amount_out; return true; } //--------------------------------------------------------------- @@ -424,19 +925,18 @@ namespace currency //--------------------------------------------------------------- struct tx_extra_handler : public boost::static_visitor { - mutable bool was_padding; //let the padding goes only at the end - mutable bool was_pubkey; - mutable bool was_attachment; - mutable bool was_userdata; - mutable bool was_alias; + mutable bool was_padding = false; //let the padding goes only at the end + mutable bool was_pubkey = false; + mutable bool was_attachment = false; + mutable bool was_userdata = false; + mutable bool was_alias = false; + mutable bool was_asset = false; tx_extra_info& rei; const transaction& rtx; tx_extra_handler(tx_extra_info& ei, const transaction& tx) :rei(ei), rtx(tx) - { - was_padding = was_pubkey = was_attachment = was_userdata = was_alias = false; - } + {} #define ENSURE_ONETIME(varname, entry_name) CHECK_AND_ASSERT_MES(varname == false, false, "double entry in tx_extra: " entry_name); varname = true; @@ -459,6 +959,12 @@ namespace currency rei.m_alias = ae; return true; } + bool operator()(const asset_descriptor_operation & ado) const + { + ENSURE_ONETIME(was_asset, "asset"); + rei.m_asset_operation = ado; + return true; + } bool operator()(const extra_alias_entry_old& ae) const { return operator()(static_cast(ae)); @@ -478,7 +984,7 @@ namespace currency template bool operator()(const t_extra_typename& k) const { - //do notheing for rest + //do nothing for rest return true; } }; @@ -503,13 +1009,29 @@ namespace currency return true; } //--------------------------------------------------------------- + // puts explicit fee amount to tx extra, should be used only for tx.verson > TRANSACTION_VERSION_PRE_HF4 + bool add_tx_fee_amount_to_extra(transaction& tx, uint64_t fee, bool make_sure_its_unique /* = true */) + { + if (make_sure_its_unique) + { + if (count_type_in_variant_container(tx.extra) != 0) + return false; + } + + zarcanum_tx_data_v1 ztd = AUTO_VAL_INIT(ztd); + ztd.fee = fee; + + tx.extra.push_back(ztd); + return true; + } + //--------------------------------------------------------------- //--------------------------------------------------------------- struct multisig_id_generator { //std::vector vin; crypto::public_key onetime_key; - std::vector vout; + std::vector vout; BEGIN_SERIALIZE() //FIELD(vin) @@ -523,14 +1045,15 @@ namespace currency //msg.vin = tx.vin; msg.onetime_key = get_tx_pub_key_from_extra(tx); CHECK_AND_ASSERT_MES(tx.vout.size() > n, null_hash, "tx.vout.size() > n condition failed "); - CHECK_AND_ASSERT_MES(tx.vout[n].target.type() == typeid(txout_multisig), null_hash, "tx.vout[n].target.type() == typeid(txout_multisig) condition failed"); - msg.vout.push_back(tx.vout[n]); + CHECK_AND_ASSERT_MES(tx.vout[n].type() == typeid(tx_out_bare), null_hash, "Unexpected type of out:" << tx.vout[n].type().name()); + CHECK_AND_ASSERT_MES(boost::get(tx.vout[n]).target.type() == typeid(txout_multisig), null_hash, "tx.vout[n].target.type() == typeid(txout_multisig) condition failed"); + msg.vout.push_back(boost::get(tx.vout[n])); return get_object_hash(msg); } //--------------------------------------------------------------- bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce) { - CHECK_AND_ASSERT_MES(extra_nonce.size() <= 255, false, "extra nonce could be 255 bytes max"); + CHECK_AND_ASSERT_MES(extra_nonce.size() <= 255, false, "extra nonce size exceeded (255 bytes max)"); extra_user_data eud = AUTO_VAL_INIT(eud); eud.buff = extra_nonce; tx.extra.push_back(eud); @@ -543,6 +1066,21 @@ namespace currency return derive_public_key_from_target_address(destination_addr, tx_sec_key, index, out_eph_public_key, derivation); } //--------------------------------------------------------------- + // derived_sec_key = Hs(domain, 8 * src_sec_key * src_pub_key, index) + // derived_pub_key = derived_sec_key * G + bool derive_key_pair_from_key_pair(const crypto::public_key& src_pub_key, const crypto::secret_key& src_sec_key, crypto::secret_key& derived_sec_key, crypto::public_key& derived_pub_key, const char(&hs_domain)[32], uint64_t index) + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + bool r = crypto::generate_key_derivation(src_pub_key, src_sec_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "at creation outs: failed to generate_key_derivation(" << src_pub_key << ", " << src_sec_key << ")"); + crypto::scalar_t sec_key = crypto::hash_helper_t::hs(hs_domain, derivation, index); + derived_sec_key = sec_key.as_secret_key(); + derived_pub_key = (sec_key * crypto::c_point_G).to_public_key(); + return true; + } + //--------------------------------------------------------------- + // derivation = 8 * tx_sec_key * destination_addr.view_public_key + // out_eph_public_key = destination_addr.spend_public_key + Hs(derivation, index) * G bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation) { bool r = crypto::generate_key_derivation(destination_addr.view_public_key, tx_sec_key, derivation); @@ -599,114 +1137,233 @@ namespace currency return origin_blob; } //--------------------------------------------------------------- - bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, uint8_t tx_outs_attr) + bool validate_ado_update_allowed(const asset_descriptor_base& new_ado, const asset_descriptor_base& prev_ado) { - finalized_tx result = AUTO_VAL_INIT(result); - return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, result, tx_outs_attr); + if (new_ado.total_max_supply != prev_ado.total_max_supply) return false; + if (new_ado.current_supply > prev_ado.total_max_supply) return false; + if (new_ado.decimal_point != prev_ado.decimal_point) return false; + if (new_ado.ticker != prev_ado.ticker) return false; + if (new_ado.full_name != prev_ado.full_name) return false; + //a.meta_info; + //if (a.owner != b.owner) return false; + if (new_ado.hidden_supply != prev_ado.hidden_supply) return false; + + return true; } //--------------------------------------------------------------- - bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, finalized_tx& result, uint8_t tx_outs_attr) + /* + crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado) { - CHECK_AND_ASSERT_MES(de.addr.size() == 1 || (de.addr.size() > 1 && de.minimum_sigs <= de.addr.size()), false, "Invalid destination entry: amount: " << de.amount << " minimum_sigs: " << de.minimum_sigs << " addr.size(): " << de.addr.size()); + asset_descriptor_operation ado_local = ado; + normalize_asset_operation_for_hashing(ado_local); + std::string buff = t_serializable_object_to_blob(ado_local); + return crypto::cn_fast_hash(buff.data(), buff.size()); + } - std::vector target_keys; - target_keys.reserve(de.addr.size()); - for (auto& apa : de.addr) + //--------------------------------------------------------------- + void normalize_asset_operation_for_hashing(asset_descriptor_operation& op) + { + op.opt_proof = boost::none; + } + */ + + //--------------------------------------------------------------- + bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, uint8_t tx_outs_attr /* = CURRENCY_TO_KEY_OUT_RELAXED */) + { + finalized_tx result = AUTO_VAL_INIT(result); + crypto::scalar_t asset_blinding_mask{}, amount_blinding_mask{}; + crypto::point_t blinded_asset_id{}, amount_commitment{}; + return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, asset_blinding_mask, amount_blinding_mask, blinded_asset_id, amount_commitment, result, tx_outs_attr); + } + //--------------------------------------------------------------- + bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, + const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment, + finalized_tx& result, uint8_t tx_outs_attr) + { + if (tx.version > TRANSACTION_VERSION_PRE_HF4) { - crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); + // create tx_out_zarcanum + CHECK_AND_ASSERT_MES(de.addr.size() == 1, false, "zarcanum multisig not implemented for tx_out_zarcanum yet"); + // TODO @#@# implement multisig support + + tx_out_zarcanum out = AUTO_VAL_INIT(out); + + const account_public_address& apa = de.addr.front(); if (apa.spend_public_key == null_pkey && apa.view_public_key == null_pkey) { - //burning money(for example alias reward) - out_eph_public_key = null_pkey; + // burn money + // calculate encrypted_amount and amount_commitment anyway, but using modified derivation + crypto::scalar_t h = crypto::hash_helper_t::hs(crypto::scalar_t(tx_sec_key), output_index); // h = Hs(r, i) + + out.stealth_address = null_pkey; + out.concealing_point = null_pkey; + + crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h); + out.encrypted_amount = de.amount ^ amount_mask.m_u64[0]; + + CHECK_AND_ASSERT_MES(~de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id"); + asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // s = Hs(domain_sep, Hs(8 * r * V, i)) + blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X; + out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X) + + amount_blinding_mask = de.flags & tx_destination_entry_flags::tdef_zero_amount_blinding_mask ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // y = Hs(domain_sep, Hs(8 * r * V, i)) + amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G; + out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G + + out.mix_attr = tx_outs_attr; // TODO @#@# @CZ check this } else { - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - bool r = derive_public_key_from_target_address(apa, tx_sec_key, output_index, out_eph_public_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); + // normal output + crypto::public_key derivation = (crypto::scalar_t(tx_sec_key) * crypto::point_t(apa.view_public_key)).modify_mul8().to_public_key(); // d = 8 * r * V + crypto::scalar_t h = 0; + crypto::derivation_to_scalar((const crypto::key_derivation&)derivation, output_index, h.as_secret_key()); // h = Hs(8 * r * V, i) - uint16_t hint = get_derivation_hint(derivation); + out.stealth_address = (h * crypto::c_point_G + crypto::point_t(apa.spend_public_key)).to_public_key(); + out.concealing_point = (crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(apa.view_public_key)).to_public_key(); // Q = 1/8 * Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V + + crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h); + out.encrypted_amount = de.amount ^ amount_mask.m_u64[0]; + + CHECK_AND_ASSERT_MES(~de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id || de.asset_id == currency::native_coin_asset_id, false, "explicit_native_asset_id may be used only with native asset id"); + asset_blinding_mask = de.flags & tx_destination_entry_flags::tdef_explicit_native_asset_id ? 0 : crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // s = Hs(domain_sep, Hs(8 * r * V, i)) + blinded_asset_id = crypto::point_t(de.asset_id) + asset_blinding_mask * crypto::c_point_X; + out.blinded_asset_id = (crypto::c_scalar_1div8 * blinded_asset_id).to_public_key(); // T = 1/8 * (H_asset + s * X) + + amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // y = Hs(domain_sep, Hs(8 * r * V, i)) + amount_commitment = de.amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G; + out.amount_commitment = (crypto::c_scalar_1div8 * amount_commitment).to_public_key(); // E = 1/8 * e * T + 1/8 * y * G + + DBG_VAL_PRINT(output_index); + DBG_VAL_PRINT(de.amount); + DBG_VAL_PRINT(de.asset_id); + DBG_VAL_PRINT(amount_mask); + DBG_VAL_PRINT(asset_blinding_mask); + DBG_VAL_PRINT(blinded_asset_id); + DBG_VAL_PRINT(amount_blinding_mask); + DBG_VAL_PRINT(amount_mask); + DBG_VAL_PRINT(amount_commitment); + + if (de.addr.front().is_auditable()) + out.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses + else + out.mix_attr = tx_outs_attr; + + uint16_t hint = get_derivation_hint(reinterpret_cast(derivation)); if (deriv_cache.count(hint) == 0) { tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint)); deriv_cache.insert(hint); } } - target_keys.push_back(out_eph_public_key); - } - tx_out out; - out.amount = de.amount; - if (de.htlc_options.expiration != 0) - { - const destination_option_htlc_out& htlc_dest = de.htlc_options; - //out htlc - CHECK_AND_ASSERT_MES(target_keys.size() == 1, false, "Unexpected htl keys count = " << target_keys.size() << ", expected ==1"); - txout_htlc htlc = AUTO_VAL_INIT(htlc); - htlc.expiration = htlc_dest.expiration; - htlc.flags = 0; //0 - SHA256, 1 - RIPEMD160, by default leave SHA256 - //receiver key - htlc.pkey_redeem = *target_keys.begin(); - //generate refund key - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); - crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); - bool r = derive_public_key_from_target_address(self.account_address, tx_sec_key, output_index, out_eph_public_key, derivation); - CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); - htlc.pkey_refund = out_eph_public_key; - //add derivation hint for refund address - uint16_t hint = get_derivation_hint(derivation); - if (deriv_cache.count(hint) == 0) - { - tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint)); - deriv_cache.insert(hint); - } - - - if (htlc_dest.htlc_hash == null_hash) - { - //we use deterministic origin, to make possible access origin on different wallets copies - - result.htlc_origin = generate_origin_for_htlc(htlc, self); - - //calculate hash - if (!htlc.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK) - { - htlc.htlc_hash = crypto::sha256_hash(result.htlc_origin.data(), result.htlc_origin.size()); - } - else - { - crypto::hash160 h160 = crypto::RIPEMD160_hash(result.htlc_origin.data(), result.htlc_origin.size()); - std::memcpy(&htlc.htlc_hash, &h160, sizeof(h160)); - } - } - else - { - htlc.htlc_hash = htlc_dest.htlc_hash; - } - out.target = htlc; - } - else if (target_keys.size() == 1) - { - //out to key - txout_to_key tk = AUTO_VAL_INIT(tk); - tk.key = target_keys.back(); - - if (de.addr.front().is_auditable()) // check only the first address because there's only one in this branch - tk.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses - else - tk.mix_attr = tx_outs_attr; - - out.target = tk; + tx.vout.push_back(out); } else { - //multisig out - txout_multisig ms = AUTO_VAL_INIT(ms); - ms.keys = std::move(target_keys); - ms.minimum_sigs = de.minimum_sigs; - out.target = ms; + // create tx_out_bare, this section can be removed after HF4 + CHECK_AND_ASSERT_MES(de.addr.size() == 1 || (de.addr.size() > 1 && de.minimum_sigs <= de.addr.size()), false, "Invalid destination entry: amount: " << de.amount << " minimum_sigs: " << de.minimum_sigs << " addr.size(): " << de.addr.size()); + CHECK_AND_ASSERT_MES(de.asset_id == currency::native_coin_asset_id, false, "assets are not allowed prior to HF4"); + + std::vector target_keys; + target_keys.reserve(de.addr.size()); + for (auto& apa : de.addr) + { + crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); + if (apa.spend_public_key == null_pkey && apa.view_public_key == null_pkey) + { + //burning money(for example alias reward) + out_eph_public_key = null_pkey; + } + else + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + bool r = derive_public_key_from_target_address(apa, tx_sec_key, output_index, out_eph_public_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); + + uint16_t hint = get_derivation_hint(derivation); + if (deriv_cache.count(hint) == 0) + { + tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint)); + deriv_cache.insert(hint); + } + } + target_keys.push_back(out_eph_public_key); + } + + tx_out_bare out; + out.amount = de.amount; + if (de.htlc_options.expiration != 0) + { + const destination_option_htlc_out& htlc_dest = de.htlc_options; + //out htlc + CHECK_AND_ASSERT_MES(target_keys.size() == 1, false, "Unexpected htl keys count = " << target_keys.size() << ", expected ==1"); + txout_htlc htlc = AUTO_VAL_INIT(htlc); + htlc.expiration = htlc_dest.expiration; + htlc.flags = 0; //0 - SHA256, 1 - RIPEMD160, by default leave SHA256 + //receiver key + htlc.pkey_redeem = *target_keys.begin(); + //generate refund key + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + crypto::public_key out_eph_public_key = AUTO_VAL_INIT(out_eph_public_key); + bool r = derive_public_key_from_target_address(self.account_address, tx_sec_key, output_index, out_eph_public_key, derivation); + CHECK_AND_ASSERT_MES(r, false, "failed to derive_public_key_from_target_address"); + htlc.pkey_refund = out_eph_public_key; + //add derivation hint for refund address + uint16_t hint = get_derivation_hint(derivation); + if (deriv_cache.count(hint) == 0) + { + tx.extra.push_back(make_tx_derivation_hint_from_uint16(hint)); + deriv_cache.insert(hint); + } + + + if (htlc_dest.htlc_hash == null_hash) + { + //we use deterministic origin, to make possible access origin on different wallets copies + + result.htlc_origin = generate_origin_for_htlc(htlc, self); + + //calculate hash + if (!htlc.flags&CURRENCY_TXOUT_HTLC_FLAGS_HASH_TYPE_MASK) + { + htlc.htlc_hash = crypto::sha256_hash(result.htlc_origin.data(), result.htlc_origin.size()); + } + else + { + crypto::hash160 h160 = crypto::RIPEMD160_hash(result.htlc_origin.data(), result.htlc_origin.size()); + std::memcpy(&htlc.htlc_hash, &h160, sizeof(h160)); + } + } + else + { + htlc.htlc_hash = htlc_dest.htlc_hash; + } + out.target = htlc; + } + else if (target_keys.size() == 1) + { + //out to key + txout_to_key tk = AUTO_VAL_INIT(tk); + tk.key = target_keys.back(); + + if (de.addr.front().is_auditable()) // check only the first address because there's only one in this branch + tk.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses + else + tk.mix_attr = tx_outs_attr; + + out.target = tk; + } + else + { + //multisig out + txout_multisig ms = AUTO_VAL_INIT(ms); + ms.keys = std::move(target_keys); + ms.minimum_sigs = de.minimum_sigs; + out.target = ms; + } + tx.vout.push_back(out); } - tx.vout.push_back(out); return true; } //--------------------------------------------------------------- @@ -741,26 +1398,67 @@ namespace currency eai.cnt = attachment.size(); } //--------------------------------------------------------------- - bool construct_tx(const account_keys& sender_account_keys, const std::vector& sources, + bool construct_tx(const account_keys& sender_account_keys, + const std::vector& sources, const std::vector& destinations, - const std::vector& attachments, + const std::vector& attachments, transaction& tx, + uint64_t tx_version, uint64_t unlock_time, - uint8_t tx_outs_attr, bool shuffle) + uint8_t tx_outs_attr, + bool shuffle) { crypto::secret_key one_time_secret_key = AUTO_VAL_INIT(one_time_secret_key); - return construct_tx(sender_account_keys, sources, destinations, std::vector(), attachments, tx, one_time_secret_key, unlock_time, tx_outs_attr, shuffle); + return construct_tx(sender_account_keys, sources, destinations, std::vector(), attachments, tx, tx_version, one_time_secret_key, unlock_time, tx_outs_attr, shuffle); } //--------------------------------------------------------------- + + void deterministic_generate_tx_onetime_key(std::list& images, const account_keys& acc, keypair& res_keypair, uint64_t height = 0) + { + images.sort([](const crypto::key_image& a, const crypto::key_image& b) {return memcmp(&a, &b, sizeof(a)); }); + std::string hashing_buff; + for (const auto& im : images) + epee::string_tools::append_pod_to_strbuff(hashing_buff, im); + epee::string_tools::append_pod_to_strbuff(hashing_buff, acc.spend_secret_key); + hashing_buff.append(CRYPTO_HDS_DETERMINISTIC_TX_KEY); + crypto::scalar_t sec_key = crypto::hash_helper_t::hs(hashing_buff.data(), hashing_buff.length()); + sec_key *= 8; + res_keypair.sec = sec_key.as_secret_key(); + crypto::secret_key_to_public_key(res_keypair.sec, res_keypair.pub); + } + //--------------------------------------------------------------- + void deterministic_generate_tx_onetime_key(const transaction& tx, const account_keys& acc, keypair& res_keypair) + { + uint64_t h = 0; + std::list images; + for (const auto& in : tx.vin) + { + crypto::key_image ki = AUTO_VAL_INIT(ki); + if (get_key_image_from_txin_v(in, ki)) + { + images.push_back(ki); + } + if (in.type() == typeid(txin_gen)) + { + h = boost::get(in).height; + continue; + } + } + deterministic_generate_tx_onetime_key(images, acc, res_keypair, h); + } + + //--------------------------------------------------------------- + struct encrypt_attach_visitor : public boost::static_visitor { bool& m_was_crypted_entries; const keypair& m_onetime_keypair; const account_public_address& m_destination_addr; const crypto::key_derivation& m_key; + const account_keys& m_sender_account_keys; - encrypt_attach_visitor(bool& was_crypted_entries, const crypto::key_derivation& key, const keypair& onetime_keypair = null_keypair, const account_public_address& destination_addr = null_pub_addr) : - m_was_crypted_entries(was_crypted_entries), m_key(key), m_onetime_keypair(onetime_keypair), m_destination_addr(destination_addr) + encrypt_attach_visitor(bool& was_crypted_entries, const crypto::key_derivation& key, const keypair& onetime_keypair, const account_public_address& destination_addr, const account_keys& sender_account_keys) : + m_was_crypted_entries(was_crypted_entries), m_key(key), m_onetime_keypair(onetime_keypair), m_destination_addr(destination_addr), m_sender_account_keys(sender_account_keys) {} void operator()(tx_comment& comment) { @@ -805,6 +1503,9 @@ namespace currency bool r = crypto::generate_key_derivation(m_destination_addr.spend_public_key, m_onetime_keypair.sec, derivation_local); CHECK_AND_ASSERT_THROW_MES(r, "tx_service_attachment with TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE: Failed to make derivation"); crypto::chacha_crypt(sa.body, derivation_local); + //we add derivation encrypted with sender spend key, so sender can derive information later if the wallet got restored from seed + sa.security.push_back(*(crypto::public_key*)&derivation_local); + crypto::chacha_crypt(sa.security.back(), m_sender_account_keys.spend_secret_key); } else { @@ -830,15 +1531,21 @@ namespace currency struct decrypt_attach_visitor : public boost::static_visitor { + const bool m_is_income; + const transaction& m_tx; const account_keys& m_acc_keys; const crypto::public_key& m_tx_onetime_pubkey; const crypto::key_derivation& rkey; std::vector& rdecrypted_att; decrypt_attach_visitor(const crypto::key_derivation& key, std::vector& decrypted_att, - const account_keys& acc_keys = null_acc_keys, + const account_keys& acc_keys, + bool is_income, + const transaction& tx, const crypto::public_key& tx_onetime_pubkey = null_pkey) : rkey(key), + m_tx(tx), + m_is_income(is_income), rdecrypted_att(decrypted_att), m_acc_keys(acc_keys), m_tx_onetime_pubkey(tx_onetime_pubkey) @@ -858,16 +1565,23 @@ namespace currency { if (sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE) { - if (m_acc_keys.spend_secret_key == null_skey) + if (!m_is_income) { - //this watch only wallet, decrypting supposed to be impossible - return; + //check if we have key for decrypting body for sender + if (sa.security.size() < 1) + { + return; // this field invisible for sender + } + //decrypting derivation + derivation_local = *(crypto::key_derivation*)&sa.security[0]; + crypto::chacha_crypt(derivation_local, m_acc_keys.spend_secret_key); + } + else { + CHECK_AND_ASSERT_THROW_MES(m_acc_keys.spend_secret_key != currency::null_skey && m_tx_onetime_pubkey != currency::null_pkey, "tx_service_attachment with TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE: keys uninitialized"); + bool r = crypto::generate_key_derivation(m_tx_onetime_pubkey, m_acc_keys.spend_secret_key, derivation_local); + CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate_key_derivation at TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE"); } - CHECK_AND_ASSERT_THROW_MES(m_acc_keys.spend_secret_key != currency::null_skey && m_tx_onetime_pubkey != currency::null_pkey, "tx_service_attachment with TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE: keys uninitialized"); - bool r = crypto::generate_key_derivation(m_tx_onetime_pubkey, m_acc_keys.spend_secret_key, derivation_local); - CHECK_AND_ASSERT_THROW_MES(r, "Failed to generate_key_derivation at TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE"); crypto::chacha_crypt(local_sa.body, derivation_local); - } else { @@ -882,13 +1596,13 @@ namespace currency if (sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY && sa.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF) { - CHECK_AND_ASSERT_MES(sa.security.size() == 1, void(), "Unexpected key in tx_service_attachment with TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE"); + CHECK_AND_ASSERT_MES(sa.security.size() >= 1, void(), "Unexpected key in tx_service_attachment with TX_SERVICE_ATTACHMENT_ENCRYPT_BODY_ISOLATE_AUDITABLE"); //take hash from derivation and use it as a salt crypto::hash derivation_hash = crypto::cn_fast_hash(&derivation_local, sizeof(derivation_local)); std::string salted_body = local_sa.body; string_tools::append_pod_to_strbuff(salted_body, derivation_hash); crypto::hash proof_hash = crypto::cn_fast_hash(salted_body.data(), salted_body.size()); // proof_hash = Hs(local_sa.body || Hs(s * R)), s - spend secret, R - tx pub - CHECK_AND_ASSERT_MES(*(crypto::public_key*)&proof_hash == sa.security.front(), void(), "Proof hash missmatch on decrypting with TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF"); + CHECK_AND_ASSERT_MES(*(crypto::public_key*)&proof_hash == sa.security.back(), void(), "Proof hash missmatch on decrypting with TX_SERVICE_ATTACHMENT_ENCRYPT_ADD_PROOF"); } rdecrypted_att.push_back(local_sa); @@ -927,10 +1641,10 @@ namespace currency //--------------------------------------------------------------- template - bool decrypt_payload_items(const crypto::key_derivation& derivation, const items_container_t& items_to_decrypt, std::vector& decrypted_att, const account_keys& acc_keys = null_acc_keys, + bool decrypt_payload_items(const crypto::key_derivation& derivation, const items_container_t& items_to_decrypt, std::vector& decrypted_att, bool is_income, const transaction& tx, const account_keys& acc_keys = null_acc_keys, const crypto::public_key& tx_onetime_pubkey = null_pkey) { - decrypt_attach_visitor v(derivation, decrypted_att, acc_keys, tx_onetime_pubkey); + decrypt_attach_visitor v(derivation, decrypted_att, acc_keys, is_income, tx, tx_onetime_pubkey); for (auto& a : items_to_decrypt) boost::apply_visitor(v, a); @@ -956,13 +1670,6 @@ namespace currency crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys) { crypto::key_derivation derivation = null_derivation; - tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info); - if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info)) - { - //no crypt info in tx - return null_derivation; - } - if (is_income) { crypto::public_key tx_pub_key = currency::get_tx_pub_key_from_extra(tx); @@ -970,18 +1677,25 @@ namespace currency bool r = crypto::generate_key_derivation(tx_pub_key, acc_keys.view_secret_key, derivation); CHECK_AND_ASSERT_MES(r, null_derivation, "failed to generate_key_derivation"); LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key derived from destination addr: " << currency::get_account_address_as_str(acc_keys.account_address), LOG_LEVEL_0); + return derivation; } else { + tx_crypto_checksum crypto_info = AUTO_VAL_INIT(crypto_info); + if (!get_type_in_variant_container(tx.extra, crypto_info) && !get_type_in_variant_container(tx.attachment, crypto_info)) + { + //no crypt info in tx + return null_derivation; + } + derivation = crypto_info.encrypted_key_derivation; crypto::chacha_crypt(derivation, acc_keys.spend_secret_key); LOG_PRINT_GREEN("DECRYPTING ON KEY: " << epee::string_tools::pod_to_hex(derivation) << ", key decrypted from sender address: " << currency::get_account_address_as_str(acc_keys.account_address), LOG_LEVEL_0); + //validate derivation we here. Yoda style + crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation)); + CHECK_AND_ASSERT_MES(*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash, null_derivation, "Derivation hash missmatched in tx id " << currency::get_transaction_hash(tx)); + return derivation; } - - //validate derivation we here. Yoda style - crypto::hash hash_for_check_sum = crypto::cn_fast_hash(&derivation, sizeof(derivation)); - CHECK_AND_ASSERT_MES(*(uint32_t*)&hash_for_check_sum == crypto_info.derivation_hash, null_derivation, "Derivation hash missmatched in tx id " << currency::get_transaction_hash(tx)); - return derivation; } //--------------------------------------------------------------- template @@ -1012,26 +1726,26 @@ namespace currency return true; } + const crypto::public_key onetime_pub = get_tx_pub_key_from_extra(tx); - decrypt_payload_items(derivation, tx.extra, decrypted_items, is_income ? acc_keys: account_keys(), get_tx_pub_key_from_extra(tx)); - decrypt_payload_items(derivation, tx.attachment, decrypted_items, is_income ? acc_keys : account_keys(), get_tx_pub_key_from_extra(tx)); + decrypt_payload_items(derivation, tx.extra, decrypted_items, is_income, tx, acc_keys, onetime_pub); + decrypt_payload_items(derivation, tx.attachment, decrypted_items, is_income, tx, acc_keys, onetime_pub); return true; } //--------------------------------------------------------------- - void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key) + void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation) { - crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); bool r = crypto::generate_key_derivation(destination_addr.view_public_key, tx_random_key.sec, derivation); CHECK_AND_ASSERT_MES(r, void(), "failed to generate_key_derivation"); bool was_attachment_crypted_entries = false; bool was_extra_crypted_entries = false; - encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, tx_random_key, destination_addr); + encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, tx_random_key, destination_addr, sender_keys); for (auto& a : tx.attachment) boost::apply_visitor(v, a); - encrypt_attach_visitor v2(was_extra_crypted_entries, derivation, tx_random_key, destination_addr); + encrypt_attach_visitor v2(was_extra_crypted_entries, derivation, tx_random_key, destination_addr, sender_keys); for (auto& a : tx.extra) boost::apply_visitor(v2, a); @@ -1052,6 +1766,12 @@ namespace currency } } //--------------------------------------------------------------- + void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key) + { + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + return encrypt_attachments(tx, sender_keys, destination_addr, tx_random_key, derivation); + } + //--------------------------------------------------------------- void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x) { x.is_service = currency::is_service_tx(x.tx); @@ -1062,19 +1782,19 @@ namespace currency else x.fee = 0; x.show_sender = currency::is_showing_sender_addres(x.tx); - tx_out htlc_out = AUTO_VAL_INIT(htlc_out); + tx_out_bare htlc_out = AUTO_VAL_INIT(htlc_out); txin_htlc htlc_in = AUTO_VAL_INIT(htlc_in); x.tx_type = get_tx_type_ex(x.tx, htlc_out, htlc_in); - if(x.tx_type == GUI_TX_TYPE_HTLC_DEPOSIT && x.is_income == true) + if(x.tx_type == GUI_TX_TYPE_HTLC_DEPOSIT && !x.has_outgoing_entries()) { //need to override amount - x.amount = htlc_out.amount; + x.get_native_income_amount() = htlc_out.amount; } } //--------------------------------------------------------------- - uint64_t get_tx_type_ex(const transaction& tx, tx_out& htlc_out, txin_htlc& htlc_in) + uint64_t get_tx_type_ex(const transaction& tx, tx_out_bare& htlc_out, txin_htlc& htlc_in) { if (is_coinbase(tx)) return GUI_TX_TYPE_COIN_BASE; @@ -1120,13 +1840,17 @@ namespace currency if (bc_services::get_first_service_attachment_by_id(tx, BC_ESCROW_SERVICE_ID, BC_ESCROW_SERVICE_INSTRUCTION_CANCEL_PROPOSAL, tsa)) return GUI_TX_TYPE_ESCROW_CANCEL_PROPOSAL; - for (auto o : tx.vout) + for (auto ov : tx.vout) { - if (o.target.type() == typeid(txout_htlc)) - { - htlc_out = o; - return GUI_TX_TYPE_HTLC_DEPOSIT; - } + VARIANT_SWITCH_BEGIN(ov); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_htlc)) + { + htlc_out = o; + return GUI_TX_TYPE_HTLC_DEPOSIT; + } + VARIANT_SWITCH_END(); + } if (get_type_in_variant_container(tx.vin, htlc_in)) @@ -1140,18 +1864,23 @@ namespace currency //--------------------------------------------------------------- uint64_t get_tx_type(const transaction& tx) { - tx_out htlc_out = AUTO_VAL_INIT(htlc_out); + tx_out_bare htlc_out = AUTO_VAL_INIT(htlc_out); txin_htlc htlc_in = AUTO_VAL_INIT(htlc_in); return get_tx_type_ex(tx, htlc_out, htlc_in); } //--------------------------------------------------------------- - size_t get_multisig_out_index(const std::vector& outs) + size_t get_multisig_out_index(const std::vector& outs) { size_t n = 0; for (; n != outs.size(); n++) { - if (outs[n].target.type() == typeid(txout_multisig)) - break; + VARIANT_SWITCH_BEGIN(outs[n]); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_multisig)) + break; + VARIANT_CASE_CONST(tx_out_zarcanum, o) + //@#@ + VARIANT_SWITCH_END(); } return n; } @@ -1174,6 +1903,7 @@ namespace currency const std::vector& extra, const std::vector& attachments, transaction& tx, + uint64_t tx_version, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, uint8_t tx_outs_attr, @@ -1186,7 +1916,7 @@ namespace currency //in case if there is no real targets we use sender credentials to encrypt attachments account_public_address crypt_destination_addr = get_crypt_address_from_destinations(sender_account_keys, destinations); - return construct_tx(sender_account_keys, sources, destinations, extra, attachments, tx, one_time_secret_key, unlock_time, + return construct_tx(sender_account_keys, sources, destinations, extra, attachments, tx, tx_version, one_time_secret_key, unlock_time, crypt_destination_addr, 0, tx_outs_attr, @@ -1199,6 +1929,7 @@ namespace currency const std::vector& extra, const std::vector& attachments, transaction& tx, + uint64_t tx_version, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, const account_public_address& crypt_destination_addr, @@ -1209,6 +1940,7 @@ namespace currency { //extra copy operation, but creating transaction is not sensitive to this finalize_tx_param ftp = AUTO_VAL_INIT(ftp); + ftp.tx_version = tx_version; ftp.sources = sources; ftp.prepared_destinations = destinations; ftp.extra = extra; @@ -1229,6 +1961,346 @@ namespace currency return r; } //--------------------------------------------------------------- + // prepare inputs + struct input_generation_context_data + { + keypair in_ephemeral {}; // ephemeral output key (stealth_address and secret_x) + size_t real_out_index = SIZE_MAX; // index of real output in local outputs vector + std::vector outputs{}; // sorted by gindex + }; + //-------------------------------------------------------------------------------- + bool generate_ZC_sig(const crypto::hash& tx_hash_for_signature, size_t input_index, const tx_source_entry& se, const input_generation_context_data& in_context, + const account_keys& sender_account_keys, const uint64_t tx_flags, tx_generation_context& ogc, transaction& tx, bool last_output, bool separately_signed_tx_complete) + { + bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey; + CHECK_AND_ASSERT_MES(se.is_zc(), false, "sources contains a non-zc input"); + CHECK_AND_ASSERT_MES(input_index < tx.vin.size(), false, "input_index (" << input_index << ") is out-of-bounds, vin.size = " << tx.vin.size()); + CHECK_AND_ASSERT_MES(tx.vin[input_index].type() == typeid(txin_zc_input), false, "Unexpected type of input #" << input_index); + + txin_zc_input& in = boost::get(tx.vin[input_index]); + tx.signatures.emplace_back(ZC_sig()); + ZC_sig& sig = boost::get(tx.signatures.back()); + + if (watch_only_mode) + return true; // in this mode just append empty signatures + + crypto::point_t asset_id_pt(se.asset_id); + crypto::point_t source_blinded_asset_id = asset_id_pt + se.real_out_asset_id_blinding_mask * crypto::c_point_X; // T_i = H_i + r_i * X + CHECK_AND_ASSERT_MES(crypto::point_t(in_context.outputs[in_context.real_out_index].blinded_asset_id).modify_mul8() == source_blinded_asset_id, false, "real output blinded asset id check failed"); + ogc.real_zc_ins_asset_ids.emplace_back(asset_id_pt); + +#ifndef NDEBUG + { + crypto::point_t source_amount_commitment = se.amount * source_blinded_asset_id + se.real_out_amount_blinding_mask * crypto::c_point_G; + CHECK_AND_ASSERT_MES(crypto::point_t(in_context.outputs[in_context.real_out_index].amount_commitment).modify_mul8() == source_amount_commitment, false, "real output amount commitment check failed"); + } +#endif + + crypto::scalar_t pseudo_out_amount_blinding_mask = 0; + crypto::scalar_t pseudo_out_asset_id_blinding_mask = crypto::scalar_t::random(); + if (last_output && ((tx_flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) == 0 || separately_signed_tx_complete)) + { + // either normal tx or the last signature of consolidated tx -- in both cases we need to calculate non-random blinding mask for pseudo output commitment + pseudo_out_amount_blinding_mask = ogc.amount_blinding_masks_sum - ogc.pseudo_out_amount_blinding_masks_sum + (ogc.ao_commitment_in_outputs ? ogc.ao_amount_blinding_mask : -ogc.ao_amount_blinding_mask); // A_1 - A^p_0 = (f_1 - f'_1) * G => f'_{i-1} = sum{y_j} - sum{f'_i} + } + else + { + pseudo_out_amount_blinding_mask.make_random(); + ogc.pseudo_out_amount_blinding_masks_sum += pseudo_out_amount_blinding_mask; + } + + DBG_VAL_PRINT("ZC sig generation"); + DBG_VAL_PRINT(input_index); + DBG_VAL_PRINT(source_blinded_asset_id); + DBG_VAL_PRINT(pseudo_out_asset_id_blinding_mask); + DBG_VAL_PRINT(se.real_out_amount_blinding_mask); + DBG_VAL_PRINT(se.real_out_asset_id_blinding_mask); + DBG_VAL_PRINT(se.asset_id); + DBG_VAL_PRINT(se.amount); + DBG_VAL_PRINT(pseudo_out_amount_blinding_mask); + + crypto::point_t pseudo_out_blinded_asset_id = source_blinded_asset_id + pseudo_out_asset_id_blinding_mask * crypto::c_point_X; // T^p_i = T_i + r'_i * X + sig.pseudo_out_blinded_asset_id = (crypto::c_scalar_1div8 * pseudo_out_blinded_asset_id).to_public_key(); + ogc.real_in_asset_id_blinding_mask_x_amount_sum += se.real_out_asset_id_blinding_mask * se.amount; // += r_i * a_i + ogc.pseudo_outs_blinded_asset_ids.emplace_back(pseudo_out_blinded_asset_id); + ogc.pseudo_outs_plus_real_out_blinding_masks.emplace_back(pseudo_out_asset_id_blinding_mask + se.real_out_asset_id_blinding_mask); + + crypto::point_t pseudo_out_amount_commitment = se.amount * source_blinded_asset_id + pseudo_out_amount_blinding_mask * crypto::c_point_G; // A^p_i = a_i * T_i + f'_i * G + sig.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key(); + ogc.pseudo_out_amount_commitments_sum += pseudo_out_amount_commitment; + + // = three-layers ring signature data outline = + // (j in [0, ring_size-1]) + // layer 0 ring + // se.outputs[j].stealth_address; + // layer 0 secret (with respect to G) + // in_contexts[i].in_ephemeral.sec; + // layer 0 linkability + // in.k_image; + // + // layer 1 ring + // crypto::point_t(se.outputs[j].amount_commitment) - pseudo_out_amount_commitment; + // layer 1 secret (with respect to G) + // se.real_out_amount_blinding_mask - pseudo_out_amount_blinding_mask; + // + // layer 2 ring + // crypto::point_t(se.outputs[j].blinded_asset_id) - pseudo_out_asset_id; + // layer 2 secret (with respect to X) + // -pseudo_out_asset_id_blinding_mask; + + std::vector ring; + for(size_t j = 0; j < in_context.outputs.size(); ++j) + ring.emplace_back(in_context.outputs[j].stealth_address, in_context.outputs[j].amount_commitment, in_context.outputs[j].blinded_asset_id); + + return crypto::generate_CLSAG_GGX(tx_hash_for_signature, ring, pseudo_out_amount_commitment, pseudo_out_blinded_asset_id, in.k_image, in_context.in_ephemeral.sec, + se.real_out_amount_blinding_mask - pseudo_out_amount_blinding_mask, + -pseudo_out_asset_id_blinding_mask, in_context.real_out_index, sig.clsags_ggx); + } + //-------------------------------------------------------------------------------- + bool generate_NLSAG_sig(const crypto::hash& tx_hash_for_signature, const crypto::hash& tx_prefix_hash, size_t input_index, const tx_source_entry& src_entr, + const account_keys& sender_account_keys, const input_generation_context_data& in_context, const keypair& txkey, const uint64_t tx_flags, transaction& tx, std::stringstream* pss_ring_s) + { + bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey; + CHECK_AND_ASSERT_MES(input_index < tx.vin.size(), false, "input_index (" << input_index << ") is out-of-bounds, vin.size = " << tx.vin.size()); + + tx.signatures.push_back(NLSAG_sig()); + NLSAG_sig& nlsag = boost::get(tx.signatures.back()); + std::vector& sigs = nlsag.s; + + if (src_entr.is_multisig()) + { + // NLSAG-based multisig -- don't sign anything here (see also sign_multisig_input_in_tx()) + sigs.resize(src_entr.ms_keys_count, null_sig); // just reserve keys.size() null signatures (NOTE: not minimum_sigs!) + } + else + { + // regular txin_to_key or htlc + if (pss_ring_s) + *pss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL; + + std::vector keys_ptrs; + for(const tx_source_entry::output_entry& o : in_context.outputs) + { + keys_ptrs.push_back(&o.stealth_address); + if (pss_ring_s) + *pss_ring_s << o.stealth_address << ENDL; + } + sigs.resize(in_context.outputs.size()); + + if (!watch_only_mode) + crypto::generate_ring_signature(tx_hash_for_signature, get_key_image_from_txin_v(tx.vin[input_index]), keys_ptrs, in_context.in_ephemeral.sec, in_context.real_out_index, sigs.data()); + + if (pss_ring_s) + { + *pss_ring_s << "signatures:" << ENDL; + std::for_each(sigs.begin(), sigs.end(), [&pss_ring_s](const crypto::signature& s) { *pss_ring_s << s << ENDL; }); + *pss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_context.in_ephemeral.sec << ENDL << "real_output: " << in_context.real_out_index << ENDL; + } + } + + if (src_entr.separately_signed_tx_complete) + { + // if separately signed tx is complete, put one more signature to the last bunch using tx secret key, which confirms that transaction has been generated by authorized subject + CHECK_AND_ASSERT_MES(input_index == tx.vin.size() - 1, false, "separately_signed_tx_complete flag is set for source entry #" << input_index << ", allowed only for the last one"); + CHECK_AND_ASSERT_MES(get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE, false, "sorce entry separately_signed_tx_complete flag is set for tx with no TX_FLAG_SIGNATURE_MODE_SEPARATE flag"); + CHECK_AND_ASSERT_MES(tx_hash_for_signature == tx_prefix_hash, false, "internal error: hash_for_sign for the last input of separately signed complete tx expected to be the same as tx prefix hash"); + sigs.resize(sigs.size() + 1); + crypto::generate_signature(tx_prefix_hash, txkey.pub, txkey.sec, sigs.back()); + } + + return true; + } + +#define CRYPTO_HASH_ASSET_ID_ITERATIONS 1024 + bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key) + { + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT || + ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE || + ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN ) + { + CHECK_AND_ASSERT_MES(ado.opt_asset_id.has_value(), false, "ado.opt_asset_id has no value, op: " << (int)ado.operation_type << ", " << get_asset_operation_type_string(ado.operation_type)); + //LOG_PRINT_YELLOW("ado.opt_asset_id = " << ado.opt_asset_id.get(), LOG_LEVEL_0); + if (p_result_pub_key) + *p_result_pub_key = ado.opt_asset_id.get(); + if (p_result_point) + *p_result_point = crypto::point_t(ado.opt_asset_id.get()); + return true; + } + + // otherwise, calculate asset id + + crypto::hash_helper_t::hs_t hsc; + hsc.add_32_chars(CRYPTO_HDS_ASSET_ID); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.ticker)); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.full_name)); + hsc.add_hash(crypto::hash_helper_t::h(ado.descriptor.meta_info)); + hsc.add_scalar(crypto::scalar_t(ado.descriptor.total_max_supply)); + hsc.add_scalar(crypto::scalar_t(ado.descriptor.decimal_point)); + hsc.add_pub_key(ado.descriptor.owner); + crypto::hash h = hsc.calc_hash_no_reduce(); + + // this hash function needs to be computationally expensive (s.a. the whitepaper) + for(uint64_t i = 0; i < CRYPTO_HASH_ASSET_ID_ITERATIONS; ++i) + h = get_hash_from_POD_objects(CRYPTO_HDS_ASSET_ID, h, i); + + crypto::point_t result = crypto::hash_helper_t::hp(&h, sizeof h); + if (p_result_point) + *p_result_point = result; + if (p_result_pub_key) + result.to_public_key(*p_result_pub_key); + + //LOG_PRINT_YELLOW("calculated asset_id = " << result, LOG_LEVEL_0); + return true; + } + + const asset_descriptor_base& get_native_coin_asset_descriptor() + { + static asset_descriptor_base native_coin_asset_descriptor = [](){ + asset_descriptor_base adb{}; + adb.total_max_supply = UINT64_MAX; + adb.current_supply = 0; + adb.decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT; + adb.ticker = CURRENCY_NAME_ABR; + adb.full_name = CURRENCY_NAME_BASE; + adb.meta_info = ""; + adb.owner = currency::null_pkey; + adb.hidden_supply = false; + adb.version = 0; + return adb; + }(); + + return native_coin_asset_descriptor; + } + + bool construct_tx_handle_ado(const account_keys& sender_account_keys, + const finalize_tx_param& ftp, + asset_descriptor_operation& ado, + tx_generation_context& gen_context, + const keypair& tx_key, + std::vector& shuffled_dsts) + { + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER) + { + //crypto::secret_key asset_control_key{}; + //bool r = derive_key_pair_from_key_pair(sender_account_keys.account_address.spend_public_key, tx_key.sec, asset_control_key, ado.descriptor.owner, CRYPTO_HDS_ASSET_CONTROL_KEY); + //CHECK_AND_ASSERT_MES(r, false, "derive_key_pair_from_key_pair failed"); + // + // old: + // asset_control_key = Hs(CRYPTO_HDS_ASSET_CONTROL_KEY, 8 * tx_key.sec * sender_account_keys.account_address.spend_public_key, 0) + // ado.descriptor.owner = asset_control_key * G + + ado.descriptor.owner = sender_account_keys.account_address.spend_public_key; + + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); + + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_emitted_asset = 0; + for (auto& item : shuffled_dsts) + { + if (item.asset_id == currency::null_pkey) + { + item.asset_id = gen_context.ao_asset_id; // set calculated asset_id to the asset's outputs, if this asset is being emitted within this tx + amount_of_emitted_asset += item.amount; + } + } + ado.descriptor.current_supply = amount_of_emitted_asset; // TODO: consider setting current_supply beforehand, not setting it hear in ad-hoc manner -- sowle + + gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN) + { + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); + + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); + gen_context.ao_commitment_in_outputs = true; + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_burned_assets = 0; + for (auto& item : ftp.sources) + { + if (item.asset_id == gen_context.ao_asset_id) + { + amount_of_burned_assets += item.amount; + } + } + for (auto& item : ftp.prepared_destinations) + { + if (item.asset_id == gen_context.ao_asset_id) + { + CHECK_AND_ASSERT_THROW_MES(amount_of_burned_assets >= item.amount, "Failed to find burn amount, failed condition: amount_of_burned_assets(" << amount_of_burned_assets << ") >= item.amount(" << item.amount << ")"); + amount_of_burned_assets -= item.amount; + } + } + ado.descriptor.current_supply -= amount_of_burned_assets; + + gen_context.ao_amount_commitment = amount_of_burned_assets * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_burn{ &ado }); + + } + else + { + if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + { + CHECK_AND_ASSERT_MES(get_or_calculate_asset_id(ado, &gen_context.ao_asset_id_pt, &gen_context.ao_asset_id), false, "get_or_calculate_asset_id failed"); + + // calculate amount blinding mask + gen_context.ao_amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_ASSET_CONTROL_ABM, tx_key.sec); + + // set correct asset_id to the corresponding destination entries + uint64_t amount_of_emitted_asset = 0; + for (auto& item : shuffled_dsts) + { + if (item.asset_id == currency::null_pkey) + { + amount_of_emitted_asset += item.amount; + item.asset_id = gen_context.ao_asset_id; + } + } + ado.descriptor.current_supply += amount_of_emitted_asset; + + gen_context.ao_amount_commitment = amount_of_emitted_asset * gen_context.ao_asset_id_pt + gen_context.ao_amount_blinding_mask * crypto::c_point_G; + ado.amount_commitment = (crypto::c_scalar_1div8 * gen_context.ao_amount_commitment).to_public_key(); + + } + else if (ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE) + { + CHECK_AND_ASSERT_MES(ado.opt_asset_id, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE"); + //CHECK_AND_ASSERT_MES(ado.opt_proof, false, "ado.opt_asset_id is not found at ado.operation_type == ASSET_DESCRIPTOR_OPERATION_UPDATE"); + + //fields that not supposed to be changed? + } + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation_before_seal{ &ado }); + + ftp.need_to_generate_ado_proof = true; + /* + //seal it with owners signature + crypto::signature sig = currency::null_sig; + crypto::hash h = get_signature_hash_for_asset_operation(ado); + if (ftp.pthirdparty_sign_handler) + { + bool r = ftp.pthirdparty_sign_handler->sign(h, ftp.ado_current_asset_owner, sig); + CHECK_AND_ASSERT_MES(r, false, "asset thirparty sign failed"); + } + else + { + crypto::public_key pub_k = currency::null_pkey; + crypto::secret_key_to_public_key(sender_account_keys.spend_secret_key, pub_k); + CHECK_AND_ASSERT_MES(ftp.ado_current_asset_owner == pub_k, false, "asset owner key not matched with provided private key for asset operation signing"); + crypto::generate_signature(h, pub_k, account_keys.spend_secret_key, sig); + } + ado.opt_proof = sig; + */ + } + return true; + } + bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& ftp, finalized_tx& result) { const std::vector& sources = ftp.sources; @@ -1241,30 +2313,26 @@ namespace currency const uint8_t& tx_outs_attr = ftp.tx_outs_attr; const bool& shuffle = ftp.shuffle; const uint64_t& flags = ftp.flags; - + + bool r = false; transaction& tx = result.tx; - crypto::secret_key& one_time_secret_key = result.one_time_key; + crypto::secret_key& one_time_tx_secret_key = result.one_time_key; result.ftp = ftp; CHECK_AND_ASSERT_MES(destinations.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "Too many outs (" << destinations.size() << ")! Tx can't be constructed."); - bool watch_only_mode = sender_account_keys.spend_secret_key == null_skey; - bool append_mode = false; if (flags&TX_FLAG_SIGNATURE_MODE_SEPARATE && tx.vin.size()) append_mode = true; - keypair txkey = AUTO_VAL_INIT(txkey); - - if (!append_mode) { tx.vin.clear(); tx.vout.clear(); - tx.signatures.clear(); tx.extra = extra; + tx.signatures.clear(); - tx.version = CURRENT_TRANSACTION_VERSION; + tx.version = ftp.tx_version; if (unlock_time != 0) set_tx_unlock_time(tx, unlock_time); @@ -1273,10 +2341,154 @@ namespace currency //generate key pair if (expiration_time != 0) set_tx_expiration_time(tx, expiration_time); + } - txkey = keypair::generate(); - add_tx_pub_key_to_extra(tx, txkey.pub); - one_time_secret_key = txkey.sec; + size_t zc_inputs_count = 0; + bool has_non_zc_inputs = false; + + std::list key_images_total; + // + // INs + // + uint64_t native_coins_input_sum = 0; + std::vector in_contexts; + std::vector inputs_mapping; + size_t current_index = 0; + inputs_mapping.resize(sources.size()); + size_t input_starter_index = tx.vin.size(); + bool all_inputs_are_obviously_native_coins = true; + for (const tx_source_entry& src_entr : sources) + { + inputs_mapping[current_index] = current_index; + current_index++; + in_contexts.push_back(input_generation_context_data{}); + input_generation_context_data& in_context = in_contexts.back(); + + // sort src_entr.outputs entries by global out index, put it to in_context.outputs, convert to relative gindices, and put new real out index into in_context.real_out_index + in_context.outputs = prepare_outputs_entries_for_key_offsets(src_entr.outputs, src_entr.real_output, in_context.real_out_index); + + if (src_entr.is_multisig()) + {//multisig input + txin_multisig input_multisig = AUTO_VAL_INIT(input_multisig); + input_multisig.amount = src_entr.amount; + input_multisig.multisig_out_id = src_entr.multisig_id; + input_multisig.sigs_count = src_entr.ms_sigs_count; + tx.vin.push_back(input_multisig); + has_non_zc_inputs = true; + } + else if (src_entr.htlc_origin.size()) + { + //htlc redeem + keypair& in_ephemeral = in_context.in_ephemeral; + //txin_to_key + if (src_entr.outputs.size() != 1) + { + LOG_ERROR("htlc in: wrong output src_entr.outputs.size() = " << src_entr.outputs.size()); + return false; + } + + //key_derivation recv_derivation; + crypto::key_image img; + if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) + return false; + + //check that derivated key is equal with real output key + if (!(in_ephemeral.pub == src_entr.outputs.front().stealth_address)) + { + LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" + << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" + << string_tools::pod_to_hex(src_entr.outputs.front().stealth_address)); + return false; + } + key_images_total.push_back(img); + + //put key image into tx input + txin_htlc input_to_key; + input_to_key.amount = src_entr.amount; + input_to_key.k_image = img; + input_to_key.hltc_origin = src_entr.htlc_origin; + input_to_key.key_offsets.push_back(src_entr.outputs.front().out_reference); + + tx.vin.push_back(input_to_key); + has_non_zc_inputs = true; + } + else + { + // txin_to_key or txin_zc_input + CHECK_AND_ASSERT_MES(in_context.real_out_index < in_context.outputs.size(), false, + "real_output index (" << in_context.real_out_index << ") greater than or equal to in_context.outputs.size()=" << in_context.outputs.size()); + + crypto::key_image img; + if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_context.in_ephemeral, img)) + return false; + + //check that derivated key is equal with real output key + if (!(in_context.in_ephemeral.pub == in_context.outputs[in_context.real_out_index].stealth_address)) + { + LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" + << string_tools::pod_to_hex(in_context.in_ephemeral.pub) << ENDL << "real output_public_key:" + << string_tools::pod_to_hex(in_context.outputs[in_context.real_out_index].stealth_address)); + return false; + } + + + key_images_total.push_back(img); + //fill key_offsets array with relative offsets + std::vector key_offsets; + for (const tx_source_entry::output_entry& out_entry : in_context.outputs) + key_offsets.push_back(out_entry.out_reference); + + //TODO: Might need some refactoring since this scheme is not the clearest one(did it this way for now to keep less changes to not broke anything) + //potentially this approach might help to support htlc and multisig without making to complicated code + if (src_entr.is_zc()) + { + ++zc_inputs_count; + txin_zc_input zc_in = AUTO_VAL_INIT(zc_in); + zc_in.k_image = img; + zc_in.key_offsets = std::move(key_offsets); + tx.vin.push_back(zc_in); + } + else + { + txin_to_key input_to_key = AUTO_VAL_INIT(input_to_key); + input_to_key.amount = src_entr.amount; + input_to_key.k_image = img; + input_to_key.key_offsets = std::move(key_offsets); + tx.vin.push_back(input_to_key); + has_non_zc_inputs = true; + } + } + + if (src_entr.is_native_coin()) + native_coins_input_sum += src_entr.amount; + + if (src_entr.is_zc()) + { + // if at least one decoy output of a ZC input has a non-explicit asset id, then we can't say that all inputs are obviously native coins + for (const tx_source_entry::output_entry& oe : in_context.outputs) + { + if (crypto::point_t(oe.blinded_asset_id).modify_mul8() != currency::native_coin_asset_id_pt) + { + all_inputs_are_obviously_native_coins = false; + break; + } + } + } + } + + if (zc_inputs_count != 0 && tx.version <= TRANSACTION_VERSION_PRE_HF4) + { + LOG_PRINT_YELLOW("WARNING: tx v1 should not use ZC inputs", LOG_LEVEL_0); + } + + tx_generation_context& gen_context = result.ftp.gen_context; + + if (!append_mode) + { + gen_context.set_tx_key(keypair::generate()); + //deterministic_generate_tx_onetime_key(key_images_total, sender_account_keys, txkey); + add_tx_pub_key_to_extra(tx, gen_context.tx_key.pub); + one_time_tx_secret_key = gen_context.tx_key.sec; //add flags etc_tx_flags16_t e = AUTO_VAL_INIT(e); @@ -1285,22 +2497,22 @@ namespace currency //include offers if need tx.attachment = attachments; - encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, txkey); + encrypt_attachments(tx, sender_account_keys, crypt_destination_addr, gen_context.tx_key, result.derivation); } else { - txkey.pub = get_tx_pub_key_from_extra(tx); - txkey.sec = one_time_secret_key; - CHECK_AND_ASSERT_MES(txkey.pub != null_pkey && txkey.sec != null_skey, false, "In append mode both public and secret keys must be provided"); + gen_context.set_tx_key(keypair{get_tx_pub_key_from_extra(tx), one_time_tx_secret_key}); + CHECK_AND_ASSERT_MES(gen_context.tx_key.pub != null_pkey && gen_context.tx_key.sec != null_skey, false, "In append mode both public and secret keys must be provided"); //separately encrypt attachments without putting extra - crypto::key_derivation derivation = get_encryption_key_derivation(true, tx, sender_account_keys); + result.derivation = get_encryption_key_derivation(true, tx, sender_account_keys); + crypto::key_derivation& derivation = result.derivation; CHECK_AND_ASSERT_MES(derivation != null_derivation, false, "failed to generate_key_derivation"); bool was_attachment_crypted_entries = false; std::vector extra_local = extra; std::vector attachments_local = attachments; - encrypt_attach_visitor v(was_attachment_crypted_entries, derivation); + encrypt_attach_visitor v(was_attachment_crypted_entries, derivation, gen_context.tx_key, account_public_address(), sender_account_keys); for (auto& a : attachments_local) boost::apply_visitor(v, a); for (auto& a : extra_local) @@ -1309,161 +2521,70 @@ namespace currency tx.attachment.insert(tx.attachment.end(), attachments_local.begin(), attachments_local.end()); tx.extra.insert(tx.extra.end(), extra_local.begin(), extra_local.end()); + + for (const auto& in : tx.vin) + { + if (in.type() == typeid(txin_zc_input)) + { + zc_inputs_count++; + } + else { + has_non_zc_inputs = true; + } + } } + + // + // OUTs + // + std::vector shuffled_dsts(destinations); + gen_context.resize(zc_inputs_count, tx.vout.size() + shuffled_dsts.size()); - // prepare inputs - struct input_generation_context_data + // ASSET oprations handling + if (tx.version > TRANSACTION_VERSION_PRE_HF4) { - keypair in_ephemeral; - //std::vector participants_derived_keys; - }; - std::vector in_contexts; - - size_t input_starter_index = tx.vin.size(); - uint64_t summary_inputs_money = 0; - //fill inputs - for (const tx_source_entry& src_entr : sources) - { - in_contexts.push_back(input_generation_context_data()); - if(src_entr.is_multisig()) - {//multisig input - txin_multisig input_multisig = AUTO_VAL_INIT(input_multisig); - summary_inputs_money += input_multisig.amount = src_entr.amount; - input_multisig.multisig_out_id = src_entr.multisig_id; - input_multisig.sigs_count = src_entr.ms_sigs_count; - tx.vin.push_back(input_multisig); - } - else if (src_entr.htlc_origin.size()) + asset_descriptor_operation* pado = nullptr; + pado = get_type_in_variant_container(tx.extra); + if (pado) { - //htlc redeem - keypair& in_ephemeral = in_contexts.back().in_ephemeral; - //txin_to_key - if(src_entr.outputs.size() != 1) - { - LOG_ERROR("htlc in: wrong output src_entr.outputs.size() = " << src_entr.outputs.size()); - return false; - } - summary_inputs_money += src_entr.amount; - - //key_derivation recv_derivation; - crypto::key_image img; - if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) - return false; - - //check that derivated key is equal with real output key - if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second)) - { - LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" - << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" - << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second)); - return false; - } - - //put key image into tx input - txin_htlc input_to_key; - input_to_key.amount = src_entr.amount; - input_to_key.k_image = img; - input_to_key.hltc_origin = src_entr.htlc_origin; - - //fill outputs array and use relative offsets - BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs) - input_to_key.key_offsets.push_back(out_entry.first); - - input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); - tx.vin.push_back(input_to_key); + bool r = construct_tx_handle_ado(sender_account_keys, ftp, *pado, gen_context, gen_context.tx_key, shuffled_dsts); + CHECK_AND_ASSERT_MES(r, false, "Failed to construct_tx_handle_ado()"); + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_handle_asset_descriptor_operation{ pado }); } - else - { - //regular to key out - keypair& in_ephemeral = in_contexts.back().in_ephemeral; - //txin_to_key - if (src_entr.real_output >= src_entr.outputs.size()) - { - LOG_ERROR("real_output index (" << src_entr.real_output << ") greater than or equal to output_keys.size()=" << src_entr.outputs.size()); - return false; - } - summary_inputs_money += src_entr.amount; - - //key_derivation recv_derivation; - crypto::key_image img; - if (!generate_key_image_helper(sender_account_keys, src_entr.real_out_tx_key, src_entr.real_output_in_tx_index, in_ephemeral, img)) - return false; - - //check that derivated key is equal with real output key - if (!(in_ephemeral.pub == src_entr.outputs[src_entr.real_output].second)) - { - LOG_ERROR("derived public key missmatch with output public key! " << ENDL << "derived_key:" - << string_tools::pod_to_hex(in_ephemeral.pub) << ENDL << "real output_public_key:" - << string_tools::pod_to_hex(src_entr.outputs[src_entr.real_output].second)); - return false; - } - - //put key image into tx input - txin_v in_v; - txin_to_key* ptokey = nullptr; - if (src_entr.htlc_origin.size()) - { - //add txin_htlc - txin_htlc in_htlc = AUTO_VAL_INIT(in_htlc); - in_htlc.hltc_origin = src_entr.htlc_origin; - in_v = in_htlc; - txin_htlc& in_v_ref = boost::get(in_v); - ptokey = static_cast(&in_v_ref); - } - else - { - in_v = txin_to_key(); - txin_to_key& in_v_ref = boost::get(in_v); - ptokey = &in_v_ref; - } - txin_to_key& input_to_key = *ptokey; - - - input_to_key.amount = src_entr.amount; - input_to_key.k_image = img; - - //fill outputs array and use relative offsets - BOOST_FOREACH(const tx_source_entry::output_entry& out_entry, src_entr.outputs) - input_to_key.key_offsets.push_back(out_entry.first); - - input_to_key.key_offsets = absolute_output_offsets_to_relative(input_to_key.key_offsets); - tx.vin.push_back(in_v); - } - } // "Shuffle" outs - std::vector shuffled_dsts(destinations); if (shuffle) std::sort(shuffled_dsts.begin(), shuffled_dsts.end(), [](const tx_destination_entry& de1, const tx_destination_entry& de2) { return de1.amount < de2.amount; }); - uint64_t summary_outs_money = 0; - //fill outputs + // TODO: consider "Shuffle" inputs + + // construct outputs + uint64_t native_coins_output_sum = 0; size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1 + uint64_t range_proof_start_index = 0; std::set deriv_cache; - for(const tx_destination_entry& dst_entr : shuffled_dsts) + for(size_t destination_index = 0; destination_index < shuffled_dsts.size(); ++destination_index, ++output_index) { - CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); - bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys, result, tx_outs_attr); - CHECK_AND_ASSERT_MES(r, false, "Failed to construc tx out"); - output_index++; - summary_outs_money += dst_entr.amount; + tx_destination_entry& dst_entr = shuffled_dsts[destination_index]; + if (!(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) && all_inputs_are_obviously_native_coins && gen_context.ao_asset_id == currency::null_pkey) + dst_entr.flags |= tx_destination_entry_flags::tdef_explicit_native_asset_id; // all inputs are obviously native coins -- all outputs must have explicit asset ids (unless there's an asset emission) + + r = construct_tx_out(dst_entr, gen_context.tx_key.sec, output_index, tx, deriv_cache, sender_account_keys, + gen_context.asset_id_blinding_masks[output_index], gen_context.amount_blinding_masks[output_index], + gen_context.blinded_asset_ids[output_index], gen_context.amount_commitments[output_index], result, tx_outs_attr); + CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out"); + gen_context.amounts[output_index] = dst_entr.amount; + gen_context.asset_ids[output_index] = crypto::point_t(dst_entr.asset_id); + gen_context.asset_id_blinding_mask_x_amount_sum += gen_context.asset_id_blinding_masks[output_index] * dst_entr.amount; + gen_context.amount_blinding_masks_sum += gen_context.amount_blinding_masks[output_index]; + gen_context.amount_commitments_sum += gen_context.amount_commitments[output_index]; + if (dst_entr.is_native_coin()) + native_coins_output_sum += dst_entr.amount; } - //check money - if (!(flags&TX_FLAG_SIGNATURE_MODE_SEPARATE)) - { - if (summary_outs_money > summary_inputs_money) - { - LOG_ERROR("Transaction inputs money (" << summary_inputs_money << ") less than outputs money (" << summary_outs_money << ")"); - return false; - } - } - - - //process offers and put there offers derived keys uint64_t att_count = 0; for (auto& o : tx.attachment) @@ -1475,19 +2596,40 @@ namespace currency { CHECK_AND_ASSERT_MES(tsa.security.size() == 1, false, "Wrong tsa.security.size() = " << tsa.security.size()); - bool r = derive_public_key_from_target_address(sender_account_keys.account_address, one_time_secret_key, att_count, tsa.security.back()); + r = derive_public_key_from_target_address(sender_account_keys.account_address, one_time_tx_secret_key, att_count, tsa.security.back()); CHECK_AND_ASSERT_MES(r, false, "Failed to derive_public_key_from_target_address"); } att_count++; } } - if (!(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)) + + //sort inputs and mapping if it's zarcanum hardfork + if (tx.version > TRANSACTION_VERSION_PRE_HF4) { - //take hash from attachment and put into extra - if (tx.attachment.size()) - add_attachments_info_to_extra(tx.extra, tx.attachment); + //1 sort mapping + std::sort(inputs_mapping.begin(), inputs_mapping.end(), [&](size_t a, size_t b) { + return less_txin_v(tx.vin[input_starter_index + a], tx.vin[input_starter_index + b]); + }); + + //2 sort the inputs in given range + std::sort(tx.vin.begin() + input_starter_index, tx.vin.end(), less_txin_v); + + // add explicit fee info + uint64_t fee_to_declare = native_coins_input_sum - native_coins_output_sum; + if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + fee_to_declare = ftp.mode_separate_fee; + } + if (fee_to_declare) + { + r = add_tx_fee_amount_to_extra(tx, fee_to_declare); + CHECK_AND_ASSERT_MES(r, false, "add_tx_fee_amount_to_extra failed"); + } } - else + + // attachments container should be sealed by now + + if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) { // for separately signed tx each input has to contain information about corresponding outputs, extra entries and attachments for (size_t in_index = input_starter_index; in_index != tx.vin.size(); in_index++) @@ -1497,69 +2639,129 @@ namespace currency so.n_outs = tx.vout.size(); so.n_extras = tx.extra.size(); get_txin_etc_options(tx.vin[in_index]).push_back(so); - + // put attachment extra info to each input's details (in case there are attachments) add_attachments_info_to_extra(get_txin_etc_options(tx.vin[in_index]), tx.attachment); } } - - //generate ring signatures - crypto::hash tx_prefix_hash; - get_transaction_prefix_hash(tx, tx_prefix_hash); - - std::stringstream ss_ring_s; - size_t input_index = input_starter_index; - size_t in_context_index = 0; - BOOST_FOREACH(const tx_source_entry& src_entr, sources) + else { - crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, input_index, tx_prefix_hash); - CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "failed to prepare_prefix_hash_for_sign"); + //take hash from attachment and put into extra + if (tx.attachment.size()) + add_attachments_info_to_extra(tx.extra, tx.attachment); + } + - tx.signatures.push_back(std::vector()); - std::vector& sigs = tx.signatures.back(); + // + // generate proofs and signatures + // (any changes made below should only affect the signatures/proofs and should not impact the prefix hash calculation) + // + crypto::hash tx_prefix_hash = get_transaction_prefix_hash(tx); - if(src_entr.is_multisig()) + // ring signatures (per-input proofs) + r = false; + bool separately_signed_tx_complete = !sources.empty() ? sources.back().separately_signed_tx_complete : false; + size_t zc_input_index = 0; + for (size_t i_ = 0; i_ != sources.size(); i_++) + { + size_t i_mapped = inputs_mapping[i_]; + const tx_source_entry& source_entry = sources[i_mapped]; + crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, i_ + input_starter_index, tx_prefix_hash); + CHECK_AND_ASSERT_MES(tx_hash_for_signature != null_hash, false, "prepare_prefix_hash_for_sign failed"); + std::stringstream ss_ring_s; + + if (source_entry.is_zc()) { - // txin_multisig -- don't sign anything here (see also sign_multisig_input_in_tx()) - sigs.resize(src_entr.ms_keys_count, null_sig); // just reserve keys.size() null signatures (NOTE: not minimum_sigs!) + // ZC + r = generate_ZC_sig(tx_hash_for_signature, i_ + input_starter_index, source_entry, in_contexts[i_mapped], sender_account_keys, flags, gen_context, tx, i_ + 1 == sources.size(), separately_signed_tx_complete); + CHECK_AND_ASSERT_MES(r, false, "generate_ZC_sigs failed"); + gen_context.zc_input_amounts[zc_input_index] = source_entry.amount; + zc_input_index++; } else { - // regular txin_to_key or htlc - ss_ring_s << "input #" << input_index << ", pub_keys:" << ENDL; - std::vector keys_ptrs; - BOOST_FOREACH(const tx_source_entry::output_entry& o, src_entr.outputs) - { - keys_ptrs.push_back(&o.second); - ss_ring_s << o.second << ENDL; - } - sigs.resize(src_entr.outputs.size()); - - if (!watch_only_mode) - crypto::generate_ring_signature(tx_hash_for_signature, get_to_key_input_from_txin_v(tx.vin[input_index]).k_image, keys_ptrs, in_contexts[in_context_index].in_ephemeral.sec, src_entr.real_output, sigs.data()); - - ss_ring_s << "signatures:" << ENDL; - std::for_each(sigs.begin(), sigs.end(), [&ss_ring_s](const crypto::signature& s) { ss_ring_s << s << ENDL; }); - ss_ring_s << "prefix_hash: " << tx_prefix_hash << ENDL << "in_ephemeral_key: " << in_contexts[in_context_index].in_ephemeral.sec << ENDL << "real_output: " << src_entr.real_output << ENDL; - } - if (src_entr.separately_signed_tx_complete) - { - // if separately signed tx is complete, put one more signature to the last bunch using tx secret key, which confirms that transaction has been generated by authorized subject - CHECK_AND_ASSERT_MES(input_index == tx.vin.size() - 1, false, "separately_signed_tx_complete flag is set for source entry #" << input_index << ", allowed only for the last one"); - CHECK_AND_ASSERT_MES(flags & TX_FLAG_SIGNATURE_MODE_SEPARATE, false, "sorce entry separately_signed_tx_complete flag is set for tx with no TX_FLAG_SIGNATURE_MODE_SEPARATE flag"); - CHECK_AND_ASSERT_MES(tx_hash_for_signature == tx_prefix_hash, false, "internal error: hash_for_sign for the last input of separately signed complete tx expected to be the same as tx prefix hash"); - sigs.resize(sigs.size() + 1); - crypto::generate_signature(tx_prefix_hash, txkey.pub, txkey.sec, sigs.back()); + // NLSAG + r = generate_NLSAG_sig(tx_hash_for_signature, tx_prefix_hash, i_ + input_starter_index, source_entry, sender_account_keys, in_contexts[i_mapped], gen_context.tx_key, flags, tx, &ss_ring_s); + CHECK_AND_ASSERT_MES(r, false, "generate_NLSAG_sig failed"); } - input_index++; - in_context_index++; + LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3); } - LOG_PRINT2("construct_tx.log", "transaction_created: " << get_transaction_hash(tx) << ENDL << obj_to_json_str(tx) << ENDL << ss_ring_s.str(), LOG_LEVEL_3); + // + // proofs (transaction-wise, not pre-input) + // + if (tx.version > TRANSACTION_VERSION_PRE_HF4 && + (append_mode || (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) == 0)) + { + // asset surjection proof + currency::zc_asset_surjection_proof asp{}; + bool r = generate_asset_surjection_proof(tx_prefix_hash, has_non_zc_inputs, gen_context, asp); + CHECK_AND_ASSERT_MES(r, false, "generete_asset_surjection_proof failed"); + tx.proofs.emplace_back(std::move(asp)); + + // range proofs + currency::zc_outs_range_proof range_proofs{}; + r = generate_zc_outs_range_proof(tx_prefix_hash, range_proof_start_index, gen_context, tx.vout, range_proofs); + CHECK_AND_ASSERT_MES(r, false, "Failed to generate zc_outs_range_proof()"); + tx.proofs.emplace_back(std::move(range_proofs)); + + // balance proof + currency::zc_balance_proof balance_proof{}; + r = generate_tx_balance_proof(tx, tx_prefix_hash, gen_context, 0, balance_proof); + CHECK_AND_ASSERT_MES(r, false, "generate_tx_balance_proof failed"); + tx.proofs.emplace_back(std::move(balance_proof)); + + // asset operation proof (if necessary) + if (gen_context.ao_asset_id != currency::null_pkey) + { + // construct the asset operation proof + // TODO @#@# add support for hidden supply + crypto::signature aop_g_sig{}; + crypto::generate_signature(tx_prefix_hash, crypto::point_t(gen_context.ao_amount_blinding_mask * crypto::c_point_G).to_public_key(), gen_context.ao_amount_blinding_mask, aop_g_sig); + asset_operation_proof aop{}; + aop.opt_amount_commitment_g_proof = aop_g_sig; + tx.proofs.emplace_back(std::move(aop)); + } + if(ftp.need_to_generate_ado_proof) + { + asset_operation_ownership_proof aoop = AUTO_VAL_INIT(aoop); + + if (ftp.pthirdparty_sign_handler) + { + //ask third party to generate proof + r = ftp.pthirdparty_sign_handler->sign(tx_prefix_hash, ftp.ado_current_asset_owner, aoop.gss); + CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado by thirdparty"); + } + else + { + //generate signature by wallet account + r = crypto::generate_schnorr_sig(tx_prefix_hash, ftp.ado_current_asset_owner, sender_account_keys.spend_secret_key, aoop.gss); + CHECK_AND_ASSERT_MES(r, false, "Failed to sign ado proof"); + } + if (ftp.pevents_dispatcher) ftp.pevents_dispatcher->RAISE_DEBUG_EVENT(wde_construct_tx_after_asset_ownership_proof_generated{ &aoop }); + tx.proofs.emplace_back(aoop); + } + } + + //size_t prefix_size = get_object_blobsize(static_cast(tx)); + //size_t full_blob_size = t_serializable_object_to_blob(tx).size(); + //size_t estimated_blob_size = get_object_blobsize(tx); + //CHECK_AND_ASSERT_MES(full_blob_size == estimated_blob_size, false, "!"); return true; } + + + //--------------------------------------------------------------- + uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd) + { + if (!hfd.is_hardfork_active_for_height(ZANO_HARDFORK_04_ZARCANUM, tx_expected_block_height)) + { + return TRANSACTION_VERSION_PRE_HF4; + } + return CURRENT_TRANSACTION_VERSION; + } //--------------------------------------------------------------- uint64_t get_reward_from_miner_tx(const transaction& tx) { @@ -1578,7 +2780,12 @@ namespace currency uint64_t reward = 0; for (auto& out : tx.vout) { - reward += out.amount; + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, o) + reward += o.amount; + VARIANT_CASE_CONST(tx_out_zarcanum, o) + //@#@ + VARIANT_SWITCH_END(); } reward -= income; return reward; @@ -1615,6 +2822,35 @@ namespace currency return timestamp; } //--------------------------------------------------------------- + bool parse_vote(const std::string& json_, std::list>& votes) + { + //do preliminary check of text if it looks like json + std::string::size_type pos = json_.find('{'); + if (pos == std::string::npos) + return false; + std::string json = json_.substr(pos); + + epee::serialization::portable_storage ps; + bool rs = ps.load_from_json(json); + if (!rs) + return false; + + + + auto cb = [&](const std::string& name, const epee::serialization::storage_entry& entry) { + if (entry.type() == typeid(uint64_t)) + { + bool vote = boost::get(entry) ? true : false; + votes.push_back(std::make_pair(epee::string_encoding::toupper(name), vote)); + } + return true; + }; + + ps.enum_entries(nullptr, cb); + return true; + + } + //--------------------------------------------------------------- bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed /* = nullptr */) { #define LOC_CHK(cond, msg) CHECK_AND_ASSERT_MES(cond, false, msg << ", ms input index: " << ms_input_index << ", tx: " << get_transaction_hash(tx) << ", source tx: " << get_transaction_hash(source_tx)) @@ -1629,14 +2865,17 @@ namespace currency size_t ms_out_index = SIZE_MAX; for (size_t i = 0; i < source_tx.vout.size(); ++i) { - if (source_tx.vout[i].target.type() == typeid(txout_multisig) && ms_in.multisig_out_id == get_multisig_out_id(source_tx, i)) - { - ms_out_index = i; - break; - } + VARIANT_SWITCH_BEGIN(source_tx.vout[i]); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_multisig) && ms_in.multisig_out_id == get_multisig_out_id(source_tx, i)) + { + ms_out_index = i; + break; + } + VARIANT_SWITCH_END(); } LOC_CHK(ms_out_index != SIZE_MAX, "failed to find ms output in source tx " << get_transaction_hash(source_tx) << " by ms id " << ms_in.multisig_out_id); - const txout_multisig& out_ms = boost::get(source_tx.vout[ms_out_index].target); + const txout_multisig& out_ms = boost::get( boost::get(source_tx.vout[ms_out_index]).target); crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx); @@ -1646,9 +2885,10 @@ namespace currency size_t participant_index = std::find(out_ms.keys.begin(), out_ms.keys.end(), ms_in_ephemeral_key.pub) - out_ms.keys.begin(); LOC_CHK(participant_index < out_ms.keys.size(), "Can't find given participant's ms key in ms output keys list"); - LOC_CHK(ms_input_index < tx.signatures.size(), "transaction does not have signatures vectory entry for ms input #" << ms_input_index); - - auto& sigs = tx.signatures[ms_input_index]; + LOC_CHK(ms_input_index < tx.signatures.size(), "transaction does not have signatures vector entry for ms input #" << ms_input_index); + + LOC_CHK(tx.signatures[ms_input_index].type() == typeid(NLSAG_sig), "Wrong type of signature"); + auto& sigs = boost::get(tx.signatures[ms_input_index]).s; LOC_CHK(!sigs.empty(), "empty signatures container"); bool extra_signature_expected = (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) && ms_input_index == tx.vin.size() - 1; @@ -1694,8 +2934,6 @@ namespace currency for(const auto& in : tx.vin) { uint64_t this_amount = get_amount_from_variant(in); - if (!this_amount) - return false; money += this_amount; } return true; @@ -1717,9 +2955,12 @@ namespace currency { for(const auto& in : tx.vin) { - CHECK_AND_ASSERT_MES(in.type() == typeid(txin_to_key) || in.type() == typeid(txin_multisig) || in.type() == typeid(txin_htlc), false, "wrong variant type: " - << in.type().name() - << ", in transaction id=" << get_transaction_hash(tx)); + CHECK_AND_ASSERT_MES( + in.type() == typeid(txin_to_key) || + in.type() == typeid(txin_multisig) || + in.type() == typeid(txin_htlc) || + in.type() == typeid(txin_zc_input), + false, "wrong input type: " << in.type().name() << ", in transaction " << get_transaction_hash(tx)); } return true; } @@ -1782,36 +3023,45 @@ namespace currency //----------------------------------------------------------------------------------------------- bool check_outs_valid(const transaction& tx) { - for(const tx_out& out : tx.vout) + for(const auto& vo : tx.vout) { - CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx)); - if (out.target.type() == typeid(txout_to_key)) + VARIANT_SWITCH_BEGIN(vo); + VARIANT_CASE_CONST(tx_out_bare, out) { - if (!check_key(boost::get(out.target).key)) + CHECK_AND_NO_ASSERT_MES(0 < out.amount, false, "zero amount output in transaction id=" << get_transaction_hash(tx)); + + VARIANT_SWITCH_BEGIN(out.target); + VARIANT_CASE_CONST(txout_to_key, tk) + if (!check_key(tk.key)) + return false; + VARIANT_CASE_CONST(txout_htlc, htlc) + if (!check_key(htlc.pkey_redeem)) + return false; + if (!check_key(htlc.pkey_refund)) + return false; + VARIANT_CASE_CONST(txout_multisig, ms) + if (!(ms.keys.size() > 0 && ms.minimum_sigs > 0 && ms.minimum_sigs <= ms.keys.size())) + { + LOG_ERROR("wrong multisig output in transaction " << get_transaction_hash(tx)); + return false; + } + VARIANT_CASE_OTHER() + LOG_ERROR("wrong output type: " << out.target.type().name() << " in transaction " << get_transaction_hash(tx)); + return false; + VARIANT_SWITCH_END(); + } + VARIANT_CASE_CONST(tx_out_zarcanum, o) + { + if (!check_key(o.stealth_address)) + return false; + if (!check_key(o.concealing_point)) + return false; + if (!check_key(o.amount_commitment)) + return false; + if (!check_key(o.blinded_asset_id)) return false; } - else if (out.target.type() == typeid(txout_htlc)) - { - const txout_htlc& htlc = boost::get(out.target); - if (!check_key(htlc.pkey_redeem)) - return false; - if (!check_key(htlc.pkey_refund)) - return false; - } - else if (out.target.type() == typeid(txout_multisig)) - { - const txout_multisig& ms = boost::get(out.target); - if (!(ms.keys.size() > 0 && ms.minimum_sigs > 0 && ms.minimum_sigs <= ms.keys.size())) - { - LOG_ERROR("wrong multisig in transaction id=" << get_transaction_hash(tx)); - return false; - } - } - else - { - LOG_ERROR("wrong variant type: " << out.target.type().name() << ", expected " << typeid(txout_to_key).name() - << ", in transaction id=" << get_transaction_hash(tx)); - } + VARIANT_SWITCH_END(); } return true; } @@ -1824,7 +3074,7 @@ namespace currency bool check_inputs_overflow(const transaction& tx) { uint64_t money = 0; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in : tx.vin) { uint64_t this_amount = 0; if (in.type() == typeid(txin_to_key)) @@ -1842,9 +3092,13 @@ namespace currency CHECKED_GET_SPECIFIC_VARIANT(in, const txin_htlc, htlc_in, false); this_amount = htlc_in.amount; } + else if (in.type() == typeid(txin_zc_input)) + { + // ignore inputs with hidden amounts + } else { - LOG_ERROR("Unknow type in in: " << in.type().name()); + LOG_ERROR("wrong input type: " << in.type().name()); return false; } if (money > this_amount + money) @@ -1857,20 +3111,55 @@ namespace currency bool check_outs_overflow(const transaction& tx) { uint64_t money = 0; - BOOST_FOREACH(const auto& o, tx.vout) + for(const auto& o : tx.vout) { - if (money > o.amount + money) - return false; - money += o.amount; + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE_CONST(tx_out_bare, o) + if (money > o.amount + money) + return false; + money += o.amount; + // VARIANT_CASE_CONST(tx_out_zarcanum, o) + // ignore inputs with hidden amounts + VARIANT_SWITCH_END(); } return true; } //--------------------------------------------------------------- - uint64_t get_outs_money_amount(const transaction& tx) + uint64_t get_outs_money_amount(const transaction& tx, const currency::account_keys& keys /* = currency::null_acc_keys */) { uint64_t outputs_amount = 0; - for(const auto& o : tx.vout) - outputs_amount += o.amount; + + bool process_hidden_amounts = false; + crypto::key_derivation derivation = null_derivation; + if (keys.spend_secret_key != null_skey && keys.view_secret_key != null_skey) + { + process_hidden_amounts = true; + bool r = crypto::generate_key_derivation(get_tx_pub_key_from_extra(tx), keys.view_secret_key, derivation); + if (!r) + LOG_PRINT_YELLOW("generate_key_derivation failed in get_outs_money_amount", LOG_LEVEL_0); + } + + for (size_t output_index = 0; output_index < tx.vout.size(); ++output_index) + { + const auto& o = tx.vout[output_index]; + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE_CONST(tx_out_bare, bo) + outputs_amount += bo.amount; + VARIANT_CASE_CONST(tx_out_zarcanum, zo) + if (process_hidden_amounts) + { + uint64_t decoded_amount = 0; + crypto::public_key decoded_asset_id{}; + crypto::scalar_t amount_blinding_mask{}, asset_id_blinding_mask{}; + if (is_out_to_acc(keys.account_address, zo, derivation, output_index, decoded_amount, decoded_asset_id, amount_blinding_mask, asset_id_blinding_mask)) + { + if (decoded_asset_id == currency::native_coin_asset_id) + outputs_amount += decoded_amount; + } + } + VARIANT_SWITCH_END(); + } + return outputs_amount; } //--------------------------------------------------------------- @@ -1883,18 +3172,19 @@ namespace currency return res; } //--------------------------------------------------------------- - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index) + // out_key.key =?= Hs(derivation || output_index) * G + addr.spend_public_key + bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index) { crypto::public_key pk; - if (!derive_public_key(derivation, output_index, acc.account_address.spend_public_key, pk)) + if (!derive_public_key(derivation, output_index, addr.spend_public_key, pk)) return false; return pk == out_key.key; } //--------------------------------------------------------------- - bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index) + bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index) { crypto::public_key pk; - if (!derive_public_key(derivation, output_index, acc.account_address.spend_public_key, pk)) + if (!derive_public_key(derivation, output_index, addr.spend_public_key, pk)) return false; auto it = std::find(out_multisig.keys.begin(), out_multisig.keys.end(), pk); if (out_multisig.keys.end() == it) @@ -1902,12 +3192,65 @@ namespace currency return true; } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + bool decode_output_amount_and_asset_id(const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, const size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, + crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask, crypto::scalar_t* derived_h_ptr /* = nullptr */) + { + crypto::scalar_t local_h{}; + if (derived_h_ptr == nullptr) + derived_h_ptr = &local_h; + crypto::scalar_t& h = *derived_h_ptr; + + crypto::derivation_to_scalar(derivation, output_index, h.as_secret_key()); // h = Hs(8 * r * V, i) + + crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h); + decoded_amount = zo.encrypted_amount ^ amount_mask.m_u64[0]; + + amount_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_BLINDING_MASK, h); // f = Hs(domain_sep, h) + + crypto::point_t blinded_asset_id = crypto::point_t(zo.blinded_asset_id).modify_mul8(); + crypto::point_t A_prime = decoded_amount * blinded_asset_id + amount_blinding_mask * crypto::c_point_G; // A' * 8 =? a * T + f * G + if (A_prime != crypto::point_t(zo.amount_commitment).modify_mul8()) + return false; + + if (blinded_asset_id == currency::native_coin_asset_id_pt) + { + asset_id_blinding_mask = 0; + decoded_asset_id = currency::native_coin_asset_id; + } + else + { + asset_id_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_ASSET_BLINDING_MASK, h); // f = Hs(domain_sep, d, i) + crypto::point_t asset_id = blinded_asset_id - asset_id_blinding_mask * crypto::c_point_X; // H = T - s * X + decoded_asset_id = asset_id.to_public_key(); + } + + return true; + } + //--------------------------------------------------------------- + bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, + crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask) + { + crypto::scalar_t h{}; + if (!decode_output_amount_and_asset_id(zo, derivation, output_index, decoded_amount, decoded_asset_id, amount_blinding_mask, asset_id_blinding_mask, &h)) + return false; + + crypto::point_t P_prime = h * crypto::c_point_G + crypto::point_t(addr.spend_public_key); // P =? Hs(8rV, i) * G + S + if (P_prime.to_public_key() != zo.stealth_address) + return false; + + crypto::point_t Q_prime = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(addr.view_public_key).modify_mul8(); // Q' * 8 =? Hs(domain_sep, Hs(8 * r * V, i) ) * 8 * V + if (Q_prime != crypto::point_t(zo.concealing_point).modify_mul8()) + return false; + + return true; + } + //--------------------------------------------------------------- + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, crypto::key_derivation& derivation) { crypto::public_key tx_pub_key = get_tx_pub_key_from_extra(tx); if (null_pkey == tx_pub_key) return false; - return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, money_transfered, derivation); + return lookup_acc_outs(acc, tx, get_tx_pub_key_from_extra(tx), outs, derivation); } //--------------------------------------------------------------- bool check_tx_derivation_hint(const transaction& tx, const crypto::key_derivation& derivation) @@ -1935,7 +3278,7 @@ namespace currency return false; } //--------------------------------------------------------------- - bool lookup_acc_outs_genesis(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + bool lookup_acc_outs_genesis(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation) { uint64_t offset = 0; bool r = get_account_genesis_offset_by_address(get_account_address_as_str(acc.account_address), offset); @@ -1943,84 +3286,98 @@ namespace currency return true; CHECK_AND_ASSERT_MES(offset < tx.vout.size(), false, "condition failed: offset(" << offset << ") < tx.vout.size() (" << tx.vout.size() << ")"); - auto& o = tx.vout[offset]; + auto& ov = tx.vout[offset]; + CHECK_AND_ASSERT_MES(ov.type() == typeid(tx_out_bare), false, "unexpected type id in lookup_acc_outs_genesis:" << ov.type().name()); + const tx_out_bare& o = boost::get(ov); + CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "condition failed: o.target.type() == typeid(txout_to_key)"); - if (is_out_to_acc(acc, boost::get(o.target), derivation, offset)) + if (is_out_to_acc(acc.account_address, boost::get(o.target), derivation, offset)) { - outs.push_back(offset); - money_transfered += o.amount; + outs.emplace_back(offset, o.amount); } return true; } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation) { std::list htlc_info_list; - return lookup_acc_outs(acc, tx, tx_pub_key, outs, money_transfered, derivation, htlc_info_list); + return lookup_acc_outs(acc, tx, tx_pub_key, outs, derivation, htlc_info_list); } //--------------------------------------------------------------- - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list& htlc_info_list) + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation, std::list& htlc_info_list) { - money_transfered = 0; bool r = generate_key_derivation(tx_pub_key, acc.view_secret_key, derivation); CHECK_AND_ASSERT_MES(r, false, "unable to generate derivation from tx_pub = " << tx_pub_key << " * view_sec, invalid tx_pub?"); if (is_coinbase(tx) && get_block_height(tx) == 0 && tx_pub_key == ggenesis_tx_pub_key) { //genesis coinbase - return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, money_transfered, derivation); + return lookup_acc_outs_genesis(acc, tx, tx_pub_key, outs, derivation); } if (!check_tx_derivation_hint(tx, derivation)) return true; - size_t i = 0; - for(const tx_out& o : tx.vout) + size_t output_index = 0; + for(const auto& ov : tx.vout) { - if (o.target.type() == typeid(txout_to_key)) + VARIANT_SWITCH_BEGIN(ov); + VARIANT_CASE_CONST(tx_out_bare, o) { - if (is_out_to_acc(acc, boost::get(o.target), derivation, i)) + VARIANT_SWITCH_BEGIN(o.target); + VARIANT_CASE_CONST(txout_to_key, t) + if (is_out_to_acc(acc.account_address, t, derivation, output_index)) + { + outs.emplace_back(output_index, o.amount); + } + VARIANT_CASE_CONST(txout_multisig, t) + if (is_out_to_acc(acc.account_address, t, derivation, output_index)) + { + outs.emplace_back(output_index, o.amount); // TODO: @#@# consider this + //don't cout this money in sum_of_native_outs + } + VARIANT_CASE_CONST(txout_htlc, htlc) + htlc_info hi = AUTO_VAL_INIT(hi); + if (is_out_to_acc(acc.account_address, htlc.pkey_redeem, derivation, output_index)) + { + hi.hltc_our_out_is_before_expiration = true; + htlc_info_list.push_back(hi); + } + else if (is_out_to_acc(acc.account_address, htlc.pkey_refund, derivation, output_index)) + { + hi.hltc_our_out_is_before_expiration = false; + htlc_info_list.push_back(hi); + } + else + { + LOG_ERROR("lookup_acc_outs: handling txout_htlc went wrong, output_index: " << output_index); + return false; + } + outs.emplace_back(output_index, o.amount); + VARIANT_CASE_OTHER() + LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name()); + return false; + VARIANT_SWITCH_END(); + } + VARIANT_CASE_CONST(tx_out_zarcanum, zo) + { + uint64_t amount = 0; + crypto::public_key asset_id{}; + crypto::scalar_t amount_blinding_mask = 0, asset_id_blinding_mask = 0; + if (is_out_to_acc(acc.account_address, zo, derivation, output_index, amount, asset_id, amount_blinding_mask, asset_id_blinding_mask)) { - outs.push_back(i); - money_transfered += o.amount; + crypto::point_t asset_id_pt = crypto::point_t(zo.blinded_asset_id).modify_mul8() - asset_id_blinding_mask * crypto::c_point_X; + crypto::public_key asset_id = asset_id_pt.to_public_key(); + outs.emplace_back(output_index, amount, amount_blinding_mask, asset_id_blinding_mask, asset_id); } } - else if (o.target.type() == typeid(txout_multisig)) - { - if (is_out_to_acc(acc, boost::get(o.target), derivation, i)) - { - outs.push_back(i); - //don't count this money - } - } - else if (o.target.type() == typeid(txout_htlc)) - { - htlc_info hi = AUTO_VAL_INIT(hi); - const txout_htlc& htlc = boost::get(o.target); - if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, i)) - { - hi.hltc_our_out_is_before_expiration = true; - htlc_info_list.push_back(hi); - outs.push_back(i); - } - else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, i)) - { - hi.hltc_our_out_is_before_expiration = false; - htlc_info_list.push_back(hi); - outs.push_back(i); - } - } - else - { - LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name()); - return false; - } - i++; + VARIANT_SWITCH_END(); + output_index++; } return true; } //--------------------------------------------------------------- - bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id) + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id, bool is_in_hardfork4) { if (!is_payment_id_size_ok(payment_id)) return false; @@ -2028,22 +3385,33 @@ namespace currency tx_service_attachment tsa = AUTO_VAL_INIT(tsa); tsa.service_id = BC_PAYMENT_ID_SERVICE_ID; tsa.body = payment_id; + if (is_in_hardfork4) + { + tsa.flags = TX_SERVICE_ATTACHMENT_ENCRYPT_BODY; + } att.push_back(tsa); return true; } - - - //--------------------------------------------------------------- - std::string print_money_brief(uint64_t amount) + bool validate_output_key_legit(const crypto::public_key& k) { - uint64_t remainder = amount % COIN; - amount /= COIN; + if (currency::null_pkey == k) + { + return false; + } + return true; + } + //--------------------------------------------------------------- + std::string print_money_brief(uint64_t amount, size_t decimal_point /* = CURRENCY_DISPLAY_DECIMAL_POINT */) + { + uint64_t coin = decimal_point == CURRENCY_DISPLAY_DECIMAL_POINT ? COIN : crypto::constexpr_pow(decimal_point, 10); + uint64_t remainder = amount % coin; + amount /= coin; if (remainder == 0) return std::to_string(amount) + ".0"; std::string r = std::to_string(remainder); - if (r.size() < CURRENCY_DISPLAY_DECIMAL_POINT) - r.insert(0, CURRENCY_DISPLAY_DECIMAL_POINT - r.size(), '0'); + if (r.size() < decimal_point) + r.insert(0, decimal_point - r.size(), '0'); return std::to_string(amount) + '.' + r.substr(0, r.find_last_not_of('0') + 1); } //--------------------------------------------------------------- @@ -2109,9 +3477,8 @@ namespace currency return median_fee * 10; } //--------------------------------------------------------------- - // NOTE: this function is obsolete and depricated - // PoS block real timestamp is set using a service attachment in mining tx extra since 2021-10 - uint64_t get_actual_timestamp(const block& b) + // TODO: remove this function after HF4 -- sowle + uint64_t get_block_timestamp_from_miner_tx_extra(const block& b) { uint64_t tes_ts = b.timestamp; if (is_pos_block(b)) @@ -2403,47 +3770,32 @@ namespace currency return res; } //--------------------------------------------------------------- - std::vector absolute_output_offsets_to_relative(const std::vector& off) + bool absolute_sorted_output_offsets_to_relative_in_place(std::vector& offsets) noexcept { - std::vector res = off; - if (off.size() < 2) - return res; + if (offsets.size() < 2) + return true; - std::sort(res.begin(), res.end(), [](const txout_ref_v& lft, const txout_ref_v& rght) - { - if (lft.type() == typeid(uint64_t)) - { - if (rght.type() == typeid(uint64_t)) - return boost::get(lft) < boost::get(rght); - else if (rght.type() == typeid(ref_by_id)) - return true; - else - LOG_ERROR("Unknown type in txout_v"); - } - else if (lft.type() == typeid(ref_by_id)) - { - if (rght.type() == typeid(uint64_t)) - return false; - else if (rght.type() == typeid(ref_by_id)) - return false; // don't change the order of ref_by_id elements - else - LOG_ERROR("Unknown type in txout_v"); - } - return false; - });//just to be sure, actually it is already should be sorted - - //find starter index - skip ref_by_id entries - size_t i = res.size() - 1; - while (i != 0 && res[i].type() == typeid(ref_by_id)) + size_t i = offsets.size() - 1; + while (i != 0 && offsets[i].type() == typeid(ref_by_id)) --i; - for (; i != 0; i--) + try { - boost::get(res[i]) -= boost::get(res[i - 1]); + for (; i != 0; i--) + { + uint64_t& offset_i = boost::get(offsets[i]); + uint64_t& offset_im1 = boost::get(offsets[i - 1]); + if (offset_i <= offset_im1) + return false; // input was not properly sorted + offset_i -= offset_im1; + } + } + catch(...) + { + return false; // unexpected type in boost::get (all ref_by_id's must be at the end of 'offsets') } - - return res; + return true; } //--------------------------------------------------------------- bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b) @@ -2480,21 +3832,40 @@ namespace currency return true; } //--------------------------------------------------------------- - uint64_t get_amount_for_zero_pubkeys(const transaction& tx) + bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt /* = nullptr */) { - uint64_t found_alias_reward = 0; + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + { + uint64_t sum_of_bare_outs_burnt = 0; + for (const auto& out : tx.vout) + { + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, out) + if (out.target.type() != typeid(txout_to_key)) + continue; + const txout_to_key& o = boost::get(out.target); + if (o.key == null_pkey) + sum_of_bare_outs_burnt += out.amount; + VARIANT_SWITCH_END(); + } + if (p_amount_burnt) + *p_amount_burnt = sum_of_bare_outs_burnt; + return sum_of_bare_outs_burnt >= amount; + } + + // post HF-4 txs + // assuming: zero out pubkey, explicit asset_id, zero amount blinding mask + crypto::point_t sum_of_amount_commitments = crypto::c_point_0; for (const auto& out : tx.vout) { - if (out.target.type() != typeid(txout_to_key)) - continue; - - const txout_to_key& o = boost::get(out.target); - if (o.key == null_pkey) - found_alias_reward += out.amount; + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_zarcanum, out_zc) + if (out_zc.stealth_address == null_pkey && out_zc.blinded_asset_id == native_coin_asset_id_1div8) + sum_of_amount_commitments += crypto::point_t(out_zc.amount_commitment).modify_mul8(); + VARIANT_SWITCH_END(); } - return found_alias_reward; + return sum_of_amount_commitments == amount * native_coin_asset_id_pt; } - //--------------------------------------------------------------- bool get_aliases_reward_account(account_public_address& acc) { @@ -2514,210 +3885,7 @@ namespace currency return cnt; } - struct rpc_tx_payload_handler : public boost::static_visitor - { - tx_extra_rpc_entry& tv; - rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t) - {} - bool operator()(const tx_service_attachment& ee) - { - tv.type = "service"; - tv.short_view = ee.service_id + ":" + ee.instruction; - if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY) - tv.short_view += "(encrypted)"; - else - { - std::string deflated_buff; - const std::string* pfinalbuff = &ee.body; - if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) - { - bool r = epee::zlib_helper::unpack(ee.body, deflated_buff); - CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); - pfinalbuff = &deflated_buff; - } - if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID) - tv.datails_view = *pfinalbuff; - else - tv.datails_view = "BINARY DATA"; - } - return true; - } - bool operator()(const tx_crypto_checksum& ee) - { - tv.type = "crypto_checksum"; - tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash); - tv.datails_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n" - + "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation); - - return true; - } - bool operator()(const etc_tx_time& ee) - { - tv.type = "pos_time"; - tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); - return true; - } - bool operator()(const etc_tx_details_unlock_time& ee) - { - tv.type = "unlock_time"; - if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) - tv.short_view = std::string("height: ") + std::to_string(ee.v); - else - tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); - - return true; - } - bool operator()(const etc_tx_details_unlock_time2& ee) - { - tv.type = "unlock_time"; - std::stringstream ss; - ss << "["; - for (auto v : ee.unlock_time_array) - { - ss << " " << v; - } - ss << "]"; - tv.short_view = ss.str(); - - return true; - } - bool operator()(const etc_tx_details_expiration_time& ee) - { - tv.type = "expiration_time"; - if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) - tv.short_view = std::string("height: ") + std::to_string(ee.v); - else - tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); - - return true; - } - bool operator()(const etc_tx_details_flags& ee) - { - tv.type = "details_flags"; - tv.short_view = epee::string_tools::pod_to_hex(ee.v); - return true; - } - bool operator()(const crypto::public_key& ee) - { - tv.type = "pub_key"; - tv.short_view = epee::string_tools::pod_to_hex(ee); - return true; - } - bool operator()(const extra_attachment_info& ee) - { - tv.type = "attachment_info"; - tv.short_view = std::to_string(ee.sz) + " bytes"; - tv.datails_view = currency::obj_to_json_str(ee); - return true; - } - bool operator()(const extra_alias_entry& ee) - { - tv.type = "alias_info"; - tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address); - tv.datails_view = currency::obj_to_json_str(ee); - - return true; - } - bool operator()(const extra_alias_entry_old& ee) - { - return operator()(static_cast(ee)); - } - bool operator()(const extra_user_data& ee) - { - tv.type = "user_data"; - tv.short_view = std::to_string(ee.buff.size()) + " bytes"; - tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff); - - return true; - } - bool operator()(const extra_padding& ee) - { - tv.type = "extra_padding"; - tv.short_view = std::to_string(ee.buff.size()) + " bytes"; - if (!ee.buff.empty()) - tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(&ee.buff[0]), ee.buff.size())); - - return true; - } - bool operator()(const tx_comment& ee) - { - tv.type = "comment"; - tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)"; - tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment); - - return true; - } - bool operator()(const tx_payer& ee) - { - //const tx_payer& ee = boost::get(extra); - tv.type = "payer"; - tv.short_view = "(encrypted)"; - - return true; - } - bool operator()(const tx_payer_old&) - { - tv.type = "payer_old"; - tv.short_view = "(encrypted)"; - - return true; - } - bool operator()(const tx_receiver& ee) - { - //const tx_payer& ee = boost::get(extra); - tv.type = "receiver"; - tv.short_view = "(encrypted)"; - - return true; - } - bool operator()(const tx_receiver_old& ee) - { - tv.type = "receiver_old"; - tv.short_view = "(encrypted)"; - - return true; - } - bool operator()(const tx_derivation_hint& ee) - { - tv.type = "derivation_hint"; - tv.short_view = std::to_string(ee.msg.size()) + " bytes"; - tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg); - - return true; - } - bool operator()(const std::string& ee) - { - tv.type = "string"; - tv.short_view = std::to_string(ee.size()) + " bytes"; - tv.datails_view = epee::string_tools::buff_to_hex_nodelimer(ee); - - return true; - } - bool operator()(const etc_tx_flags16_t& dh) - { - tv.type = "FLAGS16"; - tv.short_view = epee::string_tools::pod_to_hex(dh); - tv.datails_view = epee::string_tools::pod_to_hex(dh); - - return true; - } - }; - //------------------------------------------------------------------ - template - bool fill_tx_rpc_payload_items(std::vector& target_vector, const t_container& tc) - { - //handle extra - for (auto& extra : tc) - { - target_vector.push_back(tx_extra_rpc_entry()); - tx_extra_rpc_entry& tv = target_vector.back(); - - rpc_tx_payload_handler vstr(tv); - boost::apply_visitor(vstr, extra); - } - return true; - } //------------------------------------------------------------------ bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce) { @@ -2725,35 +3893,38 @@ namespace currency for (auto& out : tx.vout) { tei.outs.push_back(tx_out_rpc_entry()); - tei.outs.back().amount = out.amount; tei.outs.back().is_spent = ptce ? ptce->m_spent_flags[i] : false; tei.outs.back().global_index = ptce ? ptce->m_global_output_indexes[i] : 0; + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, out) + { + tei.outs.back().amount = out.amount; - if (out.target.type() == typeid(txout_to_key)) - { - const txout_to_key& otk = boost::get(out.target); - tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.key)); - if (otk.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) - tei.outs.back().pub_keys.back() += "(FORCED_NO_MIX)"; - if (otk.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) - tei.outs.back().pub_keys.back() += std::string("(FORCED_MIX_LOWER_BOUND: ") + std::to_string(otk.mix_attr) + ")"; + VARIANT_SWITCH_BEGIN(out.target); + VARIANT_CASE_CONST(txout_to_key, otk) + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.key)); + if (otk.mix_attr == CURRENCY_TO_KEY_OUT_FORCED_NO_MIX) + tei.outs.back().pub_keys.back() += "(FORCED_NO_MIX)"; + if (otk.mix_attr >= CURRENCY_TO_KEY_OUT_FORCED_MIX_LOWER_BOUND) + tei.outs.back().pub_keys.back() += std::string("(FORCED_MIX_LOWER_BOUND: ") + std::to_string(otk.mix_attr) + ")"; + VARIANT_CASE_CONST(txout_multisig, otm) + for (auto& k : otm.keys) + { + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(k)); + } + tei.outs.back().minimum_sigs = otm.minimum_sigs; + VARIANT_CASE_CONST(txout_htlc, otk) + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.pkey_redeem) + "(htlc_pkey_redeem)"); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.pkey_refund) + "(htlc_pkey_refund)"); + VARIANT_SWITCH_END(); } - else if (out.target.type() == typeid(txout_multisig)) - { - const txout_multisig& otm = boost::get(out.target); - for (auto& k : otm.keys) - { - tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(k)); - } - tei.outs.back().minimum_sigs = otm.minimum_sigs; - } - else if (out.target.type() == typeid(txout_htlc)) - { - const txout_htlc& otk = boost::get(out.target); - tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.pkey_redeem) + "(htlc_pkey_redeem)"); - tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(otk.pkey_refund) + "(htlc_pkey_refund)"); - } - + VARIANT_CASE_CONST(tx_out_zarcanum, o) + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.stealth_address)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.concealing_point)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.amount_commitment)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.blinded_asset_id)); + tei.outs.back().pub_keys.push_back(epee::string_tools::pod_to_hex(o.encrypted_amount)); + VARIANT_SWITCH_END(); ++i; } return true; @@ -2765,43 +3936,48 @@ namespace currency for (auto in : tx.vin) { tei.ins.push_back(tx_in_rpc_entry()); + tx_in_rpc_entry& entry_to_fill = tei.ins.back(); if (in.type() == typeid(txin_gen)) { - tei.ins.back().amount = 0; + entry_to_fill.amount = 0; } - else if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc)) + else if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input)) { //TODO: add htlc info - const txin_to_key& tk = get_to_key_input_from_txin_v(in); - tei.ins.back().amount = tk.amount; - tei.ins.back().kimage_or_ms_id = epee::string_tools::pod_to_hex(tk.k_image); - std::vector absolute_offsets = relative_output_offsets_to_absolute(tk.key_offsets); + entry_to_fill.amount = get_amount_from_variant(in); + entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(get_key_image_from_txin_v(in)); + const std::vector& key_offsets = get_key_offsets_from_txin_v(in); + std::vector absolute_offsets = relative_output_offsets_to_absolute(key_offsets); for (auto& ao : absolute_offsets) { - tei.ins.back().global_indexes.push_back(0); + entry_to_fill.global_indexes.push_back(0); if (ao.type() == typeid(uint64_t)) { - tei.ins.back().global_indexes.back() = boost::get(ao); + entry_to_fill.global_indexes.back() = boost::get(ao); } else// if (ao.type() == typeid(ref_by_id)) { //disable for the reset at the moment - tei.ins.back().global_indexes.back() = std::numeric_limits::max(); + entry_to_fill.global_indexes.back() = std::numeric_limits::max(); } } if (in.type() == typeid(txin_htlc)) { - tei.ins.back().htlc_origin = epee::string_tools::buff_to_hex_nodelimer(boost::get(in).hltc_origin); + entry_to_fill.htlc_origin = epee::string_tools::buff_to_hex_nodelimer(boost::get(in).hltc_origin); } //tk.etc_details -> visualize it may be later } else if (in.type() == typeid(txin_multisig)) { txin_multisig& tms = boost::get(in); - tei.ins.back().amount = tms.amount; - tei.ins.back().kimage_or_ms_id = epee::string_tools::pod_to_hex(tms.multisig_out_id); - if (tx.signatures.size() >= tei.ins.size()) - tei.ins.back().multisig_count = tx.signatures[tei.ins.size() - 1].size(); + entry_to_fill.amount = tms.amount; + entry_to_fill.kimage_or_ms_id = epee::string_tools::pod_to_hex(tms.multisig_out_id); + if (tx.signatures.size() >= tei.ins.size() && + tx.signatures[tei.ins.size() - 1].type() == typeid(NLSAG_sig)) + { + entry_to_fill.multisig_count = boost::get(tx.signatures[tei.ins.size() - 1]).s.size(); + } + } } return true; @@ -2834,38 +4010,22 @@ namespace currency pei_rpc.penalty = (pei_rpc.base_reward + pei_rpc.total_fee) - pei_rpc.summary_reward; return true; } - //--------------------------------------------------------------- - bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short) - { - //tei.blob = tx_ptr->tx - tei.id = epee::string_tools::pod_to_hex(h); - if(!tei.blob_size) - tei.blob_size = get_object_blobsize(tx); - tei.fee = get_tx_fee(tx); - tei.pub_key = epee::string_tools::pod_to_hex(get_tx_pub_key_from_extra(tx)); - tei.timestamp = timestamp; - tei.amount = get_outs_money_amount(tx); - - if (is_short) - return true; - - fill_tx_rpc_inputs(tei, tx); - fill_tx_rpc_outputs(tei, tx, ptce); - fill_tx_rpc_payload_items(tei.extra, tx.extra); - fill_tx_rpc_payload_items(tei.attachments, tx.attachment); - return true; - } //------------------------------------------------------------------ void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices) { for (size_t n = 0; n < tx.vout.size(); ++n) { - if (tx.vout[n].target.type() == typeid(txout_to_key) || tx.vout[n].target.type() == typeid(txout_htlc)) - { - uint64_t amount = tx.vout[n].amount; - gindices[amount] += 1; - } + VARIANT_SWITCH_BEGIN(tx.vout[n]); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_to_key) || o.target.type() == typeid(txout_htlc)) + { + uint64_t amount = o.amount; + gindices[amount] += 1; + } + VARIANT_CASE_CONST(tx_out_zarcanum, o) + //@#@ + VARIANT_SWITCH_END(); } } //--------------------------------------------------------------- @@ -2880,17 +4040,19 @@ namespace currency { if (!(b.flags & CURRENCY_BLOCK_FLAG_POS_BLOCK)) return false; - return is_pos_block(b.miner_tx); + return is_pos_miner_tx(b.miner_tx); } //--------------------------------------------------------------- - bool is_pos_block(const transaction& tx) + bool is_pos_miner_tx(const transaction& tx) { if (tx.vin.size() == 2 && tx.vin[0].type() == typeid(txin_gen) && - tx.vin[1].type() == typeid(txin_to_key)) + (tx.vin[1].type() == typeid(txin_to_key) || + tx.vin[1].type() == typeid(txin_zc_input))) return true; return false; } + //--------------------------------------------------------------- size_t get_max_block_size() { return CURRENCY_MAX_BLOCK_SIZE; @@ -2958,12 +4120,17 @@ namespace currency return true; } //----------------------------------------------------------------------- + bool is_pos_coinbase(const transaction& tx) + { + return is_pos_miner_tx(tx); + } + //----------------------------------------------------------------------- bool is_coinbase(const transaction& tx, bool& pos_coinbase) { if (!is_coinbase(tx)) return false; - pos_coinbase = (tx.vin.size() == 2 && tx.vin[1].type() == typeid(txin_to_key)); + pos_coinbase = is_pos_coinbase(tx); return true; } //----------------------------------------------------------------------- @@ -3183,6 +4350,25 @@ namespace currency return tx_hash_for_signature; } //------------------------------------------------------------------ + const char* get_asset_operation_type_string(size_t asset_operation_type, bool short_name /* = false */) + { + switch(asset_operation_type) + { + case ASSET_DESCRIPTOR_OPERATION_UNDEFINED: + return short_name ? "undefined" : "ASSET_DESCRIPTOR_OPERATION_UNDEFINED"; + case ASSET_DESCRIPTOR_OPERATION_REGISTER: + return short_name ? "register" : "ASSET_DESCRIPTOR_OPERATION_REGISTER"; + case ASSET_DESCRIPTOR_OPERATION_UPDATE: + return short_name ? "update" : "ASSET_DESCRIPTOR_OPERATION_UPDATE"; + case ASSET_DESCRIPTOR_OPERATION_EMIT: + return short_name ? "emit" : "ASSET_DESCRIPTOR_OPERATION_EMIT"; + case ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN: + return short_name ? "burn" : "ASSET_DESCRIPTOR_OPERATION_PUBLIC_BURN"; + default: + return "unknown"; + } + } + //------------------------------------------------------------------ std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig) { std::stringstream s; @@ -3233,10 +4419,11 @@ namespace currency bool operator ==(const currency::transaction& a, const currency::transaction& b) { return currency::get_transaction_hash(a) == currency::get_transaction_hash(b); } - + //-------------------------------------------------------------------------------- bool operator ==(const currency::block& a, const currency::block& b) { return currency::get_block_hash(a) == currency::get_block_hash(b); } + //-------------------------------------------------------------------------------- bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b) { if (a.cnt == b.cnt && a.hsh == b.hsh && a.sz == b.sz) @@ -3244,18 +4431,92 @@ namespace currency else return false; } - - + //-------------------------------------------------------------------------------- + bool operator ==(const currency::NLSAG_sig& a, const currency::NLSAG_sig& b) + { + return a.s == b.s; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::void_sig& a, const currency::void_sig& b) + { + //@#@ + ASSERT_MES_AND_THROW("not implemented yet"); + return false; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::ZC_sig& a, const currency::ZC_sig& b) + { + //@#@ TODO + ASSERT_MES_AND_THROW("not implemented yet"); + return false; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::zarcanum_sig& a, const currency::zarcanum_sig& b) + { + //@#@ TODO + ASSERT_MES_AND_THROW("not implemented yet"); + return false; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::ref_by_id& a, const currency::ref_by_id& b) + { + return a.n == b.n && a.tx_id == b.tx_id; + } + //-------------------------------------------------------------------------------- + bool operator ==(const currency::signed_parts& a, const currency::signed_parts& b) + { + return + a.n_extras == b.n_extras && + a.n_outs == b.n_outs; + } + bool operator ==(const currency::txin_gen& a, const currency::txin_gen& b) + { + return a.height == b.height; + } + bool operator ==(const currency::txin_to_key& a, const currency::txin_to_key& b) + { + return + a.amount == b.amount && + a.etc_details == b.etc_details && + a.key_offsets == b.key_offsets && + a.k_image == b.k_image; + } + bool operator ==(const currency::txin_multisig& a, const currency::txin_multisig& b) + { + return + a.amount == b.amount && + a.etc_details == b.etc_details && + a.multisig_out_id == b.multisig_out_id && + a.sigs_count == b.sigs_count; + } + bool operator ==(const currency::txin_htlc& a, const currency::txin_htlc& b) + { + return + a.amount == b.amount && + a.etc_details == b.etc_details && + a.hltc_origin == b.hltc_origin && + a.key_offsets == b.key_offsets && + a.k_image == b.k_image; + } + bool operator ==(const currency::txin_zc_input& a, const currency::txin_zc_input& b) + { + return + a.etc_details == b.etc_details && + a.key_offsets == b.key_offsets && + a.k_image == b.k_image; + } + //-------------------------------------------------------------------------------- boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point, const wide_difficulty_type& difficulty_pow_at_split_point, const difficulties& a_diff, const difficulties& b_diff ) { - static const wide_difficulty_type difficulty_starter = DIFFICULTY_STARTER; - const wide_difficulty_type& a_pos_cumulative_difficulty = a_diff.pos_diff > 0 ? a_diff.pos_diff : difficulty_starter; - const wide_difficulty_type& b_pos_cumulative_difficulty = b_diff.pos_diff > 0 ? b_diff.pos_diff : difficulty_starter; - const wide_difficulty_type& a_pow_cumulative_difficulty = a_diff.pow_diff > 0 ? a_diff.pow_diff : difficulty_starter; - const wide_difficulty_type& b_pow_cumulative_difficulty = b_diff.pow_diff > 0 ? b_diff.pow_diff : difficulty_starter; + static const wide_difficulty_type difficulty_pos_starter = DIFFICULTY_POS_STARTER; + static const wide_difficulty_type difficulty_pow_starter = DIFFICULTY_POW_STARTER; + const wide_difficulty_type& a_pos_cumulative_difficulty = a_diff.pos_diff > 0 ? a_diff.pos_diff : difficulty_pos_starter; + const wide_difficulty_type& b_pos_cumulative_difficulty = b_diff.pos_diff > 0 ? b_diff.pos_diff : difficulty_pos_starter; + const wide_difficulty_type& a_pow_cumulative_difficulty = a_diff.pow_diff > 0 ? a_diff.pow_diff : difficulty_pow_starter; + const wide_difficulty_type& b_pow_cumulative_difficulty = b_diff.pow_diff > 0 ? b_diff.pow_diff : difficulty_pow_starter; boost::multiprecision::uint1024_t basic_sum = boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty) + (boost::multiprecision::uint1024_t(a_pos_cumulative_difficulty)*difficulty_pow_at_split_point) / difficulty_pos_at_split_point; boost::multiprecision::uint1024_t res = @@ -3277,6 +4538,51 @@ namespace currency return res; CATCH_ENTRY_WITH_FORWARDING_EXCEPTION(); } + //-------------------------------------------------------------------------------- + // Note: we adjust formula and introduce multiplier, + // that let us never dive into floating point calculations (which we can't use in consensus) + // this multiplier should be greater than max multiprecision::uint128_t power 2 + + boost::multiprecision::uint1024_t get_adjuster_for_fork_choice_rule_hf4() + { + return boost::multiprecision::uint1024_t(std::numeric_limits::max()) * 10 * std::numeric_limits::max(); + } + + const boost::multiprecision::uint1024_t adjusting_multiplier = get_adjuster_for_fork_choice_rule_hf4(); + + boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty_hf4(const wide_difficulty_type& difficulty_pos_at_split_point, + const wide_difficulty_type& difficulty_pow_at_split_point, + const difficulties& a_diff, + const difficulties& b_diff) + { + static const wide_difficulty_type difficulty_pos_starter = DIFFICULTY_POS_STARTER; + static const wide_difficulty_type difficulty_pow_starter = DIFFICULTY_POW_STARTER; + const wide_difficulty_type& a_pos_cumulative_difficulty = a_diff.pos_diff > 0 ? a_diff.pos_diff : difficulty_pos_starter; + const wide_difficulty_type& b_pos_cumulative_difficulty = b_diff.pos_diff > 0 ? b_diff.pos_diff : difficulty_pos_starter; + const wide_difficulty_type& a_pow_cumulative_difficulty = a_diff.pow_diff > 0 ? a_diff.pow_diff : difficulty_pow_starter; + const wide_difficulty_type& b_pow_cumulative_difficulty = b_diff.pow_diff > 0 ? b_diff.pow_diff : difficulty_pow_starter; + + boost::multiprecision::uint1024_t basic_sum_ = boost::multiprecision::uint1024_t(a_pow_cumulative_difficulty) + (boost::multiprecision::uint1024_t(a_pos_cumulative_difficulty)*difficulty_pow_at_split_point) / difficulty_pos_at_split_point; + boost::multiprecision::uint1024_t basic_sum_pow_minus2 = adjusting_multiplier /(basic_sum_ * basic_sum_); + boost::multiprecision::uint1024_t res = + (basic_sum_pow_minus2 * a_pow_cumulative_difficulty * a_pos_cumulative_difficulty) / (boost::multiprecision::uint1024_t(b_pow_cumulative_difficulty)*b_pos_cumulative_difficulty); + + // if (res > boost::math::tools::max_value()) + // { + // ASSERT_MES_AND_THROW("[INTERNAL ERROR]: Failed to get_a_to_b_relative_cumulative_difficulty, res = " << res << ENDL + // << ", difficulty_pos_at_split_point: " << difficulty_pos_at_split_point << ENDL + // << ", difficulty_pow_at_split_point:" << difficulty_pow_at_split_point << ENDL + // << ", a_pos_cumulative_difficulty:" << a_pos_cumulative_difficulty << ENDL + // << ", b_pos_cumulative_difficulty:" << b_pos_cumulative_difficulty << ENDL + // << ", a_pow_cumulative_difficulty:" << a_pow_cumulative_difficulty << ENDL + // << ", b_pow_cumulative_difficulty:" << b_pow_cumulative_difficulty << ENDL + // ); + // } + TRY_ENTRY(); + // wide_difficulty_type short_res = res.convert_to(); + return res; + CATCH_ENTRY_WITH_FORWARDING_EXCEPTION(); + } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 725b39e1..73acd76e 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2023 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Copyright (c) 2012-2013 The Boolberry developers @@ -29,6 +29,9 @@ #include "currency_format_utils_transactions.h" #include "core_runtime_config.h" #include "wallet/wallet_public_structs_defs.h" +#include "bc_attachments_helpers.h" +#include "bc_payments_id_service.h" +#include "bc_offers_service_basic.h" // ------ get_tx_type_definition ------------- @@ -53,11 +56,6 @@ namespace currency { - bool operator ==(const currency::transaction& a, const currency::transaction& b); - bool operator ==(const currency::block& a, const currency::block& b); - bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b); - - typedef boost::multiprecision::uint128_t uint128_tl; @@ -68,6 +66,7 @@ namespace currency extra_alias_entry m_alias; std::string m_user_data_blob; extra_attachment_info m_attachment_info; + asset_descriptor_operation m_asset_operation; }; //--------------------------------------------------------------------------------------------------------------- @@ -135,11 +134,15 @@ namespace currency END_KV_SERIALIZE_MAP() }; - struct htlc_info - { - bool hltc_our_out_is_before_expiration; - }; + struct htlc_info + { + bool hltc_our_out_is_before_expiration; + }; + struct thirdparty_sign_handler + { + virtual bool sign(const crypto::hash& h, const crypto::public_key& owner_public_key, crypto::generic_schnorr_sig& sig); + }; struct finalize_tx_param { @@ -156,6 +159,17 @@ namespace currency std::vector prepared_destinations; uint64_t expiration_time; crypto::public_key spend_pub_key; // only for validations + uint64_t tx_version; + uint64_t mode_separate_fee = 0; + + epee::misc_utils::events_dispatcher* pevents_dispatcher; + tx_generation_context gen_context{}; // solely for consolidated txs + + //crypto::secret_key asset_control_key = currency::null_skey; + crypto::public_key ado_current_asset_owner = null_pkey; + thirdparty_sign_handler* pthirdparty_sign_handler = nullptr; + mutable bool need_to_generate_ado_proof = false; + BEGIN_SERIALIZE_OBJECT() FIELD(unlock_time) @@ -171,6 +185,14 @@ namespace currency FIELD(prepared_destinations) FIELD(expiration_time) FIELD(spend_pub_key) + FIELD(tx_version) + FIELD(mode_separate_fee) + if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE) + { + FIELD(gen_context); + } + FIELD(ado_current_asset_owner) + FIELD(need_to_generate_ado_proof) END_SERIALIZE() }; @@ -181,6 +203,8 @@ namespace currency finalize_tx_param ftp; std::string htlc_origin; std::vector> outs_key_images; // pairs (out_index, key_image) for each change output + crypto::key_derivation derivation; + bool was_not_prepared = false; // true if tx was not prepared/created for some good reason (e.g. not enough outs for UTXO defragmentation tx). Because we decided not to throw exceptions for non-error cases. -- sowle BEGIN_SERIALIZE_OBJECT() FIELD(tx) @@ -188,37 +212,94 @@ namespace currency FIELD(ftp) FIELD(htlc_origin) FIELD(outs_key_images) + FIELD(derivation) + FIELD(was_not_prepared) END_SERIALIZE() }; + struct wallet_out_info + { + wallet_out_info() = default; + wallet_out_info(size_t index, uint64_t amount) + : index(index) + , amount(amount) + {} + wallet_out_info(size_t index, uint64_t amount, const crypto::scalar_t& amount_blinding_mask, const crypto::scalar_t& asset_id_blinding_mask, const crypto::public_key& asset_id) + : index(index) + , amount(amount) + , amount_blinding_mask(amount_blinding_mask) + , asset_id_blinding_mask(asset_id_blinding_mask) + , asset_id(asset_id) + {} + size_t index = SIZE_MAX; + uint64_t amount = 0; + crypto::scalar_t amount_blinding_mask = 0; + crypto::scalar_t asset_id_blinding_mask = 0; + crypto::public_key asset_id = currency::native_coin_asset_id; // use point_t instead as this is for internal use only? + + bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; } + }; + + + // TODO @#@# consider refactoring to eliminate redundant coping and to imporve performance + struct zc_outs_range_proofs_with_commitments + { + zc_outs_range_proofs_with_commitments(const zc_outs_range_proof& range_proof, const std::vector& amount_commitments) + : range_proof(range_proof) + , amount_commitments(amount_commitments) + {} + zc_outs_range_proofs_with_commitments(const zc_outs_range_proof& range_proof) + : range_proof(range_proof) + {} + zc_outs_range_proof range_proof; + std::vector amount_commitments; + }; + + struct asset_op_verification_context + { + const transaction& tx; + const crypto::hash& tx_id; + const asset_descriptor_operation& ado; + crypto::public_key asset_id = currency::null_pkey; + crypto::point_t asset_id_pt = crypto::c_point_0; + uint64_t amount_to_validate = 0; + std::shared_ptr< const std::list > asset_op_history; + }; + + bool verify_multiple_zc_outs_range_proofs(const std::vector& range_proofs); + bool generate_asset_surjection_proof(const crypto::hash& context_hash, bool has_non_zc_inputs, tx_generation_context& ogc, zc_asset_surjection_proof& result); + bool verify_asset_surjection_proof(const transaction& tx, const crypto::hash& tx_id); + bool generate_tx_balance_proof(const transaction &tx, const crypto::hash& tx_id, const tx_generation_context& ogc, uint64_t block_reward_for_miner_tx, zc_balance_proof& proof); + bool generate_zc_outs_range_proof(const crypto::hash& context_hash, size_t out_index_start, const tx_generation_context& outs_gen_context, + const std::vector& vouts, zc_outs_range_proof& result); + bool check_tx_bare_balance(const transaction& tx, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0); + bool check_tx_balance(const transaction& tx, const crypto::hash& tx_id, uint64_t additional_inputs_amount_and_fees_for_mining_tx = 0); + bool validate_asset_operation_amount_commitment(asset_op_verification_context& context); + const char* get_asset_operation_type_string(size_t asset_operation_type, bool short_name = false); //--------------------------------------------------------------- bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, size_t current_block_size, uint64_t fee, const account_public_address &miner_address, const account_public_address &stakeholder_address, - transaction& tx, - const blobdata& extra_nonce = blobdata(), - size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, - bool pos = false, - const pos_entry& pe = pos_entry()); - - bool construct_miner_tx(size_t height, size_t median_size, const boost::multiprecision::uint128_t& already_generated_coins, - size_t current_block_size, - uint64_t fee, - const std::vector& destinations, - transaction& tx, - const blobdata& extra_nonce = blobdata(), - size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, - bool pos = false, - const pos_entry& pe = pos_entry()); - - + transaction& tx, + uint64_t& block_reward_without_fee, + uint64_t& block_reward, + uint64_t tx_version, + const blobdata& extra_nonce = blobdata(), + size_t max_outs = CURRENCY_MINER_TX_MAX_OUTS, + bool pos = false, + const pos_entry& pe = pos_entry(), + tx_generation_context* ogc_ptr = nullptr, + const keypair* tx_one_time_key_to_use = nullptr, + const std::vector& destinations = std::vector() + ); //--------------------------------------------------------------- uint64_t get_string_uint64_hash(const std::string& str); - bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED); + bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, crypto::scalar_t& asset_blinding_mask, crypto::scalar_t& amount_blinding_mask, crypto::point_t& blinded_asset_id, crypto::point_t& amount_commitment, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED); bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set& deriv_cache, const account_keys& self, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED); + bool validate_alias_name(const std::string& al); bool validate_password(const std::string& password); void get_attachment_extra_info_details(const std::vector& attachment, extra_attachment_info& eai); @@ -227,6 +308,7 @@ namespace currency const std::vector& destinations, const std::vector& attachments, transaction& tx, + uint64_t tx_version, uint64_t unlock_time, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, bool shuffle = true); @@ -236,6 +318,7 @@ namespace currency const std::vector& extra, const std::vector& attachments, transaction& tx, + uint64_t tx_version, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED, @@ -248,6 +331,7 @@ namespace currency const std::vector& extra, const std::vector& attachments, transaction& tx, + uint64_t tx_version, crypto::secret_key& one_time_secret_key, uint64_t unlock_time, const account_public_address& crypt_account, @@ -256,8 +340,10 @@ namespace currency bool shuffle = true, uint64_t flags = 0); + uint64_t get_tx_version(uint64_t tx_expected_block_height, const hard_forks_descriptor& hfd); // returns tx version based on the height of the block where the transaction is expected to be bool construct_tx(const account_keys& sender_account_keys, const finalize_tx_param& param, finalized_tx& result); - + bool get_or_calculate_asset_id(const asset_descriptor_operation& ado, crypto::point_t* p_result_point, crypto::public_key* p_result_pub_key); + const asset_descriptor_base& get_native_coin_asset_descriptor(); bool sign_multisig_input_in_tx(currency::transaction& tx, size_t ms_input_index, const currency::account_keys& keys, const currency::transaction& source_tx, bool *p_is_input_fully_signed = nullptr); @@ -268,32 +354,40 @@ namespace currency bool parse_and_validate_tx_extra(const transaction& tx, crypto::public_key& tx_pub_key); crypto::public_key get_tx_pub_key_from_extra(const transaction& tx); bool add_tx_pub_key_to_extra(transaction& tx, const crypto::public_key& tx_pub_key); + bool add_tx_fee_amount_to_extra(transaction& tx, uint64_t fee, bool make_sure_its_unique = true); bool add_tx_extra_userdata(transaction& tx, const blobdata& extra_nonce); crypto::hash get_multisig_out_id(const transaction& tx, size_t n); - bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); - bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list& htlc_info_list); - bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); + bool decode_output_amount_and_asset_id(const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, const size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask, crypto::scalar_t* derived_h_ptr = nullptr); + bool is_out_to_acc(const account_public_address& addr, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); + bool is_out_to_acc(const account_public_address& addr, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index); + bool is_out_to_acc(const account_public_address& addr, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount, crypto::public_key& decoded_asset_id, crypto::scalar_t& amount_blinding_mask, crypto::scalar_t& asset_id_blinding_mask); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, crypto::key_derivation& derivation, std::list& htlc_info_list); + bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, crypto::key_derivation& derivation); bool get_tx_fee(const transaction& tx, uint64_t & fee); uint64_t get_tx_fee(const transaction& tx); bool derive_ephemeral_key_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral); bool generate_key_image_helper(const account_keys& ack, const crypto::public_key& tx_public_key, size_t real_output_index, keypair& in_ephemeral, crypto::key_image& ki); bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key, crypto::key_derivation& derivation); bool derive_public_key_from_target_address(const account_public_address& destination_addr, const crypto::secret_key& tx_sec_key, size_t index, crypto::public_key& out_eph_public_key); + bool derive_key_pair_from_key_pair(const crypto::public_key& src_pub_key, const crypto::secret_key& src_sec_key, crypto::secret_key& derived_sec_key, crypto::public_key& derived_pub_key, const char(&hs_domain)[32], uint64_t index = 0); + uint16_t get_derivation_hint(const crypto::key_derivation& derivation); + tx_derivation_hint make_tx_derivation_hint_from_uint16(uint16_t hint); + std::string short_hash_str(const crypto::hash& h); - bool is_mixattr_applicable_for_fake_outs_counter(uint8_t mix_attr, uint64_t fake_attr_count); + bool is_mixattr_applicable_for_fake_outs_counter(uint64_t out_tx_version, uint8_t out_mix_attr, uint64_t fake_outputs_count, const core_runtime_config& rtc); bool is_tx_spendtime_unlocked(uint64_t unlock_time, uint64_t current_blockchain_size, uint64_t current_time); crypto::key_derivation get_encryption_key_derivation(bool is_income, const transaction& tx, const account_keys& acc_keys); bool decrypt_payload_items(bool is_income, const transaction& tx, const account_keys& acc_keys, std::vector& decrypted_items); + void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key, crypto::key_derivation& derivation); void encrypt_attachments(transaction& tx, const account_keys& sender_keys, const account_public_address& destination_addr, const keypair& tx_random_key); bool is_derivation_used_to_encrypt(const transaction& tx, const crypto::key_derivation& derivation); bool is_address_like_wrapped(const std::string& addr); void load_wallet_transfer_info_flags(tools::wallet_public::wallet_transfer_info& x); uint64_t get_tx_type(const transaction& tx); - uint64_t get_tx_type_ex(const transaction& tx, tx_out& htlc_out, txin_htlc& htlc_in); - size_t get_multisig_out_index(const std::vector& outs); + uint64_t get_tx_type_ex(const transaction& tx, tx_out_bare& htlc_out, txin_htlc& htlc_in); + size_t get_multisig_out_index(const std::vector& outs); size_t get_multisig_in_index(const std::vector& inputs); uint64_t get_reward_from_miner_tx(const transaction& tx); @@ -304,7 +398,7 @@ namespace currency bool parse_and_validate_block_from_blob(const blobdata& b_blob, block& b); uint64_t get_inputs_money_amount(const transaction& tx); bool get_inputs_money_amount(const transaction& tx, uint64_t& money); - uint64_t get_outs_money_amount(const transaction& tx); + uint64_t get_outs_money_amount(const transaction& tx, const currency::account_keys& acc_keys_for_hidden_amounts = currency::null_acc_keys); bool check_inputs_types_supported(const transaction& tx); bool check_outs_valid(const transaction& tx); bool parse_amount(uint64_t& amount, const std::string& str_amount); @@ -325,29 +419,31 @@ namespace currency uint64_t get_block_height(const transaction& coinbase); uint64_t get_block_height(const block& b); std::vector relative_output_offsets_to_absolute(const std::vector& off); - std::vector absolute_output_offsets_to_relative(const std::vector& off); + bool absolute_sorted_output_offsets_to_relative_in_place(std::vector& offsets) noexcept; + + bool validate_output_key_legit(const crypto::public_key& k); // prints amount in format "3.14", "0.0" - std::string print_money_brief(uint64_t amount); - uint64_t get_actual_timestamp(const block& b); // obsolete and depricated, use get_block_datetime + std::string print_money_brief(uint64_t amount, size_t decimal_point = CURRENCY_DISPLAY_DECIMAL_POINT); + uint64_t get_block_timestamp_from_miner_tx_extra(const block& b); // remove this function after HF4 -- sowle uint64_t get_block_datetime(const block& b); void set_block_datetime(uint64_t datetime, block& b); bool addendum_to_hexstr(const std::vector& add, std::string& hex_buff); bool hexstr_to_addendum(const std::string& hex_buff, std::vector& add); - bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id); + bool set_payment_id_to_tx(std::vector& att, const std::string& payment_id, bool is_in_hardfork4 = false); bool add_padding_to_tx(transaction& tx, size_t count); bool is_service_tx(const transaction& tx); bool does_tx_have_only_mixin_inputs(const transaction& tx); + uint64_t get_hf4_inputs_key_offsets_count(const transaction& tx); bool is_showing_sender_addres(const transaction& tx); - uint64_t get_amount_for_zero_pubkeys(const transaction& tx); - //std::string get_comment_from_tx(const transaction& tx); + bool check_native_coins_amount_burnt_in_outs(const transaction& tx, const uint64_t amount, uint64_t* p_amount_burnt = nullptr); std::string print_stake_kernel_info(const stake_kernel& sk); std::string dump_ring_sig_data(const crypto::hash& hash_for_sig, const crypto::key_image& k_image, const std::vector& output_keys_ptrs, const std::vector& sig); //PoS bool is_pos_block(const block& b); - bool is_pos_block(const transaction& tx); + bool is_pos_miner_tx(const transaction& tx); wide_difficulty_type correct_difficulty_with_sequence_factor(size_t sequence_factor, wide_difficulty_type diff); void print_currency_details(); std::string print_reward_change_first_blocks(size_t n_of_first_blocks); @@ -357,31 +453,56 @@ namespace currency update_alias_rpc_details alias_info_to_rpc_update_alias_info(const currency::extra_alias_entry& ai, const std::string& old_address); size_t get_service_attachments_count_in_tx(const transaction& tx); bool fill_tx_rpc_outputs(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce); - bool fill_tx_rpc_inputs(tx_rpc_extended_info& tei, const transaction& tx); - bool fill_tx_rpc_details(tx_rpc_extended_info& tei, const transaction& tx, const transaction_chain_entry* ptce, const crypto::hash& h, uint64_t timestamp, bool is_short = false); + bool fill_block_rpc_details(block_rpc_extended_info& pei_rpc, const block_extended_info& bei_chain, const crypto::hash& h); void append_per_block_increments_for_tx(const transaction& tx, std::unordered_map& gindices); std::string get_word_from_timstamp(uint64_t timestamp, bool use_password); + uint64_t get_timstamp_from_word(std::string word, bool& password_used, const std::string& buff); uint64_t get_timstamp_from_word(std::string word, bool& password_used); + bool parse_vote(const std::string& buff, std::list>& votes); + std::string generate_origin_for_htlc(const txout_htlc& htlc, const account_keys& acc_keys); + bool validate_ado_update_allowed(const asset_descriptor_base& a, const asset_descriptor_base& b); + + + void normalize_asset_operation_for_hashing(asset_descriptor_operation& op); + crypto::hash get_signature_hash_for_asset_operation(const asset_descriptor_operation& ado); + template typename std::conditional::value, const std::vector, std::vector >::type& get_txin_etc_options(t_txin_v& in) { static typename std::conditional::value, const std::vector, std::vector >::type stub; - - //static stub; - if (in.type() == typeid(txin_to_key)) return boost::get(in).etc_details; - else if (in.type() == typeid(txin_htlc)) - return boost::get(in).etc_details; else if (in.type() == typeid(txin_multisig)) return boost::get(in).etc_details; - else + else if (in.type() == typeid(txin_htlc)) + return boost::get(in).etc_details; + else if (in.type() == typeid(txin_zc_input)) + return boost::get(in).etc_details; + else return stub; } + template + inline bool is_out_burned(const out_t& out) { CHECK_AND_ASSERT_THROW_MES(false, "incorrect out type: " << typeid(out).name()); } + template<> + inline bool is_out_burned(const txout_to_key& o) { return o.key == null_pkey; } + template<> + inline bool is_out_burned(const tx_out_zarcanum& o) { return o.stealth_address == null_pkey; } + struct zz_is_out_burned_helper_visitor : boost::static_visitor + { + template + bool operator()(const T& v) const { return is_out_burned(v); } + }; + template<> + inline bool is_out_burned(const txout_target_v& v) { return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v); } + template<> + inline bool is_out_burned(const tx_out_v& v) { return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v); } + template<> + inline bool is_out_burned(const tx_out_bare& o) { return is_out_burned(o.target); } + template bool add_attachments_info_to_extra(t_extra_container& extra_container, const std::vector& attachments) { @@ -410,6 +531,7 @@ namespace currency bool parse_payment_id_from_hex_str(const std::string& payment_id_str, payment_id_t& payment_id); bool is_coinbase(const transaction& tx); bool is_coinbase(const transaction& tx, bool& pos_coinbase); + bool is_pos_coinbase(const transaction& tx); bool have_attachment_service_in_container(const std::vector& av, const std::string& service_id, const std::string& instruction); crypto::hash prepare_prefix_hash_for_sign(const transaction& tx, uint64_t in_index, const crypto::hash& tx_id); @@ -472,16 +594,34 @@ namespace currency return true; } //--------------------------------------------------------------- + // outputs "1391306.970000000000" template std::string print_fixed_decimal_point(t_number amount, size_t decimal_point) { return epee::string_tools::print_fixed_decimal_point(amount, decimal_point); } //--------------------------------------------------------------- + // outputs "1391306.97 " template - std::string print_money(t_number amount) + std::string print_fixed_decimal_point_with_trailing_spaces(t_number amount, size_t decimal_point) { - return print_fixed_decimal_point(amount, CURRENCY_DISPLAY_DECIMAL_POINT); + std::string s = epee::string_tools::print_fixed_decimal_point(amount, decimal_point); + for(size_t n = s.size() - 1; n != 0 && s[n] == '0' && s[n-1] != '.'; --n) + s[n] = ' '; + return s; + } + //--------------------------------------------------------------- + template + std::string print_money(t_number amount, uint64_t decimals = CURRENCY_DISPLAY_DECIMAL_POINT) + { + return print_fixed_decimal_point(amount, decimals); + } + //--------------------------------------------------------------- + + template + std::string print_asset_money(t_number amount, size_t decimal_point) + { + return print_fixed_decimal_point(amount, decimal_point); } //--------------------------------------------------------------- template @@ -531,38 +671,8 @@ namespace currency return get_or_add_field_to_variant_vector(extra); } //--------------------------------------------------------------- - template - void update_or_add_field_to_extra(std::vector& variant_container, const variant_type_t& v) - { - for (auto& ev : variant_container) - { - if (ev.type() == typeid(variant_type_t)) - { - boost::get(ev) = v; - return; - } - } - variant_container.push_back(v); - } - //--------------------------------------------------------------- - template - void remove_field_of_type_from_extra(std::vector& variant_container) - { - for (size_t i = 0; i != variant_container.size();) - { - if (variant_container[i].type() == typeid(variant_type_t)) - { - variant_container.erase(variant_container.begin()+i); - } - else - { - i++; - } - } - } - //--------------------------------------------------------------- template - bool get_payment_id_from_tx(const t_container& att, std::string& payment_id) + bool get_payment_id_from_decrypted_container(const t_container& att, std::string& payment_id) { tx_service_attachment sa = AUTO_VAL_INIT(sa); if (bc_services::get_first_service_attachment_by_id(att, BC_PAYMENT_ID_SERVICE_ID, "", sa)) @@ -647,59 +757,136 @@ namespace currency { decompose_amount_into_digits(amount, dust_threshold, chunk_handler, dust_handler, max_output_allowed, CURRENCY_TX_MAX_ALLOWED_OUTS, 0); } + + // num_digits_to_keep -- how many digits to keep in chunks, 0 means all digits + // Ex.: num_digits_to_keep == 3, number_of_outputs == 2 then 1.0 may be decomposed into 0.183 + 0.817 + // num_digits_to_keep == 0, number_of_outputs == 2 then 1.0 may be decomposed into 0.183374827362 + 0.816625172638 + template + void decompose_amount_randomly(uint64_t amount, chunk_handler_t chunk_cb, size_t number_of_outputs = CURRENCY_TX_MIN_ALLOWED_OUTS, size_t num_digits_to_keep = CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP) + { + if (amount < number_of_outputs) + return; + + uint64_t boundary = 1000; + if (num_digits_to_keep != CURRENCY_TX_OUTS_RND_SPLIT_DIGITS_TO_KEEP) + { + boundary = 1; + for(size_t i = 0; i < num_digits_to_keep; ++i) + boundary *= 10; + } + + auto trim_digits_and_add_variance = [boundary, num_digits_to_keep](uint64_t& v){ + if (num_digits_to_keep != 0 && v > 1) + { + uint64_t multiplier = 1; + while(v >= boundary) + { + v /= 10; + multiplier *= 10; + } + v = v / 2 + crypto::rand() % (v + 1); + v *= multiplier; + } + }; + + uint64_t amount_remaining = amount; + for(size_t i = 1; i < number_of_outputs && amount_remaining > 1; ++i) // starting from 1 for one less iteration + { + uint64_t chunk_amount = amount_remaining / (number_of_outputs - i + 1); + trim_digits_and_add_variance(chunk_amount); + amount_remaining -= chunk_amount; + chunk_cb(chunk_amount); + } + chunk_cb(amount_remaining); + } + //--------------------------------------------------------------- + /* inline size_t get_input_expected_signatures_count(const txin_v& tx_in) { struct txin_signature_size_visitor : public boost::static_visitor { - size_t operator()(const txin_gen& /*txin*/) const { return 0; } - size_t operator()(const txin_to_key& txin) const { return txin.key_offsets.size(); } - size_t operator()(const txin_multisig& txin) const { return txin.sigs_count; } - size_t operator()(const txin_htlc& txin) const { return 1; } + size_t operator()(const txin_gen& txin) const { return 0; } + size_t operator()(const txin_to_key& txin) const { return txin.key_offsets.size(); } + size_t operator()(const txin_multisig& txin) const { return txin.sigs_count; } + size_t operator()(const txin_htlc& txin) const { return 1; } + size_t operator()(const txin_zc_input& txin) const { throw std::runtime_error("Not implemented yet"); } }; return boost::apply_visitor(txin_signature_size_visitor(), tx_in); - } + }*/ //--------------------------------------------------------------- - inline const std::vector* get_input_etc_details(const txin_v& in) + inline size_t get_input_expected_signature_size(const txin_v& tx_in, bool last_input_in_separately_signed_tx) { - if (in.type().hash_code() == typeid(txin_to_key).hash_code()) - return &boost::get(in).etc_details; - if (in.type().hash_code() == typeid(txin_htlc).hash_code()) - return &boost::get(in).etc_details; - if (in.type().hash_code() == typeid(txin_multisig).hash_code()) - return &boost::get(in).etc_details; - return nullptr; - } - //--------------------------------------------------------------- - inline std::vector* get_input_etc_details(txin_v& in) - { - if (in.type().hash_code() == typeid(txin_to_key).hash_code()) - return &boost::get(in).etc_details; - if (in.type().hash_code() == typeid(txin_htlc).hash_code()) - return &boost::get(in).etc_details; - if (in.type().hash_code() == typeid(txin_multisig).hash_code()) - return &boost::get(in).etc_details; - return nullptr; - } - //--------------------------------------------------------------- + struct txin_signature_size_visitor : public boost::static_visitor + { + txin_signature_size_visitor(size_t add) : a(add) {} + size_t a; + size_t operator()(const txin_gen& /*txin*/) const { return 0; } + size_t operator()(const txin_to_key& txin) const { return tools::get_varint_packed_size(txin.key_offsets.size() + a) + sizeof(crypto::signature) * (txin.key_offsets.size() + a); } + size_t operator()(const txin_multisig& txin) const { return tools::get_varint_packed_size(txin.sigs_count + a) + sizeof(crypto::signature) * (txin.sigs_count + a); } + size_t operator()(const txin_htlc& txin) const { return tools::get_varint_packed_size(1 + a) + sizeof(crypto::signature) * (1 + a); } + size_t operator()(const txin_zc_input& txin) const { return 97 + tools::get_varint_packed_size(txin.key_offsets.size()) + txin.key_offsets.size() * 32; } + }; + return boost::apply_visitor(txin_signature_size_visitor(last_input_in_separately_signed_tx ? 1 : 0), tx_in); + } + //--------------------------------------------------------------- + template + typename std::conditional::value, const std::vector, std::vector >::type* + get_input_etc_details(txin_t& in) + { + if (in.type() == typeid(txin_to_key)) + return &boost::get(in).etc_details; + if (in.type() == typeid(txin_multisig)) + return &boost::get(in).etc_details; + if (in.type() == typeid(txin_htlc)) + return &boost::get(in).etc_details; + if (in.type() == typeid(txin_zc_input)) + return &boost::get(in).etc_details; + return nullptr; + } + //--------------------------------------------------------------- struct input_amount_getter : public boost::static_visitor { template - uint64_t operator()(const t_input& i) const{return i.amount;} - uint64_t operator()(const txin_gen& i) const {return 0;} + uint64_t operator()(const t_input& i) const { return i.amount; } + uint64_t operator()(const txin_zc_input&) const { return 0; } + uint64_t operator()(const txin_gen& i) const { return 0; } }; - - inline uint64_t get_amount_from_variant(const txin_v& v) + inline uint64_t get_amount_from_variant(const txin_v& v) noexcept { - return boost::apply_visitor(input_amount_getter(), v); + try + { + return boost::apply_visitor(input_amount_getter(), v); + } + catch(...) + { + return 0; + } + } + //--------------------------------------------------------------- + struct output_amount_getter : public boost::static_visitor + { + template + uint64_t operator()(const out_t&) const { return 0; } + uint64_t operator()(const tx_out_bare& ob) const { return ob.amount; } + }; + inline uint64_t get_amount_from_variant(const tx_out_v& out_v) + { + return boost::apply_visitor(output_amount_getter(), out_v); + } + //--------------------------------------------------------------- + inline const tx_out_bare& get_tx_out_bare_from_out_v(const tx_out_v& o) + { + //this function will throw if type is not matching + return boost::get(o); } //--------------------------------------------------------------- template void create_and_add_tx_payer_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc) { - if (top_block_height > crc.hard_fork_02_starts_after_height) + if (crc.is_hardfork_active_for_height(2, top_block_height)) { // after hardfork 2 tx_payer result = AUTO_VAL_INIT(result); @@ -721,7 +908,7 @@ namespace currency template void create_and_add_tx_receiver_to_container_from_address(container_t& container, const account_public_address& addr, uint64_t top_block_height, const core_runtime_config& crc) { - if (top_block_height > crc.hard_fork_02_starts_after_height) + if (crc.is_hardfork_active_for_height(2, top_block_height)) { // after hardfork 2 tx_receiver result = AUTO_VAL_INIT(result); @@ -761,5 +948,243 @@ namespace currency const difficulties& b_diff ); + boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty_hf4(const wide_difficulty_type& difficulty_pos_at_split_point, + const wide_difficulty_type& difficulty_pow_at_split_point, + const difficulties& a_diff, + const difficulties& b_diff + ); + + + struct rpc_tx_payload_handler : public boost::static_visitor + { + tx_extra_rpc_entry& tv; + rpc_tx_payload_handler(tx_extra_rpc_entry& t) : tv(t) + {} + + bool operator()(const tx_service_attachment& ee) + { + tv.type = "service"; + tv.short_view = ee.service_id + ":" + ee.instruction; + if (ee.flags&TX_SERVICE_ATTACHMENT_ENCRYPT_BODY) + tv.short_view += "(encrypted)"; + else + { + std::string deflated_buff; + const std::string* pfinalbuff = &ee.body; + if (ee.flags&TX_SERVICE_ATTACHMENT_DEFLATE_BODY) + { + bool r = epee::zlib_helper::unpack(ee.body, deflated_buff); + CHECK_AND_ASSERT_MES(r, false, "Failed to unpack"); + pfinalbuff = &deflated_buff; + } + if (ee.service_id == BC_PAYMENT_ID_SERVICE_ID || ee.service_id == BC_OFFERS_SERVICE_ID) + tv.details_view = *pfinalbuff; + else + tv.details_view = "BINARY DATA"; + } + return true; + } + bool operator()(const tx_crypto_checksum& ee) + { + tv.type = "crypto_checksum"; + tv.short_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash); + tv.details_view = std::string("derivation_hash: ") + epee::string_tools::pod_to_hex(ee.derivation_hash) + "\n" + + "encrypted_key_derivation: " + epee::string_tools::pod_to_hex(ee.encrypted_key_derivation); + + return true; + } + bool operator()(const etc_tx_time& ee) + { + tv.type = "pos_time"; + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + return true; + } + bool operator()(const etc_tx_details_unlock_time& ee) + { + tv.type = "unlock_time"; + if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) + tv.short_view = std::string("height: ") + std::to_string(ee.v); + else + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + + return true; + } + bool operator()(const etc_tx_details_unlock_time2& ee) + { + tv.type = "unlock_time"; + std::stringstream ss; + ss << "["; + for (auto v : ee.unlock_time_array) + { + ss << " " << v; + } + ss << "]"; + tv.short_view = ss.str(); + + return true; + } + bool operator()(const etc_tx_details_expiration_time& ee) + { + tv.type = "expiration_time"; + if (ee.v < CURRENCY_MAX_BLOCK_NUMBER) + tv.short_view = std::string("height: ") + std::to_string(ee.v); + else + tv.short_view = std::string("timestamp: ") + std::to_string(ee.v) + " " + epee::misc_utils::get_internet_time_str(ee.v); + + return true; + } + bool operator()(const etc_tx_details_flags& ee) + { + tv.type = "details_flags"; + tv.short_view = epee::string_tools::pod_to_hex(ee.v); + return true; + } + bool operator()(const crypto::public_key& ee) + { + tv.type = "pub_key"; + tv.short_view = epee::string_tools::pod_to_hex(ee); + return true; + } + bool operator()(const extra_attachment_info& ee) + { + tv.type = "attachment_info"; + tv.short_view = std::to_string(ee.sz) + " bytes"; + tv.details_view = currency::obj_to_json_str(ee); + return true; + } + bool operator()(const extra_alias_entry& ee) + { + tv.type = "alias_info"; + tv.short_view = ee.m_alias + "-->" + get_account_address_as_str(ee.m_address); + tv.details_view = currency::obj_to_json_str(ee); + + return true; + } + bool operator()(const extra_alias_entry_old& ee) + { + return operator()(static_cast(ee)); + } + bool operator()(const extra_user_data& ee) + { + tv.type = "user_data"; + tv.short_view = std::to_string(ee.buff.size()) + " bytes"; + tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.buff); + + return true; + } + bool operator()(const extra_padding& ee) + { + tv.type = "extra_padding"; + tv.short_view = std::to_string(ee.buff.size()) + " bytes"; + if (!ee.buff.empty()) + tv.details_view = epee::string_tools::buff_to_hex_nodelimer(std::string(reinterpret_cast(&ee.buff[0]), ee.buff.size())); + + return true; + } + bool operator()(const tx_comment& ee) + { + tv.type = "comment"; + tv.short_view = std::to_string(ee.comment.size()) + " bytes(encrypted)"; + tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.comment); + + return true; + } + bool operator()(const tx_payer& ee) + { + //const tx_payer& ee = boost::get(extra); + tv.type = "payer"; + tv.short_view = "(encrypted)"; + + return true; + } + bool operator()(const tx_payer_old&) + { + tv.type = "payer_old"; + tv.short_view = "(encrypted)"; + + return true; + } + bool operator()(const tx_receiver& ee) + { + //const tx_payer& ee = boost::get(extra); + tv.type = "receiver"; + tv.short_view = "(encrypted)"; + + return true; + } + bool operator()(const tx_receiver_old& ee) + { + tv.type = "receiver_old"; + tv.short_view = "(encrypted)"; + + return true; + } + bool operator()(const tx_derivation_hint& ee) + { + tv.type = "derivation_hint"; + tv.short_view = std::to_string(ee.msg.size()) + " bytes"; + tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee.msg); + + return true; + } + bool operator()(const std::string& ee) + { + tv.type = "string"; + tv.short_view = std::to_string(ee.size()) + " bytes"; + tv.details_view = epee::string_tools::buff_to_hex_nodelimer(ee); + + return true; + } + bool operator()(const etc_tx_flags16_t& dh) + { + tv.type = "FLAGS16"; + tv.short_view = epee::string_tools::pod_to_hex(dh); + tv.details_view = epee::string_tools::pod_to_hex(dh); + + return true; + } + bool operator()(const zarcanum_tx_data_v1& ztxd) + { + tv.type = "zarcanum_tx_data_v1"; + tv.short_view = "fee = " + print_money_brief(ztxd.fee); + tv.details_view = tv.short_view; + return true; + } + bool operator()(const zc_outs_range_proof& rp) + { + tv.type = "zc_outs_range_proof"; + // TODO @#@# + //tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count); + return true; + } + bool operator()(const zc_balance_proof& bp) + { + tv.type = "zc_balance_proof"; + return true; + } + template + bool operator()(const t_type& t_t) + { + tv.type = typeid(t_t).name(); + return true; + } + }; + //------------------------------------------------------------------ + + + template + bool fill_tx_rpc_payload_items(std::vector& target_vector, const t_container& tc) + { + //handle extra + for (auto& extra : tc) + { + target_vector.push_back(tx_extra_rpc_entry()); + tx_extra_rpc_entry& tv = target_vector.back(); + + rpc_tx_payload_handler vstr(tv); + boost::apply_visitor(vstr, extra); + } + return true; + } } // namespace currency diff --git a/src/currency_core/currency_format_utils_abstract.h b/src/currency_core/currency_format_utils_abstract.h index 611511fc..11d051b9 100644 --- a/src/currency_core/currency_format_utils_abstract.h +++ b/src/currency_core/currency_format_utils_abstract.h @@ -42,7 +42,7 @@ namespace currency /* */ /************************************************************************/ template - struct array_hasher : std::unary_function + struct array_hasher { std::size_t operator()(const t_array& val) const { @@ -91,22 +91,66 @@ namespace currency ++result; } return result; - } + } //--------------------------------------------------------------- template - bool get_type_in_variant_container(const variant_t_container& av, specific_type_t& a) + specific_type_t* get_type_in_variant_container(variant_t_container& av) { for (auto& ai : av) { if (ai.type() == typeid(specific_type_t)) { - a = boost::get(ai); - return true; + return &boost::get(ai); } } + return nullptr; + } + //--------------------------------------------------------------- + template + bool get_type_in_variant_container(variant_t_container& av, specific_type_t& a) + { + const specific_type_t* pa = get_type_in_variant_container(av); + if (pa) + { + a = *pa; + return true; + } return false; } //--------------------------------------------------------------- + //--------------------------------------------------------------- + template + specific_type_t& get_type_in_variant_container_by_ref(variant_t_container& av) + { + for (auto& ai : av) + { + if (ai.type() == typeid(specific_type_t)) + { + return boost::get(ai); + } + } + ASSERT_MES_AND_THROW("Object with type " << typeid(specific_type_t).name() << " was not found in a container"); + } + //--------------------------------------------------------------- + // if cb returns true, it means "continue", false -- means "stop" + template + bool process_type_in_variant_container(const variant_container_t& av, callback_t& cb, bool return_value_if_none_found = true) + { + bool found = false; + for (auto& ai : av) + { + if (ai.type() == typeid(specific_type_t)) + { + found = true; + if (!cb(boost::get(ai))) + return false; + } + } + if (found) + return true; + return return_value_if_none_found; + } + //--------------------------------------------------------------- // callback should return true to continue iterating through the container template bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb) @@ -131,20 +175,158 @@ namespace currency } //--------------------------------------------------------------- inline - const txin_to_key& get_to_key_input_from_txin_v(const txin_v& in_v) + bool get_key_image_from_txin_v(const txin_v& in_v, crypto::key_image& result) noexcept + { + try + { + if (in_v.type() == typeid(txin_to_key)) + { + result = boost::get(in_v).k_image; + return true; + } + + if (in_v.type() == typeid(txin_htlc)) + { + result = boost::get(in_v).k_image; + return true; + } + + if (in_v.type() == typeid(txin_zc_input)) + { + result = boost::get(in_v).k_image; + return true; + } + } + catch(...) + { + // should never go here, just precaution + } + + return false; + } + //--------------------------------------------------------------- + inline + const crypto::key_image& get_key_image_from_txin_v(const txin_v& in_v) { if (in_v.type() == typeid(txin_to_key)) + return boost::get(in_v).k_image; + + if (in_v.type() == typeid(txin_htlc)) + return boost::get(in_v).k_image; + + if (in_v.type() == typeid(txin_zc_input)) + return boost::get(in_v).k_image; + + CHECK_AND_ASSERT_THROW_MES(false, "[get_key_image_from_txin_v] Wrong type: " << in_v.type().name()); + } + //--------------------------------------------------------------- + inline + const std::vector& get_key_offsets_from_txin_v(const txin_v& in_v) + { + if (in_v.type() == typeid(txin_to_key)) + return boost::get(in_v).key_offsets; + + if (in_v.type() == typeid(txin_htlc)) + return boost::get(in_v).key_offsets; + + if (in_v.type() == typeid(txin_zc_input)) + return boost::get(in_v).key_offsets; + + CHECK_AND_ASSERT_THROW_MES(false, "[get_key_offsets_from_txin_v] Wrong type: " << in_v.type().name()); + } + //--------------------------------------------------------------- + inline + bool get_mix_attr_from_tx_out_v(const tx_out_v& out_v, uint8_t& result) noexcept + { + try { - return boost::get(in_v); + if (out_v.type() == typeid(tx_out_bare)) + { + const tx_out_bare& ob = boost::get(out_v); + if (ob.target.type() == typeid(txout_to_key)) + { + result = boost::get(ob.target).mix_attr; + return true; + } + } + + if (out_v.type() == typeid(tx_out_zarcanum)) + { + result = boost::get(out_v).mix_attr; + return true; + } } - else if (in_v.type() == typeid(txin_htlc)) + catch(...) { - const txin_htlc& in = boost::get(in_v); - return static_cast(in); + // should never go here, just precaution } - else { - ASSERT_MES_AND_THROW("[get_to_key_input_from_txin_v] Wrong type " << in_v.type().name()); + + return false; + } + //--------------------------------------------------------------- + //, txin_htlc, txin_zc_input + inline bool compare_variant_by_types(const txin_multisig& left, const txin_multisig& right) + { + return (left.multisig_out_id < right.multisig_out_id); + } + //--------------------------------------------------------------- + inline bool compare_variant_by_types(const txin_gen& left, const txin_gen& right) + { + //actually this should never happen, should we leave it in case it happen in unit tests? @sowle + return (left.height < right.height); + } + //--------------------------------------------------------------- + template + bool compare_variant_by_types(const type_with_kimage_t& left, const type_with_kimage_t& right) + { + return (left.k_image < right.k_image); + } + //--------------------------------------------------------------- + template + bool compare_variant_by_types(const t_type_left& left, const t_type_right& right) + { + if (typeid(t_type_left) == typeid(t_type_right)) + { + ASSERT_MES_AND_THROW("[compare_varian_by_types] Left and Right types matched type " << typeid(t_type_left).name()); } + typedef binary_archive bin_archive; + typedef variant_serialization_traits traits_left; + typedef variant_serialization_traits traits_right; + return (traits_left::get_tag() < traits_right::get_tag()); + } + //--------------------------------------------------------------- + template + struct right_visitor : public boost::static_visitor + { + const t_type_left& m_rleft; + + right_visitor(const t_type_left& left) : m_rleft(left) + {} + + template + bool operator()(const t_type_right& right)const + { + return compare_variant_by_types(m_rleft, right); + } + }; + + struct left_visitor : public boost::static_visitor + { + const txin_v& m_rright; + + left_visitor(const txin_v& right) : m_rright(right) + {} + template + bool operator()(const t_type_left& left)const + { + return boost::apply_visitor(right_visitor(left), m_rright); + } + }; + //--------------------------------------------------------------- + inline bool less_txin_v(const txin_v& left, const txin_v& right) + { + //predefined type hierarchy based on it's tags defined in currency_basic.h, call compare_variant_by_types via 2-level visitor + return boost::apply_visitor(left_visitor(right), left); } //--------------------------------------------------------------- template @@ -247,6 +429,26 @@ namespace currency size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size); + inline + void put_t_to_buff(std::string& buff) + {} + + template + void put_t_to_buff(std::string& buff, const T& var1, Types&... var2) + { + static_assert(std::is_pod::value, "T must be a POD type."); + buff.append((const char*)&var1, sizeof(var1)); + put_t_to_buff(buff, var2...); + } + + template + crypto::hash get_hash_from_POD_objects(Types&... var1) + { + std::string buff; + put_t_to_buff(buff, var1...); + return crypto::cn_fast_hash(buff.data(), buff.size()); + } + #define CHECKED_GET_SPECIFIC_VARIANT(variant_var, specific_type, variable_name, fail_return_val) \ CHECK_AND_ASSERT_MES(variant_var.type() == typeid(specific_type), fail_return_val, "wrong variant type: " << variant_var.type().name() << ", expected " << typeid(specific_type).name()); \ diff --git a/src/currency_core/currency_format_utils_transactions.cpp b/src/currency_core/currency_format_utils_transactions.cpp index 264f604e..291010a6 100644 --- a/src/currency_core/currency_format_utils_transactions.cpp +++ b/src/currency_core/currency_format_utils_transactions.cpp @@ -8,6 +8,7 @@ #include "serialization/serialization.h" #include "currency_format_utils.h" #include "currency_format_utils_abstract.h" +#include "common/variant_helper.h" namespace currency { @@ -24,6 +25,8 @@ namespace currency //------------------------------------------------------------------ bool is_tx_expired(const transaction& tx, uint64_t expiration_ts_median) { + if (expiration_ts_median == 0) + return false; /// tx expiration condition (tx is ok if the following is true) /// tx_expiration_time - TX_EXPIRATION_MEDIAN_SHIFT > get_last_n_blocks_timestamps_median(TX_EXPIRATION_TIMESTAMP_CHECK_WINDOW) uint64_t expiration_time = get_tx_expiration_time(tx); @@ -37,11 +40,17 @@ namespace currency uint64_t res = 0; for (auto& o : tx.vout) { - if (o.target.type() == typeid(txout_to_key)) - { - if (boost::get(o.target).key == null_pkey) - res += o.amount; - } + VARIANT_SWITCH_BEGIN(o); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_to_key)) + { + if (boost::get(o.target).key == null_pkey) + res += o.amount; + } + VARIANT_CASE_CONST(tx_out_zarcanum, o) + //@#@# TODO obtain info about public burn of native coins in ZC outputs + VARIANT_CASE_THROW_ON_OTHER(); + VARIANT_SWITCH_END(); } return res; } @@ -203,12 +212,35 @@ namespace currency return total; } //--------------------------------------------------------------- + inline size_t get_input_expected_signature_size_local(const txin_v& tx_in, bool last_input_in_separately_signed_tx) + { + struct txin_signature_size_visitor : public boost::static_visitor + { + txin_signature_size_visitor(size_t add) : a(add) {} + size_t a; + size_t operator()(const txin_gen& /*txin*/) const { return 0; } + size_t operator()(const txin_to_key& txin) const { return tools::get_varint_packed_size(txin.key_offsets.size() + a) + sizeof(crypto::signature) * (txin.key_offsets.size() + a); } + size_t operator()(const txin_multisig& txin) const { return tools::get_varint_packed_size(txin.sigs_count + a) + sizeof(crypto::signature) * (txin.sigs_count + a); } + size_t operator()(const txin_htlc& txin) const { return tools::get_varint_packed_size(1 + a) + sizeof(crypto::signature) * (1 + a); } + size_t operator()(const txin_zc_input& txin) const { return 96 + tools::get_varint_packed_size(txin.key_offsets.size()) + txin.key_offsets.size() * 32; } + }; + + return boost::apply_visitor(txin_signature_size_visitor(last_input_in_separately_signed_tx ? 1 : 0), tx_in); + } + //--------------------------------------------------------------- size_t get_object_blobsize(const transaction& t, uint64_t prefix_blob_size) { size_t tx_blob_size = prefix_blob_size; if (is_coinbase(t)) + { + if (is_pos_miner_tx(t) && t.version > TRANSACTION_VERSION_PRE_HF4) + { + // Zarcanum + return tx_blob_size; + } return tx_blob_size; + } // for purged tx, with empty signatures and attachments, this function should return the blob size // which the tx would have if the signatures and attachments were correctly filled with actual data @@ -217,14 +249,13 @@ namespace currency bool separately_signed_tx = get_tx_flags(t) & TX_FLAG_SIGNATURE_MODE_SEPARATE; tx_blob_size += tools::get_varint_packed_size(t.vin.size()); // size of transaction::signatures (equals to total inputs count) + if (t.version > TRANSACTION_VERSION_PRE_HF4) + tx_blob_size += t.vin.size(); // for HF4 txs 'signatures' is a verctor of variants, so it's +1 byte per signature (assuming sigs count equals to inputs count) for (size_t i = 0; i != t.vin.size(); i++) { - size_t sig_count = get_input_expected_signatures_count(t.vin[i]); - if (separately_signed_tx && i == t.vin.size() - 1) - ++sig_count; // count in one more signature for the last input in a complete separately signed tx - tx_blob_size += tools::get_varint_packed_size(sig_count); // size of transaction::signatures[i] - tx_blob_size += sizeof(crypto::signature) * sig_count; // size of signatures' data itself + size_t sig_size = get_input_expected_signature_size_local(t.vin[i], separately_signed_tx && i == t.vin.size() - 1); + tx_blob_size += sig_size; } // 2. attachments (try to find extra_attachment_info in tx prefix and count it in if succeed) @@ -260,16 +291,134 @@ namespace currency bool read_keyimages_from_tx(const transaction& tx, std::list& kil) { std::unordered_set ki; - BOOST_FOREACH(const auto& in, tx.vin) + for(const auto& in : tx.vin) { - if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc)) + if (in.type() == typeid(txin_to_key) || in.type() == typeid(txin_htlc) || in.type() == typeid(txin_zc_input)) { - if (!ki.insert(get_to_key_input_from_txin_v(in).k_image).second) + if (!ki.insert(get_key_image_from_txin_v(in)).second) return false; } } return true; } + //--------------------------------------------------------------- + bool validate_inputs_sorting(const transaction& tx) + { + if (get_tx_flags(tx) & TX_FLAG_SIGNATURE_MODE_SEPARATE) + return true; + + + size_t i = 0; + for(; i+1 < tx.vin.size(); i++) + { + //same less_txin_v() function should be used for sorting inputs during transacction creation + if (less_txin_v(tx.vin[i+1], tx.vin[i])) + { + return false; + } + } + return true; + } + //--------------------------------------------------------------- + bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado /* = nullptr */) + { + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + return false; + + asset_descriptor_operation local_ado{}; + if (p_ado == nullptr) + p_ado = &local_ado; + + if (!get_type_in_variant_container(tx.extra, *p_ado)) + return false; + + if (p_ado->operation_type == ASSET_DESCRIPTOR_OPERATION_REGISTER || p_ado->operation_type == ASSET_DESCRIPTOR_OPERATION_EMIT) + return true; + + return false; + } + //--------------------------------------------------------------- + // Prepapres vector of output_entry to be used in key_offsets in a transaction input: + // 1) sort all entries by gindex (while moving all ref_by_id to the end, keeping they relative order) + // 2) convert absolute global indices to relative key_offsets + std::vector prepare_outputs_entries_for_key_offsets(const std::vector& outputs, size_t old_real_index, size_t& new_real_index) noexcept + { + TRY_ENTRY() + + std::vector result = outputs; + if (outputs.size() < 2) + { + new_real_index = old_real_index; + return result; + } + + std::sort(result.begin(), result.end(), [](const tx_source_entry::output_entry& lhs, const tx_source_entry::output_entry& rhs) + { + if (lhs.out_reference.type() == typeid(uint64_t)) + { + if (rhs.out_reference.type() == typeid(uint64_t)) + return boost::get(lhs.out_reference) < boost::get(rhs.out_reference); + if (rhs.out_reference.type() == typeid(ref_by_id)) + return true; + CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 1: " << rhs.out_reference.type().name()); + } + else if (lhs.out_reference.type() == typeid(ref_by_id)) + { + if (rhs.out_reference.type() == typeid(uint64_t)) + return false; + if (rhs.out_reference.type() == typeid(ref_by_id)) + return false; // don't change the order of ref_by_id elements + CHECK_AND_ASSERT_THROW_MES(false, "unexpected type in out_reference 2: " << rhs.out_reference.type().name()); + } + return false; + }); + + // restore index of the selected element, if needed + if (old_real_index != SIZE_MAX) + { + CHECK_AND_ASSERT_THROW_MES(old_real_index < outputs.size(), "old_real_index is OOB"); + auto it = std::find(result.begin(), result.end(), outputs[old_real_index]); + CHECK_AND_ASSERT_THROW_MES(it != result.end(), "internal error: cannot find old_real_index"); + new_real_index = it - result.begin(); + } + + // find the last uint64_t entry - skip ref_by_id entries goint from the end to the beginnning + size_t i = result.size() - 1; + while (i != 0 && result[i].out_reference.type() == typeid(ref_by_id)) + --i; + + for (; i != 0; i--) + { + boost::get(result[i].out_reference) -= boost::get(result[i - 1].out_reference); + } + + return result; + + CATCH_ENTRY2(std::vector{}); + } + //--------------------------------------------------------------- + bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context) + { + //TODO: Implement this function before mainnet +#ifdef TESTNET + return true; +#else + return true; +#endif + } + + //---------------------------------------------------------------------------------------------------- + std::string transform_tx_to_str(const currency::transaction& tx) + { + return currency::obj_to_json_str(tx); + } + //---------------------------------------------------------------------------------------------------- + transaction transform_str_to_tx(const std::string& tx_str) + { + CHECK_AND_ASSERT_THROW_MES(false, "transform_str_to_tx shoruld never be called"); + return transaction(); + } + } \ No newline at end of file diff --git a/src/currency_core/currency_format_utils_transactions.h b/src/currency_core/currency_format_utils_transactions.h index 337d40d7..aeaa551a 100644 --- a/src/currency_core/currency_format_utils_transactions.h +++ b/src/currency_core/currency_format_utils_transactions.h @@ -1,4 +1,4 @@ -// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2018-2023 Zano Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,26 +16,60 @@ namespace currency { struct tx_source_entry { - typedef serializable_pair output_entry; // txout_v is either global output index or ref_by_id; public_key - is output ephemeral pub key + struct output_entry + { + output_entry() = default; + output_entry(const output_entry &) = default; + output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address) + : out_reference(out_reference), stealth_address(stealth_address), concealing_point(null_pkey), amount_commitment(null_pkey) {} + output_entry(const txout_ref_v& out_reference, const crypto::public_key& stealth_address, const crypto::public_key& concealing_point, const crypto::public_key& amount_commitment, const crypto::public_key& blinded_asset_id) + : out_reference(out_reference), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment), blinded_asset_id(blinded_asset_id) {} - std::vector outputs; //index + key - uint64_t real_output; //index in outputs vector of real output_entry - crypto::public_key real_out_tx_key; //real output's transaction's public key - size_t real_output_in_tx_index; //index in transaction outputs vector - uint64_t amount; //money - uint64_t transfer_index; //money - crypto::hash multisig_id; //if txin_multisig: multisig output id - size_t ms_sigs_count; //if txin_multisig: must be equal to output's minimum_sigs - size_t ms_keys_count; //if txin_multisig: must be equal to size of output's keys container - bool separately_signed_tx_complete; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation - std::string htlc_origin; //for htlc, specify origin + txout_ref_v out_reference; // either global output index or ref_by_id + crypto::public_key stealth_address; // a.k.a output's one-time public key + crypto::public_key concealing_point; // only for ZC outputs + crypto::public_key amount_commitment; // only for ZC outputs + crypto::public_key blinded_asset_id; // only for ZC outputs - bool is_multisig() const { return ms_sigs_count > 0; } + bool operator==(const output_entry& rhs) const { return out_reference == rhs.out_reference; } // used in prepare_outputs_entries_for_key_offsets, it's okay to do partially comparison + + BEGIN_SERIALIZE_OBJECT() + FIELD(out_reference) + FIELD(stealth_address) + FIELD(concealing_point) + FIELD(amount_commitment) + FIELD(blinded_asset_id) + END_SERIALIZE() + }; + + //typedef serializable_pair output_entry; // txout_ref_v is either global output index or ref_by_id; public_key - is output's stealth address + + std::vector outputs; + uint64_t real_output = 0; //index in outputs vector of real output_entry + crypto::public_key real_out_tx_key = currency::null_pkey; //real output's transaction's public key + crypto::scalar_t real_out_amount_blinding_mask = 0; //blinding mask of real out's amount committment (only for ZC inputs, otherwise must be 0) + crypto::scalar_t real_out_asset_id_blinding_mask = 0; //blinding mask of real out's asset_od (only for ZC inputs, otherwise must be 0) + size_t real_output_in_tx_index = 0; //index in transaction outputs vector + uint64_t amount = 0; //money + uint64_t transfer_index = 0; //index in m_transfers + crypto::hash multisig_id = currency::null_hash; //if txin_multisig: multisig output id + size_t ms_sigs_count = 0; //if txin_multisig: must be equal to output's minimum_sigs + size_t ms_keys_count = 0; //if txin_multisig: must be equal to size of output's keys container + bool separately_signed_tx_complete = false; //for separately signed tx only: denotes the last source entry in complete tx to explicitly mark the final step of tx creation + std::string htlc_origin; //for htlc, specify origin + crypto::public_key asset_id = currency::native_coin_asset_id; //asset id (not blinded, not premultiplied by 1/8) TODO @#@# consider changing to crypto::point_t + + bool is_multisig() const { return ms_sigs_count > 0; } + bool is_zc() const { return !real_out_amount_blinding_mask.is_zero(); } + bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; } + uint64_t amount_for_global_output_index() const { return is_zc() ? 0 : amount; } // amount value for global outputs index, it's zero for outputs with hidden amounts BEGIN_SERIALIZE_OBJECT() FIELD(outputs) FIELD(real_output) FIELD(real_out_tx_key) + FIELD(real_out_amount_blinding_mask) + FIELD(real_out_asset_id_blinding_mask) FIELD(real_output_in_tx_index) FIELD(amount) FIELD(transfer_index) @@ -51,8 +85,8 @@ namespace currency //if this struct is present, then creating htlc out, expiration -> number of blocks that htlc proposal is active struct destination_option_htlc_out { - uint64_t expiration; - crypto::hash htlc_hash; + uint64_t expiration = 0; + crypto::hash htlc_hash = currency::null_hash; BEGIN_SERIALIZE_OBJECT() FIELD(expiration) @@ -61,20 +95,34 @@ namespace currency }; + enum tx_destination_entry_flags + { + tdef_none = 0, + tdef_explicit_native_asset_id = 0x0001, + tdef_explicit_amount_to_provide = 0x0002, + tdef_zero_amount_blinding_mask = 0x0004 // currently it's only used for burning native coins + }; + struct tx_destination_entry { - uint64_t amount; //money - std::list addr; //destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig - size_t minimum_sigs; //if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used - uint64_t amount_to_provide; //amount money that provided by initial creator of tx, used with partially created transactions - uint64_t unlock_time; - destination_option_htlc_out htlc_options; //htlc options + uint64_t amount = 0; // money + std::list addr; // destination address, in case of 1 address - txout_to_key, in case of more - txout_multisig + size_t minimum_sigs = 0; // if txout_multisig: minimum signatures that are required to spend this output (minimum_sigs <= addr.size()) IF txout_to_key - not used + uint64_t amount_to_provide = 0; // amount money that provided by initial creator of tx, used with partially created transactions + uint64_t unlock_time = 0; + destination_option_htlc_out htlc_options; // htlc options + crypto::public_key asset_id = currency::native_coin_asset_id; // not blinded, not premultiplied + uint64_t flags = 0; // set of flags (see tx_destination_entry_flags) - - tx_destination_entry() : amount(0), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()){} - tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()) {} - tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), minimum_sigs(0), amount_to_provide(0), unlock_time(ut), htlc_options(destination_option_htlc_out()) {} - tx_destination_entry(uint64_t a, const std::list& addr) : amount(a), addr(addr), minimum_sigs(addr.size()), amount_to_provide(0), unlock_time(0), htlc_options(destination_option_htlc_out()) {} + tx_destination_entry() = default; + tx_destination_entry(uint64_t a, const account_public_address& ad) : amount(a), addr(1, ad) {} + tx_destination_entry(uint64_t a, const account_public_address& ad, const crypto::public_key& aid) : amount(a), addr(1, ad), asset_id(aid) {} + tx_destination_entry(uint64_t a, const account_public_address& ad, uint64_t ut) : amount(a), addr(1, ad), unlock_time(ut) {} + tx_destination_entry(uint64_t a, const std::list& addr) : amount(a), addr(addr), minimum_sigs(addr.size()){} + tx_destination_entry(uint64_t a, const std::list& addr, const crypto::public_key& aid) : amount(a), addr(addr), minimum_sigs(addr.size()), asset_id(aid) {} + + bool is_native_coin() const { return asset_id == currency::native_coin_asset_id; } + BEGIN_SERIALIZE_OBJECT() FIELD(amount) @@ -83,9 +131,41 @@ namespace currency FIELD(amount_to_provide) FIELD(unlock_time) FIELD(htlc_options) + FIELD(asset_id) + FIELD(flags) END_SERIALIZE() }; - + //--------------------------------------------------------------- + template + void update_or_add_field_to_extra(std::vector& variant_container, const variant_type_t& v) + { + for (auto& ev : variant_container) + { + if (ev.type() == typeid(variant_type_t)) + { + boost::get(ev) = v; + return; + } + } + variant_container.push_back(v); + } + //--------------------------------------------------------------- + template + void remove_field_of_type_from_extra(std::vector& variant_container) + { + for (size_t i = 0; i != variant_container.size();) + { + if (variant_container[i].type() == typeid(variant_type_t)) + { + variant_container.erase(variant_container.begin()+i); + } + else + { + i++; + } + } + } + //--------------------------------------------------------------- template uint64_t get_tx_x_detail(const transaction& tx) { @@ -93,6 +173,7 @@ namespace currency get_type_in_variant_container(tx.extra, e); return e.v; } + //--------------------------------------------------------------- template void set_tx_x_detail(transaction& tx, uint64_t v) { @@ -100,7 +181,7 @@ namespace currency e.v = v; update_or_add_field_to_extra(tx.extra, e); } - + //--------------------------------------------------------------- uint64_t get_tx_unlock_time(const transaction& tx, uint64_t o_i); uint64_t get_tx_max_unlock_time(const transaction& tx); bool get_tx_max_min_unlock_time(const transaction& tx, uint64_t& max_unlock_time, uint64_t& min_unlock_time); @@ -128,6 +209,145 @@ namespace currency blobdata tx_to_blob(const transaction& b); bool tx_to_blob(const transaction& b, blobdata& b_blob); bool read_keyimages_from_tx(const transaction& tx, std::list& kil); + bool validate_inputs_sorting(const transaction& tx); + bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado = nullptr); + + std::vector prepare_outputs_entries_for_key_offsets(const std::vector& outputs, size_t old_real_index, size_t& new_real_index) noexcept; -} + struct tx_generation_context + { + tx_generation_context() = default; + + void resize(size_t zc_ins_count, size_t outs_count) + { + asset_ids.resize(outs_count); + blinded_asset_ids.resize(outs_count); + amount_commitments.resize(outs_count); + asset_id_blinding_masks.resize(outs_count); + amounts.resize(outs_count); + amount_blinding_masks.resize(outs_count); + zc_input_amounts.resize(zc_ins_count); + } + + // TODO @#@# reconsider this check -- sowle + bool check_sizes(size_t zc_ins_count, size_t outs_count) const + { + return + pseudo_outs_blinded_asset_ids.size() == zc_ins_count && + asset_ids.size() == outs_count && + blinded_asset_ids.size() == outs_count && + amount_commitments.size() == outs_count && + asset_id_blinding_masks.size() == outs_count && + amounts.size() == outs_count && + amount_blinding_masks.size() == outs_count; + } + + void set_tx_key(const keypair& kp) + { + tx_key = kp; + tx_pub_key_p = crypto::point_t(tx_key.pub); + } + + // per output data + std::vector asset_ids; + std::vector blinded_asset_ids; // generate_zc_outs_range_proof + std::vector amount_commitments; // generate_zc_outs_range_proof construct_tx_out + crypto::scalar_vec_t asset_id_blinding_masks; // construct_tx_out + crypto::scalar_vec_t amounts; // generate_zc_outs_range_proof + crypto::scalar_vec_t amount_blinding_masks; // generate_zc_outs_range_proof + + // per zc input data + std::vector pseudo_outs_blinded_asset_ids; // generate_asset_surjection_proof + crypto::scalar_vec_t pseudo_outs_plus_real_out_blinding_masks; // r_pi + r'_j // generate_asset_surjection_proof + std::vector real_zc_ins_asset_ids; // H_i // generate_asset_surjection_proof + std::vector zc_input_amounts; // ZC only input amounts + + // common data: inputs + crypto::point_t pseudo_out_amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof generate_ZC_sig + crypto::scalar_t pseudo_out_amount_blinding_masks_sum = 0; // generate_ZC_sig + crypto::scalar_t real_in_asset_id_blinding_mask_x_amount_sum = 0; // = sum( real_out_blinding_mask[i] * amount[i] ) generate_tx_balance_proof generate_ZC_sig + + // common data: outputs + crypto::point_t amount_commitments_sum = crypto::c_point_0; // generate_tx_balance_proof + crypto::scalar_t amount_blinding_masks_sum = 0; // construct_tx_out generate_tx_balance_proof generate_ZC_sig + crypto::scalar_t asset_id_blinding_mask_x_amount_sum = 0; // = sum( blinding_mask[j] * amount[j] ) generate_tx_balance_proof + + // data for ongoing asset operation in tx (if applicable, tx extra should contain asset_descriptor_operation) + crypto::public_key ao_asset_id {}; + crypto::point_t ao_asset_id_pt = crypto::c_point_0; + crypto::point_t ao_amount_commitment = crypto::c_point_0; + crypto::scalar_t ao_amount_blinding_mask {}; // generate_tx_balance_proof generate_ZC_sig + bool ao_commitment_in_outputs = false; + + // per tx data + keypair tx_key {}; // + crypto::point_t tx_pub_key_p = crypto::c_point_0; // == tx_key.pub + + // consider redesign, some data may possibly be excluded from kv serialization -- sowle + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_ids) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(blinded_asset_ids) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_commitments) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(asset_id_blinding_masks) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amounts) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(amount_blinding_masks) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_blinded_asset_ids) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(pseudo_outs_plus_real_out_blinding_masks) + KV_SERIALIZE_CONTAINER_POD_AS_BLOB(real_zc_ins_asset_ids) + KV_SERIALIZE(zc_input_amounts) + KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_commitments_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(pseudo_out_amount_blinding_masks_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(real_in_asset_id_blinding_mask_x_amount_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(amount_commitments_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(amount_blinding_masks_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id_blinding_mask_x_amount_sum) + KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id) + KV_SERIALIZE_POD_AS_HEX_STRING(ao_asset_id_pt) + KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_commitment) + KV_SERIALIZE_POD_AS_HEX_STRING(ao_amount_blinding_mask) + KV_SERIALIZE_POD_AS_HEX_STRING(ao_commitment_in_outputs) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_key) + KV_SERIALIZE_POD_AS_HEX_STRING(tx_pub_key_p) + END_KV_SERIALIZE_MAP() + + // solely for consolidated txs, asset opration fields are not serialized + BEGIN_SERIALIZE_OBJECT() + VERSION(0) + FIELD(asset_ids) + FIELD(blinded_asset_ids) + FIELD(amount_commitments) + FIELD((std::vector&)(asset_id_blinding_masks)) + FIELD((std::vector&)(amounts)) + FIELD((std::vector&)(amount_blinding_masks)) + FIELD(pseudo_outs_blinded_asset_ids) + FIELD((std::vector&)(pseudo_outs_plus_real_out_blinding_masks)) + FIELD(real_zc_ins_asset_ids) + FIELD(zc_input_amounts) + FIELD(pseudo_out_amount_commitments_sum) + FIELD(pseudo_out_amount_blinding_masks_sum) + FIELD(real_in_asset_id_blinding_mask_x_amount_sum) + FIELD(amount_commitments_sum) + FIELD(amount_blinding_masks_sum) + FIELD(asset_id_blinding_mask_x_amount_sum) + + // no asset operation fields here + //ao_asset_id + //ao_asset_id_pt + //ao_amount_commitment + //ao_amount_blinding_mask + //ao_commitment_in_outputs + + FIELD(tx_key.pub) // TODO: change to sane serialization FIELD(tx_key) + FIELD(tx_key.sec) + FIELD(tx_pub_key_p) + END_SERIALIZE() + }; // struct tx_generation_context + + bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context); + std::string transform_tx_to_str(const transaction& tx); + transaction transform_str_to_tx(const std::string& tx_str); + + + +} // namespace currency diff --git a/src/currency_core/difficulty.cpp b/src/currency_core/difficulty.cpp index 68d82c15..b0bdfac0 100644 --- a/src/currency_core/difficulty.cpp +++ b/src/currency_core/difficulty.cpp @@ -179,7 +179,7 @@ namespace currency { return res.convert_to(); } - wide_difficulty_type next_difficulty_1(vector& timestamps, vector& cumulative_difficulties, size_t target_seconds) + wide_difficulty_type next_difficulty_1(vector& timestamps, vector& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter) { // timestamps - first is latest, back - is oldest timestamps @@ -194,7 +194,7 @@ namespace currency { CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed"); if (length <= 1) { - return DIFFICULTY_STARTER; + return difficulty_starter; } static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); @@ -221,7 +221,7 @@ namespace currency { return summ / devider; } - wide_difficulty_type next_difficulty_2(vector& timestamps, vector& cumulative_difficulties, size_t target_seconds) + wide_difficulty_type next_difficulty_2(vector& timestamps, vector& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter) { // timestamps - first is latest, back - is oldest timestamps @@ -236,7 +236,7 @@ namespace currency { CHECK_AND_ASSERT_MES(length == cumulative_difficulties.size(), 0, "Check \"length == cumulative_difficulties.size()\" failed"); if (length <= 1) { - return DIFFICULTY_STARTER; + return difficulty_starter; } static_assert(DIFFICULTY_WINDOW >= 2, "Window is too small"); diff --git a/src/currency_core/difficulty.h b/src/currency_core/difficulty.h index ab97f142..731fb26f 100644 --- a/src/currency_core/difficulty.h +++ b/src/currency_core/difficulty.h @@ -19,8 +19,8 @@ namespace currency typedef boost::multiprecision::uint128_t wide_difficulty_type; bool check_hash(const crypto::hash &hash, wide_difficulty_type difficulty); - wide_difficulty_type next_difficulty_1(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds); - wide_difficulty_type next_difficulty_2(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds); + wide_difficulty_type next_difficulty_1(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter); + wide_difficulty_type next_difficulty_2(std::vector& timestamps, std::vector& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter); uint64_t difficulty_to_boundary(wide_difficulty_type difficulty); void difficulty_to_boundary_long(wide_difficulty_type difficulty, crypto::hash& result); } diff --git a/src/currency_core/dispatch_core_events.h b/src/currency_core/dispatch_core_events.h index dadff8b1..19d3df40 100644 --- a/src/currency_core/dispatch_core_events.h +++ b/src/currency_core/dispatch_core_events.h @@ -17,6 +17,7 @@ #define CORE_EVENT_ADD_ALIAS "CORE_EVENT_ADD_ALIAS" #define CORE_EVENT_UPDATE_ALIAS "CORE_EVENT_UPDATE_ALIAS" #define CORE_EVENT_BLOCK_ADDED "CORE_EVENT_BLOCK_ADDED" +#define CORE_EVENT_ADD_ASSET "CORE_EVENT_ADD_ASSET" namespace currency diff --git a/src/currency_core/miner.h b/src/currency_core/miner.h index 69a4bdc7..94caea2b 100644 --- a/src/currency_core/miner.h +++ b/src/currency_core/miner.h @@ -68,7 +68,7 @@ namespace currency crypto::hash h = get_block_longhash(height, bd_hash, bl.nonce); if(check_hash(h, diffic)) { - LOG_PRINT_L0("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << "(diff:" << diffic << "), ts: " << bl.timestamp); + LOG_PRINT_L1("Found nonce for block: " << get_block_hash(bl) << "[" << height << "]: PoW:" << h << " (diff:" << diffic << "), ts: " << bl.timestamp); return true; } } @@ -92,7 +92,7 @@ namespace currency volatile uint32_t m_stop; - ::critical_section m_template_lock; + epee::critical_section m_template_lock; block m_template; std::atomic m_template_no; std::atomic m_starter_nonce; @@ -101,15 +101,15 @@ namespace currency volatile uint32_t m_thread_index; volatile uint32_t m_threads_total; std::atomic m_pausers_count; - ::critical_section m_miners_count_lock; + epee::critical_section m_miners_count_lock; std::list m_threads; - ::critical_section m_threads_lock; + epee::critical_section m_threads_lock; i_miner_handler* m_phandler; //blockchain_storage& m_bc; account_public_address m_mine_address; - math_helper::once_a_time_seconds<5> m_update_block_template_interval; - math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; + epee::math_helper::once_a_time_seconds<5> m_update_block_template_interval; + epee::math_helper::once_a_time_seconds<2> m_update_merge_hr_interval; std::vector m_extra_messages; miner_config m_config; std::string m_config_folder; diff --git a/src/currency_core/offers_service_basics.h b/src/currency_core/offers_service_basics.h index 809bf88b..1dffe367 100644 --- a/src/currency_core/offers_service_basics.h +++ b/src/currency_core/offers_service_basics.h @@ -19,9 +19,9 @@ namespace bc_services { //fields filled in UI - uint8_t offer_type; // OFFER_TYPE_PRIMARY_TO_TARGET(SELL ORDER) - 0, OFFER_TYPE_TARGET_TO_PRIMARY(BUY ORDER) - 1 etc. - uint64_t amount_primary; // amount of the currency - uint64_t amount_target; // amount of other currency or goods + uint8_t offer_type = 0; // OFFER_TYPE_PRIMARY_TO_TARGET(SELL ORDER) - 0, OFFER_TYPE_TARGET_TO_PRIMARY(BUY ORDER) - 1 etc. + uint64_t amount_primary = 0; // amount of the currency + uint64_t amount_target = 0; // amount of other currency or goods std::string bonus; // std::string target; // [] currency / goods std::string primary; // currency for goods @@ -33,7 +33,7 @@ namespace bc_services std::string deal_option; // []full amount, by parts std::string category; // [] std::string preview_url; // [] - uint8_t expiration_time; // n-days + uint8_t expiration_time = 0; // n-days //----------------- BEGIN_KV_SERIALIZE_MAP() diff --git a/src/currency_core/pos_mining.cpp b/src/currency_core/pos_mining.cpp new file mode 100644 index 00000000..5bc1d973 --- /dev/null +++ b/src/currency_core/pos_mining.cpp @@ -0,0 +1,108 @@ +// Copyright (c) 2022 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#include "currency_basic.h" +#include "difficulty.h" +#include "pos_mining.h" +#include "wallet/wallet2.h" +#include "crypto/zarcanum.h" +#include "crypto_config.h" + +namespace currency +{ + void pos_mining_context::init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum) + { + this->basic_diff = pos_diff; + this->sk.stake_modifier = sm; + this->zarcanum = is_zarcanum; + + if (is_zarcanum) + { + this->last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, this->sk.stake_modifier.last_pow_id); + this->z_l_div_z_D = crypto::zarcanum_precalculate_z_l_div_z_D(this->basic_diff); + } + } + + void pos_mining_context::prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index, + const crypto::scalar_t& stake_out_amount_blinding_mask, const crypto::secret_key& view_secret) + { + this->stake_amount = stake_amount; + this->sk.kimage = stake_out_ki; + + if (this->zarcanum) + { + crypto::scalar_t v = view_secret; + crypto::key_derivation derivation = AUTO_VAL_INIT(derivation); + bool r = crypto::generate_key_derivation(stake_source_tx_pub_key, view_secret, derivation); // 8 * v * R + CHECK_AND_ASSERT_MES_NO_RET(r, "generate_key_derivation failed"); + crypto::scalar_t h = AUTO_VAL_INIT(h); + crypto::derivation_to_scalar(derivation, stake_out_in_tx_index, h.as_secret_key()); // h = Hs(8 * v * R, i) + + // q = Hs(domain_sep, Hs(8 * v * R, i) ) * 8 * v + this->secret_q = v * 8 * crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h); + this->stake_out_amount_blinding_mask = stake_out_amount_blinding_mask; + } + } + + bool pos_mining_context::do_iteration(uint64_t ts) + { + // update stake kernel and calculate it's hash + this->sk.block_timestamp = ts; + { + PROFILE_FUNC("calc_hash"); + this->kernel_hash = crypto::cn_fast_hash(&this->sk, sizeof(this->sk)); + } + + bool found = false; + + if (this->zarcanum /* && td.is_zc() */) + { + crypto::mp::uint256_t lhs; + crypto::mp::uint512_t rhs; + { + PROFILE_FUNC("check_zarcanum"); + found = crypto::zarcanum_check_main_pos_inequality(this->kernel_hash, this->stake_out_amount_blinding_mask, this->secret_q, this->last_pow_block_id_hashed, this->z_l_div_z_D, this->stake_amount, lhs, rhs); + } + if (found) + { + found = true; + const boost::multiprecision::uint256_t d_mp = lhs / (crypto::c_zarcanum_z_coeff_mp * this->stake_amount) + 1; + const boost::multiprecision::uint256_t ba = d_mp * crypto::c_zarcanum_z_coeff_mp * this->stake_amount - lhs; + const boost::multiprecision::uint256_t l_div_z_D = this->z_l_div_z_D / crypto::c_zarcanum_z_coeff_mp; + LOG_PRINT_GREEN("Found Zarcanum kernel: amount: " << currency::print_money_brief(this->stake_amount) << /* ", gindex: " << td.m_global_output_index << */ ENDL + << "difficulty: " << this->basic_diff << ENDL + << "kernel info: " << ENDL + << print_stake_kernel_info(this->sk) + << "kernel_hash: " << this->kernel_hash << ENDL + << "lhs: 0x" << crypto::scalar_t(lhs).to_string_as_hex_number() << " = 0x" << std::hex << d_mp << " * 2^64 * " << this->stake_amount << " - 0x" << std::hex << ba << ENDL + << "rhs: 0x" << crypto::scalar_t(rhs).to_string_as_hex_number() << ENDL + << "d: 0x" << std::hex << d_mp << ENDL + << "l / floor(z * D): 0x" << std::hex << l_div_z_D + , LOG_LEVEL_0); + + } + } + else + { + // old PoS with non-hidden amounts + currency::wide_difficulty_type final_diff = this->basic_diff / this->stake_amount; + { + PROFILE_FUNC("check_hash"); + found = currency::check_hash(this->kernel_hash, final_diff); + } + if (found) + { + LOG_PRINT_GREEN("Found kernel: amount: " << currency::print_money_brief(this->stake_amount)<< /* ", gindex: " << td.m_global_output_index << */ ENDL + << "difficulty: " << this->basic_diff << ", final_diff: " << final_diff << ENDL + << "kernel info: " << ENDL + << print_stake_kernel_info(this->sk) + << "kernel_hash(proof): " << this->kernel_hash, + LOG_LEVEL_0); + } + } + + return found; + } + +}; // namespace currency diff --git a/src/currency_core/pos_mining.h b/src/currency_core/pos_mining.h new file mode 100644 index 00000000..ae6baf03 --- /dev/null +++ b/src/currency_core/pos_mining.h @@ -0,0 +1,32 @@ +// Copyright (c) 2022 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#pragma once + +namespace currency +{ + + struct pos_mining_context + { + // Zarcanum notation: + wide_difficulty_type basic_diff; // D + stake_kernel sk; + crypto::scalar_t last_pow_block_id_hashed; // f' + crypto::scalar_t secret_q; // q + boost::multiprecision::uint256_t z_l_div_z_D; // z * floor( l / (z * D) ) (max possible value (assuming z=2^64) : z * 2^252 / (z * 1) ~= 2^252) + crypto::hash kernel_hash; // h + crypto::scalar_t stake_out_amount_blinding_mask; // f + uint64_t stake_amount; // a + + bool zarcanum; // false for pre-HF4 classic PoS with explicit amounts + + void init(const wide_difficulty_type& pos_diff, const stake_modifier_type& sm, bool is_zarcanum); + + void prepare_entry(uint64_t stake_amount, const crypto::key_image& stake_out_ki, const crypto::public_key& stake_source_tx_pub_key, uint64_t stake_out_in_tx_index, + const crypto::scalar_t& stake_out_blinding_mask, const crypto::secret_key& view_secret); + + bool do_iteration(uint64_t ts); + }; + +}; diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp index 581dfdb8..94a69124 100644 --- a/src/currency_core/tx_pool.cpp +++ b/src/currency_core/tx_pool.cpp @@ -21,6 +21,7 @@ #include "crypto/hash.h" #include "profile_tools.h" #include "common/db_backend_selector.h" +#include "tx_semantic_validation.h" DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated name length exceeded, name was truncated @@ -40,6 +41,8 @@ DISABLE_VS_WARNINGS(4244 4345 4503) //'boost::foreach_detail_::or_' : decorated #define LOG_DEFAULT_CHANNEL "tx_pool" ENABLE_CHANNEL_BY_DEFAULT("tx_pool"); +using namespace epee; + namespace currency { //--------------------------------------------------------------------------------- @@ -90,8 +93,23 @@ namespace currency return true; } //--------------------------------------------------------------------------------- + bool tx_memory_pool::check_tx_fee(const transaction &tx, uint64_t amount_fee) + { + if (amount_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee) + return false; + + //m_blockchain.get + return true; + } + //--------------------------------------------------------------------------------- bool tx_memory_pool::add_tx(const transaction &tx, const crypto::hash &id, uint64_t blob_size, tx_verification_context& tvc, bool kept_by_block, bool from_core) - { + { + bool r = false; + + // defaults + tvc.m_added_to_pool = false; + tvc.m_verification_failed = true; + if (!kept_by_block && !from_core && m_blockchain.is_in_checkpoint_zone()) { // BCS is in CP zone, tx verification is impossible until it gets synchronized @@ -102,21 +120,13 @@ namespace currency return false; } - if (!m_blockchain.validate_tx_for_hardfork_specific_terms(tx, id)) - { - // - LOG_ERROR("Transaction " << id <<" doesn't fit current hardfork"); - tvc.m_verification_failed = true; - return false; - } + r = m_blockchain.validate_tx_for_hardfork_specific_terms(tx, id); + CHECK_AND_ASSERT_MES(r, false, "Transaction " << id <<" doesn't fit current hardfork"); TIME_MEASURE_START_PD(tx_processing_time); TIME_MEASURE_START_PD(check_inputs_types_supported_time); - if(!check_inputs_types_supported(tx)) - { - tvc.m_verification_failed = true; - return false; - } + r = check_inputs_types_supported(tx); + CHECK_AND_ASSERT_MES(r, false, "tx " << id << " has wrong inputs types"); TIME_MEASURE_FINISH_PD(check_inputs_types_supported_time); TIME_MEASURE_START_PD(expiration_validate_time); @@ -132,61 +142,60 @@ namespace currency } TIME_MEASURE_FINISH_PD(expiration_validate_time); + TIME_MEASURE_START_PD(validate_amount_time); - uint64_t inputs_amount = 0; - if(!get_inputs_money_amount(tx, inputs_amount)) - { - tvc.m_verification_failed = true; - return false; - } + CHECK_AND_ASSERT_MES(tx.vout.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, "transaction has too many outs = " << tx.vout.size()); - CHECK_AND_ASSERT_MES_CUSTOM(tx.vout.size() <= CURRENCY_TX_MAX_ALLOWED_OUTS, false, tvc.m_verification_failed = true, "transaction has too many outs = " << tx.vout.size()); + uint64_t tx_fee = 0; + r = get_tx_fee(tx, tx_fee); + CHECK_AND_ASSERT_MES(r, false, "get_tx_fee failed"); - uint64_t outputs_amount = get_outs_money_amount(tx); - - if(outputs_amount > inputs_amount) - { - LOG_PRINT_L0("transaction use more money then it has: use " << outputs_amount << ", have " << inputs_amount); - tvc.m_verification_failed = true; - return false; - } + // @#@# consider removing the following + //if (!check_tx_balance(tx)) // TODO (performance): check_tx_balance calls get_tx_fee as well, consider refactoring -- sowle + //{ + // LOG_PRINT_L0("balance check failed for tx " << id); + // tvc.m_verification_failed = true; + // return false; + //} TIME_MEASURE_FINISH_PD(validate_amount_time); TIME_MEASURE_START_PD(validate_alias_time); - if (!from_core && !validate_alias_info(tx, kept_by_block)) - { - LOG_PRINT_RED_L0("validate_alias_info failed"); - tvc.m_verification_failed = true; - return false; - } + r = from_core || validate_alias_info(tx, kept_by_block); + CHECK_AND_ASSERT_MES(r, false, "validate_alias_info failed"); TIME_MEASURE_FINISH_PD(validate_alias_time); TIME_MEASURE_START_PD(check_keyimages_ws_ms_time); //check key images for transaction if it is not kept by block if(!from_core && !kept_by_block) { - crypto::key_image spent_ki = AUTO_VAL_INIT(spent_ki); - if(have_tx_keyimges_as_spent(tx, &spent_ki)) - { - LOG_ERROR("Transaction " << id << " uses already spent key image " << spent_ki); + + if(!validate_tx_semantic(tx, blob_size)) + { + // tx semantics check failed + LOG_PRINT_RED_L0("Transaction " << id << " semantics check failed "); tvc.m_verification_failed = true; + tvc.m_should_be_relayed = false; + tvc.m_added_to_pool = false; return false; } + crypto::key_image spent_ki = AUTO_VAL_INIT(spent_ki); + r = !have_tx_keyimges_as_spent(tx, &spent_ki); + CHECK_AND_ASSERT_MES(r, false, "Transaction " << id << " uses already spent key image " << spent_ki); + //transaction spam protection, soft rule - uint64_t tx_fee = inputs_amount - outputs_amount; - if (tx_fee < m_blockchain.get_core_runtime_config().tx_pool_min_fee) + if (!check_tx_fee(tx, tx_fee)) { - if (is_valid_contract_finalization_tx(tx)) - { + //if (is_valid_contract_finalization_tx(tx)) + //{ // that means tx has less fee then allowed by current tx pull rules, but this transaction is actually // a finalization of contract, and template of this contract finalization tx was prepared actually before // fee rules had been changed, so it's ok, let it in. - } - else + //} + //else { // this tx has no fee - LOG_PRINT_RED_L0("Transaction with id= " << id << " has too small fee: " << tx_fee << ", expected fee: " << m_blockchain.get_core_runtime_config().tx_pool_min_fee); + LOG_PRINT_RED_L0("Transaction " << id << " has too small fee: " << print_money_brief(tx_fee) << ", minimum fee: " << print_money_brief(m_blockchain.get_core_runtime_config().tx_pool_min_fee)); tvc.m_verification_failed = false; tvc.m_should_be_relayed = false; tvc.m_added_to_pool = false; @@ -209,13 +218,13 @@ namespace currency bool ch_inp_res = m_blockchain.check_tx_inputs(tx, id, max_used_block_height, max_used_block_id); if (!ch_inp_res && !kept_by_block && !from_core) { - LOG_PRINT_L0("tx used wrong inputs, rejected"); + LOG_PRINT_L0("check_tx_inputs failed, tx rejected"); tvc.m_verification_failed = true; return false; } TIME_MEASURE_FINISH_PD(check_inputs_time); - do_insert_transaction(tx, id, blob_size, kept_by_block, inputs_amount - outputs_amount, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0); + do_insert_transaction(tx, id, blob_size, kept_by_block, tx_fee, ch_inp_res ? max_used_block_id : null_hash, ch_inp_res ? max_used_block_height : 0); TIME_MEASURE_FINISH_PD(tx_processing_time); tvc.m_added_to_pool = true; @@ -477,10 +486,10 @@ namespace currency should_be_spent_before_height -= CONFLICT_KEY_IMAGE_SPENT_DEPTH_TO_REMOVE_TX_FROM_POOL; for (auto& in : tx_entry.tx.vin) { - if (in.type() == typeid(txin_to_key)) + crypto::key_image ki = AUTO_VAL_INIT(ki); + if (get_key_image_from_txin_v(in, ki)) { // if at least one key image is spent deep enought -- remove such tx - const crypto::key_image& ki = boost::get(in).k_image; if (m_blockchain.have_tx_keyimg_as_spent(ki, should_be_spent_before_height)) { LOG_PRINT_L0("tx " << h << " is about to be removed from tx pool, reason: ki was spent in the blockchain before height " << should_be_spent_before_height << ", tx age: " << misc_utils::get_time_interval_string(tx_age)); @@ -528,7 +537,7 @@ namespace currency txs.push_back(tx_rpc_extended_info()); tx_rpc_extended_info& trei = txs.back(); trei.blob_size = tx_entry.blob_size; - fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true); + m_blockchain.fill_tx_rpc_details(trei, tx_entry.tx, nullptr, h, tx_entry.receive_time, true); return true; }); @@ -580,7 +589,7 @@ namespace currency txs.push_back(tx_rpc_extended_info()); tx_rpc_extended_info& trei = txs.back(); trei.blob_size = ptei->blob_size; - fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); + m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); } return true; } @@ -617,7 +626,7 @@ namespace currency if (!ptei) return false; - fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); + m_blockchain.fill_tx_rpc_details(trei, ptei->tx, nullptr, id, ptei->receive_time, false); return true; } //--------------------------------------------------------------------------------- @@ -707,16 +716,15 @@ namespace currency { for(const auto& in : tx.vin) { - if (in.type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(in, k_image)) { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, true);//should never fail - if (have_tx_keyimg_as_spent(tokey_in.k_image)) + if (have_tx_keyimg_as_spent(k_image)) { if (p_spent_ki) - *p_spent_ki = tokey_in.k_image; + *p_spent_ki = k_image; return true; } - } } return false; @@ -727,13 +735,13 @@ namespace currency CRITICAL_REGION_LOCAL(m_key_images_lock); for(const auto& in : tx.vin) { - if (in.type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(in, k_image)) { - const txin_to_key& tokey_in = boost::get(in); - auto& id_set = m_key_images[tokey_in.k_image]; + auto& id_set = m_key_images[k_image]; size_t sz_before = id_set.size(); id_set.insert(tx_id); - LOG_PRINT_L2("tx pool: key image added: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << sz_before << " -> " << id_set.size()); + LOG_PRINT_L2("tx pool: key image added: " << k_image << ", from tx " << tx_id << ", counter: " << sz_before << " -> " << id_set.size()); } } return false; @@ -787,11 +795,10 @@ namespace currency CRITICAL_REGION_LOCAL(m_key_images_lock); for(const auto& in : tx.vin) { - if (in.type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(in, k_image)) { - const txin_to_key& tokey_in = boost::get(in); - - auto it_map = epee::misc_utils::it_get_or_insert_value_initialized(m_key_images, tokey_in.k_image); + auto it_map = epee::misc_utils::it_get_or_insert_value_initialized(m_key_images, k_image); auto& id_set = it_map->second; size_t count_before = id_set.size(); auto it_set = id_set.find(tx_id); @@ -802,22 +809,22 @@ namespace currency if (id_set.size() == 0) m_key_images.erase(it_map); - LOG_PRINT_L2("tx pool: key image removed: " << tokey_in.k_image << ", from tx " << tx_id << ", counter: " << count_before << " -> " << count_after); + LOG_PRINT_L2("tx pool: key image removed: " << k_image << ", from tx " << tx_id << ", counter: " << count_before << " -> " << count_after); } } return false; } //--------------------------------------------------------------------------------- bool tx_memory_pool::get_key_images_from_tx_pool(key_image_cache& key_images) const - { - + { m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& h, const tx_details &tx_entry) { for (auto& in : tx_entry.tx.vin) { - if (in.type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(in, k_image)) { - key_images[boost::get(in).k_image].insert(h); + key_images[k_image].insert(h); } } return true; @@ -921,10 +928,10 @@ namespace currency LOCAL_READONLY_TRANSACTION(); for(size_t i = 0; i!= tx.vin.size(); i++) { - if (tx.vin[i].type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(tx.vin[i], k_image)) { - CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false); - if (k_images.count(itk.k_image)) + if (k_images.count(k_image)) return true; } } @@ -933,13 +940,13 @@ namespace currency //--------------------------------------------------------------------------------- bool tx_memory_pool::append_key_images(std::unordered_set& k_images, const transaction& tx) { - for(size_t i = 0; i!= tx.vin.size(); i++) + for(size_t i = 0; i != tx.vin.size(); i++) { - if (tx.vin[i].type() == typeid(txin_to_key)) + crypto::key_image k_image = AUTO_VAL_INIT(k_image); + if (get_key_image_from_txin_v(tx.vin[i], k_image)) { - CHECKED_GET_SPECIFIC_VARIANT(tx.vin[i], const txin_to_key, itk, false); - auto i_res = k_images.insert(itk.k_image); - CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << itk.k_image); + auto i_res = k_images.insert(k_image); + CHECK_AND_ASSERT_MES(i_res.second, false, "internal error: key images pool cache - inserted duplicate image in set: " << k_image); } } return true; @@ -959,8 +966,8 @@ namespace currency return "(no transactions, the pool is empty)"; // sort output by receive time txs.sort([](const std::pair& lhs, const std::pair& rhs) -> bool { return lhs.second.receive_time < rhs.second.receive_time; }); - ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL; - // 1234 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES + ss << "# | transaction id | size | fee | ins | outs | outs money | live_time | max used block | last failed block | kept by a block?" << ENDL; + // 1234 f99fe6d4335fc0ddd69e6880a4d95e0f6ea398de0324a6837021a61c6a31cacd 87157 0.10000111 2000 2000 112000.12345678 d0.h10.m16.s17 123456 <12345..> 123456 <12345..> YES size_t i = 0; for (auto& tx : txs) { @@ -1328,8 +1335,11 @@ namespace currency idx = 0; for (const auto& out : tx.vout) { - if (out.target.type() == typeid(txout_multisig)) - result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false })); + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_multisig)) + result.push_back(ms_out_info({ get_multisig_out_id(tx, idx), idx, false })); + VARIANT_SWITCH_END(); ++idx; } } @@ -1345,8 +1355,11 @@ namespace currency size_t idx = 0; for (const auto& out : tx.vout) { - if (out.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id) - return true; + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, o) + if (o.target.type() == typeid(txout_multisig) && get_multisig_out_id(tx, idx) == multisig_id) + return true; + VARIANT_SWITCH_END(); ++idx; } diff --git a/src/currency_core/tx_pool.h b/src/currency_core/tx_pool.h index 4e660a68..4ede52a2 100644 --- a/src/currency_core/tx_pool.h +++ b/src/currency_core/tx_pool.h @@ -6,7 +6,6 @@ #pragma once #include "include_base_utils.h" -using namespace epee; #include @@ -146,6 +145,7 @@ namespace currency bool remove_key_images(const crypto::hash &tx_id, const transaction& tx, bool kept_by_block); bool insert_alias_info(const transaction& tx); bool remove_alias_info(const transaction& tx); + bool check_tx_fee(const transaction &tx, uint64_t amount_fee); bool is_valid_contract_finalization_tx(const transaction &tx)const; void store_db_solo_options_values(); diff --git a/src/currency_core/tx_semantic_validation.cpp b/src/currency_core/tx_semantic_validation.cpp index 252c60be..26d95916 100644 --- a/src/currency_core/tx_semantic_validation.cpp +++ b/src/currency_core/tx_semantic_validation.cpp @@ -21,27 +21,27 @@ namespace currency //----------------------------------------------------------------------------------------------- bool check_tx_inputs_keyimages_diff(const transaction& tx) { - std::unordered_set ki; - BOOST_FOREACH(const auto& in, tx.vin) + std::unordered_set key_images; + crypto::key_image ki{}; + for(const auto& in_v : tx.vin) { - if (in.type() == typeid(txin_to_key)) + if (get_key_image_from_txin_v(in_v, ki)) { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_to_key, tokey_in, false); - if (!ki.insert(tokey_in.k_image).second) - return false; - } - else if (in.type() == typeid(txin_htlc)) - { - CHECKED_GET_SPECIFIC_VARIANT(in, const txin_htlc, htlc_in, false); - if (!ki.insert(htlc_in.k_image).second) + if (!key_images.insert(ki).second) return false; } } return true; } //----------------------------------------------------------------------------------------------- - bool validate_tx_semantic(const transaction& tx, size_t tx_block_size) + bool validate_tx_semantic(const transaction& tx, size_t tx_blob_size) { + if (tx_blob_size >= CURRENCY_MAX_TRANSACTION_BLOB_SIZE) + { + LOG_PRINT_RED_L0("tx blob size is " << tx_blob_size << ", it is greater than or equal to allowed maximum of " << CURRENCY_MAX_TRANSACTION_BLOB_SIZE); + return false; + } + if (!tx.vin.size()) { LOG_PRINT_RED_L0("tx with empty inputs, rejected for tx id= " << get_transaction_hash(tx)); @@ -56,7 +56,7 @@ namespace currency if (!check_outs_valid(tx)) { - LOG_PRINT_RED_L0("tx with invalid outputs, rejected for tx id= " << get_transaction_hash(tx)); + LOG_PRINT_RED_L0("tx has invalid outputs, rejected for tx id= " << get_transaction_hash(tx)); return false; } @@ -66,22 +66,6 @@ namespace currency return false; } - uint64_t amount_in = 0; - get_inputs_money_amount(tx, amount_in); - uint64_t amount_out = get_outs_money_amount(tx); - - if (amount_in < amount_out) - { - LOG_PRINT_RED_L0("tx with wrong amounts: ins " << amount_in << ", outs " << amount_out << ", rejected for tx id= " << get_transaction_hash(tx)); - return false; - } - - if (tx_block_size >= CURRENCY_MAX_TRANSACTION_BLOB_SIZE) - { - LOG_PRINT_RED_L0("tx has too big size " << tx_block_size << ", expected no bigger than " << CURRENCY_BLOCK_GRANTED_FULL_REWARD_ZONE); - return false; - } - //check if tx use different key images if (!check_tx_inputs_keyimages_diff(tx)) { @@ -95,6 +79,17 @@ namespace currency return false; } + // inexpensive check for pre-HF4 txs + // post-HF4 txs balance are being checked in check_tx_balance() + if (tx.version <= TRANSACTION_VERSION_PRE_HF4) + { + if (!check_tx_bare_balance(tx)) + { + LOG_PRINT_RED_L0("balance check failed for tx " << get_transaction_hash(tx)); + return false; + } + } + return true; } } \ No newline at end of file diff --git a/src/currency_core/tx_semantic_validation.h b/src/currency_core/tx_semantic_validation.h index 2e6f4790..03a946c7 100644 --- a/src/currency_core/tx_semantic_validation.h +++ b/src/currency_core/tx_semantic_validation.h @@ -1,16 +1,14 @@ -// Copyright (c) 2018-2019 Zano Project +// Copyright (c) 2018-2023 Zano Project // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. - #pragma once - #include "include_base_utils.h" #include "currency_format_utils_transactions.h" namespace currency { - //check correct values, amounts and all lightweight checks not related with database + //check correct values, ins and outs types, amounts and all lightweight checks not related to the database bool validate_tx_semantic(const transaction& tx, size_t tx_block_size); } diff --git a/src/currency_protocol/currency_protocol_handler.inl b/src/currency_protocol/currency_protocol_handler.inl index 2ec82588..a23e85b5 100644 --- a/src/currency_protocol/currency_protocol_handler.inl +++ b/src/currency_protocol/currency_protocol_handler.inl @@ -107,7 +107,7 @@ namespace currency std::stringstream conn_ss; time_t livetime = time(NULL) - cntxt.m_started; conn_ss << std::setw(29) << std::left << std::string(cntxt.m_is_income ? "[INC]":"[OUT]") + - string_tools::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) + epst::get_ip_string_from_int32(cntxt.m_remote_ip) + ":" + std::to_string(cntxt.m_remote_port) << std::setw(20) << std::hex << peer_id << std::setw(25) << std::to_string(cntxt.m_recv_cnt)+ "(" + std::to_string(time(NULL) - cntxt.m_last_recv) + ")" + "/" + std::to_string(cntxt.m_send_cnt) + "(" + std::to_string(time(NULL) - cntxt.m_last_send) + ")" << std::setw(25) << get_protocol_state_string(cntxt.m_state) @@ -523,7 +523,7 @@ namespace currency if(!parse_and_validate_block_from_blob(block_entry.block, b)) { LOG_ERROR_CCONTEXT("sent wrong block: failed to parse and validate block: \r\n" - << string_tools::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); + << epst::buff_to_hex_nodelimer(block_entry.block) << "\r\n dropping connection"); m_p2p->drop_connection(context); m_p2p->add_ip_fail(context.m_remote_ip); return 1; @@ -547,20 +547,22 @@ namespace currency auto req_it = context.m_priv.m_requested_objects.find(get_block_hash(b)); if(req_it == context.m_priv.m_requested_objects.end()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epst::pod_to_hex(get_blob_hash(block_entry.block)) << " wasn't requested, dropping connection"); m_p2p->drop_connection(context); return 1; } if(b.tx_hashes.size() != block_entry.txs.size()) { - LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << string_tools::pod_to_hex(get_blob_hash(block_entry.block)) + LOG_ERROR_CCONTEXT("sent wrong NOTIFY_RESPONSE_GET_OBJECTS: block with id=" << epst::pod_to_hex(get_blob_hash(block_entry.block)) << ", tx_hashes.size()=" << b.tx_hashes.size() << " mismatch with block_complete_entry.m_txs.size()=" << block_entry.txs.size() << ", dropping connection"); m_p2p->drop_connection(context); return 1; } context.m_priv.m_requested_objects.erase(req_it); + + LOG_PRINT_L4("[NOTIFY_RESPONSE_GET_OBJECTS] BLOCK " << get_block_hash(b) << "[" << get_block_height(b) << "/" << count << "], txs: " << b.tx_hashes.size()); } LOG_PRINT_CYAN("Block parsing time avr: " << (count > 0 ? total_blocks_parsing_time / count : 0) << " mcs, total for " << count << " blocks: " << total_blocks_parsing_time / 1000 << " ms", LOG_LEVEL_2); @@ -575,29 +577,31 @@ namespace currency { m_core.pause_mine(); - misc_utils::auto_scope_leave_caller scope_exit_handler = misc_utils::create_scope_leave_handler( + epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler( boost::bind(&t_core::resume_mine, &m_core)); size_t count = 0; for (const block_complete_entry& block_entry : arg.blocks) { CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Blocks processing interrupted, connection dropped"); - block_verification_context bvc = boost::value_initialized(); //process transactions + size_t count_txs = 0; TIME_MEASURE_START(transactions_process_time); for (const auto& tx_blob : block_entry.txs) { + LOG_PRINT_L4("[NOTIFY_RESPONSE_GET_OBJECTS] BL/TX ["<< count << "/" << count_txs << "]: " << epst::buff_to_hex_nodelimer(tx_blob)); CHECK_STOP_FLAG__DROP_AND_RETURN_IF_SET(1, "Block txs processing interrupted, connection dropped"); crypto::hash tx_id = null_hash; transaction tx = AUTO_VAL_INIT(tx); if (!parse_and_validate_tx_from_blob(tx_blob, tx, tx_id)) { LOG_ERROR_CCONTEXT("failed to parse tx: " - << string_tools::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); + << epst::pod_to_hex(get_blob_hash(tx_blob)) << ", dropping connection"); m_p2p->drop_connection(context); return 1; } bvc.m_onboard_transactions[tx_id] = tx; + count_txs++; // tx_verification_context tvc = AUTO_VAL_INIT(tvc); // m_core.handle_incoming_tx(tx_blob, tvc, true); // if(tvc.m_verification_failed) @@ -742,7 +746,7 @@ namespace currency << "\r\nm_remote_blockchain_height=" << context.m_remote_blockchain_height << "\r\nm_needed_objects.size()=" << context.m_priv.m_needed_objects.size() << "\r\nm_requested_objects.size()=" << context.m_priv.m_requested_objects.size() - << "\r\non connection [" << net_utils::print_connection_context_short(context)<< "]"); + << "\r\non connection [" << epee::net_utils::print_connection_context_short(context)<< "]"); context.m_state = currency_connection_context::state_normal; LOG_PRINT_GREEN("[REQUEST_MISSING_OBJECTS]: SYNCHRONIZED OK", LOG_LEVEL_0); @@ -919,7 +923,7 @@ namespace currency void t_currency_protocol_handler::set_to_debug_mode(uint32_t ip) { m_debug_ip_address = ip; - LOG_PRINT_L0("debug mode is set for IP " << epee::string_tools::get_ip_string_from_int32(m_debug_ip_address)); + LOG_PRINT_L0("debug mode is set for IP " << epst::get_ip_string_from_int32(m_debug_ip_address)); } //------------------------------------------------------------------------------------------------------------------------ template @@ -944,7 +948,7 @@ namespace currency if(!m_core.have_block(arg.m_block_ids.front().h)) { LOG_ERROR_CCONTEXT("sent m_block_ids starting from unknown id: " - << string_tools::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); + << epst::pod_to_hex(arg.m_block_ids.front()) << " , dropping connection"); m_p2p->drop_connection(context); m_p2p->add_ip_fail(context.m_remote_ip); return 1; diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 43f1efe6..cb09bdb2 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -125,7 +125,7 @@ int main(int argc, char* argv[]) #endif log_space::get_set_log_detalisation_level(true, LOG_LEVEL_0); log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL); - log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet"); + log_space::log_singletone::enable_channels("core,currency_protocol,tx_pool,wallet", false); LOG_PRINT_L0("Starting..."); tools::signal_handler::install_fatal([](int sig_number, void* address) { @@ -162,6 +162,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_cmd_sett, command_line::arg_no_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_force_predownload); + command_line::add_arg(desc_cmd_sett, command_line::arg_process_predownload_from_path); command_line::add_arg(desc_cmd_sett, command_line::arg_validate_predownload); command_line::add_arg(desc_cmd_sett, command_line::arg_predownload_link); command_line::add_arg(desc_cmd_sett, command_line::arg_disable_ntp); diff --git a/src/daemon/daemon_commands_handler.h b/src/daemon/daemon_commands_handler.h index 78d2ffef..7e395584 100644 --- a/src/daemon/daemon_commands_handler.h +++ b/src/daemon/daemon_commands_handler.h @@ -665,9 +665,9 @@ private: if (ptx->signatures.size() == 0) pruned_txs += 1; + signatures += ptx->signatures.size(); txs += 1; - signatures += ptx->signatures.size(); attachments += ptx->attachment.size(); } } diff --git a/src/gui/qt-daemon/application/mainwindow.cpp b/src/gui/qt-daemon/application/mainwindow.cpp index 77e558cb..3afb4e5a 100644 --- a/src/gui/qt-daemon/application/mainwindow.cpp +++ b/src/gui/qt-daemon/application/mainwindow.cpp @@ -18,6 +18,7 @@ #define PREPARE_ARG_FROM_JSON(arg_type, var_name) \ arg_type var_name = AUTO_VAL_INIT(var_name); \ view::api_response default_ar = AUTO_VAL_INIT(default_ar); \ + LOG_PRINT_BLUE("[REQUEST]: " << param.toStdString(), LOG_LEVEL_3); \ if (!epee::serialization::load_t_from_json(var_name, param.toStdString())) \ { \ default_ar.error_code = API_RETURN_CODE_BAD_ARG; \ @@ -28,6 +29,7 @@ template QString make_response(const T& r) { std::string str = epee::serialization::store_t_to_json(r); + LOG_PRINT_BLUE("[RESPONSE]: " << str, LOG_LEVEL_3); return str.c_str(); } @@ -142,6 +144,8 @@ bool MainWindow::init_window() m_view->page()->setWebChannel(m_channel); QWidget* central_widget_to_be_set = m_view; + double zoom_factor_test = 0.75; + m_view->setZoomFactor(zoom_factor_test); std::string qt_dev_tools_option = m_backend.get_qt_dev_tools_option(); if (!qt_dev_tools_option.empty()) @@ -265,7 +269,28 @@ QString MainWindow::request_dummy() CATCH_ENTRY_FAIL_API_RESPONCE(); } +QString MainWindow::call_rpc(const QString& params) +{ + TRY_ENTRY(); + epee::net_utils::http::http_request_info query_info = AUTO_VAL_INIT(query_info); + epee::net_utils::http::http_response_info response_info = AUTO_VAL_INIT(response_info); + currency::core_rpc_server::connection_context dummy_context = AUTO_VAL_INIT(dummy_context); + query_info.m_URI = "/json_rpc"; + query_info.m_body = params.toStdString(); + + m_backend.get_rpc_server().handle_http_request(query_info, response_info, dummy_context); + if (response_info.m_response_code != 200) + { + epee::json_rpc::error_response rsp; + rsp.jsonrpc = "2.0"; + rsp.error.code = response_info.m_response_code; + rsp.error.message = response_info.m_response_comment; + return QString::fromStdString(epee::serialization::store_t_to_json(static_cast(rsp))); + } + return QString::fromStdString(response_info.m_body); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} QString MainWindow::get_default_fee() { TRY_ENTRY(); @@ -547,6 +572,14 @@ void MainWindow::store_pos(bool consider_showed) void MainWindow::restore_pos(bool consider_showed) { TRY_ENTRY(); + if (consider_showed) + { + if (m_config.is_showed) + this->showNormal(); + else + this->showMinimized(); + } + if (m_config.is_maximazed) { this->setWindowState(windowState() | Qt::WindowMaximized); @@ -578,14 +611,6 @@ void MainWindow::restore_pos(bool consider_showed) } } - if (consider_showed) - { - if (m_config.is_showed) - this->showNormal(); - else - this->showMinimized(); - } - CATCH_ENTRY2(void()); } void MainWindow::trayIconActivated(QSystemTrayIcon::ActivationReason reason) @@ -1055,9 +1080,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) if (!m_tray_icon) return true; - if (!tei.ti.is_income) + if (tei.ti.has_outgoing_entries()) return true; - if (!tei.ti.amount) + if (!tei.ti.get_native_amount()) return true; // if (tei.ti.is_mining && m_wallet_states->operator [](tei.wallet_id) != view::wallet_status_info::wallet_state_ready) // return true; @@ -1071,9 +1096,9 @@ bool MainWindow::money_transfer(const view::transfer_event_info& tei) return true; } - auto amount_str = currency::print_money_brief(tei.ti.amount); + auto amount_str = currency::print_money_brief(tei.ti.get_native_amount()); //@#@ add handling of assets std::string title, msg; - if (tei.ti.height == 0) // unconfirmed trx + if (tei.ti.height == 0) // unconfirmed tx { msg = amount_str + " " + CURRENCY_NAME_ABR + " " + m_localization[localization_id_is_received]; title = m_localization[localization_id_income_transfer_unconfirmed]; @@ -1914,6 +1939,17 @@ QString MainWindow::restore_wallet(const QString& param) return MAKE_RESPONSE(ar); CATCH_ENTRY_FAIL_API_RESPONCE(); } +QString MainWindow::use_whitelisting(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + //return que_call2("restore_wallet", param, [this](const view::restore_wallet_request& owd, view::api_response& ar){ + PREPARE_ARG_FROM_JSON(view::api_request_t, owd); + PREPARE_RESPONSE(view::api_responce_return_code, ar); + ar.error_code = m_backend.use_whitelisting(owd.wallet_id, owd.req_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} QString MainWindow::open_wallet(const QString& param) { TRY_ENTRY(); @@ -2127,6 +2163,70 @@ QString MainWindow::get_mining_estimate(const QString& param) return MAKE_RESPONSE(ar); CATCH_ENTRY_FAIL_API_RESPONCE(); } +QString MainWindow::add_custom_asset_id(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_and_asset_id, waid); + PREPARE_RESPONSE(currency::COMMAND_RPC_GET_ASSET_INFO::response, ar); + + ar.error_code = m_backend.add_custom_asset_id(waid.wallet_id, waid.asset_id, ar.response_data.asset_descriptor); + ar.response_data.status = ar.error_code; + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} +QString MainWindow::remove_custom_asset_id(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_and_asset_id, waid); + default_ar.error_code = m_backend.delete_custom_asset_id(waid.wallet_id, waid.asset_id); + return MAKE_RESPONSE(default_ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} +QString MainWindow::get_wallet_info(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::wallet_id_obj, waid); + PREPARE_RESPONSE(view::wallet_info, ar); + ar.error_code = m_backend.get_wallet_info(waid.wallet_id, ar.response_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} +QString MainWindow::create_ionic_swap_proposal(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::create_ionic_swap_proposal_request, cispr); + PREPARE_RESPONSE(std::string, ar); + ar.error_code = m_backend.create_ionic_swap_proposal(cispr.wallet_id, cispr, ar.response_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} + +QString MainWindow::get_ionic_swap_proposal_info(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::api_request_t, tx_raw_hex); + PREPARE_RESPONSE(tools::wallet_public::ionic_swap_proposal_info, ar); + ar.error_code = m_backend.get_ionic_swap_proposal_info(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); + +} + +QString MainWindow::accept_ionic_swap_proposal(const QString& param) +{ + TRY_ENTRY(); + LOG_API_TIMING(); + PREPARE_ARG_FROM_JSON(view::api_request_t, tx_raw_hex); + PREPARE_RESPONSE(std::string, ar); + ar.error_code = m_backend.accept_ionic_swap_proposal(tx_raw_hex.wallet_id, tx_raw_hex.req_data, ar.response_data); + return MAKE_RESPONSE(ar); + CATCH_ENTRY_FAIL_API_RESPONCE(); +} QString MainWindow::backup_wallet_keys(const QString& param) { TRY_ENTRY(); @@ -2184,6 +2284,7 @@ QString MainWindow::toggle_autostart(const QString& param) return MAKE_RESPONSE(default_ar); CATCH_ENTRY_FAIL_API_RESPONCE(); } +/* QString MainWindow::check_available_sources(const QString& param) { TRY_ENTRY(); @@ -2192,6 +2293,7 @@ QString MainWindow::check_available_sources(const QString& param) return m_backend.check_available_sources(sources.wallet_id, sources.req_data).c_str(); CATCH_ENTRY2(API_RETURN_CODE_INTERNAL_ERROR); } +*/ QString MainWindow::open_url_in_browser(const QString& param) { diff --git a/src/gui/qt-daemon/application/mainwindow.h b/src/gui/qt-daemon/application/mainwindow.h index f01dbe93..ed980f7d 100644 --- a/src/gui/qt-daemon/application/mainwindow.h +++ b/src/gui/qt-daemon/application/mainwindow.h @@ -144,6 +144,7 @@ public: QString webkit_launched_script(); QString get_smart_wallet_info(const QString& param); QString restore_wallet(const QString& param); + QString use_whitelisting(const QString& param); QString is_pos_allowed(); QString store_to_file(const QString& path, const QString& buff); QString load_from_file(const QString& path); @@ -168,12 +169,19 @@ public: QString get_default_fee(); QString get_options(); void bool_toggle_icon(const QString& param); - + QString add_custom_asset_id(const QString& param); + QString remove_custom_asset_id(const QString& param); + QString get_wallet_info(const QString& param); + + QString create_ionic_swap_proposal(const QString& param); + QString get_ionic_swap_proposal_info(const QString& param); + QString accept_ionic_swap_proposal(const QString& param); + bool get_is_disabled_notifications(); bool set_is_disabled_notifications(const bool& param); QString export_wallet_history(const QString& param); QString get_log_file(); - QString check_available_sources(const QString& param); + //QString check_available_sources(const QString& param); QString open_url_in_browser(const QString& param); void trayIconActivated(QSystemTrayIcon::ActivationReason reason); @@ -188,6 +196,8 @@ public: //for test purposes onlys QString request_dummy(); + QString call_rpc(const QString& params); + signals: void quit_requested(const QString str); void update_daemon_state(const QString str); diff --git a/src/gui/qt-daemon/layout b/src/gui/qt-daemon/layout index 047a4602..f040b100 160000 --- a/src/gui/qt-daemon/layout +++ b/src/gui/qt-daemon/layout @@ -1 +1 @@ -Subproject commit 047a4602748e0d3e40456f9d2fc2eeef1bc89b06 +Subproject commit f040b10090a0246ee5f68a37bb4fcc13e6abebcc diff --git a/src/gui/qt-daemon/main.cpp b/src/gui/qt-daemon/main.cpp index 39ecae9d..8d3a3244 100644 --- a/src/gui/qt-daemon/main.cpp +++ b/src/gui/qt-daemon/main.cpp @@ -56,7 +56,7 @@ int main(int argc, char *argv[]) #ifdef _MSC_VER #if _MSC_VER >= 1910 QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps); //HiDPI pixmaps - qputenv("QT_SCALE_FACTOR", "0.75"); + //qputenv("QT_SCALE_FACTOR", "0.75"); #endif #endif diff --git a/src/p2p/maintainers_info_boost_serialization.h b/src/p2p/maintainers_info_boost_serialization.h index fafc659e..b8b5df48 100644 --- a/src/p2p/maintainers_info_boost_serialization.h +++ b/src/p2p/maintainers_info_boost_serialization.h @@ -6,7 +6,7 @@ #pragma once #include "p2p_protocol_defs.h" -#include "common/crypto_boost_serialization.h" +#include "common/crypto_serialization.h" namespace boost { diff --git a/src/p2p/net_node.h b/src/p2p/net_node.h index 5c0fb12e..9ec3cc17 100644 --- a/src/p2p/net_node.h +++ b/src/p2p/net_node.h @@ -6,7 +6,7 @@ #pragma once #include -#include +#include #include #include #include diff --git a/src/p2p/net_node.inl b/src/p2p/net_node.inl index a63e88ed..22c2e457 100644 --- a/src/p2p/net_node.inl +++ b/src/p2p/net_node.inl @@ -32,7 +32,7 @@ namespace nodetool const command_line::arg_descriptor arg_p2p_allow_local_ip ("allow-local-ip", "Allow local ip add to peer list, mostly in debug purposes"); const command_line::arg_descriptor > arg_p2p_add_peer ("add-peer", "Manually add peer to local peerlist"); const command_line::arg_descriptor > arg_p2p_add_priority_node ("add-priority-node", "Specify list of peers to connect to and attempt to keep the connection open"); - const command_line::arg_descriptor arg_p2p_use_only_priority_nodes ("use-only-priority-nodes", "Try to connect only to priority nodes"); + const command_line::arg_descriptor arg_p2p_use_only_priority_nodes ("use-only-priority-nodes", "Connect only to priority nodes"); const command_line::arg_descriptor > arg_p2p_seed_node ("seed-node", "Connect to a node to retrieve peer addresses, and disconnect"); const command_line::arg_descriptor arg_p2p_hide_my_port ("hide-my-port", "Do not announce yourself as peerlist candidate"); const command_line::arg_descriptor arg_p2p_offline_mode ( "offline-mode", "Don't connect to any node and reject any connections"); @@ -321,11 +321,15 @@ namespace nodetool ADD_HARDCODED_SEED_NODE("159.69.76.144", P2P_DEFAULT_PORT); ADD_HARDCODED_SEED_NODE("144.76.183.143", P2P_DEFAULT_PORT); #else - //TODO: + // TESTNET ADD_HARDCODED_SEED_NODE("95.217.43.225", P2P_DEFAULT_PORT); ADD_HARDCODED_SEED_NODE("94.130.137.230", P2P_DEFAULT_PORT); ADD_HARDCODED_SEED_NODE("95.217.42.247", P2P_DEFAULT_PORT); ADD_HARDCODED_SEED_NODE("94.130.160.115", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("195.201.107.230", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("95.217.46.49", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("159.69.76.144", P2P_DEFAULT_PORT); + ADD_HARDCODED_SEED_NODE("144.76.183.143", P2P_DEFAULT_PORT); #endif bool res = handle_command_line(vm); @@ -846,7 +850,7 @@ namespace nodetool if (m_offline_mode) return true; - if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size() && !m_priority_peers.size()) + if(!m_peerlist.get_white_peers_count() && m_seed_nodes.size() && !m_priority_peers.size() && !m_use_only_priority_peers) { size_t try_count = 0; size_t current_index = crypto::rand()%m_seed_nodes.size(); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 5adc60f9..f1460e35 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2018 Zano Project +// Copyright (c) 2014-2022 Zano Project // Copyright (c) 2014-2018 The Louisdor Project // Copyright (c) 2012-2013 The Cryptonote developers // Distributed under the MIT/X11 software license, see the accompanying @@ -35,8 +35,11 @@ namespace currency } //------------------------------------------------------------------------------------------------------------------------------ core_rpc_server::core_rpc_server(core& cr, nodetool::node_server >& p2p, - bc_services::bc_offers_service& of - ) :m_core(cr), m_p2p(p2p), m_of(of), m_session_counter(0), m_ignore_status(false) + bc_services::bc_offers_service& of) + : m_core(cr) + , m_p2p(p2p) + , m_of(of) + , m_ignore_status(false) {} //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::handle_command_line(const boost::program_options::variables_map& vm) @@ -114,6 +117,12 @@ namespace currency res.default_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee; res.minimum_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_pool_min_fee; + auto & hf = m_core.get_blockchain_storage().get_core_runtime_config().hard_forks.m_height_the_hardfork_n_active_after; + for (size_t i = 0; i != hf.size(); i++) + { + res.is_hardfok_active.push_back(m_core.get_blockchain_storage().is_hardfork_active(i)); + } + //conditional values if (req.flags&COMMAND_RPC_GET_INFO_FLAG_NET_TIME_DELTA_MEDIAN) { @@ -353,13 +362,15 @@ namespace currency bool core_rpc_server::on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx) { CHECK_CORE_READY(); - res.status = "Failed"; + res.status = API_RETURN_CODE_FAIL; if(!m_core.get_random_outs_for_amounts(req, res)) { return true; } res.status = API_RETURN_CODE_OK; + + /* std::stringstream ss; typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::outs_for_amount outs_for_amount; typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::out_entry out_entry; @@ -375,6 +386,19 @@ namespace currency }); std::string s = ss.str(); LOG_PRINT_L2("COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS: " << ENDL << s); + */ + + return true; + } + bool core_rpc_server::on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx) + { + CHECK_CORE_READY(); + res.status = API_RETURN_CODE_FAIL; + if (!m_core.get_blockchain_storage().get_random_outs_for_amounts2(req, res)) + { + return true; + } + res.status = API_RETURN_CODE_OK; return true; } @@ -431,13 +455,6 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_scan_pos(const COMMAND_RPC_SCAN_POS::request& req, COMMAND_RPC_SCAN_POS::response& res, connection_context& cntx) - { - CHECK_CORE_READY(); - m_core.get_blockchain_storage().scan_pos(req, res); - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx) { m_core.get_blockchain_storage().check_keyimages(req.images, res.images_stat); @@ -495,6 +512,39 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_validate_signature(const COMMAND_VALIDATE_SIGNATURE::request& req, COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx) + { + if (!m_p2p.get_connections_count()) + { + res.status = API_RETURN_CODE_DISCONNECTED; + return true; + } + std::string buff = epee::string_encoding::base64_decode(req.buff); + crypto::public_key pkey = req.pkey; + + if(pkey == currency::null_pkey) + { + //need to load pkey from alias + extra_alias_entry_base eaeb = AUTO_VAL_INIT(eaeb); + if (!m_core.get_blockchain_storage().get_alias_info(req.alias, eaeb)) + { + res.status = API_RETURN_CODE_NOT_FOUND; + return true; + } + pkey = eaeb.m_address.spend_public_key; + } + + crypto::hash h = crypto::cn_fast_hash(buff.data(), buff.size()); + bool sig_check_res = crypto::check_signature(h, pkey, req.sig); + if (!sig_check_res) + { + res.status = API_RETURN_CODE_FAIL; + return true; + } + res.status = API_RETURN_CODE_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx) { if (!m_p2p.get_connections_count()) @@ -509,6 +559,12 @@ namespace currency return true; } + res.pos_sequence_factor_is_good = true; + uint64_t new_block_expected_height = m_core.get_blockchain_storage().get_top_block_height() + 1; + size_t new_block_expected_sequence_factor = m_core.get_blockchain_storage().get_current_sequence_factor(true); + if (new_block_expected_height > BLOCKCHAIN_HEIGHT_FOR_POS_STRICT_SEQUENCE_LIMITATION && new_block_expected_sequence_factor > BLOCK_POS_STRICT_SEQUENCE_LIMIT) + res.pos_sequence_factor_is_good = false; + res.pos_basic_difficulty = m_core.get_blockchain_storage().get_next_diff_conditional(true).convert_to(); m_core.get_blockchain_storage().build_stake_modifier(res.sm, blockchain_storage::alt_chain_type(), 0, &res.last_block_hash);// , &res.height); @@ -623,7 +679,7 @@ namespace currency { std::list al_list; m_core.get_tx_pool().get_aliases_from_tx_pool(al_list); - for (const auto a : al_list) + for (const auto& a : al_list) { res.aliases_que.push_back(alias_info_to_rpc_alias_info(a)); } @@ -631,6 +687,29 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_pos_votes(req.h_start, req.h_end, res.votes)) + { + res.status = API_RETURN_CODE_INTERNAL_ERROR; + res.error_code = "Internal error"; + return true; + } + res.status = API_RETURN_CODE_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx) + { + if (!m_core.get_blockchain_storage().get_asset_info(req.asset_id, res.asset_descriptor)) + { + res.status = API_RETURN_CODE_NOT_FOUND; + return true; + } + res.status = API_RETURN_CODE_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { if (!m_core.get_blockchain_storage().get_main_block_rpc_details(req.id, res.block_details)) @@ -837,9 +916,7 @@ namespace currency params.stakeholder_address = stakeholder_address; params.ex_nonce = req.extra_text; params.pos = req.pos_block; - params.pe.amount = req.pos_amount; - params.pe.index = req.pos_index; - params.pe.stake_unlock_time = req.stake_unlock_time; + params.pe = req.pe; //params.pe.keyimage key image will be set in the wallet //params.pe.wallet_index is not included in serialization map, TODO: refactoring here params.pcustom_fill_block_template_func = nullptr; @@ -869,7 +946,11 @@ namespace currency blobdata block_blob = t_serializable_object_to_blob(resp.b); res.blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob); res.prev_hash = string_tools::pod_to_hex(resp.b.prev_id); + res.miner_tx_tgc = resp.miner_tx_tgc; res.height = resp.height; + res.block_reward_without_fee = resp.block_reward_without_fee; + res.block_reward = resp.block_reward; + res.txs_fee = resp.txs_fee; //calculate epoch seed res.seed = currency::ethash_epoch_to_seed(currency::ethash_height_to_epoch(res.height)); @@ -970,9 +1051,14 @@ namespace currency uint64_t core_rpc_server::get_block_reward(const block& blk) { uint64_t reward = 0; - BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout) + BOOST_FOREACH(const auto& out, blk.miner_tx.vout) { - reward += out.amount; + VARIANT_SWITCH_BEGIN(out); + VARIANT_CASE_CONST(tx_out_bare, out) + reward += out.amount; + VARIANT_CASE_CONST(tx_out_zarcanum, out) + //@#@ + VARIANT_SWITCH_END(); } return reward; } @@ -1156,122 +1242,11 @@ namespace currency return true; } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::get_current_hi(mining::height_info& hi) - { - block prev_block = AUTO_VAL_INIT(prev_block); - m_core.get_blockchain_storage().get_top_block(prev_block); - hi.block_id = string_tools::pod_to_hex(currency::get_block_hash(prev_block)); - hi.height = get_block_height(prev_block); - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - void core_rpc_server::set_session_blob(const std::string& session_id, const currency::block& blob) - { - CRITICAL_REGION_LOCAL(m_session_jobs_lock); - m_session_jobs[session_id] = blob; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::get_session_blob(const std::string& session_id, currency::block& blob) - { - CRITICAL_REGION_LOCAL(m_session_jobs_lock); - auto it = m_session_jobs.find(session_id); - if(it == m_session_jobs.end()) - return false; - - blob = it->second; - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::get_job(const std::string& job_id, mining::job_details& job, epee::json_rpc::error& err, connection_context& cntx) - { - COMMAND_RPC_GETBLOCKTEMPLATE::request bt_req = AUTO_VAL_INIT(bt_req); - COMMAND_RPC_GETBLOCKTEMPLATE::response bt_res = AUTO_VAL_INIT(bt_res); - - // !!!!!!!! SET YOUR WALLET ADDRESS HERE !!!!!!!! - bt_req.wallet_address = "1HNJjUsofq5LYLoXem119dd491yFAb5g4bCHkecV4sPqigmuxw57Ci9am71fEN4CRmA9jgnvo5PDNfaq8QnprWmS5uLqnbq"; - - if(!on_getblocktemplate(bt_req, bt_res, err, cntx)) - return false; - - //patch block blob if you need(bt_res.blocktemplate_blob), and than load block from blob template - //important: you can't change block size, since it could touch reward and block became invalid - - block b = AUTO_VAL_INIT(b); - std::string bin_buff; - bool r = string_tools::parse_hexstr_to_binbuff(bt_res.blocktemplate_blob, bin_buff); - CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse hex block"); - r = currency::parse_and_validate_block_from_blob(bin_buff, b); - CHECK_AND_ASSERT_MES(r, false, "internal error, failed to parse block"); - - set_session_blob(job_id, b); - job.blob = string_tools::buff_to_hex_nodelimer(currency::get_block_hashing_blob(b)); - //TODO: set up share difficulty here! - job.difficulty = bt_res.difficulty; //difficulty leaved as string field since it will be refactored into 128 bit format - job.job_id = "SOME_JOB_ID"; - get_current_hi(job.prev_hi); - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_login(const mining::COMMAND_RPC_LOGIN::request& req, mining::COMMAND_RPC_LOGIN::response& res, connection_context& cntx) - { - if(!check_core_ready()) - { - res.status = API_RETURN_CODE_BUSY; - return true; - } - - //TODO: add login information here - - - res.id = std::to_string(m_session_counter++); //session id - - if(req.hi.height) - { - epee::json_rpc::error err = AUTO_VAL_INIT(err); - if(!get_job(res.id, res.job, err, cntx)) - { - res.status = err.message; - return true; - } - } - - res.status = API_RETURN_CODE_OK; - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_getjob(const mining::COMMAND_RPC_GETJOB::request& req, mining::COMMAND_RPC_GETJOB::response& res, connection_context& cntx) - { - if(!check_core_ready()) - { - res.status = API_RETURN_CODE_BUSY; - return true; - } - - - - /*epee::json_rpc::error err = AUTO_VAL_INIT(err); - if(!get_job(req.id, res.jd, err, cntx)) - { - res.status = err.message; - return true; - }*/ - - return true; - } //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { - - uint64_t default_tx_fee = m_core.get_blockchain_storage().get_core_runtime_config().tx_default_fee; - uint64_t current_median_fee = m_core.get_blockchain_storage().get_tx_fee_median(); - - res.reward = get_alias_coast_from_fee(req.alias, std::max(default_tx_fee, current_median_fee)); - - if (res.reward) - res.status = API_RETURN_CODE_OK; - else - res.status = API_RETURN_CODE_NOT_FOUND; + res.reward = m_core.get_blockchain_storage().get_alias_coast(req.alias); + res.status = API_RETURN_CODE_OK; return true; } //------------------------------------------------------------------------------------------------------------------------------ @@ -1286,7 +1261,7 @@ namespace currency return true; } //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_alias_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + bool core_rpc_server::on_aliases_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) { account_public_address addr = AUTO_VAL_INIT(addr); if (!get_account_address_from_str(addr, req)) @@ -1298,61 +1273,28 @@ namespace currency COMMAND_RPC_GET_ALIAS_DETAILS::request req2 = AUTO_VAL_INIT(req2); COMMAND_RPC_GET_ALIAS_DETAILS::response res2 = AUTO_VAL_INIT(res2); - req2.alias = m_core.get_blockchain_storage().get_alias_by_address(addr); - if (!req2.alias.size()) + std::set aliases = m_core.get_blockchain_storage().get_aliases_by_address(addr); + + if (!aliases.size()) { res.status = API_RETURN_CODE_NOT_FOUND; return true; } - bool r = this->on_get_alias_details(req2, res2, error_resp, cntx); - if (!r || res2.status != API_RETURN_CODE_OK) + for (auto it = aliases.begin(); it != aliases.end(); it++) { - res.status = API_RETURN_CODE_FAIL; - return true; - } + req2.alias = *it; + bool r = this->on_get_alias_details(req2, res2, error_resp, cntx); + if (!r || res2.status != API_RETURN_CODE_OK) + { + res.status = API_RETURN_CODE_FAIL; + return true; + } + res.alias_info_list.push_back(alias_rpc_details()); + res.alias_info_list.back().details = res2.alias_details; + res.alias_info_list.back().alias = req2.alias; - res.alias_info.details = res2.alias_details; - res.alias_info.alias = req2.alias; - res.status = API_RETURN_CODE_OK; - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_submit(const mining::COMMAND_RPC_SUBMITSHARE::request& req, mining::COMMAND_RPC_SUBMITSHARE::response& res, connection_context& cntx) - { - if(!check_core_ready()) - { - res.status = API_RETURN_CODE_BUSY; - return true; } - block b = AUTO_VAL_INIT(b); - if(!get_session_blob(req.id, b)) - { - res.status = "Wrong session id"; - return true; - } - - b.nonce = req.nonce; - - if(!m_core.handle_block_found(b)) - { - res.status = "Block not accepted"; - LOG_ERROR("Submited block not accepted"); - return true; - } - res.status = API_RETURN_CODE_OK; - return true; - } - //------------------------------------------------------------------------------------------------------------------------------ - bool core_rpc_server::on_get_addendums(const COMMAND_RPC_GET_ADDENDUMS::request& req, COMMAND_RPC_GET_ADDENDUMS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) - { - if (!check_core_ready()) - { - res.status = API_RETURN_CODE_BUSY; - return true; - } - - res.status = API_RETURN_CODE_OK; return true; } @@ -1367,4 +1309,4 @@ namespace currency #undef LOG_DEFAULT_CHANNEL -#define LOG_DEFAULT_CHANNEL NULL \ No newline at end of file +#define LOG_DEFAULT_CHANNEL NULL diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index d95dd52b..96d872fc 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -14,7 +14,6 @@ #include "currency_core/currency_core.h" #include "p2p/net_node.h" #include "currency_protocol/currency_protocol_handler.h" -#include "mining_protocol_defs.h" #include "currency_core/bc_offers_service.h" @@ -38,6 +37,7 @@ namespace currency static void init_options(boost::program_options::options_description& desc); bool init(const boost::program_options::variables_map& vm); + void set_rpc_chain_handler(epee::net_utils::http::i_chain_handler* prpc_chain_handler) { m_prpc_chain_handler = prpc_chain_handler; } bool on_get_blocks_direct(const COMMAND_RPC_GET_BLOCKS_DIRECT::request& req, COMMAND_RPC_GET_BLOCKS_DIRECT::response& res, connection_context& cntx); @@ -49,11 +49,11 @@ namespace currency bool on_start_mining(const COMMAND_RPC_START_MINING::request& req, COMMAND_RPC_START_MINING::response& res, connection_context& cntx); bool on_stop_mining(const COMMAND_RPC_STOP_MINING::request& req, COMMAND_RPC_STOP_MINING::response& res, connection_context& cntx); bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); + bool on_get_random_outs2(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2::response& res, connection_context& cntx); bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); bool on_set_maintainers_info(const COMMAND_RPC_SET_MAINTAINERS_INFO::request& req, COMMAND_RPC_SET_MAINTAINERS_INFO::response& res, connection_context& cntx); bool on_get_tx_pool(const COMMAND_RPC_GET_TX_POOL::request& req, COMMAND_RPC_GET_TX_POOL::response& res, connection_context& cntx); bool on_check_keyimages(const COMMAND_RPC_CHECK_KEYIMAGES::request& req, COMMAND_RPC_CHECK_KEYIMAGES::response& res, connection_context& cntx); - bool on_scan_pos(const COMMAND_RPC_SCAN_POS::request& req, COMMAND_RPC_SCAN_POS::response& res, connection_context& cntx); bool on_rpc_get_blocks_details(const COMMAND_RPC_GET_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_BLOCKS_DETAILS::response& res, connection_context& cntx); bool on_force_relaey_raw_txs(const COMMAND_RPC_FORCE_RELAY_RAW_TXS::request& req, COMMAND_RPC_FORCE_RELAY_RAW_TXS::response& res, connection_context& cntx); bool on_get_offers_ex(const COMMAND_RPC_GET_OFFERS_EX::request& req, COMMAND_RPC_GET_OFFERS_EX::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); @@ -71,9 +71,8 @@ namespace currency bool on_get_alias_details(const COMMAND_RPC_GET_ALIAS_DETAILS::request& req, COMMAND_RPC_GET_ALIAS_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_all_aliases(const COMMAND_RPC_GET_ALL_ALIASES::request& req, COMMAND_RPC_GET_ALL_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_aliases(const COMMAND_RPC_GET_ALIASES::request& req, COMMAND_RPC_GET_ALIASES::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); - bool on_alias_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_aliases_by_address(const COMMAND_RPC_GET_ALIASES_BY_ADDRESS::request& req, COMMAND_RPC_GET_ALIASES_BY_ADDRESS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alias_reward(const COMMAND_RPC_GET_ALIAS_REWARD::request& req, COMMAND_RPC_GET_ALIAS_REWARD::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); - bool on_get_addendums(const COMMAND_RPC_GET_ADDENDUMS::request& req, COMMAND_RPC_GET_ADDENDUMS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_reset_transaction_pool(const COMMAND_RPC_RESET_TX_POOL::request& req, COMMAND_RPC_RESET_TX_POOL::response& res, connection_context& cntx); bool on_get_pos_mining_details(const COMMAND_RPC_GET_POS_MINING_DETAILS::request& req, COMMAND_RPC_GET_POS_MINING_DETAILS::response& res, connection_context& cntx); bool on_get_current_core_tx_expiration_median(const COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::request& req, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN::response& res, connection_context& cntx); @@ -85,24 +84,17 @@ namespace currency bool on_get_pool_txs_brief_details(const COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::request& req, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS::response& res, connection_context& cntx); bool on_get_all_pool_tx_list(const COMMAND_RPC_GET_ALL_POOL_TX_LIST::request& req, COMMAND_RPC_GET_ALL_POOL_TX_LIST::response& res, connection_context& cntx); bool on_get_pool_info(const COMMAND_RPC_GET_POOL_INFO::request& req, COMMAND_RPC_GET_POOL_INFO::response& res, connection_context& cntx); - + bool on_get_votes(const COMMAND_RPC_GET_VOTES::request& req, COMMAND_RPC_GET_VOTES::response& res, connection_context& cntx); + bool on_get_asset_info(const COMMAND_RPC_GET_ASSET_INFO::request& req, COMMAND_RPC_GET_ASSET_INFO::response& res, connection_context& cntx); + bool on_get_main_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alt_block_details(const COMMAND_RPC_GET_BLOCK_DETAILS::request& req, COMMAND_RPC_GET_BLOCK_DETAILS::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_get_alt_blocks_details(const COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::request& req, COMMAND_RPC_GET_ALT_BLOCKS_DETAILS::response& res, connection_context& cntx); bool on_get_est_height_from_date(const COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::request& req, COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE::response& res, connection_context& cntx); + bool on_validate_signature(const COMMAND_VALIDATE_SIGNATURE::request& req, COMMAND_VALIDATE_SIGNATURE::response& res, epee::json_rpc::error& er, connection_context& cntx); - - //mining rpc - bool on_login(const mining::COMMAND_RPC_LOGIN::request& req, mining::COMMAND_RPC_LOGIN::response& res, connection_context& cntx); - bool on_getjob(const mining::COMMAND_RPC_GETJOB::request& req, mining::COMMAND_RPC_GETJOB::response& res, connection_context& cntx); - bool on_submit(const mining::COMMAND_RPC_SUBMITSHARE::request& req, mining::COMMAND_RPC_SUBMITSHARE::response& res, connection_context& cntx); - - - - - CHAIN_HTTP_TO_MAP2(connection_context); //forward http requests to uri map BEGIN_URI_MAP2() @@ -118,10 +110,10 @@ namespace currency MAP_URI_AUTO_BIN2("/getblocks.bin", on_get_blocks, COMMAND_RPC_GET_BLOCKS_FAST) MAP_URI_AUTO_BIN2("/get_o_indexes.bin", on_get_indexes, COMMAND_RPC_GET_TX_GLOBAL_OUTPUTS_INDEXES) MAP_URI_AUTO_BIN2("/getrandom_outs.bin", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) + MAP_URI_AUTO_BIN2("/getrandom_outs2.bin", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) MAP_URI_AUTO_BIN2("/set_maintainers_info.bin", on_set_maintainers_info, COMMAND_RPC_SET_MAINTAINERS_INFO) MAP_URI_AUTO_BIN2("/get_tx_pool.bin", on_get_tx_pool, COMMAND_RPC_GET_TX_POOL) MAP_URI_AUTO_BIN2("/check_keyimages.bin", on_check_keyimages, COMMAND_RPC_CHECK_KEYIMAGES) - MAP_URI_AUTO_BIN2("/scan_pos.bin", on_scan_pos, COMMAND_RPC_SCAN_POS) MAP_URI_AUTO_BIN2("/get_pos_details.bin", on_get_pos_mining_details, COMMAND_RPC_GET_POS_MINING_DETAILS) // JSON RPCs BEGIN_JSON_RPC_MAP("/json_rpc") @@ -134,7 +126,7 @@ namespace currency MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH) MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT) MAP_JON_RPC_WE("get_alias_details", on_get_alias_details, COMMAND_RPC_GET_ALIAS_DETAILS) - MAP_JON_RPC_WE("get_alias_by_address", on_alias_by_address, COMMAND_RPC_GET_ALIASES_BY_ADDRESS) + MAP_JON_RPC_WE("get_alias_by_address", on_aliases_by_address, COMMAND_RPC_GET_ALIASES_BY_ADDRESS) MAP_JON_RPC_WE("get_alias_reward", on_get_alias_reward, COMMAND_RPC_GET_ALIAS_REWARD) MAP_JON_RPC ("get_est_height_from_date", on_get_est_height_from_date, COMMAND_RPC_GET_EST_HEIGHT_FROM_DATE) //block explorer api @@ -150,6 +142,11 @@ namespace currency MAP_JON_RPC ("get_pool_txs_brief_details", on_get_pool_txs_brief_details, COMMAND_RPC_GET_POOL_TXS_BRIEF_DETAILS) MAP_JON_RPC ("get_all_pool_tx_list", on_get_all_pool_tx_list, COMMAND_RPC_GET_ALL_POOL_TX_LIST) MAP_JON_RPC ("get_pool_info", on_get_pool_info, COMMAND_RPC_GET_POOL_INFO) + MAP_JON_RPC ("getrandom_outs", on_get_random_outs, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS) + MAP_JON_RPC ("getrandom_outs2", on_get_random_outs2, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2) + MAP_JON_RPC ("get_votes", on_get_votes, COMMAND_RPC_GET_VOTES) + //assets api + MAP_JON_RPC ("get_asset_info", on_get_asset_info, COMMAND_RPC_GET_ASSET_INFO) MAP_JON_RPC_WE("get_main_block_details", on_get_main_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) MAP_JON_RPC_WE("get_alt_block_details", on_get_alt_block_details, COMMAND_RPC_GET_BLOCK_DETAILS) @@ -158,12 +155,11 @@ namespace currency MAP_JON_RPC ("reset_transaction_pool", on_reset_transaction_pool, COMMAND_RPC_RESET_TX_POOL) MAP_JON_RPC ("get_current_core_tx_expiration_median", on_get_current_core_tx_expiration_median, COMMAND_RPC_GET_CURRENT_CORE_TX_EXPIRATION_MEDIAN) // - MAP_JON_RPC_WE("marketplace_global_get_offers_ex", on_get_offers_ex, COMMAND_RPC_GET_OFFERS_EX) - //remote miner rpc - MAP_JON_RPC_N(on_login, mining::COMMAND_RPC_LOGIN) - MAP_JON_RPC_N(on_getjob, mining::COMMAND_RPC_GETJOB) - MAP_JON_RPC_N(on_submit, mining::COMMAND_RPC_SUBMITSHARE) + MAP_JON_RPC_WE("marketplace_global_get_offers_ex", on_get_offers_ex, COMMAND_RPC_GET_OFFERS_EX) + MAP_JON_RPC_WE("validate_signature", on_validate_signature, COMMAND_VALIDATE_SIGNATURE) + CHAIN_TO_PHANDLER(m_prpc_chain_handler) END_JSON_RPC_MAP() + CHAIN_TO_PHANDLER(m_prpc_chain_handler) END_URI_MAP2() private: @@ -171,8 +167,6 @@ namespace currency //----------------------- bool handle_command_line(const boost::program_options::variables_map& vm); bool check_core_ready_(const std::string& calling_method); - bool get_job(const std::string& job_id, mining::job_details& job, epee::json_rpc::error& err, connection_context& cntx); - bool get_current_hi(mining::height_info& hi); //utils uint64_t get_block_reward(const block& blk); @@ -186,10 +180,7 @@ namespace currency std::string m_port; std::string m_bind_ip; bool m_ignore_status; - //mining stuff - epee::critical_section m_session_jobs_lock; - std::map m_session_jobs; //session id -> blob - std::atomic m_session_counter; + epee::net_utils::http::i_chain_handler* m_prpc_chain_handler = nullptr; }; } diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 531cbe74..27393a9a 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -11,7 +11,6 @@ #include "currency_core/difficulty.h" #include "crypto/hash.h" #include "p2p/p2p_protocol_defs.h" -#include "rpc/mining_protocol_defs.h" #include "storages/portable_storage_base.h" #include "currency_core/offers_service_basics.h" #include "currency_core/basic_api_response_codes.h" @@ -83,6 +82,59 @@ namespace currency }; }; + struct COMMAND_RPC_GET_VOTES + { + struct request + { + uint64_t h_start; + uint64_t h_end; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(h_start) + KV_SERIALIZE(h_end) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::string error_code; + vote_results votes; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(error_code) + KV_SERIALIZE(votes) + END_KV_SERIALIZE_MAP() + }; + }; + + struct asset_id_kv + { + crypto::public_key asset_id; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE_POD_AS_HEX_STRING(asset_id) + END_KV_SERIALIZE_MAP() + }; + + + struct COMMAND_RPC_GET_ASSET_INFO + { + typedef asset_id_kv request; + + struct response + { + std::string status; + asset_descriptor_base asset_descriptor; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(asset_descriptor) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_GET_HEIGHT { struct request @@ -319,11 +371,13 @@ namespace currency struct request { std::list amounts; - uint64_t outs_count; + uint64_t decoys_count; // how many decoy outputs needed (per amount) + uint64_t height_upper_limit; // if nonzero, all the decoy outputs must be either older than, or the same age as this height bool use_forced_mix_outs; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amounts) - KV_SERIALIZE(outs_count) + KV_SERIALIZE(decoys_count) + KV_SERIALIZE(height_upper_limit) KV_SERIALIZE(use_forced_mix_outs) END_KV_SERIALIZE_MAP() }; @@ -331,8 +385,18 @@ namespace currency #pragma pack (push, 1) struct out_entry { + out_entry() = default; + out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address) + : global_amount_index(global_amount_index), stealth_address(stealth_address), concealing_point{}, amount_commitment{}, blinded_asset_id{} + {} + out_entry(uint64_t global_amount_index, const crypto::public_key& stealth_address, const crypto::public_key& amount_commitment, const crypto::public_key& concealing_point, const crypto::public_key& blinded_asset_id) + : global_amount_index(global_amount_index), stealth_address(stealth_address), concealing_point(concealing_point), amount_commitment(amount_commitment), blinded_asset_id(blinded_asset_id) + {} uint64_t global_amount_index; - crypto::public_key out_key; + crypto::public_key stealth_address; + crypto::public_key concealing_point; // premultiplied by 1/8 + crypto::public_key amount_commitment; // premultiplied by 1/8 + crypto::public_key blinded_asset_id; // premultiplied by 1/8 }; #pragma pack(pop) @@ -358,6 +422,42 @@ namespace currency }; }; + + //----------------------------------------------- + struct COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS2 + { + struct offsets_distribution + { + uint64_t amount; //if amount is 0 then lookup in post-zarcanum zone only, if not 0 then pre-zarcanum only + std::vector offsets; //[i] = height, estimated location where to pickup output of transaction + uint64_t own_global_index; //index to exclude from selection + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amount) + KV_SERIALIZE(offsets) + KV_SERIALIZE(own_global_index) + END_KV_SERIALIZE_MAP() + }; + + + struct request + { + std::vector amounts; + uint64_t height_upper_limit; // if nonzero, all the decoy outputs must be either older than, or the same age as this height + bool use_forced_mix_outs; + uint64_t coinbase_percents; //from 0 to 100, estimate percents of coinbase outputs included in decoy sets + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(amounts) + KV_SERIALIZE(height_upper_limit) + KV_SERIALIZE(use_forced_mix_outs) + KV_SERIALIZE(coinbase_percents) + END_KV_SERIALIZE_MAP() + }; + + typedef COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response response; + }; + + //----------------------------------------------- struct COMMAND_RPC_SET_MAINTAINERS_INFO { @@ -693,6 +793,7 @@ namespace currency uint64_t minimum_fee; uint64_t last_block_timestamp; std::string last_block_hash; + std::list is_hardfok_active; //market uint64_t offers_count; @@ -743,6 +844,7 @@ namespace currency KV_SERIALIZE(minimum_fee) KV_SERIALIZE(last_block_timestamp) KV_SERIALIZE(last_block_hash) + KV_SERIALIZE(is_hardfok_active) KV_SERIALIZE(offers_count) END_KV_SERIALIZE_MAP() }; @@ -802,21 +904,17 @@ namespace currency blobdata explicit_transaction; std::string extra_text; std::string wallet_address; - std::string stakeholder_address; - bool pos_block; //is pos block - uint64_t pos_amount; // - uint64_t pos_index; // - uint64_t stake_unlock_time; + std::string stakeholder_address; // address for stake return (PoS blocks) + pos_entry pe; // for PoS blocks + bool pos_block; // is pos block BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_BLOB_AS_HEX_STRING(explicit_transaction) KV_SERIALIZE(extra_text) KV_SERIALIZE(wallet_address) KV_SERIALIZE(stakeholder_address); + KV_SERIALIZE(pe) KV_SERIALIZE(pos_block) - KV_SERIALIZE(pos_amount) - KV_SERIALIZE(pos_index) - KV_SERIALIZE(stake_unlock_time) END_KV_SERIALIZE_MAP() }; @@ -827,6 +925,10 @@ namespace currency crypto::hash seed; blobdata blocktemplate_blob; std::string prev_hash; + tx_generation_context miner_tx_tgc; + uint64_t block_reward_without_fee; + uint64_t block_reward; // == block_reward_without_fee + txs_fee if fees are given to the miner, OR block_reward_without_fee if fees are burnt + uint64_t txs_fee; std::string status; BEGIN_KV_SERIALIZE_MAP() @@ -835,6 +937,10 @@ namespace currency KV_SERIALIZE_POD_AS_HEX_STRING(seed) KV_SERIALIZE(blocktemplate_blob) KV_SERIALIZE(prev_hash) + KV_SERIALIZE(miner_tx_tgc) + KV_SERIALIZE(block_reward_without_fee) + KV_SERIALIZE(block_reward) + KV_SERIALIZE(txs_fee) KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; @@ -1069,36 +1175,17 @@ namespace currency struct response { //std::string alias; - alias_rpc_details alias_info; + std::vector alias_info_list; std::string status; BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(alias_info) + KV_SERIALIZE(alias_info_list) KV_SERIALIZE(status) END_KV_SERIALIZE_MAP() }; }; - struct COMMAND_RPC_GET_ADDENDUMS - { - - typedef mining::height_info request; - - struct response - { - std::string status; - std::list addms; - - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(addms) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_RESET_TX_POOL { @@ -1118,41 +1205,6 @@ namespace currency }; }; - struct COMMAND_RPC_SCAN_POS - { - struct request - { - std::vector pos_entries; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(pos_entries) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; - uint64_t index; - uint64_t block_timestamp; - uint64_t height; - uint64_t starter_timestamp; - crypto::hash last_block_hash; - bool is_pos_allowed; - uint64_t iterations_processed; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(index) - KV_SERIALIZE(block_timestamp) - KV_SERIALIZE(height) - KV_SERIALIZE(is_pos_allowed) - KV_SERIALIZE(iterations_processed) - KV_SERIALIZE(starter_timestamp) - KV_SERIALIZE_VAL_POD_AS_BLOB(last_block_hash); - END_KV_SERIALIZE_MAP() - }; - }; - struct COMMAND_RPC_GET_POS_MINING_DETAILS { struct request @@ -1169,12 +1221,14 @@ namespace currency std::string status; crypto::hash last_block_hash; bool pos_mining_allowed; + bool pos_sequence_factor_is_good; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE_VAL_POD_AS_BLOB(sm) KV_SERIALIZE(pos_basic_difficulty) KV_SERIALIZE(starter_timestamp) KV_SERIALIZE(pos_mining_allowed) + KV_SERIALIZE(pos_sequence_factor_is_good) KV_SERIALIZE(status) KV_SERIALIZE_VAL_POD_AS_BLOB(last_block_hash) END_KV_SERIALIZE_MAP() @@ -1204,12 +1258,14 @@ namespace currency std::string htlc_origin; std::string kimage_or_ms_id; std::vector global_indexes; + std::vector etc_options; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(amount) KV_SERIALIZE(htlc_origin) KV_SERIALIZE(kimage_or_ms_id) KV_SERIALIZE(global_indexes) KV_SERIALIZE(multisig_count) + KV_SERIALIZE(etc_options) END_KV_SERIALIZE_MAP() }; @@ -1217,11 +1273,11 @@ namespace currency { std::string type; std::string short_view; - std::string datails_view; + std::string details_view; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(type) KV_SERIALIZE(short_view) - KV_SERIALIZE(datails_view) + KV_SERIALIZE(details_view) END_KV_SERIALIZE_MAP() }; @@ -1603,6 +1659,34 @@ namespace currency }; }; + + struct COMMAND_VALIDATE_SIGNATURE + { + struct request + { + std::string buff; //base64 encoded data + crypto::signature sig = currency::null_sig; + crypto::public_key pkey = currency::null_pkey; + std::string alias; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(buff) + KV_SERIALIZE_POD_AS_HEX_STRING(sig) + KV_SERIALIZE_POD_AS_HEX_STRING(pkey) + KV_SERIALIZE(alias) + END_KV_SERIALIZE_MAP() + }; + + + struct response + { + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + struct void_struct { BEGIN_KV_SERIALIZE_MAP() diff --git a/src/rpc/mining_protocol_defs.h b/src/rpc/mining_protocol_defs.h deleted file mode 100644 index 4a2c0f23..00000000 --- a/src/rpc/mining_protocol_defs.h +++ /dev/null @@ -1,153 +0,0 @@ -// Copyright (c) 2014-2018 Zano Project -// Copyright (c) 2014-2018 The Louisdor Project -// Copyright (c) 2012-2013 The Cryptonote developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#pragma once -#include "currency_protocol/currency_protocol_defs.h" -#include "currency_core/currency_basic.h" -#include "crypto/hash.h" -#include "net/rpc_method_name.h" - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// -// Seems to be obsolete. Consider removing due to stratum support. -// -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - -namespace mining -{ - struct height_info - { - uint64_t height; - std::string block_id; - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(height) - KV_SERIALIZE(block_id) - END_KV_SERIALIZE_MAP() - }; - - - struct addendum - { - height_info hi; - std::string prev_id; - std::string addm; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(hi) - KV_SERIALIZE(prev_id) - KV_SERIALIZE(addm) - END_KV_SERIALIZE_MAP() - }; - - struct job_details - { - std::string blob; - std::string difficulty; - std::string job_id; - height_info prev_hi; - std::list addms; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(blob) - KV_SERIALIZE(difficulty) - KV_SERIALIZE(job_id) - KV_SERIALIZE(prev_hi) - KV_SERIALIZE(addms) - END_KV_SERIALIZE_MAP() - }; - - struct COMMAND_RPC_LOGIN - { - RPC_METHOD_NAME("login"); - - struct request - { - std::string login; - std::string pass; - std::string agent; - height_info hi; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(login) - KV_SERIALIZE(pass) - KV_SERIALIZE(agent) - KV_SERIALIZE(hi) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; - std::string id; - job_details job; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_SERIALIZE(id) - KV_SERIALIZE(job) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_GETJOB - { - RPC_METHOD_NAME("getjob"); - - struct request - { - std::string id; - height_info hi; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(id) - KV_SERIALIZE(hi) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; - job_details jd; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - KV_CHAIN_MAP(jd) - END_KV_SERIALIZE_MAP() - }; - }; - - struct COMMAND_RPC_SUBMITSHARE - { - RPC_METHOD_NAME("submit"); - - struct request - { - std::string id; - uint64_t nonce; - std::string job_id; - std::string result; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(id) - KV_SERIALIZE(nonce) - KV_SERIALIZE(job_id) - KV_SERIALIZE(result) - END_KV_SERIALIZE_MAP() - }; - - struct response - { - std::string status; - - BEGIN_KV_SERIALIZE_MAP() - KV_SERIALIZE(status) - END_KV_SERIALIZE_MAP() - }; - }; - -} - diff --git a/src/serialization/binary_archive.h b/src/serialization/binary_archive.h index b951a106..3fe31e72 100644 --- a/src/serialization/binary_archive.h +++ b/src/serialization/binary_archive.h @@ -51,7 +51,7 @@ template <> struct binary_archive : public binary_archive_base { explicit binary_archive(stream_type &s) : base_type(s) { - stream_type::streampos pos = stream_.tellg(); + stream_type::pos_type pos = stream_.tellg(); stream_.seekg(0, std::ios_base::end); eof_pos_ = stream_.tellg(); stream_.seekg(pos); diff --git a/src/serialization/boost_types.h b/src/serialization/boost_types.h new file mode 100644 index 00000000..154705b8 --- /dev/null +++ b/src/serialization/boost_types.h @@ -0,0 +1,60 @@ +// Copyright (c) 2014-2017 The The Louisdor Project +// Copyright (c) 2012-2013 The Cryptonote developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#pragma once + +#include + + +template