merged from develop
|
|
@ -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
|
||||
UseTab: Never
|
||||
|
|
|
|||
5
.gitmodules
vendored
|
|
@ -4,3 +4,8 @@
|
|||
[submodule "src/gui/qt-daemon/layout"]
|
||||
path = src/gui/qt-daemon/layout
|
||||
url = https://github.com/hyle-team/zano_ui.git
|
||||
branch = main
|
||||
[submodule "contrib/tor-connect"]
|
||||
path = contrib/tor-connect
|
||||
url = https://github.com/hyle-team/tor-connect.git
|
||||
branch = main
|
||||
|
|
@ -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,24 +54,40 @@ 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")
|
||||
set(DISABLE_TOR FALSE CACHE BOOL "Disable TOR library(and related tor-connect submodule)")
|
||||
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)
|
||||
|
||||
set(TESTNET FALSE CACHE BOOL "Compile for testnet")
|
||||
if(TESTNET)
|
||||
message("!!!!!! NOTICE: Project is building for TESTNET !!!!!!")
|
||||
add_definitions(-DTESTNET)
|
||||
endif()
|
||||
|
||||
set(BUILD_GUI FALSE CACHE BOOL "Build qt-daemon")
|
||||
if(CAKEWALLET)
|
||||
message("NOTICE: Building libraries for CAKEWALLET")
|
||||
add_definitions(-DCAKEWALLET)
|
||||
endif()
|
||||
|
||||
set(OPENSSL_USE_STATIC_LIBS TRUE) # link statically
|
||||
find_package(OpenSSL REQUIRED)
|
||||
|
||||
if(DISABLE_TOR)
|
||||
message("NOTICE: Building with disabled TOR support!")
|
||||
add_definitions(-DDISABLE_TOR)
|
||||
endif()
|
||||
|
||||
|
||||
set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
|
||||
|
|
@ -84,7 +104,7 @@ 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_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}}")
|
||||
|
|
@ -98,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()
|
||||
|
|
@ -130,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")
|
||||
|
|
@ -174,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()
|
||||
|
|
@ -196,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.55 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)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
@ -219,7 +246,7 @@ elseif(NOT MSVC)
|
|||
endif()
|
||||
|
||||
if(BUILD_GUI)
|
||||
cmake_minimum_required(VERSION 2.8.11)
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
find_package(Qt5Widgets REQUIRED)
|
||||
endif()
|
||||
|
||||
|
|
|
|||
101
README.md
|
|
@ -13,12 +13,13 @@ Be sure to clone the repository properly:\
|
|||
### Dependencies
|
||||
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|
||||
|--|--|--|--|
|
||||
| gcc (Linux) | 5.4.0 | 7.4.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) | 2019 |
|
||||
| [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.20 |
|
||||
| [Boost](https://www.boost.org/users/download/) | 1.56 | 1.68 | 1.76 |
|
||||
| [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.1w | 1.1.1w |
|
||||
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 |
|
||||
|
||||
Note:\
|
||||
|
|
@ -29,79 +30,113 @@ 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
|
||||
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 mesa-common-dev libglu1-mesa-dev
|
||||
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
|
||||
|
||||
wget https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2
|
||||
tar -xjf boost_1_68_0.tar.bz2
|
||||
cd boost_1_68_0
|
||||
./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer
|
||||
./b2
|
||||
In the following steps we assume that you cloned Zano into '~/zano' folder in your home directory.
|
||||
|
||||
3. Install Qt\
|
||||
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
|
||||
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 && cd ..
|
||||
Make sure that you see "The Boost C++ Libraries were successfully built!" message at the end.
|
||||
|
||||
4. Install Qt\
|
||||
(*GUI version only, skip this step if you're building server version*)
|
||||
|
||||
[*GUI version*]
|
||||
|
||||
wget https://download.qt.io/new_archive/qt/5.11/5.11.2/qt-opensource-linux-x64-5.11.2.run
|
||||
curl -OL https://download.qt.io/new_archive/qt/5.11/5.11.2/qt-opensource-linux-x64-5.11.2.run
|
||||
chmod +x qt-opensource-linux-x64-5.11.2.run
|
||||
./qt-opensource-linux-x64-5.11.2.run
|
||||
Then follow the instructions in Wizard. Don't forget to tick the WebEngine module checkbox!
|
||||
|
||||
4. Set environment variables properly\
|
||||
|
||||
5. Install OpenSSL
|
||||
|
||||
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.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 ..
|
||||
|
||||
|
||||
6. [*OPTIONAL*] Set global environment variables for convenient use\
|
||||
For instance, by adding the following lines to `~/.bashrc`
|
||||
|
||||
[*server version*]
|
||||
|
||||
export BOOST_ROOT=/home/user/boost_1_68_0
|
||||
export BOOST_ROOT=/home/user/boost_1_70_0
|
||||
export OPENSSL_ROOT_DIR=/home/user/openssl
|
||||
|
||||
|
||||
[*GUI version*]
|
||||
|
||||
export BOOST_ROOT=/home/user/boost_1_68_0
|
||||
export BOOST_ROOT=/home/user/boost_1_70_0
|
||||
export OPENSSL_ROOT_DIR=/home/user/openssl
|
||||
export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64
|
||||
|
||||
|
||||
|
||||
5. Building binaries
|
||||
1. Building 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 ..` .
|
||||
|
||||
1. Building GUI:
|
||||
1. Build GUI:
|
||||
|
||||
cd zano
|
||||
utils/build_sript_linux.sh
|
||||
utils/build_script_linux.sh
|
||||
|
||||
7. Look for the binaries in `build` folder
|
||||
Look for the binaries in `build` folder
|
||||
|
||||
<br />
|
||||
|
||||
### Windows
|
||||
Recommended OS version: Windows 7 x64.
|
||||
1. Install required prerequisites (Boost, Qt, CMake).
|
||||
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 `utils/configure_win64_msvs2015_gui.cmd` or `utils/configure_win64_msvs2017_gui.cmd` according to your MSVC version.
|
||||
3. Run one of `utils/configure_win64_msvsNNNN_gui.cmd` according to your MSVC version.
|
||||
4. Go to the build folder and open generated Zano.sln in MSVC.
|
||||
5. Build.
|
||||
|
||||
|
|
@ -115,7 +150,7 @@ In order to correctly deploy Qt GUI application, you also need to do the followi
|
|||
<br />
|
||||
|
||||
### macOS
|
||||
Recommended OS version: macOS Sierra 10.15.4 x64.
|
||||
Recommended OS version: macOS Big Sur 11.4 x64.
|
||||
1. Install required prerequisites.
|
||||
2. Set environment variables as stated in `utils/macosx_build_config.command`.
|
||||
3. `mkdir build` <br> `cd build` <br> `cmake ..` <br> `make`
|
||||
|
|
|
|||
|
|
@ -5,6 +5,10 @@ add_subdirectory(zlib)
|
|||
add_subdirectory(db)
|
||||
add_subdirectory(ethereum)
|
||||
|
||||
if( NOT DISABLE_TOR)
|
||||
add_subdirectory(tor-connect)
|
||||
endif()
|
||||
|
||||
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "iOS" OR CMAKE_SYSTEM_NAME STREQUAL "Android")
|
||||
message("excluded upnp support for IOS build")
|
||||
|
|
@ -17,6 +21,10 @@ set_property(TARGET libminiupnpc-static PROPERTY FOLDER "contrib")
|
|||
set_property(TARGET zlibstatic PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET mdbx PROPERTY FOLDER "contrib")
|
||||
set_property(TARGET lmdb PROPERTY FOLDER "contrib")
|
||||
if( NOT DISABLE_TOR)
|
||||
set_property(TARGET tor-connect PROPERTY FOLDER "contrib")
|
||||
endif()
|
||||
|
||||
set_property(TARGET upnpc-static mdbx_chk mdbx_copy mdbx_dump mdbx_load mdbx_stat PROPERTY FOLDER "unused")
|
||||
|
||||
if(MSVC)
|
||||
|
|
|
|||
|
|
@ -88,6 +88,25 @@
|
|||
|
||||
// basic headers
|
||||
#include <boost/version.hpp>
|
||||
|
||||
// The following sixteen lines disable annoying message in Boost 1.70 (The use of BOOST_*_ENDIAN and BOOST_BYTE_ORDER is deprecated.)
|
||||
#if BOOST_VERSION == 107000 && !defined(BOOST_PREDEF_DETAIL_ENDIAN_COMPAT_H)
|
||||
# define BOOST_PREDEF_DETAIL_ENDIAN_COMPAT_H
|
||||
# include <boost/predef/other/endian.h>
|
||||
#if BOOST_ENDIAN_BIG_BYTE
|
||||
# define BOOST_BIG_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 4321
|
||||
#endif
|
||||
#if BOOST_ENDIAN_LITTLE_BYTE
|
||||
# define BOOST_LITTLE_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 1234
|
||||
#endif
|
||||
#if BOOST_ENDIAN_LITTLE_WORD
|
||||
# define BOOST_PDP_ENDIAN
|
||||
# define BOOST_BYTE_ORDER 2134
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/archive/basic_binary_iprimitive.hpp>
|
||||
#include <boost/archive/basic_binary_iarchive.hpp>
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,10 @@
|
|||
#include <limits>
|
||||
#include <set>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/any.hpp>
|
||||
#include "include_base_utils.h"
|
||||
#include "auto_val_init.h"
|
||||
|
||||
|
|
@ -111,17 +114,6 @@ namespace misc_utils
|
|||
return (std::numeric_limits<t_type>::max)();
|
||||
}
|
||||
|
||||
// TEMPLATE STRUCT less
|
||||
template<class _Ty>
|
||||
struct less_as_pod
|
||||
: public std::binary_function<_Ty, _Ty, bool>
|
||||
{ // functor for operator<
|
||||
bool operator()(const _Ty& _Left, const _Ty& _Right) const
|
||||
{ // apply operator< to operands
|
||||
return memcmp(&_Left, &_Right, sizeof(_Left)) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
template<class _Ty>
|
||||
bool is_less_as_pod(const _Ty& _Left, const _Ty& _Right)
|
||||
{ // apply operator< to operands
|
||||
|
|
@ -282,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<typename key_t, typename associated_data_t>
|
||||
friend std::ostream & operator<< (std::ostream &out, median_helper<key_t, associated_data_t> const &mh);
|
||||
}; // class median_helper
|
||||
|
|
@ -300,26 +307,25 @@ namespace misc_utils
|
|||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
template<class type_vec_type>
|
||||
type_vec_type median(std::vector<type_vec_type> &v)
|
||||
template<typename container_t>
|
||||
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<type_vec_type>();
|
||||
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;
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
|
@ -381,6 +387,11 @@ namespace misc_utils
|
|||
virtual void do_call(){};
|
||||
};
|
||||
|
||||
template<typename param_t>
|
||||
struct call_basic_param
|
||||
{
|
||||
virtual void do_call(param_t& p) {};
|
||||
};
|
||||
|
||||
template<typename t_callback>
|
||||
struct call_specific: public call_basic
|
||||
|
|
@ -395,12 +406,34 @@ namespace misc_utils
|
|||
t_callback m_cb;
|
||||
};
|
||||
|
||||
template<typename param_t, typename t_callback>
|
||||
struct call_specific_param : public call_basic_param<param_t>
|
||||
{
|
||||
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<typename t_callback>
|
||||
auto build_abstract_callback(t_callback cb) -> std::shared_ptr<call_basic>
|
||||
{
|
||||
return std::shared_ptr<call_basic>(new call_specific<t_callback>(cb));
|
||||
}
|
||||
|
||||
|
||||
template<typename param_t, typename t_callback>
|
||||
auto build_abstract_callback_param(t_callback cb) -> std::shared_ptr<call_basic_param<param_t>>
|
||||
{
|
||||
return std::shared_ptr<call_basic_param<param_t>>(new call_specific_param<param_t, t_callback>(cb));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class callback_type>
|
||||
|
|
@ -436,6 +469,67 @@ namespace misc_utils
|
|||
return res.first;
|
||||
}
|
||||
|
||||
|
||||
class events_dispatcher
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
template<typename param_t>
|
||||
struct callback_entry
|
||||
{
|
||||
std::shared_ptr<epee::misc_utils::call_basic_param<const param_t> > m_cb;
|
||||
};
|
||||
|
||||
std::map<std::type_index, boost::any> m_callbacks;
|
||||
|
||||
template<typename param_t, typename callback_t>
|
||||
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<const param_t> cb_entry = { epee::misc_utils::build_abstract_callback_param<const param_t>(cb) };
|
||||
|
||||
m_callbacks[ti] = cb_entry;
|
||||
}
|
||||
|
||||
template<typename param_t>
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename param_t>
|
||||
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<const param_t >* pcallback_entry = boost::any_cast<callback_entry<const param_t >>(&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
|
||||
|
||||
|
|
|
|||
|
|
@ -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<std::string>& genabled_channels = get_enabled_channels();
|
||||
std::list<std::string> 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<std::string>& 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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -693,7 +693,7 @@ bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, con
|
|||
shared_context->cond.notify_one();
|
||||
};
|
||||
|
||||
sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, _1, local_shared_context));
|
||||
sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, boost::placeholders::_1, local_shared_context));
|
||||
while(local_shared_context->ec == boost::asio::error::would_block) {
|
||||
bool r = false;
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -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 typename_t>
|
||||
typename_t get_documentation_json_struct()
|
||||
{
|
||||
return AUTO_VAL_INIT_T(typename_t);
|
||||
}
|
||||
|
||||
template<typename request_t, typename response_t>
|
||||
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<request_t>();
|
||||
response_t res = get_documentation_json_struct<response_t>();
|
||||
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<typename command_type_t::request, typename command_type_t::response>(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<json_command_type_t<command_type>>("[" 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<json_command_type_t<command_type>>("[" 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<json_command_type_t<command_type>>(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)) \
|
||||
{ \
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,11 +46,12 @@ namespace levin
|
|||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class levin_client_impl
|
||||
template<typename transport_t>
|
||||
class levin_client_impl_t
|
||||
{
|
||||
public:
|
||||
levin_client_impl();
|
||||
virtual ~levin_client_impl();
|
||||
levin_client_impl_t();
|
||||
virtual ~levin_client_impl_t();
|
||||
|
||||
bool connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0");
|
||||
bool connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip = "0.0.0.0");
|
||||
|
|
@ -61,26 +62,30 @@ namespace levin
|
|||
virtual int notify(int command, const std::string& in_buff);
|
||||
|
||||
protected:
|
||||
net_utils::blocked_mode_client m_transport;
|
||||
transport_t m_transport;
|
||||
//net_utils::blocked_mode_client m_transport;
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
class levin_client_impl2: public levin_client_impl
|
||||
template<typename transport_t>
|
||||
class levin_client_impl2: public levin_client_impl_t<transport_t>
|
||||
{
|
||||
public:
|
||||
|
||||
int invoke(int command, const std::string& in_buff, std::string& buff_out);
|
||||
int notify(int command, const std::string& in_buff);
|
||||
|
||||
transport_t& get_transport() {return this->m_transport;}
|
||||
};
|
||||
|
||||
}
|
||||
namespace net_utils
|
||||
{
|
||||
typedef levin::levin_client_impl levin_client;
|
||||
typedef levin::levin_client_impl2 levin_client2;
|
||||
typedef levin::levin_client_impl_t<net_utils::blocked_mode_client> levin_client;
|
||||
typedef levin::levin_client_impl2<net_utils::blocked_mode_client> levin_client2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,175 +32,174 @@
|
|||
#include "string_tools.h"
|
||||
namespace epee
|
||||
{
|
||||
namespace levin
|
||||
{
|
||||
inline
|
||||
bool levin_client_impl::connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip)
|
||||
{
|
||||
return m_transport.connect(string_tools::get_ip_string_from_int32(ip), port, timeout, timeout, bind_ip);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
bool levin_client_impl::connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip)
|
||||
{
|
||||
return m_transport.connect(addr, port, timeout, timeout, bind_ip);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
bool levin_client_impl::is_connected()
|
||||
{
|
||||
return m_transport.is_connected();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
bool levin_client_impl::disconnect()
|
||||
{
|
||||
return m_transport.disconnect();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
levin_client_impl::levin_client_impl()
|
||||
{
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
levin_client_impl::~levin_client_impl()
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
int levin_client_impl::invoke(int command, const std::string& in_buff, std::string& buff_out)
|
||||
{
|
||||
if(!is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head head = {0};
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = true;
|
||||
head.m_command = command;
|
||||
if(!m_transport.send(&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if(!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
std::string local_buff;
|
||||
if(!m_transport.recv_n(local_buff, sizeof(bucket_head)))
|
||||
return -1;
|
||||
|
||||
head = *(bucket_head*)local_buff.data();
|
||||
|
||||
|
||||
if(head.m_signature!=LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_PRINT_L0("Signature missmatch in response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(!m_transport.recv_n(buff_out, head.m_cb))
|
||||
return -1;
|
||||
|
||||
return head.m_return_code;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
int levin_client_impl::notify(int command, const std::string& in_buff)
|
||||
{
|
||||
if(!is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head head = {0};
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = false;
|
||||
head.m_command = command;
|
||||
|
||||
if(!m_transport.send((const char*)&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if(!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
int levin_client_impl2::invoke(int command, const std::string& in_buff, std::string& buff_out)
|
||||
{
|
||||
if(!is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head2 head = {0};
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = true;
|
||||
head.m_command = static_cast<uint32_t>(command);
|
||||
head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
|
||||
head.m_flags = LEVIN_PACKET_REQUEST;
|
||||
if(!m_transport.send(&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if(!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
//Since other side of connection could be running by async server,
|
||||
//we can receive some unexpected notify(forwarded broadcast notifications for example).
|
||||
//let's ignore every notify in the channel until we get invoke response
|
||||
std::string local_buff;
|
||||
|
||||
while (true)
|
||||
namespace levin
|
||||
{
|
||||
if (!m_transport.recv_n(local_buff, sizeof(bucket_head2)))
|
||||
return LEVIN_ERROR_NET_ERROR;
|
||||
|
||||
head = *(bucket_head2*)local_buff.data();
|
||||
if (head.m_signature != LEVIN_SIGNATURE)
|
||||
template<typename transport_t>
|
||||
bool levin_client_impl_t<transport_t>::connect(u_long ip, int port, unsigned int timeout, const std::string& bind_ip)
|
||||
{
|
||||
LOG_PRINT_L0("Signature missmatch in response");
|
||||
return LEVIN_ERROR_SIGNATURE_MISMATCH;
|
||||
return m_transport.connect(string_tools::get_ip_string_from_int32(ip), port, timeout, timeout, bind_ip);
|
||||
}
|
||||
if (!m_transport.recv_n(buff_out, head.m_cb))
|
||||
return LEVIN_ERROR_NET_ERROR;
|
||||
|
||||
//now check if this is response to invoke (and extra validate if it's response to this(!) invoke)
|
||||
if (head.m_flags&LEVIN_PACKET_RESPONSE)
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
bool levin_client_impl_t<transport_t>::connect(const std::string& addr, int port, unsigned int timeout, const std::string& bind_ip)
|
||||
{
|
||||
//we got response, extra validate if its response to our request
|
||||
CHECK_AND_ASSERT_MES(head.m_command == static_cast<uint32_t>(command), LEVIN_ERROR_PROTOCOL_INCONSISTENT, "command id missmatch in response: " << head.m_command << ", expected: " << command);
|
||||
return m_transport.connect(addr, port, timeout, timeout, bind_ip);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
bool levin_client_impl_t<transport_t>::is_connected()
|
||||
{
|
||||
return m_transport.is_connected();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
bool levin_client_impl_t<transport_t>::disconnect()
|
||||
{
|
||||
return m_transport.disconnect();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
levin_client_impl_t<transport_t>::levin_client_impl_t()
|
||||
{
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
levin_client_impl_t<transport_t>::~levin_client_impl_t()
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
int levin_client_impl_t<transport_t>::invoke(int command, const std::string& in_buff, std::string& buff_out)
|
||||
{
|
||||
if (!is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head head = { 0 };
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = true;
|
||||
head.m_command = command;
|
||||
if (!m_transport.send(&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if (!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
std::string local_buff;
|
||||
if (!m_transport.recv_n(local_buff, sizeof(bucket_head)))
|
||||
return -1;
|
||||
|
||||
head = *(bucket_head*)local_buff.data();
|
||||
|
||||
|
||||
if (head.m_signature != LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_PRINT_L0("Signature missmatch in response");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!m_transport.recv_n(buff_out, head.m_cb))
|
||||
return -1;
|
||||
|
||||
return head.m_return_code;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
int levin_client_impl_t<transport_t>::notify(int command, const std::string& in_buff)
|
||||
{
|
||||
if (!this->is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head head = { 0 };
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = false;
|
||||
head.m_command = command;
|
||||
|
||||
if (!m_transport.send((const char*)&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if (!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
int levin_client_impl2<transport_t>::invoke(int command, const std::string& in_buff, std::string& buff_out)
|
||||
{
|
||||
if (!this->is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head2 head = { 0 };
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = true;
|
||||
head.m_command = static_cast<uint32_t>(command);
|
||||
head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
|
||||
head.m_flags = LEVIN_PACKET_REQUEST;
|
||||
if (!this->m_transport.send(&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if (!this->m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
//Since other side of connection could be running by async server,
|
||||
//we can receive some unexpected notify(forwarded broadcast notifications for example).
|
||||
//let's ignore every notify in the channel until we get invoke response
|
||||
std::string local_buff;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!this->m_transport.recv_n(local_buff, sizeof(bucket_head2)))
|
||||
return LEVIN_ERROR_NET_ERROR;
|
||||
|
||||
head = *(bucket_head2*)local_buff.data();
|
||||
if (head.m_signature != LEVIN_SIGNATURE)
|
||||
{
|
||||
LOG_PRINT_L0("Signature missmatch in response");
|
||||
return LEVIN_ERROR_SIGNATURE_MISMATCH;
|
||||
}
|
||||
if (!this->m_transport.recv_n(buff_out, head.m_cb))
|
||||
return LEVIN_ERROR_NET_ERROR;
|
||||
|
||||
//now check if this is response to invoke (and extra validate if it's response to this(!) invoke)
|
||||
if (head.m_flags&LEVIN_PACKET_RESPONSE)
|
||||
{
|
||||
//we got response, extra validate if its response to our request
|
||||
CHECK_AND_ASSERT_MES(head.m_command == static_cast<uint32_t>(command), LEVIN_ERROR_PROTOCOL_INCONSISTENT, "command id missmatch in response: " << head.m_command << ", expected: " << command);
|
||||
return head.m_return_code;
|
||||
}
|
||||
}
|
||||
//never comes here
|
||||
return LEVIN_ERROR_INTERNAL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
template<typename transport_t>
|
||||
int levin_client_impl2<transport_t>::notify(int command, const std::string& in_buff)
|
||||
{
|
||||
if (!this->is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head2 head = { 0 };
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = false;
|
||||
head.m_command = command;
|
||||
head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
|
||||
head.m_flags = LEVIN_PACKET_REQUEST;
|
||||
|
||||
if (!this->m_transport.send((const char*)&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if (!this->m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
//never comes here
|
||||
return LEVIN_ERROR_INTERNAL;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline
|
||||
int levin_client_impl2::notify(int command, const std::string& in_buff)
|
||||
{
|
||||
if(!is_connected())
|
||||
return -1;
|
||||
|
||||
bucket_head2 head = {0};
|
||||
head.m_signature = LEVIN_SIGNATURE;
|
||||
head.m_cb = in_buff.size();
|
||||
head.m_have_to_return_data = false;
|
||||
head.m_command = command;
|
||||
head.m_protocol_version = LEVIN_PROTOCOL_VER_1;
|
||||
head.m_flags = LEVIN_PACKET_REQUEST;
|
||||
|
||||
if(!m_transport.send((const char*)&head, sizeof(head)))
|
||||
return -1;
|
||||
|
||||
if(!m_transport.send(in_buff))
|
||||
return -1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
|
|
@ -155,6 +155,13 @@ namespace net_utils
|
|||
{
|
||||
content.port = boost::lexical_cast<uint64_t>(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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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<class t_storage> \
|
||||
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<class t_storage> \
|
||||
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<type_name>(s); \
|
||||
} \
|
||||
return r; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
40
contrib/epee/include/serialization/keyvalue_helper_structs.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) 2006-2021, 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
|
||||
|
||||
namespace epee
|
||||
{
|
||||
|
||||
template<class _Ty1, class _Ty2>
|
||||
struct kvserializable_pair : public std::pair<_Ty1, _Ty2>
|
||||
{
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(first)
|
||||
KV_SERIALIZE(second)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <boost/mpl/contains.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace epee
|
||||
|
|
@ -428,6 +429,55 @@ namespace epee
|
|||
bool kv_unserialize(std::deque<t_type>& d, t_storage& stg, typename t_storage::hsection hparent_section, const char* pname)
|
||||
{
|
||||
return kv_serialization_overloads_impl_is_base_serializable_types<boost::mpl::contains<base_serializable_types<t_storage>, typename std::remove_const<t_type>::type>::value>::kv_unserialize(d, stg, hparent_section, pname);
|
||||
}
|
||||
}
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
//boost::optional
|
||||
template<class t_type, class t_storage>
|
||||
bool kv_serialize(const boost::optional<t_type>& 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<class t_type, class t_storage>
|
||||
bool kv_unserialize(boost::optional<t_type>& 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<class t_type, class t_storage>
|
||||
bool kv_serialize(const boost::shared_ptr<t_type>& 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<class t_type, class t_storage>
|
||||
bool kv_unserialize(boost::shared_ptr<t_type>& 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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -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<class t_response>
|
||||
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<class t_request, class t_response, class t_transport>
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -267,20 +267,20 @@ namespace epee
|
|||
|
||||
#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
|
||||
if(!is_notify && command_id == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);}
|
||||
|
||||
#define HANDLE_INVOKE_T2(COMMAND, func) \
|
||||
if(!is_notify && COMMAND::ID == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);}
|
||||
|
||||
|
||||
#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
|
||||
if(is_notify && command_id == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);}
|
||||
|
||||
#define HANDLE_NOTIFY_T2(NOTIFY, func) \
|
||||
if(is_notify && NOTIFY::ID == command) \
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
|
||||
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);}
|
||||
|
||||
|
||||
#define CHAIN_INVOKE_MAP2(func) \
|
||||
|
|
|
|||
|
|
@ -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<typename cb_t>
|
||||
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<typename cb_t>
|
||||
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<class t_value>
|
||||
bool portable_storage::insert_next_value(harray hval_array, const t_value& target)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<int64_t>(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);
|
||||
|
|
|
|||
|
|
@ -129,7 +129,20 @@ POP_VS_WARNINGS
|
|||
template<typename from_type, typename to_type>
|
||||
struct convert_to_integral<from_type, to_type, false>
|
||||
{
|
||||
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<typename from_type_t, typename to_type_t>
|
||||
static void convert(const from_type_t& from, to_type_t& to)
|
||||
{
|
||||
ASSERT_AND_THROW_WRONG_CONVERSION();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#include <cctype>
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <objbase.h>
|
||||
#include <locale>
|
||||
#include <cstdlib>
|
||||
//#include <strsafe.h>
|
||||
#include <map>
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
|
@ -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<typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<std::string, std::string>& res, const std::basic_string<typename t_string::value_type> & key, t_type& val)
|
||||
{
|
||||
|
||||
}
|
||||
*/
|
||||
|
||||
template<class t_string, typename t_type>
|
||||
bool get_xparam_from_command_line(const std::map<t_string, t_string>& 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_
|
||||
|
|
|
|||
|
|
@ -84,6 +84,8 @@ namespace epee
|
|||
template<typename t_proxy_object, typename t_proxy_lock_time_watching_policy>
|
||||
friend class locked_object_proxy;
|
||||
public:
|
||||
typedef std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> lock_shared_ptr;
|
||||
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> lock()
|
||||
{
|
||||
std::shared_ptr<locked_object_proxy<t_object, lock_time_watching_policy>> res;
|
||||
|
|
|
|||
|
|
@ -711,4 +711,4 @@ namespace epee
|
|||
#define EXCLUSIVE_CRITICAL_REGION_BEGIN(x) { EXCLUSIVE_CRITICAL_REGION_LOCAL(x)
|
||||
#define EXCLUSIVE_CRITICAL_REGION_END() }
|
||||
|
||||
}
|
||||
} // namespace epee
|
||||
|
|
|
|||
|
|
@ -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 <boost/preprocessor/stringize.hpp>
|
||||
|
||||
#define PUSH_VS_WARNINGS
|
||||
|
|
|
|||
1
contrib/tor-connect
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit b589edb1906dccb387cfeded6ed12286c5f0405f
|
||||
42
resources/app_icon.svg
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<svg width="512" height="512" viewBox="0 0 512 512" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_1397_4507)">
|
||||
<rect width="512" height="512" rx="115" fill="#0C0C3A"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M286.571 80H327.158C341.059 79.9997 352.756 79.9994 362.33 80.79C372.345 81.617 381.885 83.4143 390.946 88.0805C404.749 95.1883 415.972 106.53 423.005 120.48C427.622 129.638 429.4 139.279 430.218 149.4C431.001 159.076 431 170.897 431 184.947V223.852C431 237.902 431.001 249.723 430.218 259.399C429.4 269.521 427.622 279.162 423.005 288.32C415.972 302.269 404.749 313.611 390.946 320.719C381.885 325.385 372.345 327.182 362.33 328.009C352.756 328.8 341.059 328.8 327.157 328.799H205.955C197.442 328.799 189.759 323.637 186.465 315.703C183.171 307.769 184.908 298.613 190.872 292.473L290.961 189.435L321.127 219.364L256.325 286.076H326.311C341.283 286.076 351.24 286.059 358.888 285.428C366.288 284.817 369.646 283.738 371.755 282.652C377.603 279.64 382.358 274.835 385.338 268.924C386.413 266.792 387.48 263.4 388.085 255.92C388.71 248.191 388.726 238.128 388.726 222.997V185.802C388.726 170.671 388.71 160.608 388.085 152.879C387.48 145.4 386.413 142.007 385.338 139.875C382.358 133.965 377.603 129.159 371.755 126.147C369.646 125.061 366.288 123.982 358.888 123.371C351.24 122.74 341.283 122.723 326.311 122.723H287.425C272.289 122.723 262.215 122.74 254.483 123.381C246.996 124.003 243.611 125.1 241.495 126.199C235.611 129.257 230.846 134.132 227.893 140.115C226.831 142.267 225.787 145.701 225.263 153.275C224.723 161.096 224.829 171.276 225.013 186.572L225.225 204.139L182.955 204.66L182.733 186.231C182.561 172.024 182.416 160.078 183.092 150.298C183.799 140.074 185.485 130.322 190.064 121.045C197.034 106.924 208.28 95.4193 222.166 88.2041C231.289 83.4635 240.917 81.6404 251.024 80.8017C260.692 79.9994 272.513 79.9997 286.571 80Z" fill="url(#paint0_linear_1397_4507)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M286.571 80H327.158C341.059 79.9997 352.756 79.9994 362.33 80.79C372.345 81.617 381.885 83.4143 390.946 88.0805C404.749 95.1883 415.972 106.53 423.005 120.48C427.622 129.638 429.4 139.279 430.218 149.4C431.001 159.076 431 170.897 431 184.947V223.852C431 237.902 431.001 249.723 430.218 259.399C429.4 269.521 427.622 279.162 423.005 288.32C415.972 302.269 404.749 313.611 390.946 320.719C381.885 325.385 372.345 327.182 362.33 328.009C352.756 328.8 341.059 328.8 327.157 328.799H205.955C197.442 328.799 189.759 323.637 186.465 315.703C183.171 307.769 184.908 298.613 190.872 292.473L290.961 189.435L321.127 219.364L256.325 286.076H326.311C341.283 286.076 351.24 286.059 358.888 285.428C366.288 284.817 369.646 283.738 371.755 282.652C377.603 279.64 382.358 274.835 385.338 268.924C386.413 266.792 387.48 263.4 388.085 255.92C388.71 248.191 388.726 238.128 388.726 222.997V185.802C388.726 170.671 388.71 160.608 388.085 152.879C387.48 145.4 386.413 142.007 385.338 139.875C382.358 133.965 377.603 129.159 371.755 126.147C369.646 125.061 366.288 123.982 358.888 123.371C351.24 122.74 341.283 122.723 326.311 122.723H287.425C272.289 122.723 262.215 122.74 254.483 123.381C246.996 124.003 243.611 125.1 241.495 126.199C235.611 129.257 230.846 134.132 227.893 140.115C226.831 142.267 225.787 145.701 225.263 153.275C224.723 161.096 224.829 171.276 225.013 186.572L225.225 204.139L182.955 204.66L182.733 186.231C182.561 172.024 182.416 160.078 183.092 150.298C183.799 140.074 185.485 130.322 190.064 121.045C197.034 106.924 208.28 95.4193 222.166 88.2041C231.289 83.4635 240.917 81.6404 251.024 80.8017C260.692 79.9994 272.513 79.9997 286.571 80Z" fill="url(#paint1_radial_1397_4507)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M286.571 80H327.158C341.059 79.9997 352.756 79.9994 362.33 80.79C372.345 81.617 381.885 83.4143 390.946 88.0805C404.749 95.1883 415.972 106.53 423.005 120.48C427.622 129.638 429.4 139.279 430.218 149.4C431.001 159.076 431 170.897 431 184.947V223.852C431 237.902 431.001 249.723 430.218 259.399C429.4 269.521 427.622 279.162 423.005 288.32C415.972 302.269 404.749 313.611 390.946 320.719C381.885 325.385 372.345 327.182 362.33 328.009C352.756 328.8 341.059 328.8 327.157 328.799H205.955C197.442 328.799 189.759 323.637 186.465 315.703C183.171 307.769 184.908 298.613 190.872 292.473L290.961 189.435L321.127 219.364L256.325 286.076H326.311C341.283 286.076 351.24 286.059 358.888 285.428C366.288 284.817 369.646 283.738 371.755 282.652C377.603 279.64 382.358 274.835 385.338 268.924C386.413 266.792 387.48 263.4 388.085 255.92C388.71 248.191 388.726 238.128 388.726 222.997V185.802C388.726 170.671 388.71 160.608 388.085 152.879C387.48 145.4 386.413 142.007 385.338 139.875C382.358 133.965 377.603 129.159 371.755 126.147C369.646 125.061 366.288 123.982 358.888 123.371C351.24 122.74 341.283 122.723 326.311 122.723H287.425C272.289 122.723 262.215 122.74 254.483 123.381C246.996 124.003 243.611 125.1 241.495 126.199C235.611 129.257 230.846 134.132 227.893 140.115C226.831 142.267 225.787 145.701 225.263 153.275C224.723 161.096 224.829 171.276 225.013 186.572L225.225 204.139L182.955 204.66L182.733 186.231C182.561 172.024 182.416 160.078 183.092 150.298C183.799 140.074 185.485 130.322 190.064 121.045C197.034 106.924 208.28 95.4193 222.166 88.2041C231.289 83.4635 240.917 81.6404 251.024 80.8017C260.692 79.9994 272.513 79.9997 286.571 80Z" fill="url(#paint2_radial_1397_4507)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M286.571 80H327.158C341.059 79.9997 352.756 79.9994 362.33 80.79C372.345 81.617 381.885 83.4143 390.946 88.0805C404.749 95.1883 415.972 106.53 423.005 120.48C427.622 129.638 429.4 139.279 430.218 149.4C431.001 159.076 431 170.897 431 184.947V223.852C431 237.902 431.001 249.723 430.218 259.399C429.4 269.521 427.622 279.162 423.005 288.32C415.972 302.269 404.749 313.611 390.946 320.719C381.885 325.385 372.345 327.182 362.33 328.009C352.756 328.8 341.059 328.8 327.157 328.799H205.955C197.442 328.799 189.759 323.637 186.465 315.703C183.171 307.769 184.908 298.613 190.872 292.473L290.961 189.435L321.127 219.364L256.325 286.076H326.311C341.283 286.076 351.24 286.059 358.888 285.428C366.288 284.817 369.646 283.738 371.755 282.652C377.603 279.64 382.358 274.835 385.338 268.924C386.413 266.792 387.48 263.4 388.085 255.92C388.71 248.191 388.726 238.128 388.726 222.997V185.802C388.726 170.671 388.71 160.608 388.085 152.879C387.48 145.4 386.413 142.007 385.338 139.875C382.358 133.965 377.603 129.159 371.755 126.147C369.646 125.061 366.288 123.982 358.888 123.371C351.24 122.74 341.283 122.723 326.311 122.723H287.425C272.289 122.723 262.215 122.74 254.483 123.381C246.996 124.003 243.611 125.1 241.495 126.199C235.611 129.257 230.846 134.132 227.893 140.115C226.831 142.267 225.787 145.701 225.263 153.275C224.723 161.096 224.829 171.276 225.013 186.572L225.225 204.139L182.955 204.66L182.733 186.231C182.561 172.024 182.416 160.078 183.092 150.298C183.799 140.074 185.485 130.322 190.064 121.045C197.034 106.924 208.28 95.4193 222.166 88.2041C231.289 83.4635 240.917 81.6404 251.024 80.8017C260.692 79.9994 272.513 79.9997 286.571 80Z" fill="url(#paint3_radial_1397_4507)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M153.112 388.466C160.76 389.098 170.717 389.114 185.689 389.114H225.228C238.879 389.114 247.959 389.1 254.952 388.573C261.73 388.061 264.838 387.156 266.785 386.253C273.548 383.118 278.974 377.634 282.077 370.799C282.97 368.831 283.866 365.69 284.372 358.84C284.894 351.772 284.908 342.596 284.908 328.799H327.181L327.182 329.579C327.182 342.391 327.182 353.172 326.528 362.021C325.845 371.266 324.364 380.102 320.5 388.612C313.178 404.744 300.373 417.685 284.411 425.085C275.99 428.989 267.248 430.487 258.099 431.177C249.344 431.838 238.677 431.838 225.999 431.837L184.842 431.837C170.94 431.838 159.244 431.838 149.67 431.047C139.655 430.22 130.115 428.423 121.054 423.757C107.251 416.649 96.0284 405.308 88.9954 391.358C84.3783 382.2 82.5999 372.559 81.7816 362.437C80.9994 352.761 80.9997 340.94 81 326.89V287.985C80.9997 273.935 80.9994 262.115 81.7816 252.438C82.5999 242.317 84.3783 232.676 88.9954 223.518C96.0284 209.568 107.251 198.226 121.054 191.119C130.115 186.452 139.655 184.655 149.67 183.828C159.244 183.038 170.941 183.038 184.843 183.038H306.045C317.718 183.038 327.181 192.602 327.181 204.4C327.181 216.197 317.718 225.761 306.045 225.761H185.689C170.717 225.761 160.76 225.778 153.112 226.409C145.712 227.02 142.354 228.099 140.245 229.185C134.397 232.197 129.642 237.003 126.661 242.914C125.587 245.045 124.519 248.438 123.915 255.917C123.29 263.646 123.274 273.71 123.274 288.841V326.035C123.274 341.166 123.29 351.229 123.915 358.958C124.519 366.438 125.587 369.831 126.661 371.962C129.642 377.873 134.397 382.679 140.245 385.69C142.354 386.776 145.712 387.855 153.112 388.466Z" fill="url(#paint4_linear_1397_4507)"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M153.112 388.466C160.76 389.098 170.717 389.114 185.689 389.114H225.228C238.879 389.114 247.959 389.1 254.952 388.573C261.73 388.061 264.838 387.156 266.785 386.253C273.548 383.118 278.974 377.634 282.077 370.799C282.97 368.831 283.866 365.69 284.372 358.84C284.894 351.772 284.908 342.596 284.908 328.799H327.181L327.182 329.579C327.182 342.391 327.182 353.172 326.528 362.021C325.845 371.266 324.364 380.102 320.5 388.612C313.178 404.744 300.373 417.685 284.411 425.085C275.99 428.989 267.248 430.487 258.099 431.177C249.344 431.838 238.677 431.838 225.999 431.837L184.842 431.837C170.94 431.838 159.244 431.838 149.67 431.047C139.655 430.22 130.115 428.423 121.054 423.757C107.251 416.649 96.0284 405.308 88.9954 391.358C84.3783 382.2 82.5999 372.559 81.7816 362.437C80.9994 352.761 80.9997 340.94 81 326.89V287.985C80.9997 273.935 80.9994 262.115 81.7816 252.438C82.5999 242.317 84.3783 232.676 88.9954 223.518C96.0284 209.568 107.251 198.226 121.054 191.119C130.115 186.452 139.655 184.655 149.67 183.828C159.244 183.038 170.941 183.038 184.843 183.038H306.045C317.718 183.038 327.181 192.602 327.181 204.4C327.181 216.197 317.718 225.761 306.045 225.761H185.689C170.717 225.761 160.76 225.778 153.112 226.409C145.712 227.02 142.354 228.099 140.245 229.185C134.397 232.197 129.642 237.003 126.661 242.914C125.587 245.045 124.519 248.438 123.915 255.917C123.29 263.646 123.274 273.71 123.274 288.841V326.035C123.274 341.166 123.29 351.229 123.915 358.958C124.519 366.438 125.587 369.831 126.661 371.962C129.642 377.873 134.397 382.679 140.245 385.69C142.354 386.776 145.712 387.855 153.112 388.466Z" fill="url(#paint5_radial_1397_4507)"/>
|
||||
</g>
|
||||
<defs>
|
||||
<linearGradient id="paint0_linear_1397_4507" x1="247.767" y1="326.867" x2="250.596" y2="79.6832" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.43118" stop-color="#498FFD"/>
|
||||
<stop offset="1" stop-color="#16D1D6"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint1_radial_1397_4507" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(179.657 155.329) rotate(-15.5725) scale(159.744 159.494)">
|
||||
<stop stop-color="#18CFD7"/>
|
||||
<stop offset="1" stop-color="#18CFD7" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint2_radial_1397_4507" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(272.994 225.963) rotate(152.354) scale(59.8025 59.7092)">
|
||||
<stop stop-color="#4990FE"/>
|
||||
<stop offset="0.353962" stop-color="#4990FE"/>
|
||||
<stop offset="1" stop-color="#4990FE" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="paint3_radial_1397_4507" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(199.838 306.686) rotate(-45.9392) scale(108.824 108.654)">
|
||||
<stop stop-color="#4990FE"/>
|
||||
<stop offset="0.405688" stop-color="#4990FE"/>
|
||||
<stop offset="1" stop-color="#4990FE" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<linearGradient id="paint4_linear_1397_4507" x1="328.491" y1="432.817" x2="329.401" y2="180.559" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#2950FF"/>
|
||||
<stop offset="0.821717" stop-color="#498FFD"/>
|
||||
</linearGradient>
|
||||
<radialGradient id="paint5_radial_1397_4507" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(328.491 326.867) rotate(129.289) scale(107.559 106.428)">
|
||||
<stop offset="0.337169" stop-color="#2950FF"/>
|
||||
<stop offset="0.792226" stop-color="#2950FF" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<clipPath id="clip0_1397_4507">
|
||||
<rect width="512" height="512" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 12 KiB |
BIN
resources/app_icon_256.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 652 KiB |
|
Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 201 KiB |
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 287 KiB |
|
Before Width: | Height: | Size: 330 KiB After Width: | Height: | Size: 439 KiB |
|
Before Width: | Height: | Size: 604 KiB After Width: | Height: | Size: 805 KiB |
|
|
@ -121,16 +121,19 @@ add_library(currency_core ${CURRENCY_CORE})
|
|||
add_dependencies(currency_core version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(currency_core CURRENCY_CORE)
|
||||
|
||||
add_library(wallet ${WALLET})
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Android" )
|
||||
add_library(wallet ${WALLET})
|
||||
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_library(wallet ${WALLET})
|
||||
add_dependencies(wallet version ${PCH_LIB_NAME})
|
||||
ENABLE_SHARED_PCH(wallet WALLET)
|
||||
endif()
|
||||
|
||||
if(NOT DISABLE_TOR)
|
||||
target_link_libraries(wallet tor-connect)
|
||||
endif()
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -159,19 +162,20 @@ 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})
|
||||
add_dependencies(simplewallet version)
|
||||
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)
|
||||
|
||||
|
|
@ -195,7 +199,10 @@ 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()
|
||||
|
||||
if(APPLE)
|
||||
target_link_libraries(Zano ${COCOA_LIBRARY})
|
||||
|
|
|
|||
|
|
@ -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<class t_object>
|
||||
|
|
|
|||
47
src/common/boost_serialization_maps.h
Normal file
|
|
@ -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 <class t_archive> inline void serialize(t_archive &_arch, const unsigned int ver) {
|
||||
|
||||
template<size_t A, size_t B> 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<sz, sizeof(*this)>::_cResult;
|
||||
|
||||
|
||||
|
||||
#define BOOST_SERIALIZE(x) _arch & x;
|
||||
#define BOOST_SERIALIZE_BASE_CLASS(class_type) _arch & static_cast<class_type&>(*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()
|
||||
};
|
||||
*/
|
||||
|
|
@ -10,33 +10,36 @@
|
|||
|
||||
namespace command_line
|
||||
{
|
||||
const arg_descriptor<bool> arg_help = {"help", "Produce help message"};
|
||||
const arg_descriptor<bool> arg_version = {"version", "Output version information"};
|
||||
const arg_descriptor<std::string> arg_data_dir = {"data-dir", "Specify data directory", ""};
|
||||
const arg_descriptor<bool> arg_help ("help", "Produce help message");
|
||||
const arg_descriptor<bool> arg_version ("version", "Output version information");
|
||||
const arg_descriptor<std::string> arg_data_dir ("data-dir", "Specify data directory", "");
|
||||
|
||||
const arg_descriptor<int> arg_stop_after_height = { "stop-after-height", "If specified, the daemon will stop immediately after a block with the given height is added", 0 };
|
||||
const arg_descriptor<int> arg_stop_after_height ( "stop-after-height", "If specified, the daemon will stop immediately after a block with the given height is added", 0 );
|
||||
|
||||
const arg_descriptor<std::string> arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") };
|
||||
const arg_descriptor<bool> arg_os_version = { "os-version", "" };
|
||||
const arg_descriptor<std::string> arg_config_file ( "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") );
|
||||
const arg_descriptor<bool> arg_os_version ( "os-version", "" );
|
||||
|
||||
const arg_descriptor<std::string> arg_log_dir = { "log-dir", "", "", true};
|
||||
const arg_descriptor<std::string> arg_log_file = { "log-file", "", "" };
|
||||
const arg_descriptor<int> arg_log_level = { "log-level", "", LOG_LEVEL_0, true };
|
||||
const arg_descriptor<std::string> arg_log_dir ( "log-dir", "");
|
||||
const arg_descriptor<std::string> arg_log_file ( "log-file", "", "");
|
||||
const arg_descriptor<int> arg_log_level ( "log-level", "");
|
||||
|
||||
const arg_descriptor<bool> arg_console = { "no-console", "Disable daemon console commands" };
|
||||
const arg_descriptor<bool> arg_show_details = { "currency-details", "Display currency details" };
|
||||
const arg_descriptor<bool> arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" };
|
||||
const arg_descriptor<bool> arg_console ( "no-console", "Disable daemon console commands" );
|
||||
const arg_descriptor<bool> arg_show_details ( "currency-details", "Display currency details" );
|
||||
const arg_descriptor<bool> arg_show_rpc_autodoc ( "show_rpc_autodoc", "Display rpc auto-generated documentation template" );
|
||||
|
||||
const arg_descriptor<bool> arg_disable_upnp = { "disable-upnp", "Disable UPnP (enhances local network privacy)", false, true };
|
||||
const arg_descriptor<bool> arg_disable_upnp ( "disable-upnp", "Disable UPnP (enhances local network privacy)");
|
||||
const arg_descriptor<bool> arg_disable_ntp ( "disable-ntp", "Disable NTP, could enhance to time synchronization issue but increase network privacy, consider using disable-stop-if-time-out-of-sync with it");
|
||||
|
||||
const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync = { "disable-stop-if-time-out-of-sync", "Do not stop the daemon if serious time synchronization problem is detected", false, true };
|
||||
const arg_descriptor<bool> arg_disable_stop_on_low_free_space = { "disable-stop-on-low-free-space", "Do not stop the daemon if free space at data dir is critically low", false, true };
|
||||
const arg_descriptor<bool> arg_enable_offers_service = { "enable-offers-service", "Enables marketplace feature", false, false};
|
||||
const arg_descriptor<std::string> arg_db_engine = { "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB, false };
|
||||
const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync ( "disable-stop-if-time-out-of-sync", "Do not stop the daemon if serious time synchronization problem is detected");
|
||||
const arg_descriptor<bool> arg_disable_stop_on_low_free_space ( "disable-stop-on-low-free-space", "Do not stop the daemon if free space at data dir is critically low");
|
||||
const arg_descriptor<bool> arg_enable_offers_service ( "enable-offers-service", "Enables marketplace feature", false);
|
||||
const arg_descriptor<std::string> arg_db_engine ( "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB );
|
||||
|
||||
const arg_descriptor<bool> arg_no_predownload = { "no-predownload", "Do not pre-download blockchain database", };
|
||||
const arg_descriptor<bool> arg_force_predownload = { "force-predownload", "Pre-download blockchain database regardless of it's status", };
|
||||
const arg_descriptor<bool> arg_validate_predownload = { "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database", };
|
||||
const arg_descriptor<std::string> arg_predownload_link = { "predownload-link", "Override url for blockchain database pre-downloading", "", true };
|
||||
const arg_descriptor<bool> arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database");
|
||||
const arg_descriptor<bool> arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status");
|
||||
const arg_descriptor<bool> arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database");
|
||||
const arg_descriptor<std::string> arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading");
|
||||
|
||||
const arg_descriptor<std::string> arg_deeplink ( "deeplink-params", "Deeplink parameter, in that case app just forward params to running app");
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,32 +26,38 @@ namespace command_line
|
|||
arg_descriptor(const char* _name, const char* _description):
|
||||
name(_name),
|
||||
description(_description),
|
||||
not_use_default(true),
|
||||
use_default(false),
|
||||
default_value(T())
|
||||
{}
|
||||
arg_descriptor(const char* _name, const char* _description, const T& default_val) :
|
||||
name(_name),
|
||||
description(_description),
|
||||
not_use_default(false),
|
||||
use_default(true),
|
||||
default_value(default_val)
|
||||
{}
|
||||
arg_descriptor(const char* _name, const char* _description, const T& default_val, bool not_use_default) :
|
||||
name(_name),
|
||||
description(_description),
|
||||
default_value(default_val),
|
||||
not_use_default(not_use_default)
|
||||
{}
|
||||
// arg_descriptor(const char* _name, const char* _description, const T& default_val, bool not_use_default) :
|
||||
// name(_name),
|
||||
// description(_description),
|
||||
// default_value(default_val),
|
||||
// not_use_default(not_use_default)
|
||||
// {}
|
||||
|
||||
|
||||
|
||||
const char* name;
|
||||
const char* description;
|
||||
bool use_default;
|
||||
T default_value;
|
||||
bool not_use_default;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct arg_descriptor<std::vector<T>, false>
|
||||
{
|
||||
arg_descriptor(const char* _name, const char* _description) :
|
||||
name(_name),
|
||||
description(_description)
|
||||
{}
|
||||
|
||||
typedef std::vector<T> value_type;
|
||||
|
||||
const char* name;
|
||||
|
|
@ -79,7 +85,7 @@ namespace command_line
|
|||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
if (arg.use_default)
|
||||
semantic->default_value(arg.default_value);
|
||||
return semantic;
|
||||
}
|
||||
|
|
@ -88,7 +94,7 @@ namespace command_line
|
|||
boost::program_options::typed_value<T, char>* make_semantic(const arg_descriptor<T, false>& arg, const T& def)
|
||||
{
|
||||
auto semantic = boost::program_options::value<T>();
|
||||
if (!arg.not_use_default)
|
||||
if (arg.use_default)
|
||||
semantic->default_value(def);
|
||||
return semantic;
|
||||
}
|
||||
|
|
@ -216,6 +222,7 @@ namespace command_line
|
|||
extern const arg_descriptor<bool> arg_show_details;
|
||||
extern const arg_descriptor<bool> arg_show_rpc_autodoc;
|
||||
extern const arg_descriptor<bool> arg_disable_upnp;
|
||||
extern const arg_descriptor<bool> arg_disable_ntp;
|
||||
extern const arg_descriptor<bool> arg_disable_stop_if_time_out_of_sync;
|
||||
extern const arg_descriptor<bool> arg_disable_stop_on_low_free_space;
|
||||
extern const arg_descriptor<bool> arg_enable_offers_service;
|
||||
|
|
@ -224,4 +231,5 @@ namespace command_line
|
|||
extern const arg_descriptor<bool> arg_force_predownload;
|
||||
extern const arg_descriptor<bool> arg_validate_predownload;
|
||||
extern const arg_descriptor<std::string> arg_predownload_link;
|
||||
extern const arg_descriptor<std::string> arg_deeplink;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace serialization
|
||||
{
|
||||
//---------------------------------------------------
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//}
|
||||
285
src/common/crypto_serialization.h
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
// 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 <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/utility.hpp>
|
||||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
|
||||
#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<scalar_t>&)(r))
|
||||
FIELD(K1)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(c)
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(r))
|
||||
BOOST_SERIALIZE(K1)
|
||||
END_BOOST_SERIALIZATION()
|
||||
};
|
||||
|
||||
struct CLSAG_GGX_signature_serialized : public CLSAG_GGX_signature
|
||||
{
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(c)
|
||||
FIELD((std::vector<scalar_t>&)(r_g))
|
||||
FIELD((std::vector<scalar_t>&)(r_x))
|
||||
FIELD(K1)
|
||||
FIELD(K2)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(c)
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(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<scalar_t>&)(r_g))
|
||||
FIELD_N("r_x", (std::vector<scalar_t>&)(r_x))
|
||||
FIELD(K1)
|
||||
FIELD(K2)
|
||||
FIELD(K3)
|
||||
FIELD(K4)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(c)
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(r_g))
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(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<scalar_t>&)(y0s))
|
||||
FIELD((std::vector<scalar_t>&)(y1s))
|
||||
FIELD(c)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(amount_commitments_for_rp_aggregation)
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(y0s))
|
||||
BOOST_SERIALIZE((std::vector<scalar_t>&)(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 BGE_proof_s : public BGE_proof
|
||||
{
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(A)
|
||||
FIELD(B)
|
||||
FIELD(Pk)
|
||||
FIELD_N("f", (std::vector<scalar_t>&)(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 <class Archive>
|
||||
inline void serialize(Archive &a, crypto::public_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::public_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::secret_key &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::secret_key)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_derivation &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_derivation)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::key_image &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::key_image)]>(x);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::signature &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::signature)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::hash &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::hash)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::scalar_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::scalar_t)]>(x);
|
||||
}
|
||||
template <class Archive>
|
||||
inline void serialize(Archive &a, crypto::point_t &x, const boost::serialization::version_type ver)
|
||||
{
|
||||
a & reinterpret_cast<char (&)[sizeof(crypto::point_t)]>(x);
|
||||
}
|
||||
} // namespace serialization
|
||||
} // namespace boost
|
||||
|
|
@ -600,6 +600,8 @@ namespace tools
|
|||
bdb.get_backend()->enumerate(m_h, &local_enum_handler);
|
||||
}
|
||||
|
||||
// callback format: bool cb(uint64_t index, const key_t& key, const value_t& value)
|
||||
// cb should return true to continue, false -- to stop enumeration
|
||||
template<class t_cb>
|
||||
void enumerate_items(t_cb cb)const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -143,9 +143,10 @@ namespace tools
|
|||
else
|
||||
{
|
||||
int res = 0;
|
||||
//MDBX_txn_flags_t flags = MDBX_txn_flags_t();
|
||||
unsigned int flags = 0;
|
||||
if (read_only)
|
||||
flags += MDBX_RDONLY;
|
||||
flags = MDBX_RDONLY;//flags = MDBX_TXN_RDONLY;
|
||||
|
||||
//don't use parent tx in write transactions if parent tx was read-only (restriction in mdbx)
|
||||
//see "Nested transactions: Max 1 child, write txns only, no writemap"
|
||||
|
|
@ -340,7 +341,9 @@ namespace tools
|
|||
data[0].iov_base = (void*)v;
|
||||
data[0].iov_len = vs;
|
||||
|
||||
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, data, 0);
|
||||
//MDBX_put_flags_t flags = MDBX_put_flags_t();
|
||||
unsigned flags = 0;
|
||||
res = mdbx_put(get_current_tx(), static_cast<MDBX_dbi>(h), &key, data, flags);
|
||||
CHECK_AND_ASSERT_MESS_MDBX_DB(res, false, "Unable to mdbx_put");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
#define API_RETURN_CODE_WRAP "WRAP"
|
||||
#define API_RETURN_CODE_MISSING_ZC_INPUTS "MISSING_ZC_INPUTS"
|
||||
|
|
|
|||
|
|
@ -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 <boost/asio/deadline_timer.hpp>
|
||||
#include <boost/asio/io_service.hpp>
|
||||
#include <boost/asio/ip/udp.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/array.hpp>
|
||||
#include <epee/include/misc_log_ex.h>
|
||||
|
|
@ -94,7 +94,7 @@ public:
|
|||
// Start the asynchronous operation itself. The handle_receive function
|
||||
// used as a callback will update the ec and length variables.
|
||||
socket_.async_receive(boost::asio::buffer(buffer),
|
||||
boost::bind(&udp_blocking_client::handle_receive, _1, _2, &ec, &length));
|
||||
boost::bind(&udp_blocking_client::handle_receive, boost::placeholders::_1, boost::placeholders::_2, &ec, &length));
|
||||
|
||||
// Block until the asynchronous operation has completed.
|
||||
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
|
||||
|
|
@ -194,7 +194,12 @@ namespace tools
|
|||
ntp_packet packet_sent = AUTO_VAL_INIT(packet_sent);
|
||||
packet_sent.li_vn_mode = 0x1b;
|
||||
auto packet_sent_time = std::chrono::high_resolution_clock::now();
|
||||
socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint);
|
||||
auto send_res = socket.send_to(boost::asio::buffer(&packet_sent, sizeof packet_sent), receiver_endpoint);
|
||||
if (send_res != sizeof packet_sent)
|
||||
{
|
||||
LOG_PRINT_L3("NTP: get_ntp_time(" << host_name << "): wrong send_res: " << send_res << ", expected sizeof packet_sent = " << sizeof packet_sent);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ntp_packet packet_received = AUTO_VAL_INIT(packet_received);
|
||||
boost::asio::ip::udp::endpoint sender_endpoint;
|
||||
|
|
|
|||
|
|
@ -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_1161000.pak", "26660ffcdaf80a43a586e64a1a6da042dcb9ff3b58e14ce1ec9a775b995dc146", 1330022593, 2684313600 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_1161000.pak", "9dd03f08dea396fe32e6483a8221b292be35fa41c29748f119f11c3275956cdc", 1787475468, 2600247296 };
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_2390000.pak", "ffc8d2220a4d8b3fba51073a422cbb6139c60858469ea086623f9d16329eb5b4", 2767268964, 5368627200 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_2390000.pak", "7e58951bc523eb12e0ec07171bc67b3f96bad4d5454dd2da56f642a872e230d3", 3618283035, 5156397056 };
|
||||
#else
|
||||
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
|
||||
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
|
||||
|
|
|
|||
153
src/common/threads_pool.h
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
// Copyright (c) 2014-2019 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 <thread>
|
||||
#include <string>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
namespace utils
|
||||
{
|
||||
|
||||
struct call_executor_base
|
||||
{
|
||||
virtual void execute() = 0;
|
||||
};
|
||||
|
||||
template<typename t_executor_func>
|
||||
struct call_executor_t : public call_executor_base
|
||||
{
|
||||
call_executor_t(t_executor_func f) :m_func(f)
|
||||
{}
|
||||
t_executor_func m_func;
|
||||
virtual void execute()
|
||||
{
|
||||
m_func();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename t_executor_func>
|
||||
std::shared_ptr<call_executor_base> build_call_executor(t_executor_func func)
|
||||
{
|
||||
std::shared_ptr<call_executor_base> res(static_cast<call_executor_base*>(new call_executor_t<t_executor_func>(func)));
|
||||
return res;
|
||||
}
|
||||
|
||||
class threads_pool
|
||||
{
|
||||
public:
|
||||
typedef std::list<std::shared_ptr<call_executor_base>> jobs_container;
|
||||
|
||||
template<typename t_executor_func>
|
||||
static void add_job_to_container(jobs_container& cntr, t_executor_func func)
|
||||
{
|
||||
cntr.push_back(std::shared_ptr<call_executor_base>(static_cast<call_executor_base*>(new call_executor_t<t_executor_func>(func))));
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
int num_threads = std::thread::hardware_concurrency();
|
||||
this->init(num_threads);
|
||||
}
|
||||
void init(size_t num_threads)
|
||||
{
|
||||
m_is_stop = false;
|
||||
|
||||
for (size_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
m_threads.push_back(std::thread([this]() {this->worker_func(); }));
|
||||
}
|
||||
}
|
||||
|
||||
threads_pool() : m_is_stop(false), m_threads_counter(0)
|
||||
{}
|
||||
|
||||
template<typename t_executor_func>
|
||||
bool add_job(t_executor_func func)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_queue_mutex);
|
||||
m_jobs_que.push_back(build_call_executor(func));
|
||||
}
|
||||
m_condition.notify_one();
|
||||
return true;
|
||||
}
|
||||
|
||||
void add_batch_and_wait(const jobs_container& cntr)
|
||||
{
|
||||
std::condition_variable batch_condition;
|
||||
std::mutex batch_mutex;
|
||||
|
||||
|
||||
std::atomic<size_t> cnt(0);
|
||||
for (const auto& jb : cntr)
|
||||
{
|
||||
call_executor_base* pjob = jb.get();
|
||||
add_job([&, pjob]() {
|
||||
pjob->execute();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(batch_mutex);
|
||||
cnt++;
|
||||
}
|
||||
batch_condition.notify_one();
|
||||
});
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(batch_mutex);
|
||||
batch_condition.wait(lock, [&]()
|
||||
{
|
||||
return cnt == cntr.size();
|
||||
});
|
||||
LOG_PRINT_L0("All jobs finiahed");
|
||||
}
|
||||
|
||||
~threads_pool()
|
||||
{
|
||||
m_is_stop = true;
|
||||
m_condition.notify_all();
|
||||
for (auto& th : m_threads)
|
||||
{
|
||||
th.join();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void worker_func()
|
||||
{
|
||||
LOG_PRINT_L0("Worker thread is started");
|
||||
while (true)
|
||||
{
|
||||
std::shared_ptr<call_executor_base> job;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(m_queue_mutex);
|
||||
|
||||
m_condition.wait(lock, [this]()
|
||||
{
|
||||
return !m_jobs_que.empty() || m_is_stop;
|
||||
});
|
||||
if (m_is_stop)
|
||||
{
|
||||
LOG_PRINT_L0("Worker thread is finished");
|
||||
return;
|
||||
}
|
||||
|
||||
job = m_jobs_que.front();
|
||||
m_jobs_que.pop_front();
|
||||
}
|
||||
|
||||
job->execute();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
jobs_container m_jobs_que;
|
||||
std::condition_variable m_condition;
|
||||
std::mutex m_queue_mutex;
|
||||
std::vector<std::thread> m_threads;
|
||||
std::atomic<bool> m_is_stop;
|
||||
std::atomic<int64_t> m_threads_counter;
|
||||
};
|
||||
}
|
||||
17
src/common/tor_helper.h
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// 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
|
||||
|
||||
#include "tor-connect/torlib/tor_wrapper.h"
|
||||
|
||||
|
||||
|
||||
namespace tools
|
||||
{
|
||||
typedef epee::levin::levin_client_impl2<tools::tor::tor_transport> levin_over_tor_client;
|
||||
|
||||
}
|
||||
|
||||
|
||||
58
src/common/variant_helper.h
Normal file
|
|
@ -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<v_type>(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<v_type>(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();
|
||||
|
||||
|
||||
*/
|
||||
|
||||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
using namespace epee;
|
||||
#include <boost/program_options.hpp>
|
||||
//#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
#include "p2p/p2p_protocol_defs.h"
|
||||
#include "common/command_line.h"
|
||||
#include "currency_core/currency_core.h"
|
||||
|
|
@ -37,31 +38,32 @@ using namespace nodetool;
|
|||
|
||||
namespace
|
||||
{
|
||||
const command_line::arg_descriptor<std::string> arg_ip = {"ip", "set ip", "127.0.0.1", false};
|
||||
const command_line::arg_descriptor<size_t> arg_port = {"port", "set port"};
|
||||
const command_line::arg_descriptor<size_t> arg_rpc_port = {"rpc-port", "set rpc port", RPC_DEFAULT_PORT, false};
|
||||
const command_line::arg_descriptor<uint32_t> arg_timeout = {"timeout", "set timeout", 5000, false};
|
||||
const command_line::arg_descriptor<std::string> arg_priv_key = {"private-key", "private key to subscribe debug command", "", true};
|
||||
const command_line::arg_descriptor<uint64_t> arg_peer_id = {"peer-id", "peerid if known(if not - will be requested)", 0};
|
||||
const command_line::arg_descriptor<bool> arg_generate_keys = {"generate-keys-pair", "generate private and public keys pair"};
|
||||
const command_line::arg_descriptor<bool> arg_request_stat_info = {"request-stat-info", "request statistics information"};
|
||||
const command_line::arg_descriptor<uint64_t> arg_log_journal_len = { "log-journal-len", "Specify length of list of last error messages in log", 0, true };
|
||||
const command_line::arg_descriptor<bool> arg_request_net_state = {"request-net-state", "request network state information (peer list, connections count)"};
|
||||
const command_line::arg_descriptor<bool> arg_get_daemon_info = {"rpc-get-daemon-info", "request daemon state info vie rpc (--rpc-port option should be set ).", "", true};
|
||||
const command_line::arg_descriptor<bool> arg_get_aliases = {"rpc-get-aliases", "request daemon aliases all list", "", true};
|
||||
const command_line::arg_descriptor<std::string> arg_increment_build_no = { "increment-build-no", "Increment build nimber", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_upate_maintainers_info = {"update-maintainers-info", "Push maintainers info into the network, update-maintainers-info=file-with-info.json", "", true};
|
||||
const command_line::arg_descriptor<std::string> arg_update_build_no = {"update-build-no", "Updated version number in version template file", "", true};
|
||||
const command_line::arg_descriptor<std::string> arg_generate_genesis = {"generate-genesis", "Generate genesis coinbase based on config file", "", true };
|
||||
const command_line::arg_descriptor<uint64_t> arg_genesis_split_amount = { "genesis-split-amount", "Set split amount for generating genesis block", 0, true };
|
||||
const command_line::arg_descriptor<std::string> arg_get_info_flags = { "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "", true };
|
||||
const command_line::arg_descriptor<int64_t> arg_set_peer_log_level = { "set-peer-log-level", "Set log level for remote peer", 0, true };
|
||||
const command_line::arg_descriptor<std::string> arg_download_peer_log = { "download-peer-log", "Download log from remote peer <starting_offset>[,<count>]", "", true };
|
||||
const command_line::arg_descriptor<bool> arg_do_consloe_log = { "do-console-log", "Tool generates debug console output(debug purposes)", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_generate_integrated_address = { "generate-integrated-address", "Tool create integrated address from simple address and payment_id", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_pack_file = {"pack-file", "perform gzip-packing and calculate hash for a given file", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_unpack_file = {"unpack-file", "Perform gzip-unpacking and calculate hash for a given file", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_target_file = {"target-file", "Specify target file for pack-file and unpack-file commands", "", true };
|
||||
const command_line::arg_descriptor<std::string> arg_ip ("ip", "set ip", "127.0.0.1");
|
||||
const command_line::arg_descriptor<size_t> arg_port ("port", "set port");
|
||||
const command_line::arg_descriptor<size_t> arg_rpc_port ("rpc-port", "set rpc port", RPC_DEFAULT_PORT);
|
||||
const command_line::arg_descriptor<uint32_t> arg_timeout ("timeout", "set timeout", 5000);
|
||||
const command_line::arg_descriptor<std::string> arg_priv_key ("private-key", "private key to subscribe debug command");
|
||||
const command_line::arg_descriptor<uint64_t> arg_peer_id ("peer-id", "peerid if known(if not - will be requested)", 0);
|
||||
const command_line::arg_descriptor<bool> arg_generate_keys ("generate-keys-pair", "generate private and public keys pair");
|
||||
const command_line::arg_descriptor<bool> arg_request_stat_info ("request-stat-info", "request statistics information");
|
||||
const command_line::arg_descriptor<uint64_t> arg_log_journal_len ( "log-journal-len", "Specify length of list of last error messages in log");
|
||||
const command_line::arg_descriptor<bool> arg_request_net_state ("request-net-state", "request network state information (peer list, connections count)");
|
||||
const command_line::arg_descriptor<bool> arg_get_daemon_info ("rpc-get-daemon-info", "request daemon state info vie rpc (--rpc-port option should be set ).");
|
||||
const command_line::arg_descriptor<bool> arg_get_aliases ("rpc-get-aliases", "request daemon aliases all list");
|
||||
const command_line::arg_descriptor<std::string> arg_increment_build_no ( "increment-build-no", "Increment build nimber");
|
||||
const command_line::arg_descriptor<std::string> arg_upate_maintainers_info ("update-maintainers-info", "Push maintainers info into the network, update-maintainers-info=file-with-info.json");
|
||||
const command_line::arg_descriptor<std::string> arg_update_build_no ("update-build-no", "Updated version number in version template file");
|
||||
const command_line::arg_descriptor<std::string> arg_generate_genesis ("generate-genesis", "Generate genesis coinbase based on config file");
|
||||
const command_line::arg_descriptor<uint64_t> arg_genesis_split_amount ( "genesis-split-amount", "Set split amount for generating genesis block");
|
||||
const command_line::arg_descriptor<std::string> arg_get_info_flags ( "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "");
|
||||
const command_line::arg_descriptor<int64_t> arg_set_peer_log_level ( "set-peer-log-level", "Set log level for remote peer");
|
||||
const command_line::arg_descriptor<std::string> arg_download_peer_log ( "download-peer-log", "Download log from remote peer <starting_offset>[,<count>]");
|
||||
const command_line::arg_descriptor<bool> arg_do_consloe_log ( "do-console-log", "Tool generates debug console output(debug purposes)");
|
||||
const command_line::arg_descriptor<std::string> arg_generate_integrated_address ( "generate-integrated-address", "Tool create integrated address from simple address and payment_id");
|
||||
const command_line::arg_descriptor<std::string> arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file");
|
||||
const command_line::arg_descriptor<std::string> arg_unpack_file ("unpack-file", "Perform gzip-unpacking and calculate hash for a given file");
|
||||
const command_line::arg_descriptor<std::string> arg_target_file ("target-file", "Specify target file for pack-file and unpack-file commands");
|
||||
//const command_line::arg_descriptor<std::string> arg_send_ipc ("send-ipc", "Send IPC request to UI");
|
||||
}
|
||||
|
||||
typedef COMMAND_REQUEST_STAT_INFO_T<t_currency_protocol_handler<core>::stat_info> COMMAND_REQUEST_STAT_INFO;
|
||||
|
|
@ -405,8 +407,11 @@ 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;
|
||||
construct_miner_tx(0, 0, 0, 0, 0, dummy_address, dummy_address, bl.miner_tx, block_reward_without_fee, 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
|
||||
|
|
@ -638,7 +643,7 @@ bool handle_request_stat(po::variables_map& vm, peerid_type peer_id)
|
|||
|
||||
response_schema rs = AUTO_VAL_INIT(rs);
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
net_utils::levin_client2 transport;
|
||||
if(!transport.connect(command_line::get_arg(vm, arg_ip), static_cast<int>(command_line::get_arg(vm, arg_port)), static_cast<int>(command_line::get_arg(vm, arg_timeout))))
|
||||
{
|
||||
std::cout << "{" << ENDL << " \"status\": \"ERROR: " << "Failed to connect to " << command_line::get_arg(vm, arg_ip) << ":" << command_line::get_arg(vm, arg_port) << "\"" << ENDL << "}" << ENDL;
|
||||
|
|
@ -876,7 +881,7 @@ bool generate_and_print_keys()
|
|||
}
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
template<class command_t>
|
||||
bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, levin::levin_client_impl2& transport, peerid_type& peer_id, typename command_t::request& req, typename command_t::response& rsp)
|
||||
bool invoke_debug_command(po::variables_map& vm, const crypto::secret_key& sk, net_utils::levin_client2& transport, peerid_type& peer_id, typename command_t::request& req, typename command_t::response& rsp)
|
||||
{
|
||||
if (!transport.is_connected())
|
||||
{
|
||||
|
|
@ -931,7 +936,7 @@ bool handle_set_peer_log_level(po::variables_map& vm)
|
|||
return false;
|
||||
}
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
net_utils::levin_client2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_SET_LOG_LEVEL::request req = AUTO_VAL_INIT(req);
|
||||
|
|
@ -980,7 +985,7 @@ bool handle_download_peer_log(po::variables_map& vm)
|
|||
}
|
||||
uint64_t start_offset = static_cast<uint64_t>(start_offset_signed);
|
||||
|
||||
levin::levin_client_impl2 transport;
|
||||
net_utils::levin_client2 transport;
|
||||
peerid_type peer_id = 0;
|
||||
|
||||
COMMAND_REQUEST_LOG::request req = AUTO_VAL_INIT(req);
|
||||
|
|
@ -1165,6 +1170,34 @@ bool process_archive(archive_processor_t& arch_processor, bool is_packing, std::
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
bool handle_send_ipc(const std::string& parms)
|
||||
{
|
||||
try{
|
||||
boost::interprocess::message_queue mq
|
||||
(boost::interprocess::open_only //only open
|
||||
, GUI_IPC_MESSAGE_CHANNEL_NAME //name
|
||||
);
|
||||
|
||||
mq.send(parms.data(), parms.size(), 0);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (const std::exception& ex)
|
||||
{
|
||||
boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME);
|
||||
LOG_ERROR("Failed to receive IPC que: " << ex.what());
|
||||
}
|
||||
|
||||
catch (...)
|
||||
{
|
||||
boost::interprocess::message_queue::remove(GUI_IPC_MESSAGE_CHANNEL_NAME);
|
||||
LOG_ERROR("Failed to receive IPC que: unknown exception");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
bool handle_pack_file(po::variables_map& vm)
|
||||
{
|
||||
bool do_pack = false;
|
||||
|
|
@ -1263,6 +1296,8 @@ int main(int argc, char* argv[])
|
|||
command_line::add_arg(desc_params, arg_pack_file);
|
||||
command_line::add_arg(desc_params, arg_unpack_file);
|
||||
command_line::add_arg(desc_params, arg_target_file);
|
||||
//command_line::add_arg(desc_params, arg_send_ipc);
|
||||
|
||||
|
||||
po::options_description desc_all;
|
||||
desc_all.add(desc_general).add(desc_params);
|
||||
|
|
@ -1339,6 +1374,10 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
return handle_pack_file(vm) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
/*else if (command_line::has_arg(vm, arg_send_ipc))
|
||||
{
|
||||
handle_send_ipc(command_line::get_arg(vm, arg_send_ipc)) ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}*/
|
||||
else
|
||||
{
|
||||
std::cerr << "Not enough arguments." << ENDL;
|
||||
|
|
|
|||
|
|
@ -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<dword>(length_size_t); /* length in bytes of message */
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "warnings.h"
|
||||
//#include <compat/cpuid.h>
|
||||
|
||||
#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)
|
||||
|
|
|
|||
1132
src/crypto/clsag.cpp
Normal file
178
src/crypto/clsag.h
Normal file
|
|
@ -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<CLSAG_GG_input_ref_t>& 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<CLSAG_GG_input_ref_t>& 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<CLSAG_GGX_input_ref_t>& 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<CLSAG_GGX_input_ref_t>& 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<CLSAG_GGXG_input_ref_t>& 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<CLSAG_GGXG_input_ref_t>& 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<CLSAG_GGXXG_input_ref_t>& 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<CLSAG_GGXXG_input_ref_t>& 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
|
||||
|
|
@ -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];
|
||||
|
|
@ -325,7 +324,7 @@ Preconditions:
|
|||
|f| bounded by 1.1*2^26,1.1*2^25,1.1*2^26,1.1*2^25,etc.
|
||||
*/
|
||||
|
||||
static int fe_isnegative(const fe f) {
|
||||
int fe_isnegative(const fe f) {
|
||||
unsigned char s[32];
|
||||
fe_tobytes(s, f);
|
||||
return s[0] & 1;
|
||||
|
|
@ -342,16 +341,6 @@ int fe_isnonzero(const fe f) {
|
|||
s[27] | s[28] | s[29] | s[30] | s[31]) - 1) >> 8) + 1;
|
||||
}
|
||||
|
||||
int fe_cmp(const fe a, const fe b)
|
||||
{
|
||||
for (size_t i = 9; i != SIZE_MAX; --i)
|
||||
{
|
||||
if ((const uint32_t)a[i] < (const uint32_t)b[i]) return -1;
|
||||
if ((const uint32_t)a[i] > (const uint32_t)b[i]) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* From fe_mul.c */
|
||||
|
||||
/*
|
||||
|
|
@ -970,7 +959,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_sub(fe h, const fe f, const fe g) {
|
||||
void fe_sub(fe h, const fe f, const fe g) {
|
||||
int32_t f0 = f[0];
|
||||
int32_t f1 = f[1];
|
||||
int32_t f2 = f[2];
|
||||
|
|
@ -1435,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);
|
||||
|
|
@ -4310,3 +4299,185 @@ void ge_scalarmult_vartime_p3_v2(ge_p3 *r, const unsigned char *a, const ge_p3 *
|
|||
ge_p1p1_to_p3(r, &t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ge_cached_to_p2(ge_p2 *r, const ge_cached *c)
|
||||
{
|
||||
static const fe inv2 = { 10, 0, 0, 0, 0, 0, 0, 0, 0, -16777216 };
|
||||
|
||||
fe_sub(r->X, c->YplusX, c->YminusX);
|
||||
fe_mul(r->X, r->X, inv2);
|
||||
|
||||
fe_add(r->Y, c->YplusX, c->YminusX);
|
||||
fe_mul(r->Y, r->Y, inv2);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -111,12 +112,20 @@ void ge_fromfe_frombytes_vartime(ge_p2 *, const unsigned char *);
|
|||
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;
|
||||
|
|
@ -138,8 +147,10 @@ void sc_invert(unsigned char*, const unsigned char*);
|
|||
|
||||
void fe_sq(fe h, const fe f);
|
||||
int fe_isnonzero(const fe f);
|
||||
int fe_cmp(const fe a, const fe b);
|
||||
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);
|
||||
void fe_invert(fe out, const fe z);
|
||||
void fe_tobytes(unsigned char *s, const fe h);
|
||||
int fe_isnegative(const fe f);
|
||||
|
|
|
|||
|
|
@ -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<class pod_t>
|
||||
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<class pod_t>
|
||||
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<unsigned int>(p[i]) << "'";
|
||||
if (i + 1 != len)
|
||||
ss << ", ";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<class pod_t>
|
||||
std::string pod_to_hex_comma_separated_uint64(const pod_t &h)
|
||||
{
|
||||
|
|
@ -87,6 +133,22 @@ namespace crypto
|
|||
return ss.str();
|
||||
}
|
||||
|
||||
template<class pod_t>
|
||||
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<int32_t>(p[i]);
|
||||
if (i + 1 != len)
|
||||
ss << ", ";
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
template<typename t_pod_type>
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -246,7 +299,7 @@ namespace crypto
|
|||
return result;
|
||||
}
|
||||
|
||||
// genrate 0 <= x < L
|
||||
// generate 0 <= x < L
|
||||
void make_random()
|
||||
{
|
||||
unsigned char tmp[64];
|
||||
|
|
@ -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;
|
||||
|
|
@ -431,19 +499,67 @@ namespace crypto
|
|||
return result;
|
||||
}
|
||||
|
||||
// Little-endian assumed; TODO: consider Big-endian support
|
||||
bool get_bit(uint8_t bit_index) const
|
||||
{
|
||||
return (m_u64[bit_index >> 6] & (1ull << (bit_index & 63))) != 0;
|
||||
}
|
||||
|
||||
// Little-endian assumed; TODO: consider Big-endian support
|
||||
void set_bit(size_t bit_index)
|
||||
{
|
||||
m_u64[bit_index >> 6] |= (1ull << (bit_index & 63));
|
||||
}
|
||||
|
||||
// Little-endian assumed; TODO: consider Big-endian support
|
||||
void clear_bit(size_t bit_index)
|
||||
{
|
||||
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;
|
||||
result.set_bit(exponent);
|
||||
return result;
|
||||
}
|
||||
|
||||
}; // 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");
|
||||
|
||||
//
|
||||
//
|
||||
|
|
@ -456,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;
|
||||
|
|
@ -488,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&&)
|
||||
|
|
@ -497,7 +607,22 @@ namespace crypto
|
|||
zero();
|
||||
}
|
||||
|
||||
// as we're using additive notation, zero means identity group element here and after
|
||||
explicit point_t(const key_image& ki) // can throw std::runtime_error
|
||||
: point_t(static_cast<const public_key&>(static_cast<const ec_point&>(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()
|
||||
{
|
||||
ge_p3_0(&m_p3);
|
||||
|
|
@ -505,8 +630,16 @@ namespace crypto
|
|||
|
||||
bool is_zero() const
|
||||
{
|
||||
// (0, 1) ~ (0, z, z, 0)
|
||||
return fe_isnonzero(m_p3.X) * fe_cmp(m_p3.Y, m_p3.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; // 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;
|
||||
}
|
||||
|
||||
bool is_in_main_subgroup() const
|
||||
|
|
@ -596,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;
|
||||
}
|
||||
|
||||
|
|
@ -612,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;
|
||||
}
|
||||
|
||||
|
|
@ -622,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
|
||||
{
|
||||
|
|
@ -649,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;
|
||||
|
|
@ -667,7 +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)
|
||||
{
|
||||
|
|
@ -699,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
|
||||
|
||||
|
||||
|
|
@ -707,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;
|
||||
}
|
||||
|
||||
|
|
@ -725,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;
|
||||
}
|
||||
|
||||
|
|
@ -734,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
|
||||
//
|
||||
|
|
@ -811,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
|
||||
|
|
@ -851,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
|
||||
|
||||
|
||||
|
|
@ -875,13 +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_0;
|
||||
|
||||
//
|
||||
// hash functions' helper
|
||||
|
|
@ -905,9 +1168,10 @@ namespace crypto
|
|||
|
||||
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)
|
||||
|
|
@ -949,6 +1213,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;
|
||||
|
|
@ -977,6 +1246,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);
|
||||
|
|
@ -987,6 +1266,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");
|
||||
|
|
@ -1003,17 +1292,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<item_t> m_elements;
|
||||
};
|
||||
|
||||
static scalar_t hs(const scalar_t& s, const std::vector<point_t>& ps0, const std::vector<point_t>& 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);
|
||||
|
|
@ -1023,7 +1319,7 @@ namespace crypto
|
|||
static scalar_t hs(const crypto::hash& s, const std::vector<crypto::public_key>& ps0, const std::vector<crypto::key_image>& 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<const scalar_t*>(&s));
|
||||
hs_calculator.add_pub_keys_array(ps0);
|
||||
hs_calculator.add_key_images_array(ps1);
|
||||
|
|
@ -1032,12 +1328,79 @@ namespace crypto
|
|||
|
||||
static scalar_t hs(const std::vector<point_t>& ps0, const std::vector<point_t>& 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<const crypto::public_key&>(derivation));
|
||||
hs_calculator.add_scalar(index);
|
||||
return hs_calculator.calc_hash();
|
||||
}
|
||||
|
||||
static point_t hp(const point_t& p)
|
||||
{
|
||||
point_t result;
|
||||
|
|
@ -1054,6 +1417,28 @@ namespace crypto
|
|||
ge_bytes_hash_to_ec_32(&result.m_p3, (const unsigned char*)&p);
|
||||
return result;
|
||||
}
|
||||
|
||||
static point_t hp(const scalar_t& s)
|
||||
{
|
||||
point_t result;
|
||||
ge_bytes_hash_to_ec_32(&result.m_p3, s.data());
|
||||
return result;
|
||||
}
|
||||
|
||||
static point_t hp(const void* data, size_t size)
|
||||
{
|
||||
point_t result;
|
||||
ge_bytes_hash_to_ec(&result.m_p3, data, size);
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -1061,7 +1446,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
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
25
src/crypto/msm.cpp
Normal file
|
|
@ -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
|
||||
173
src/crypto/msm.h
Normal file
|
|
@ -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<typename CT>
|
||||
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<typename CT>
|
||||
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<point_t> buckets(C * K);
|
||||
std::vector<bool> buckets_inited(C * K);
|
||||
std::vector<point_t> Sk(K);
|
||||
std::vector<bool> Sk_inited(K);
|
||||
std::vector<point_t> Gk(K);
|
||||
std::vector<bool> 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<typename CT>
|
||||
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<CT>(g_scalars, h_scalars, summand);
|
||||
return msm_and_check_zero_pippenger_v3<CT>(g_scalars, h_scalars, summand, 7);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
322
src/crypto/one_out_of_many_proofs.cpp
Normal file
|
|
@ -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<point_t> 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<point_t>& 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<uint64_t>(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<n> a_mat(mn); // m x n matrix
|
||||
a_mat.zero();
|
||||
std::vector<size_t> 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<const public_key*>& 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<uint64_t>(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
|
||||
47
src/crypto/one_out_of_many_proofs.h
Normal file
|
|
@ -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<public_key> 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<point_t>& 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<const public_key*>& ring, const BGE_proof& sig, uint8_t* p_err = nullptr);
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
729
src/crypto/range_proof_bpp.h
Normal file
|
|
@ -0,0 +1,729 @@
|
|||
// Copyright (c) 2021-2022 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2021-2022 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 the implementation of range proof protocol.
|
||||
// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735
|
||||
//
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
struct bpp_signature
|
||||
{
|
||||
std::vector<public_key> L; // size = ceil( log_2(m * n) )
|
||||
std::vector<public_key> R;
|
||||
public_key A0;
|
||||
public_key A;
|
||||
public_key B;
|
||||
scalar_t r;
|
||||
scalar_t s;
|
||||
scalar_t delta;
|
||||
};
|
||||
|
||||
#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<typename CT>
|
||||
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const std::vector<const crypto::public_key*>& commitments_1div8, bpp_signature& sig, uint8_t* p_err = nullptr)
|
||||
{
|
||||
// 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() && 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());
|
||||
const size_t c_bpp_m = 1ull << c_bpp_log2_m;
|
||||
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;
|
||||
|
||||
#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:
|
||||
// v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product
|
||||
// aR = aL - (1, 1, ... 1)
|
||||
// aR o aL = 0
|
||||
|
||||
// aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar
|
||||
|
||||
scalar_mat_t<CT::c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
|
||||
aLs.zero();
|
||||
aRs.zero();
|
||||
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
const scalar_t& v = values[i];
|
||||
for (uint8_t j = 0; j < CT::c_bpp_n; ++j)
|
||||
{
|
||||
if (v.get_bit(j))
|
||||
aLs(i, j) = c_scalar_1; // aL = 1, aR = 0
|
||||
else
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = values.size(); i < c_bpp_m; ++i)
|
||||
for (size_t j = 0; j < CT::c_bpp_n; ++j)
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
|
||||
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
|
||||
hash_helper_t::hs_t hsc;
|
||||
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)
|
||||
|
||||
scalar_t alpha = scalar_t::random();
|
||||
point_t A0 = alpha * CT::bpp_H;
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
DBG_VAL_PRINT(alpha);
|
||||
DBG_VAL_PRINT(A0);
|
||||
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
scalar_t y = hsc.calc_hash();
|
||||
scalar_t z = hash_helper_t::hs(y);
|
||||
e = z; // transcript for further steps
|
||||
DBG_VAL_PRINT(y);
|
||||
DBG_VAL_PRINT(z);
|
||||
|
||||
// Computing vector d for aggregated version of the protocol (BP+ paper, page 17)
|
||||
// (note: elements are stored column-by-column in memory)
|
||||
// d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) |
|
||||
// | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) |
|
||||
// | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) |
|
||||
// | ....................................................................................... |
|
||||
// | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) |
|
||||
// Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m))
|
||||
|
||||
scalar_t z_sq = z * z;
|
||||
scalar_mat_t<CT::c_bpp_n> d(c_bpp_mn);
|
||||
d(0, 0) = z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < CT::c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
|
||||
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
|
||||
// (calculate two more elements (1 and y^(mn+1)) for convenience)
|
||||
scalar_vec_t y_powers(c_bpp_mn + 2);
|
||||
y_powers[0] = 1;
|
||||
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
|
||||
y_powers[i] = y_powers[i - 1] * y;
|
||||
|
||||
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
|
||||
|
||||
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
|
||||
|
||||
// aL_hat = aL - 1*z
|
||||
scalar_vec_t aLs_hat = aLs - z;
|
||||
// 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];
|
||||
|
||||
DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs());
|
||||
DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs());
|
||||
|
||||
// calculate alpha_hat
|
||||
// alpha_hat = alpha + SUM(z^(2j) * gamma_j * y^(mn+1)) for j = 1..m
|
||||
// i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j
|
||||
scalar_t alpha_hat = 0;
|
||||
for (size_t i = 0; i < masks.size(); ++i)
|
||||
alpha_hat += d(i, 0) * masks[i];
|
||||
alpha_hat = alpha + y_mn_p1 * alpha_hat;
|
||||
|
||||
DBG_VAL_PRINT(alpha_hat);
|
||||
|
||||
// calculate 1, y^-1, y^-2, ...
|
||||
const scalar_t y_inverse = y.reciprocal();
|
||||
scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round)
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse;
|
||||
|
||||
// prepare generator's vector
|
||||
std::vector<point_t> g(c_bpp_mn), h(c_bpp_mn);
|
||||
for (size_t i = 0; i < c_bpp_mn; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
|
||||
// WIP zk-argument called with zk-WIP(g, h, G, H, A_hat, aL_hat, aR_hat, alpha_hat)
|
||||
|
||||
scalar_vec_t& a = aLs_hat;
|
||||
scalar_vec_t& b = aRs_hat;
|
||||
|
||||
sig.L.resize(c_bpp_log2_mn);
|
||||
sig.R.resize(c_bpp_log2_mn);
|
||||
|
||||
// zk-WIP reduction rounds (s.a. the preprint page 13 Fig. 1)
|
||||
for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni)
|
||||
{
|
||||
DBG_PRINT(ENDL << "#" << ni);
|
||||
|
||||
// zk-WIP(g, h, G, H, P, a, b, alpha)
|
||||
|
||||
scalar_t dL = scalar_t::random();
|
||||
DBG_VAL_PRINT(dL);
|
||||
scalar_t dR = scalar_t::random();
|
||||
DBG_VAL_PRINT(dR);
|
||||
|
||||
// a = (a1, a2), b = (b1, b2) -- vectors of scalars
|
||||
// cL = <a1, ((y, y^2, ...) o b2)> -- scalar
|
||||
scalar_t cL = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cL += a[i] * y_powers[i + 1] * b[n + i];
|
||||
|
||||
DBG_VAL_PRINT(cL);
|
||||
|
||||
// cR = <a2, ((y, y^2, ...) o b1)> * y^n -- scalar
|
||||
scalar_t cR = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cR += a[n + i] * y_powers[i + 1] * b[i];
|
||||
cR *= y_powers[n];
|
||||
|
||||
DBG_VAL_PRINT(cR);
|
||||
|
||||
// L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H -- point
|
||||
point_t sum = c_point_0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[i] * g[n + i];
|
||||
point_t L;
|
||||
CT::calc_pedersen_commitment(cL, dL, L);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
L += b[n + i] * h[i];
|
||||
L += y_inverse_powers[n] * sum;
|
||||
L *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(L);
|
||||
|
||||
// R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H -- point
|
||||
sum.zero();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[n + i] * g[i];
|
||||
point_t R;
|
||||
CT::calc_pedersen_commitment(cR, dR, R);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
R += b[i] * h[n + i];
|
||||
R += y_powers[n] * sum;
|
||||
R *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(R);
|
||||
|
||||
// put L, R to the sig
|
||||
L.to_public_key(sig.L[ni]);
|
||||
R.to_public_key(sig.R[ni]);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[ni]);
|
||||
hsc.add_pub_key(sig.R[ni]);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// recalculate arguments for the next round
|
||||
scalar_t e_squared = e * e;
|
||||
scalar_t e_inverse = e.reciprocal();
|
||||
scalar_t e_inverse_squared = e_inverse * e_inverse;
|
||||
scalar_t e_y_inv_n = e * y_inverse_powers[n];
|
||||
scalar_t e_inv_y_n = e_inverse * y_powers[n];
|
||||
|
||||
// g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i];
|
||||
|
||||
// h_hat = e * h1 + e^-1 * h2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
h[i] = e * h[i] + e_inverse * h[n + i];
|
||||
|
||||
// P_hat = e^2 * L + P + e^-2 * R -- point
|
||||
|
||||
// a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
a[i] = e * a[i] + e_inv_y_n * a[n + i];
|
||||
|
||||
// b_hat = e^-1 * b1 + e * b2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
b[i] = e_inverse * b[i] + e * b[n + i];
|
||||
|
||||
// alpha_hat = e^2 * dL + alpha + e^-2 * dR -- scalar
|
||||
alpha_hat += e_squared * dL + e_inverse_squared * dR;
|
||||
|
||||
// run next iteraton zk-WIP(g_hat, h_hat, G, H, P_hat, a_hat, b_hat, alpha_hat)
|
||||
}
|
||||
DBG_PRINT("");
|
||||
|
||||
// zk-WIP last round
|
||||
scalar_t r = scalar_t::random();
|
||||
scalar_t s = scalar_t::random();
|
||||
scalar_t delta = scalar_t::random();
|
||||
scalar_t eta = scalar_t::random();
|
||||
DBG_VAL_PRINT(r);
|
||||
DBG_VAL_PRINT(s);
|
||||
DBG_VAL_PRINT(delta);
|
||||
DBG_VAL_PRINT(eta);
|
||||
|
||||
// A = r * g + s * h + (r y b + s y a) * G + delta * H -- point
|
||||
point_t A = c_point_0;
|
||||
CT::calc_pedersen_commitment(y * (r * b[0] + s * a[0]), delta, A);
|
||||
A += r * g[0] + s * h[0];
|
||||
A *= c_scalar_1div8;
|
||||
A.to_public_key(sig.A);
|
||||
DBG_VAL_PRINT(A);
|
||||
|
||||
// B = (r * y * s) * G + eta * H
|
||||
point_t B = c_point_0;
|
||||
CT::calc_pedersen_commitment(r * y * s, eta, B);
|
||||
B *= c_scalar_1div8;
|
||||
B.to_public_key(sig.B);
|
||||
DBG_VAL_PRINT(B);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// finalize the signature
|
||||
sig.r = r + e * a[0];
|
||||
sig.s = s + e * b[0];
|
||||
sig.delta = eta + e * delta + e * e * alpha_hat;
|
||||
DBG_VAL_PRINT(sig.r);
|
||||
DBG_VAL_PRINT(sig.s);
|
||||
DBG_VAL_PRINT(sig.delta);
|
||||
|
||||
return true;
|
||||
} // bpp_gen()
|
||||
|
||||
|
||||
// convenient overload for tests
|
||||
template<typename CT>
|
||||
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector<point_t>& 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<crypto::public_key> commitments_1div8(values.size());
|
||||
std::vector<const crypto::public_key*> 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<CT>(values, masks, commitments_1div8_pointers, sig, p_err);
|
||||
}
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
|
||||
|
||||
struct bpp_sig_commit_ref_t
|
||||
{
|
||||
bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector<point_t>& commitments)
|
||||
: sig(sig)
|
||||
, commitments(commitments)
|
||||
{}
|
||||
const bpp_signature& sig;
|
||||
const std::vector<point_t>& commitments; // assumed to be premultiplied by 1/8
|
||||
};
|
||||
|
||||
|
||||
template<typename CT>
|
||||
bool bpp_verify(const std::vector<bpp_sig_commit_ref_t>& 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 = " << (int)err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . ");
|
||||
|
||||
static_assert(CT::c_bpp_n <= 255, "too big N");
|
||||
const size_t kn = sigs.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
|
||||
|
||||
struct intermediate_element_t
|
||||
{
|
||||
scalar_t y;
|
||||
scalar_t z;
|
||||
scalar_t z_sq;
|
||||
scalar_vec_t e;
|
||||
scalar_vec_t e_sq;
|
||||
scalar_t e_final;
|
||||
scalar_t e_final_sq;
|
||||
size_t inv_e_offset; // offset in batch_for_inverse
|
||||
size_t inv_y_offset; // offset in batch_for_inverse
|
||||
size_t c_bpp_log2_m;
|
||||
size_t c_bpp_m;
|
||||
size_t c_bpp_mn;
|
||||
point_t A;
|
||||
point_t A0;
|
||||
point_t B;
|
||||
std::vector<point_t> L;
|
||||
std::vector<point_t> R;
|
||||
};
|
||||
std::vector<intermediate_element_t> interms(kn);
|
||||
|
||||
size_t c_bpp_log2_m_max = 0;
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4);
|
||||
|
||||
intermediate_element_t& interm = interms[k];
|
||||
interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size());
|
||||
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
|
||||
c_bpp_log2_m_max = interm.c_bpp_log2_m;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5);
|
||||
|
||||
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
|
||||
interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
|
||||
interm.L.resize(sig.L.size());
|
||||
interm.R.resize(sig.R.size());
|
||||
for (size_t i = 0; i < interm.L.size(); ++i)
|
||||
{
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
|
||||
}
|
||||
}
|
||||
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
|
||||
const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n;
|
||||
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n;
|
||||
|
||||
|
||||
//
|
||||
// prepare stuff
|
||||
//
|
||||
/*
|
||||
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
|
||||
for (size_t i = 0; i < c_bpp_mn_max; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
*/
|
||||
|
||||
scalar_vec_t batch_for_inverse;
|
||||
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
|
||||
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// restore y and z
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
hash_helper_t::hs_t hsc;
|
||||
CT::update_transcript(hsc, e, bsc.commitments);
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
hsc.assign_calc_hash(interm.y);
|
||||
interm.z = hash_helper_t::hs(interm.y);
|
||||
interm.z_sq = interm.z * interm.z;
|
||||
DBG_VAL_PRINT(interm.y);
|
||||
DBG_VAL_PRINT(interm.z);
|
||||
e = interm.z; // transcript for further steps
|
||||
|
||||
interm.inv_y_offset = batch_for_inverse.size();
|
||||
batch_for_inverse.push_back(interm.y);
|
||||
interm.inv_e_offset = batch_for_inverse.size();
|
||||
|
||||
interm.e.resize(sig.L.size());
|
||||
interm.e_sq.resize(sig.L.size());
|
||||
|
||||
for (size_t i = 0; i < sig.L.size(); ++i)
|
||||
{
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[i]);
|
||||
hsc.add_pub_key(sig.R[i]);
|
||||
hsc.assign_calc_hash(e);
|
||||
interm.e[i] = e;
|
||||
interm.e_sq[i] = e * e;
|
||||
DBG_PRINT("e[" << i << "]: " << e);
|
||||
batch_for_inverse.push_back(e);
|
||||
}
|
||||
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
hsc.assign_calc_hash(interm.e_final);
|
||||
interm.e_final_sq = interm.e_final * interm.e_final;
|
||||
DBG_VAL_PRINT(interm.e_final);
|
||||
}
|
||||
|
||||
batch_for_inverse.invert();
|
||||
|
||||
// Notation:
|
||||
// 1_vec ^ n = (1, 1, 1, ..., 1)
|
||||
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
|
||||
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
|
||||
// y<^n = (y^n, y^(n-1), ..., y^1)
|
||||
// y>^n = (y^1, y^2, ..., y^n)
|
||||
|
||||
// from page 13, Fig 1:
|
||||
// Verifier outputs Accept IFF the following equality holds (single proof):
|
||||
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'
|
||||
// (where g and h are calculated in each round)
|
||||
// The same equation in additive notation:
|
||||
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H
|
||||
// <=>
|
||||
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*)
|
||||
// where A, B, r', s', delta' is taken from the signature
|
||||
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
|
||||
//
|
||||
// from page 18, Fig 3:
|
||||
// P and V computes:
|
||||
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// (calculated once)
|
||||
//
|
||||
// As suggested in Section 6.1 "Practical Optimizations":
|
||||
// 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20):
|
||||
//
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * A_hat
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (**)
|
||||
//
|
||||
// where:
|
||||
// g, h - vector of fixed generators
|
||||
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
|
||||
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
|
||||
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
|
||||
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
|
||||
//
|
||||
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
|
||||
// insert A_hat into (**) =>
|
||||
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// )
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0
|
||||
|
||||
// =>
|
||||
|
||||
// (for single signature)
|
||||
//
|
||||
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
|
||||
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
|
||||
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
|
||||
// + delta' * H | the signatures
|
||||
//
|
||||
// - e^2 * A0
|
||||
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
|
||||
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (***)
|
||||
//
|
||||
// All (***) will be muptiplied by random weightning factor and then summed up.
|
||||
|
||||
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
|
||||
scalar_vec_t g_scalars;
|
||||
g_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_vec_t h_scalars;
|
||||
h_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_t G_scalar = 0;
|
||||
scalar_t H_scalar = 0;
|
||||
point_t summand = c_point_0;
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// random weightning factor for speed-optimized batch verification (preprint page 20)
|
||||
const scalar_t rwf = scalar_t::random();
|
||||
DBG_PRINT("rwf: " << rwf);
|
||||
|
||||
// prepare d vector (see also d structure description in proof function)
|
||||
scalar_mat_t<CT::c_bpp_n> d(interm.c_bpp_mn);
|
||||
d(0, 0) = interm.z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < interm.c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * interm.z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < CT::c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < interm.c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
// sum(d) (see also note in proof function for this)
|
||||
const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
DBG_PRINT("sum(d): " << sum_d);
|
||||
|
||||
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
|
||||
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
|
||||
|
||||
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
|
||||
// complexity (sc_mul's): MN+2*log2(MN)-2
|
||||
// the idea is the following:
|
||||
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
|
||||
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
|
||||
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
|
||||
scalar_vec_t s_vec(interm.c_bpp_mn);
|
||||
s_vec[0] = get_e_inv(0);
|
||||
for (size_t i = 1; i < log2_mn; ++i)
|
||||
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
|
||||
DBG_PRINT("[0] " << s_vec[0]);
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
{
|
||||
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
|
||||
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
|
||||
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
|
||||
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
|
||||
}
|
||||
|
||||
// prepare y_inv vector
|
||||
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
|
||||
|
||||
// y^(mn+1)
|
||||
scalar_t y_power_mnp1 = interm.y;
|
||||
for (size_t i = 0; i < log2_mn; ++i)
|
||||
y_power_mnp1 *= y_power_mnp1;
|
||||
y_power_mnp1 *= interm.y;
|
||||
DBG_VAL_PRINT(y_power_mnp1);
|
||||
|
||||
// now calculate all multiplicands for common generators
|
||||
|
||||
// g vector multiplicands:
|
||||
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
|
||||
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
|
||||
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
|
||||
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
|
||||
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
|
||||
|
||||
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
|
||||
|
||||
// h vector multiplicands:
|
||||
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
|
||||
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
|
||||
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
|
||||
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
|
||||
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
|
||||
{
|
||||
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
|
||||
rwf_e_sq_y *= interm.y;
|
||||
}
|
||||
|
||||
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
|
||||
|
||||
// G point multiplicands:
|
||||
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
|
||||
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
|
||||
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
|
||||
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
|
||||
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
|
||||
DBG_PRINT("G_scalar: " << G_scalar);
|
||||
|
||||
// H point multiplicands:
|
||||
// rwf * delta
|
||||
H_scalar += rwf * sig.delta;
|
||||
DBG_PRINT("H_scalar: " << H_scalar);
|
||||
|
||||
// uncommon generators' multiplicands
|
||||
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
|
||||
// - rwf * e^2 * A0
|
||||
summand_8 -= rwf * interm.e_final_sq * interm.A0;
|
||||
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
|
||||
|
||||
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
|
||||
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
|
||||
for (size_t j = 0; j < bsc.commitments.size(); ++j)
|
||||
{
|
||||
e_sq_y_mn1_z_sq_power *= interm.z_sq;
|
||||
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
|
||||
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
|
||||
}
|
||||
|
||||
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
|
||||
for (size_t j = 0; j < log2_mn; ++j)
|
||||
{
|
||||
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
|
||||
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
|
||||
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
|
||||
}
|
||||
|
||||
// - rwf * e * A - rwf * B = 0
|
||||
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
|
||||
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
|
||||
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
|
||||
|
||||
summand_8.modify_mul8();
|
||||
summand += summand_8;
|
||||
}
|
||||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
|
||||
bool result = msm_and_check_zero<CT>(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
|
||||
747
src/crypto/range_proof_bppe.h
Normal file
|
|
@ -0,0 +1,747 @@
|
|||
// Copyright (c) 2022 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2022 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 the implementation of range proof protocol.
|
||||
// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735
|
||||
// Double-blinded commitments extension implemented as in Appendix D in the Zarcanum whitepaper: https://eprint.iacr.org/2021/1478
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
struct bppe_signature
|
||||
{
|
||||
std::vector<public_key> L; // size = log_2(m * n)
|
||||
std::vector<public_key> R;
|
||||
public_key A0;
|
||||
public_key A;
|
||||
public_key B;
|
||||
scalar_t r;
|
||||
scalar_t s;
|
||||
scalar_t delta_1;
|
||||
scalar_t delta_2;
|
||||
};
|
||||
|
||||
#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<typename CT>
|
||||
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, const std::vector<const crypto::public_key*>& commitments_1div8, bppe_signature& sig, uint8_t* p_err = nullptr)
|
||||
{
|
||||
// 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() && 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());
|
||||
const size_t c_bpp_m = 1ull << c_bpp_log2_m;
|
||||
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;
|
||||
|
||||
#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:
|
||||
// v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product
|
||||
// aR = aL - (1, 1, ... 1)
|
||||
// aR o aL = 0
|
||||
|
||||
// aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar
|
||||
|
||||
scalar_mat_t<CT::c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
|
||||
aLs.zero();
|
||||
aRs.zero();
|
||||
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
const scalar_t& v = values[i];
|
||||
for (uint8_t j = 0; j < CT::c_bpp_n; ++j)
|
||||
{
|
||||
if (v.get_bit(j))
|
||||
aLs(i, j) = c_scalar_1; // aL = 1, aR = 0
|
||||
else
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = values.size(); i < c_bpp_m; ++i)
|
||||
for (size_t j = 0; j < CT::c_bpp_n; ++j)
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
|
||||
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
|
||||
hash_helper_t::hs_t hsc;
|
||||
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)
|
||||
|
||||
scalar_t alpha_1 = scalar_t::random(), alpha_2 = scalar_t::random();
|
||||
point_t A0 = alpha_1 * CT::bpp_H + alpha_2 * CT::bpp_H2;
|
||||
|
||||
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
|
||||
A0 *= c_scalar_1div8;
|
||||
A0.to_public_key(sig.A0);
|
||||
|
||||
DBG_VAL_PRINT(alpha_1);
|
||||
DBG_VAL_PRINT(alpha_2);
|
||||
DBG_VAL_PRINT(A0);
|
||||
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
scalar_t y = hsc.calc_hash();
|
||||
scalar_t z = hash_helper_t::hs(y);
|
||||
e = z; // transcript for further steps
|
||||
DBG_VAL_PRINT(y);
|
||||
DBG_VAL_PRINT(z);
|
||||
|
||||
// Computing vector d for aggregated version of the protocol (BP+ paper, page 17)
|
||||
// (note: elements are stored column-by-column in memory)
|
||||
// d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) |
|
||||
// | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) |
|
||||
// | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) |
|
||||
// | ....................................................................................... |
|
||||
// | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) |
|
||||
// Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m))
|
||||
|
||||
scalar_t z_sq = z * z;
|
||||
scalar_mat_t<CT::c_bpp_n> d(c_bpp_mn);
|
||||
d(0, 0) = z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < CT::c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
|
||||
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
|
||||
// (calculate two more elements (1 and y^(mn+1)) for convenience)
|
||||
scalar_vec_t y_powers(c_bpp_mn + 2);
|
||||
y_powers[0] = 1;
|
||||
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
|
||||
y_powers[i] = y_powers[i - 1] * y;
|
||||
|
||||
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
|
||||
|
||||
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
|
||||
|
||||
// aL_hat = aL - 1*z
|
||||
scalar_vec_t aLs_hat = aLs - z;
|
||||
// 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];
|
||||
|
||||
DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs());
|
||||
DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs());
|
||||
|
||||
// calculate alpha_hat
|
||||
// alpha_hat_1 = alpha_1 + SUM(z^(2j) * gamma_1,j * y^(mn+1)) for j = 1..m
|
||||
// alpha_hat_2 = alpha_2 + SUM(z^(2j) * gamma_2,j * y^(mn+1)) for j = 1..m
|
||||
// i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j
|
||||
scalar_t alpha_hat_1 = 0, alpha_hat_2 = 0;
|
||||
for (size_t i = 0; i < masks.size(); ++i)
|
||||
{
|
||||
alpha_hat_1 += d(i, 0) * masks[i];
|
||||
alpha_hat_2 += d(i, 0) * masks2[i];
|
||||
}
|
||||
alpha_hat_1 = alpha_1 + y_mn_p1 * alpha_hat_1;
|
||||
alpha_hat_2 = alpha_2 + y_mn_p1 * alpha_hat_2;
|
||||
|
||||
DBG_VAL_PRINT(alpha_hat_1);
|
||||
DBG_VAL_PRINT(alpha_hat_2);
|
||||
|
||||
// calculate 1, y^-1, y^-2, ...
|
||||
const scalar_t y_inverse = y.reciprocal();
|
||||
scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round)
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse;
|
||||
|
||||
// prepare generator's vector
|
||||
std::vector<point_t> g(c_bpp_mn), h(c_bpp_mn);
|
||||
for (size_t i = 0; i < c_bpp_mn; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
|
||||
// WIP zk-argument called with zk-WIP(g, h, G, H, H2, A_hat, aL_hat, aR_hat, alpha_hat_1, alpha_hat_2)
|
||||
|
||||
scalar_vec_t& a = aLs_hat;
|
||||
scalar_vec_t& b = aRs_hat;
|
||||
|
||||
sig.L.resize(c_bpp_log2_mn);
|
||||
sig.R.resize(c_bpp_log2_mn);
|
||||
|
||||
// zk-WIP reduction rounds (s.a. Zarcanum preprint page 24 Fig. D.1)
|
||||
for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni)
|
||||
{
|
||||
DBG_PRINT(ENDL << "#" << ni);
|
||||
|
||||
// zk-WIP(g, h, G, H, H2, P, a, b, alpha_1, alpha_2)
|
||||
|
||||
scalar_t dL = scalar_t::random(), dL2 = scalar_t::random();
|
||||
DBG_VAL_PRINT(dL); DBG_VAL_PRINT(dL2);
|
||||
scalar_t dR = scalar_t::random(), dR2 = scalar_t::random();
|
||||
DBG_VAL_PRINT(dR); DBG_VAL_PRINT(dR2);
|
||||
|
||||
// a = (a1, a2), b = (b1, b2) -- vectors of scalars
|
||||
// cL = <a1, ((y, y^2, ...) o b2)> -- scalar
|
||||
scalar_t cL = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cL += a[i] * y_powers[i + 1] * b[n + i];
|
||||
|
||||
DBG_VAL_PRINT(cL);
|
||||
|
||||
// cR = <a2, ((y, y^2, ...) o b1)> * y^n -- scalar
|
||||
scalar_t cR = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cR += a[n + i] * y_powers[i + 1] * b[i];
|
||||
cR *= y_powers[n];
|
||||
|
||||
DBG_VAL_PRINT(cR);
|
||||
|
||||
// L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H + dL2 * H2 -- point
|
||||
point_t sum = c_point_0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[i] * g[n + i];
|
||||
point_t L;
|
||||
CT::calc_pedersen_commitment_2(cL, dL, dL2, L);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
L += b[n + i] * h[i];
|
||||
L += y_inverse_powers[n] * sum;
|
||||
L *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(L);
|
||||
|
||||
// R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H + dR2 * H2 -- point
|
||||
sum.zero();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[n + i] * g[i];
|
||||
point_t R;
|
||||
CT::calc_pedersen_commitment_2(cR, dR, dR2, R);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
R += b[i] * h[n + i];
|
||||
R += y_powers[n] * sum;
|
||||
R *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(R);
|
||||
|
||||
// put L, R to the sig
|
||||
L.to_public_key(sig.L[ni]);
|
||||
R.to_public_key(sig.R[ni]);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[ni]);
|
||||
hsc.add_pub_key(sig.R[ni]);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// recalculate arguments for the next round
|
||||
scalar_t e_squared = e * e;
|
||||
scalar_t e_inverse = e.reciprocal();
|
||||
scalar_t e_inverse_squared = e_inverse * e_inverse;
|
||||
scalar_t e_y_inv_n = e * y_inverse_powers[n];
|
||||
scalar_t e_inv_y_n = e_inverse * y_powers[n];
|
||||
|
||||
// g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i];
|
||||
|
||||
// h_hat = e * h1 + e^-1 * h2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
h[i] = e * h[i] + e_inverse * h[n + i];
|
||||
|
||||
// P_hat = e^2 * L + P + e^-2 * R -- point
|
||||
|
||||
// a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
a[i] = e * a[i] + e_inv_y_n * a[n + i];
|
||||
|
||||
// b_hat = e^-1 * b1 + e * b2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
b[i] = e_inverse * b[i] + e * b[n + i];
|
||||
|
||||
// alpha_hat_1 = e^2 * dL + alpha_1 + e^-2 * dR -- scalar
|
||||
// alpha_hat_2 = e^2 * dL2 + alpha_2 + e^-2 * dR2 -- scalar
|
||||
alpha_hat_1 += e_squared * dL + e_inverse_squared * dR;
|
||||
alpha_hat_2 += e_squared * dL2 + e_inverse_squared * dR2;
|
||||
|
||||
// run next iteraton zk-WIP(g_hat, h_hat, G, H, H2, P_hat, a_hat, b_hat, alpha_hat_1, alpha_hat_2)
|
||||
}
|
||||
DBG_PRINT("");
|
||||
|
||||
// zk-WIP last round
|
||||
scalar_t r = scalar_t::random();
|
||||
scalar_t s = scalar_t::random();
|
||||
scalar_t delta_1 = scalar_t::random(), delta_2 = scalar_t::random();
|
||||
scalar_t eta_1 = scalar_t::random(), eta_2 = scalar_t::random();
|
||||
DBG_VAL_PRINT(r);
|
||||
DBG_VAL_PRINT(s);
|
||||
DBG_VAL_PRINT(delta_1); DBG_VAL_PRINT(delta_2);
|
||||
DBG_VAL_PRINT(eta_1); DBG_VAL_PRINT(eta_2);
|
||||
|
||||
// A = r * g + s * h + (r y b + s y a) * G + delta_1 * H + delta_2 * H2 -- point
|
||||
point_t A = c_point_0;
|
||||
CT::calc_pedersen_commitment_2(y * (r * b[0] + s * a[0]), delta_1, delta_2, A);
|
||||
A += r * g[0] + s * h[0];
|
||||
A *= c_scalar_1div8;
|
||||
A.to_public_key(sig.A);
|
||||
DBG_VAL_PRINT(A);
|
||||
|
||||
// B = (r * y * s) * G + eta_1 * H + eta_2 * H2
|
||||
point_t B = c_point_0;
|
||||
CT::calc_pedersen_commitment_2(r * y * s, eta_1, eta_2, B);
|
||||
B *= c_scalar_1div8;
|
||||
B.to_public_key(sig.B);
|
||||
DBG_VAL_PRINT(B);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// finalize the signature
|
||||
sig.r = r + e * a[0];
|
||||
sig.s = s + e * b[0];
|
||||
sig.delta_1 = eta_1 + e * delta_1 + e * e * alpha_hat_1;
|
||||
sig.delta_2 = eta_2 + e * delta_2 + e * e * alpha_hat_2;
|
||||
DBG_VAL_PRINT(sig.r);
|
||||
DBG_VAL_PRINT(sig.s);
|
||||
DBG_VAL_PRINT(sig.delta_1);
|
||||
DBG_VAL_PRINT(sig.delta_2);
|
||||
|
||||
return true;
|
||||
} // bppe_gen()
|
||||
|
||||
|
||||
// convenient overload for tests
|
||||
template<typename CT>
|
||||
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector<point_t>& 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<crypto::public_key> commitments_1div8(values.size());
|
||||
std::vector<const crypto::public_key*> 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<CT>(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<point_t>& commitments)
|
||||
: sig(sig)
|
||||
, commitments(commitments)
|
||||
{}
|
||||
const bppe_signature& sig;
|
||||
const std::vector<point_t>& commitments; // assumed to be premultiplied by 1/8
|
||||
};
|
||||
|
||||
|
||||
template<typename CT>
|
||||
bool bppe_verify(const std::vector<bppe_sig_commit_ref_t>& 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 = " << (int)err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . ");
|
||||
|
||||
static_assert(CT::c_bpp_n <= 255, "too big N");
|
||||
const size_t kn = sigs.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
|
||||
|
||||
struct intermediate_element_t
|
||||
{
|
||||
scalar_t y;
|
||||
scalar_t z;
|
||||
scalar_t z_sq;
|
||||
scalar_vec_t e;
|
||||
scalar_vec_t e_sq;
|
||||
scalar_t e_final;
|
||||
scalar_t e_final_sq;
|
||||
size_t inv_e_offset; // offset in batch_for_inverse
|
||||
size_t inv_y_offset; // offset in batch_for_inverse
|
||||
size_t c_bpp_log2_m;
|
||||
size_t c_bpp_m;
|
||||
size_t c_bpp_mn;
|
||||
point_t A;
|
||||
point_t A0;
|
||||
point_t B;
|
||||
std::vector<point_t> L;
|
||||
std::vector<point_t> R;
|
||||
};
|
||||
std::vector<intermediate_element_t> interms(kn);
|
||||
|
||||
size_t c_bpp_log2_m_max = 0;
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
const bppe_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bppe_signature& sig = bsc.sig;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta_1.is_reduced() && sig.delta_2.is_reduced(), 4);
|
||||
|
||||
intermediate_element_t& interm = interms[k];
|
||||
interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size());
|
||||
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
|
||||
c_bpp_log2_m_max = interm.c_bpp_log2_m;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5);
|
||||
|
||||
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
|
||||
interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
|
||||
interm.L.resize(sig.L.size());
|
||||
interm.R.resize(sig.R.size());
|
||||
for (size_t i = 0; i < interm.L.size(); ++i)
|
||||
{
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
|
||||
}
|
||||
}
|
||||
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
|
||||
const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n;
|
||||
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n;
|
||||
|
||||
|
||||
//
|
||||
// prepare stuff
|
||||
//
|
||||
/*
|
||||
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
|
||||
for (size_t i = 0; i < c_bpp_mn_max; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
*/
|
||||
|
||||
scalar_vec_t batch_for_inverse;
|
||||
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
|
||||
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bppe_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bppe_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// restore y and z
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
hash_helper_t::hs_t hsc;
|
||||
CT::update_transcript(hsc, e, bsc.commitments);
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
hsc.assign_calc_hash(interm.y);
|
||||
interm.z = hash_helper_t::hs(interm.y);
|
||||
interm.z_sq = interm.z * interm.z;
|
||||
DBG_VAL_PRINT(interm.y);
|
||||
DBG_VAL_PRINT(interm.z);
|
||||
e = interm.z; // transcript for further steps
|
||||
|
||||
interm.inv_y_offset = batch_for_inverse.size();
|
||||
batch_for_inverse.push_back(interm.y);
|
||||
interm.inv_e_offset = batch_for_inverse.size();
|
||||
|
||||
interm.e.resize(sig.L.size());
|
||||
interm.e_sq.resize(sig.L.size());
|
||||
|
||||
for (size_t i = 0; i < sig.L.size(); ++i)
|
||||
{
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[i]);
|
||||
hsc.add_pub_key(sig.R[i]);
|
||||
hsc.assign_calc_hash(e);
|
||||
interm.e[i] = e;
|
||||
interm.e_sq[i] = e * e;
|
||||
DBG_PRINT("e[" << i << "]: " << e);
|
||||
batch_for_inverse.push_back(e);
|
||||
}
|
||||
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
hsc.assign_calc_hash(interm.e_final);
|
||||
interm.e_final_sq = interm.e_final * interm.e_final;
|
||||
DBG_VAL_PRINT(interm.e_final);
|
||||
}
|
||||
|
||||
batch_for_inverse.invert();
|
||||
|
||||
// Notation:
|
||||
// 1_vec ^ n = (1, 1, 1, ..., 1)
|
||||
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
|
||||
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
|
||||
// y<^n = (y^n, y^(n-1), ..., y^1)
|
||||
// y>^n = (y^1, y^2, ..., y^n)
|
||||
|
||||
// from Zarcanum page 24, Fig D.1:
|
||||
// Verifier outputs Accept IFF the following holds:
|
||||
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'_1 * H2 ^ delta'_2
|
||||
// (where g and h are calculated in each round)
|
||||
// The same equation in additive notation:
|
||||
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2
|
||||
// <=>
|
||||
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 - e^2 * P - e * A - B == 0 (*)
|
||||
// where A, B, r', s', delta'_1, delta'_2 is taken from the signature
|
||||
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
|
||||
//
|
||||
// from Zarcanum preprint page 33, Fig D.3:
|
||||
// P and V computes:
|
||||
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// (calculated once)
|
||||
//
|
||||
// As suggested in BPP preprint Section 6.1 "Practical Optimizations":
|
||||
// 1) g and h exponentianions can be optimized in order not to be calculated at each round
|
||||
// as the following (page 20, with delta'_2 and H2 added):
|
||||
//
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 -
|
||||
// - e^2 * A_hat
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (**)
|
||||
//
|
||||
// where:
|
||||
// g, h - vector of fixed generators
|
||||
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
|
||||
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
|
||||
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
|
||||
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
|
||||
//
|
||||
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
|
||||
// insert A_hat into (**) =>
|
||||
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 -
|
||||
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// )
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0
|
||||
|
||||
// =>
|
||||
|
||||
// (for single signature)
|
||||
//
|
||||
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
|
||||
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
|
||||
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
|
||||
// + delta'_1 * H | the signatures
|
||||
// + delta'_2 * H2 | the signatures
|
||||
//
|
||||
// - e^2 * A0
|
||||
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
|
||||
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (***)
|
||||
//
|
||||
// All (***) will be muptiplied by random weightning factor and then summed up.
|
||||
|
||||
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
|
||||
scalar_vec_t g_scalars;
|
||||
g_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_vec_t h_scalars;
|
||||
h_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_t G_scalar = 0;
|
||||
scalar_t H_scalar = 0;
|
||||
scalar_t H2_scalar = 0;
|
||||
point_t summand = c_point_0;
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bppe_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bppe_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// random weightning factor for speed-optimized batch verification (preprint page 20)
|
||||
const scalar_t rwf = scalar_t::random();
|
||||
DBG_PRINT("rwf: " << rwf);
|
||||
|
||||
// prepare d vector (see also d structure description in proof function)
|
||||
scalar_mat_t<CT::c_bpp_n> d(interm.c_bpp_mn);
|
||||
d(0, 0) = interm.z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < interm.c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * interm.z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < CT::c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < interm.c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
// sum(d) (see also note in proof function for this)
|
||||
const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
DBG_PRINT("sum(d): " << sum_d);
|
||||
|
||||
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
|
||||
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
|
||||
|
||||
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
|
||||
// complexity (sc_mul's): MN+2*log2(MN)-2
|
||||
// the idea is the following:
|
||||
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
|
||||
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
|
||||
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
|
||||
scalar_vec_t s_vec(interm.c_bpp_mn);
|
||||
s_vec[0] = get_e_inv(0);
|
||||
for (size_t i = 1; i < log2_mn; ++i)
|
||||
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
|
||||
DBG_PRINT("[0] " << s_vec[0]);
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
{
|
||||
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
|
||||
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
|
||||
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
|
||||
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
|
||||
}
|
||||
|
||||
// prepare y_inv vector
|
||||
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
|
||||
|
||||
// y^(mn+1)
|
||||
scalar_t y_power_mnp1 = interm.y;
|
||||
for (size_t i = 0; i < log2_mn; ++i)
|
||||
y_power_mnp1 *= y_power_mnp1;
|
||||
y_power_mnp1 *= interm.y;
|
||||
DBG_VAL_PRINT(y_power_mnp1);
|
||||
|
||||
// now calculate all multiplicands for common generators
|
||||
|
||||
// g vector multiplicands:
|
||||
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
|
||||
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
|
||||
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
|
||||
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
|
||||
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
|
||||
|
||||
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
|
||||
|
||||
// h vector multiplicands:
|
||||
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
|
||||
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
|
||||
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
|
||||
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
|
||||
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
|
||||
{
|
||||
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
|
||||
rwf_e_sq_y *= interm.y;
|
||||
}
|
||||
|
||||
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
|
||||
|
||||
// G point multiplicands:
|
||||
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
|
||||
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
|
||||
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
|
||||
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
|
||||
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
|
||||
DBG_PRINT("G_scalar: " << G_scalar);
|
||||
|
||||
// H point multiplicands:
|
||||
// rwf * delta_1
|
||||
H_scalar += rwf * sig.delta_1;
|
||||
DBG_PRINT("H_scalar: " << H_scalar);
|
||||
|
||||
// H2 point multiplicands:
|
||||
// rwf * delta_2
|
||||
H2_scalar += rwf * sig.delta_2;
|
||||
DBG_PRINT("H2_scalar: " << H2_scalar);
|
||||
|
||||
// uncommon generators' multiplicands
|
||||
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
|
||||
// - rwf * e^2 * A0
|
||||
summand_8 -= rwf * interm.e_final_sq * interm.A0;
|
||||
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
|
||||
|
||||
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
|
||||
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
|
||||
for (size_t j = 0; j < bsc.commitments.size(); ++j)
|
||||
{
|
||||
e_sq_y_mn1_z_sq_power *= interm.z_sq;
|
||||
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
|
||||
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
|
||||
}
|
||||
|
||||
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
|
||||
for (size_t j = 0; j < log2_mn; ++j)
|
||||
{
|
||||
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
|
||||
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
|
||||
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
|
||||
}
|
||||
|
||||
// - rwf * e * A - rwf * B = 0
|
||||
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
|
||||
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
|
||||
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
|
||||
|
||||
summand_8.modify_mul8();
|
||||
summand += summand_8;
|
||||
}
|
||||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents);
|
||||
bool result = msm_and_check_zero<CT>(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
|
||||
|
|
@ -6,7 +6,12 @@
|
|||
|
||||
namespace crypto
|
||||
{
|
||||
const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
// Copyright (c) 2021 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2021 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
|
||||
|
||||
//
|
||||
// This file contains the implementation of range proof protocol.
|
||||
// Namely, Bulletproofs+ https://eprint.iacr.org/2020/735.pdf
|
||||
//
|
||||
|
||||
#include "epee/include/misc_log_ex.h"
|
||||
#include "crypto-sugar.h"
|
||||
|
||||
|
|
@ -28,27 +23,6 @@ namespace crypto
|
|||
return result;
|
||||
}
|
||||
|
||||
constexpr size_t c_bpp_log2_n = 6;
|
||||
constexpr size_t c_bpp_n = 64; // 2^64 is the upper bound for the witness's range
|
||||
constexpr size_t c_bpp_values_max = 16; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs
|
||||
constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max;
|
||||
|
||||
// returns smallest k, s.t. v <= 2**k
|
||||
inline size_t calc_exp_power_of_2_upper_bound(size_t v)
|
||||
{
|
||||
constexpr size_t max_v = (SIZE_MAX >> 1) + 1;
|
||||
//if (v > max_v)
|
||||
// return 0;
|
||||
|
||||
size_t pow = 1, result = 0;
|
||||
while (v > pow)
|
||||
{
|
||||
pow <<= 1;
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns least significant bit uing de Bruijn sequence
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html
|
||||
inline uint8_t calc_lsb_32(uint32_t v)
|
||||
|
|
@ -61,15 +35,45 @@ namespace crypto
|
|||
return multiply_de_bruijn_bit_position[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27];
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// crypto trait for Zano
|
||||
////////////////////////////////////////
|
||||
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<typename gen_trait_t, size_t N = 64, size_t values_max = 32>
|
||||
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
|
||||
static constexpr size_t c_bpp_log2_n = constexpr_ceil_log2(c_bpp_n);
|
||||
static constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max;
|
||||
|
||||
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 * 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()
|
||||
|
|
@ -86,6 +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<const public_key*>& 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)
|
||||
|
|
@ -107,717 +122,27 @@ namespace crypto
|
|||
return generators[2 * index + (select_H ? 1 : 0)];
|
||||
}
|
||||
|
||||
static const point_t& bpp_H;
|
||||
};
|
||||
|
||||
|
||||
struct bpp_signature
|
||||
{
|
||||
std::vector<public_key> L; // size = log_2(m * n)
|
||||
std::vector<public_key> R;
|
||||
public_key A0;
|
||||
public_key A;
|
||||
public_key B;
|
||||
scalar_t r;
|
||||
scalar_t s;
|
||||
scalar_t delta;
|
||||
};
|
||||
|
||||
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
|
||||
#define DBG_PRINT(x) std::cout << x << ENDL
|
||||
|
||||
template<typename CT>
|
||||
bool bpp_gen(const std::vector<uint64_t>& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector<point_t>& commitments, 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; }
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= c_bpp_values_max && values.size() == masks.size(), 1);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3);
|
||||
|
||||
const size_t c_bpp_log2_m = calc_exp_power_of_2_upper_bound(values.size());
|
||||
const size_t c_bpp_m = 1ull << c_bpp_log2_m;
|
||||
const size_t c_bpp_mn = c_bpp_m * c_bpp_n;
|
||||
const size_t c_bpp_log2_mn = c_bpp_log2_m + 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(scalar_t(values[i]) * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]);
|
||||
|
||||
|
||||
// s.a. BP+ paper, page 15, eq. 11
|
||||
// decompose v into aL and aR:
|
||||
// v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product
|
||||
// aR = aL - (1, 1, ... 1)
|
||||
// aR o aL = 0
|
||||
|
||||
// aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar
|
||||
|
||||
scalar_mat_t<c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
|
||||
aLs.zero();
|
||||
aRs.zero();
|
||||
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
static const scalar_t& get_2_to_the_power_of_N_minus_1()
|
||||
{
|
||||
uint64_t v = values[i];
|
||||
for (size_t j = 0; j < c_bpp_n; ++j)
|
||||
{
|
||||
if (v & 1)
|
||||
aLs(i, j) = c_scalar_1; // aL = 1, aR = 0
|
||||
else
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
v >>= 1;
|
||||
}
|
||||
static scalar_t result = scalar_t::power_of_2(c_bpp_n) - 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
for (size_t i = values.size(); i < c_bpp_m; ++i)
|
||||
for (size_t j = 0; j < c_bpp_n; ++j)
|
||||
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
|
||||
using gen_trait_t::bpp_G;
|
||||
using gen_trait_t::bpp_H;
|
||||
using gen_trait_t::bpp_H2;
|
||||
}; // struct bpp_crypto_trait_zano
|
||||
|
||||
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
typedef bpp_crypto_trait_zano<bpp_ct_generators_UGX, 64, 32> bpp_crypto_trait_ZC_out;
|
||||
|
||||
hash_helper_t::hs_t hsc;
|
||||
CT::update_transcript(hsc, e, commitments);
|
||||
typedef bpp_crypto_trait_zano<bpp_ct_generators_HGX, 128, 16> bpp_crypto_trait_Zarcanum;
|
||||
|
||||
// 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)
|
||||
|
||||
scalar_t alpha = scalar_t::random();
|
||||
point_t A0 = alpha * CT::bpp_H;
|
||||
|
||||
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
|
||||
A0 *= c_scalar_1div8;
|
||||
A0.to_public_key(sig.A0);
|
||||
|
||||
DBG_VAL_PRINT(alpha);
|
||||
DBG_VAL_PRINT(A0);
|
||||
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
scalar_t y = hsc.calc_hash();
|
||||
scalar_t z = hash_helper_t::hs(y);
|
||||
e = z; // transcript for further steps
|
||||
DBG_VAL_PRINT(y);
|
||||
DBG_VAL_PRINT(z);
|
||||
|
||||
// Computing vector d for aggregated version of the protocol (BP+ paper, page 17)
|
||||
// (note: elements is stored column-by-column in memory)
|
||||
// d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) |
|
||||
// | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) |
|
||||
// | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) |
|
||||
// | ....................................................................................... |
|
||||
// | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) |
|
||||
// Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m))
|
||||
|
||||
scalar_t z_sq = z * z;
|
||||
scalar_mat_t<c_bpp_n> d(c_bpp_mn);
|
||||
d(0, 0) = z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
|
||||
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
|
||||
// (calculate two more elements (1 and y^(mn+1)) for convenience)
|
||||
scalar_vec_t y_powers(c_bpp_mn + 2);
|
||||
y_powers[0] = 1;
|
||||
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
|
||||
y_powers[i] = y_powers[i - 1] * y;
|
||||
|
||||
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
|
||||
|
||||
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
|
||||
|
||||
// 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)
|
||||
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];
|
||||
|
||||
DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs());
|
||||
DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs());
|
||||
|
||||
// calculate alpha_hat
|
||||
// alpha_hat = alpha + SUM(z^(2j) * gamma_j * y^(mn+1)) for j = 1..m
|
||||
// i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j
|
||||
scalar_t alpha_hat = 0;
|
||||
for (size_t i = 0; i < masks.size(); ++i)
|
||||
alpha_hat += d(i, 0) * masks[i];
|
||||
alpha_hat = alpha + y_mn_p1 * alpha_hat;
|
||||
|
||||
DBG_VAL_PRINT(alpha_hat);
|
||||
|
||||
// calculate y^-1, y^-2, ...
|
||||
const scalar_t y_inverse = y.reciprocal();
|
||||
scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round)
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse;
|
||||
|
||||
// prepare generator's vector
|
||||
std::vector<point_t> g(c_bpp_mn), h(c_bpp_mn);
|
||||
for (size_t i = 0; i < c_bpp_mn; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
|
||||
// WIP zk-argument called with zk-WIP(g, h, G, H, A_hat, aL_hat, aR_hat, alpha_hat)
|
||||
|
||||
scalar_vec_t& a = aLs_hat;
|
||||
scalar_vec_t& b = aRs_hat;
|
||||
|
||||
sig.L.resize(c_bpp_log2_mn);
|
||||
sig.R.resize(c_bpp_log2_mn);
|
||||
|
||||
// zk-WIP reduction rounds (s.a. the preprint page 13 Fig. 1)
|
||||
for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni)
|
||||
{
|
||||
DBG_PRINT(ENDL << "#" << ni);
|
||||
|
||||
// zk-WIP(g, h, G, H, P, a, b, alpha)
|
||||
|
||||
scalar_t dL = scalar_t::random();
|
||||
DBG_VAL_PRINT(dL);
|
||||
scalar_t dR = scalar_t::random();
|
||||
DBG_VAL_PRINT(dR);
|
||||
|
||||
// a = (a1, a2), b = (b1, b2) -- vectors of scalars
|
||||
// cL = <a1, ((y, y^2, ...) o b2)> -- scalar
|
||||
scalar_t cL = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cL += a[i] * y_powers[i + 1] * b[n + i];
|
||||
|
||||
DBG_VAL_PRINT(cL);
|
||||
|
||||
// cR = <a2, ((y, y^2, ...) o b1)> * y^n -- scalar
|
||||
scalar_t cR = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cR += a[n + i] * y_powers[i + 1] * b[i];
|
||||
cR *= y_powers[n];
|
||||
|
||||
DBG_VAL_PRINT(cR);
|
||||
|
||||
// L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H -- point
|
||||
point_t sum = c_point_0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[i] * g[n + i];
|
||||
point_t L;
|
||||
CT::calc_pedersen_commitment(cL, dL, L);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
L += b[n + i] * h[i];
|
||||
L += y_inverse_powers[n] * sum;
|
||||
L *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(L);
|
||||
|
||||
// R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H -- point
|
||||
sum.zero();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[n + i] * g[i];
|
||||
point_t R;
|
||||
CT::calc_pedersen_commitment(cR, dR, R);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
R += b[i] * h[n + i];
|
||||
R += y_powers[n] * sum;
|
||||
R *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(R);
|
||||
|
||||
// put L, R to the sig
|
||||
L.to_public_key(sig.L[ni]);
|
||||
R.to_public_key(sig.R[ni]);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[ni]);
|
||||
hsc.add_pub_key(sig.R[ni]);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// recalculate arguments for the next round
|
||||
scalar_t e_squared = e * e;
|
||||
scalar_t e_inverse = e.reciprocal();
|
||||
scalar_t e_inverse_squared = e_inverse * e_inverse;
|
||||
scalar_t e_y_inv_n = e * y_inverse_powers[n];
|
||||
scalar_t e_inv_y_n = e_inverse * y_powers[n];
|
||||
|
||||
// g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i];
|
||||
|
||||
// h_hat = e * h1 + e^-1 * h2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
h[i] = e * h[i] + e_inverse * h[n + i];
|
||||
|
||||
// P_hat = e^2 * L + P + e^-2 * R -- point
|
||||
|
||||
// a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
a[i] = e * a[i] + e_inv_y_n * a[n + i];
|
||||
|
||||
// b_hat = e^-1 * b1 + e * b2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
b[i] = e_inverse * b[i] + e * b[n + i];
|
||||
|
||||
// alpha_hat = e^2 * dL + alpha + e^-2 * dR -- scalar
|
||||
alpha_hat += e_squared * dL + e_inverse_squared * dR;
|
||||
|
||||
// run next iteraton zk-WIP(g_hat, h_hat, G, H, P_hat, a_hat, b_hat, alpha_hat)
|
||||
}
|
||||
DBG_PRINT("");
|
||||
|
||||
// zk-WIP last round
|
||||
scalar_t r = scalar_t::random();
|
||||
scalar_t s = scalar_t::random();
|
||||
scalar_t delta = scalar_t::random();
|
||||
scalar_t eta = scalar_t::random();
|
||||
DBG_VAL_PRINT(r);
|
||||
DBG_VAL_PRINT(s);
|
||||
DBG_VAL_PRINT(delta);
|
||||
DBG_VAL_PRINT(eta);
|
||||
|
||||
// A = r * g + s * h + (r y b + s y a) * G + delta * H -- point
|
||||
point_t A = c_point_0;
|
||||
CT::calc_pedersen_commitment(y * (r * b[0] + s * a[0]), delta, A);
|
||||
A += r * g[0] + s * h[0];
|
||||
A *= c_scalar_1div8;
|
||||
A.to_public_key(sig.A);
|
||||
DBG_VAL_PRINT(A);
|
||||
|
||||
// B = (r * y * s) * G + eta * H
|
||||
point_t B = c_point_0;
|
||||
CT::calc_pedersen_commitment(r * y * s, eta, B);
|
||||
B *= c_scalar_1div8;
|
||||
B.to_public_key(sig.B);
|
||||
DBG_VAL_PRINT(B);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// finalize the signature
|
||||
sig.r = r + e * a[0];
|
||||
sig.s = s + e * b[0];
|
||||
sig.delta = eta + e * delta + e * e * alpha_hat;
|
||||
DBG_VAL_PRINT(sig.r);
|
||||
DBG_VAL_PRINT(sig.s);
|
||||
DBG_VAL_PRINT(sig.delta);
|
||||
|
||||
return true;
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
} // bpp_gen()
|
||||
|
||||
|
||||
// efficient multiexponentiation (naive stub implementation atm, TODO)
|
||||
template<typename CT>
|
||||
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() < c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() < 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;
|
||||
}
|
||||
|
||||
|
||||
struct bpp_sig_commit_ref_t
|
||||
{
|
||||
bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector<point_t>& commitments)
|
||||
: sig(sig)
|
||||
, commitments(commitments)
|
||||
{}
|
||||
const bpp_signature& sig;
|
||||
const std::vector<point_t>& commitments;
|
||||
};
|
||||
|
||||
|
||||
template<typename CT>
|
||||
bool bpp_verify(const std::vector<bpp_sig_commit_ref_t>& 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 (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . ");
|
||||
|
||||
const size_t kn = sigs.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
|
||||
|
||||
struct intermediate_element_t
|
||||
{
|
||||
scalar_t y;
|
||||
scalar_t z;
|
||||
scalar_t z_sq;
|
||||
scalar_vec_t e;
|
||||
scalar_vec_t e_sq;
|
||||
scalar_t e_final;
|
||||
scalar_t e_final_sq;
|
||||
size_t inv_e_offset; // offset in batch_for_inverse
|
||||
size_t inv_y_offset; // offset in batch_for_inverse
|
||||
size_t c_bpp_log2_m;
|
||||
size_t c_bpp_m;
|
||||
size_t c_bpp_mn;
|
||||
point_t A;
|
||||
point_t A0;
|
||||
point_t B;
|
||||
std::vector<point_t> L;
|
||||
std::vector<point_t> R;
|
||||
};
|
||||
std::vector<intermediate_element_t> interms(kn);
|
||||
|
||||
size_t c_bpp_log2_m_max = 0;
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4);
|
||||
|
||||
intermediate_element_t& interm = interms[k];
|
||||
interm.c_bpp_log2_m = calc_exp_power_of_2_upper_bound(bsc.commitments.size());
|
||||
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
|
||||
c_bpp_log2_m_max = interm.c_bpp_log2_m;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + c_bpp_log2_n, 5);
|
||||
|
||||
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
|
||||
interm.c_bpp_mn = interm.c_bpp_m * c_bpp_n;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
|
||||
interm.L.resize(sig.L.size());
|
||||
interm.R.resize(sig.R.size());
|
||||
for (size_t i = 0; i < interm.L.size(); ++i)
|
||||
{
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
|
||||
}
|
||||
}
|
||||
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
|
||||
const size_t c_bpp_mn_max = c_bpp_m_max * c_bpp_n;
|
||||
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + c_bpp_log2_n;
|
||||
|
||||
|
||||
//
|
||||
// prepare stuff
|
||||
//
|
||||
/*
|
||||
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
|
||||
for (size_t i = 0; i < c_bpp_mn_max; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
*/
|
||||
|
||||
scalar_vec_t batch_for_inverse;
|
||||
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
|
||||
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// restore y and z
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
hash_helper_t::hs_t hsc;
|
||||
CT::update_transcript(hsc, e, bsc.commitments);
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
hsc.assign_calc_hash(interm.y);
|
||||
interm.z = hash_helper_t::hs(interm.y);
|
||||
interm.z_sq = interm.z * interm.z;
|
||||
DBG_VAL_PRINT(interm.y);
|
||||
DBG_VAL_PRINT(interm.z);
|
||||
e = interm.z; // transcript for further steps
|
||||
|
||||
interm.inv_y_offset = batch_for_inverse.size();
|
||||
batch_for_inverse.push_back(interm.y);
|
||||
interm.inv_e_offset = batch_for_inverse.size();
|
||||
|
||||
interm.e.resize(sig.L.size());
|
||||
interm.e_sq.resize(sig.L.size());
|
||||
|
||||
for (size_t i = 0; i < sig.L.size(); ++i)
|
||||
{
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[i]);
|
||||
hsc.add_pub_key(sig.R[i]);
|
||||
hsc.assign_calc_hash(e);
|
||||
interm.e[i] = e;
|
||||
interm.e_sq[i] = e * e;
|
||||
DBG_PRINT("e[" << i << "]: " << e);
|
||||
batch_for_inverse.push_back(e);
|
||||
}
|
||||
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
hsc.assign_calc_hash(interm.e_final);
|
||||
interm.e_final_sq = interm.e_final * interm.e_final;
|
||||
DBG_VAL_PRINT(interm.e_final);
|
||||
}
|
||||
|
||||
batch_for_inverse.invert();
|
||||
|
||||
// Notation:
|
||||
// 1_vec ^ n = (1, 1, 1, ..., 1)
|
||||
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
|
||||
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
|
||||
// y<^n = (y^n, y^(n-1), ..., y^1)
|
||||
// y>^n = (y^1, y^2, ..., y^n)
|
||||
|
||||
// from page 13, Fig 1:
|
||||
// Verifier outputs Accept IFF the following equality holds (single proof):
|
||||
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'
|
||||
// (where g and h are calculated in each round)
|
||||
// The same equation in additive notation:
|
||||
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H
|
||||
// <=>
|
||||
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*)
|
||||
// where A, B, r', s', delta' is taken from the signature
|
||||
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
|
||||
//
|
||||
// from page 18, Fig 3:
|
||||
// P and V computes:
|
||||
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// (calculated once)
|
||||
//
|
||||
// As suggested in Section 6.1 "Practical Optimizations":
|
||||
// 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20):
|
||||
//
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * A_hat
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (**)
|
||||
//
|
||||
// where:
|
||||
// g, h - vector of fixed generators
|
||||
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
|
||||
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
|
||||
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
|
||||
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
|
||||
//
|
||||
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
|
||||
// insert A_hat into (**) =>
|
||||
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// )
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0
|
||||
|
||||
// =>
|
||||
|
||||
// (for single signature)
|
||||
//
|
||||
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
|
||||
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
|
||||
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
|
||||
// + delta' * H | the signatures
|
||||
//
|
||||
// - e^2 * A0
|
||||
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
|
||||
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (***)
|
||||
//
|
||||
// All (***) will be muptiplied by random weightning factor and then summed up.
|
||||
|
||||
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
|
||||
scalar_vec_t g_scalars;
|
||||
g_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_vec_t h_scalars;
|
||||
h_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_t G_scalar = 0;
|
||||
scalar_t H_scalar = 0;
|
||||
point_t summand = c_point_0;
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// random weightning factor for speed-optimized batch verification (preprint page 20)
|
||||
const scalar_t rwf = scalar_t::random();
|
||||
DBG_PRINT("rwf: " << rwf);
|
||||
|
||||
// prepare d vector (see also d structure description in proof function)
|
||||
scalar_mat_t<c_bpp_n> d(interm.c_bpp_mn);
|
||||
d(0, 0) = interm.z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < interm.c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * interm.z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < interm.c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
// sum(d) (see also note in proof function for this)
|
||||
static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 };
|
||||
const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
DBG_PRINT("sum(d): " << sum_d);
|
||||
|
||||
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
|
||||
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
|
||||
|
||||
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
|
||||
// complexity (sc_mul's): MN+2*log2(MN)-2
|
||||
// the idea is the following:
|
||||
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
|
||||
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
|
||||
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
|
||||
scalar_vec_t s_vec(interm.c_bpp_mn);
|
||||
s_vec[0] = get_e_inv(0);
|
||||
for (size_t i = 1; i < log2_mn; ++i)
|
||||
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
|
||||
DBG_PRINT("[0] " << s_vec[0]);
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
{
|
||||
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
|
||||
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
|
||||
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
|
||||
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
|
||||
}
|
||||
|
||||
// prepare y_inv vector
|
||||
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
|
||||
|
||||
// y^(mn+1)
|
||||
scalar_t y_power_mnp1 = interm.y;
|
||||
for (size_t i = 0; i < log2_mn; ++i)
|
||||
y_power_mnp1 *= y_power_mnp1;
|
||||
y_power_mnp1 *= interm.y;
|
||||
DBG_VAL_PRINT(y_power_mnp1);
|
||||
|
||||
// now calculate all multiplicands for common generators
|
||||
|
||||
// g vector multiplicands:
|
||||
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
|
||||
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
|
||||
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
|
||||
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
|
||||
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
|
||||
|
||||
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
|
||||
|
||||
// h vector multiplicands:
|
||||
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
|
||||
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
|
||||
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
|
||||
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
|
||||
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
|
||||
{
|
||||
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
|
||||
rwf_e_sq_y *= interm.y;
|
||||
}
|
||||
|
||||
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
|
||||
|
||||
// G point multiplicands:
|
||||
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
|
||||
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
|
||||
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
|
||||
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
|
||||
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
|
||||
DBG_PRINT("G_scalar: " << G_scalar);
|
||||
|
||||
// H point multiplicands:
|
||||
// rwf * delta
|
||||
H_scalar += rwf * sig.delta;
|
||||
DBG_PRINT("H_scalar: " << H_scalar);
|
||||
|
||||
// uncommon generators' multiplicands
|
||||
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
|
||||
// - rwf * e^2 * A0
|
||||
summand_8 -= rwf * interm.e_final_sq * interm.A0;
|
||||
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
|
||||
|
||||
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
|
||||
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
|
||||
for (size_t j = 0; j < bsc.commitments.size(); ++j)
|
||||
{
|
||||
e_sq_y_mn1_z_sq_power *= interm.z_sq;
|
||||
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
|
||||
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
|
||||
}
|
||||
|
||||
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
|
||||
for (size_t j = 0; j < log2_mn; ++j)
|
||||
{
|
||||
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
|
||||
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
|
||||
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
|
||||
}
|
||||
|
||||
// - rwf * e * A - rwf * B = 0
|
||||
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
|
||||
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
|
||||
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
|
||||
|
||||
summand_8.modify_mul8();
|
||||
summand += summand_8;
|
||||
}
|
||||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
|
||||
bool result = multiexp_and_check_being_zero<CT>(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
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
#include "epee/include/profile_tools.h" // <- remove this, sowle
|
||||
|
||||
#include "msm.h"
|
||||
#include "range_proof_bpp.h"
|
||||
#include "range_proof_bppe.h"
|
||||
|
|
|
|||
425
src/crypto/zarcanum.cpp
Normal file
|
|
@ -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<mp::uint256_t>();
|
||||
|
||||
template<typename T>
|
||||
inline std::ostream &operator <<(std::ostream &o, const std::vector<T> &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<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty));
|
||||
return c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (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<mp::uint256_t>() / (c_zarcanum_z_coeff_mp * pos_difficulty)));
|
||||
return c_zarcanum_z_coeff_mp * (c_scalar_L.as_boost_mp_type<mp::uint256_t>() / (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<mp::uint256_t>();
|
||||
rhs = static_cast<mp::uint512_t>(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<CLSAG_GGXXG_input_ref_t>& 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<mp::uint256_t>() / (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<const public_key*> E_1div8_vec_ptr = { &result.E };
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen<bpp_crypto_trait_Zarcanum>(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<CLSAG_GGXXG_input_ref_t>& 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<point_t> E_for_range_proof = { point_t(sig.E) }; // consider changing to 8*sig.E to avoid additional conversion
|
||||
std::vector<bppe_sig_commit_ref_t> range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) };
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify<bpp_crypto_trait_Zarcanum>(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<point_t>& amount_commitments,
|
||||
const std::vector<point_t>& amount_commitments_for_rp_aggregation,
|
||||
const std::vector<point_t>& 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<point_t> 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<point_t> 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<const public_key*> amount_commitments_1div8, const std::vector<const public_key*> 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<point_t> 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<point_t> 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<point_t> 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
|
||||
190
src/crypto/zarcanum.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
// 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
|
||||
#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<CLSAG_GGXXG_input_ref_t>& 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<CLSAG_GGXXG_input_ref_t>& 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<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
|
||||
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<generator_tag gen0 = gt_H, generator_tag gen1 = gt_G>
|
||||
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<generator_tag gen>
|
||||
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<gt_G>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (A != secret_a * c_point_G)
|
||||
return false;
|
||||
#endif
|
||||
scalar_t r = scalar_t::random();
|
||||
point_t R = r * c_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<gt_X>(const hash& m, const point_t& A, const scalar_t& secret_a, generic_schnorr_sig& result)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (A != secret_a * c_point_X)
|
||||
return false;
|
||||
#endif
|
||||
scalar_t r = scalar_t::random();
|
||||
point_t R = r * c_point_X;
|
||||
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<generator_tag gen>
|
||||
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<gt_G>(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<gt_X>(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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// TODO: improve this proof using random weightning factor
|
||||
struct vector_UG_aggregation_proof
|
||||
{
|
||||
std::vector<public_key> 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<point_t>& amount_commitments,
|
||||
const std::vector<point_t>& amount_commitments_for_rp_aggregation,
|
||||
const std::vector<point_t>& 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<const public_key*> amount_commitments_1div8, const std::vector<const public_key*> blinded_asset_ids_1div8,
|
||||
const vector_UG_aggregation_proof& sig, uint8_t* p_err = nullptr) noexcept;
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
|
|
@ -13,7 +13,7 @@
|
|||
#include <boost/foreach.hpp>
|
||||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#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"
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#include "storages/portable_storage_template_helper.h"
|
||||
|
||||
|
||||
command_line::arg_descriptor<bool> arg_market_disable = { "disable-market", "Start GUI with market service disabled", false, true };
|
||||
command_line::arg_descriptor<bool> arg_market_disable ( "disable-market", "Start GUI with market service disabled");
|
||||
|
||||
|
||||
namespace bc_services
|
||||
|
|
|
|||
|
|
@ -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<uint64_t, 5> etc_stuff_6;
|
||||
epee::math_helper::average<uint64_t, 5> insert_time_4;
|
||||
epee::math_helper::average<uint64_t, 5> raise_block_core_event;
|
||||
epee::math_helper::average<uint64_t, 5> validate_miner_transaction_time;
|
||||
epee::math_helper::average<uint64_t, 5> collect_rangeproofs_data_from_tx_time;
|
||||
epee::math_helper::average<uint64_t, 5> verify_multiple_zc_outs_range_proofs_time;
|
||||
|
||||
|
||||
//target_calculating_time_2
|
||||
epee::math_helper::average<uint64_t, 5> target_calculating_enum_blocks;
|
||||
epee::math_helper::average<uint64_t, 5> target_calculating_calc;
|
||||
|
||||
//longhash_calculating_time_3
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_ki_search;
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_get_out_keys_for_inputs;
|
||||
epee::math_helper::average<uint64_t, 1> pos_validate_zvp;
|
||||
|
||||
//tx processing zone
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_time;
|
||||
epee::math_helper::average<uint64_t, 1> tx_add_one_tx_time;
|
||||
|
|
@ -139,6 +149,7 @@ namespace currency
|
|||
{
|
||||
bool htlc_is_expired;
|
||||
std::list<txout_htlc> htlc_outs;
|
||||
std::list<tx_out_zarcanum> zc_outs;
|
||||
};
|
||||
|
||||
// == Output indexes local lookup table conception ==
|
||||
|
|
@ -239,11 +250,11 @@ namespace currency
|
|||
|
||||
|
||||
template<class visitor_t>
|
||||
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<class visitor_t>
|
||||
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<size_t>& sz, size_t count)const;
|
||||
bool get_tx_outputs_gindexs(const crypto::hash& tx_id, std::vector<uint64_t>& 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<std::string> get_aliases_by_address(const account_public_address& addr)const;
|
||||
template<typename cb_t>
|
||||
bool enumerate_aliases(cb_t cb) const;
|
||||
template<typename cb_t>
|
||||
|
|
@ -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<crypto::signature>& 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<crypto::signature>& 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<crypto::signature>& 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<crypto::signature>& 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<crypto::public_key>& 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<crypto::public_key>& 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<crypto::signature>& sig, const std::vector<const crypto::public_key*>& 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<const crypto::public_key*>& 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<txin_etc_details_v>& in_etc_details,
|
||||
const crypto::hash& tx_prefix_hash,
|
||||
const std::vector<crypto::signature>& sig,
|
||||
const std::vector<const crypto::public_key*>& 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<const transaction_chain_entry> 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<std::pair<uint64_t, wide_difficulty_type>> &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<crypto::key_image>& images, std::list<uint64_t>& 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,8 +414,8 @@ 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)
|
||||
<< " have index record with offset=" << *block_ind_ptr << ", bigger then m_blocks.size()=" << m_db_blocks.size());
|
||||
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<crypto::hash, ms_output_entry, false, false> multisig_outs_container;// ms out id => ms_output_entry
|
||||
typedef tools::db::cached_key_value_accessor<uint64_t, uint64_t, false, true> solo_options_container;
|
||||
typedef tools::db::basic_key_value_accessor<uint32_t, block_gindex_increments, true> per_block_gindex_increments_container; // height => [(amount, gindex_increment), ...]
|
||||
|
||||
typedef tools::db::cached_key_value_accessor<crypto::public_key, std::list<asset_descriptor_operation>, 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<crypto::hash, size_t> m_alternative_chains_txs; // tx_id -> how many alt blocks it related to (always >= 1)
|
||||
std::unordered_map<crypto::key_image, std::list<crypto::hash>> 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 <std::pair<wide_difficulty_type, uint64_t>> m_pos_targetdata_cache;
|
||||
mutable std::list <std::pair<wide_difficulty_type, uint64_t>> m_pow_targetdata_cache;
|
||||
//work like a cache to avoid recalculation on read operations
|
||||
|
|
@ -567,8 +591,8 @@ namespace currency
|
|||
mutable std::atomic<bool> 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<zc_outs_range_proofs_with_commitments>& 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<crypto::key_image>& 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<crypto::signature>& input_sigs,
|
||||
uint64_t split_height,
|
||||
const alt_chain_type& alt_chain,
|
||||
const std::unordered_set<crypto::hash>& 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<crypto::signature>& 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<crypto::signature>& 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<crypto::key_image>& 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<transaction>& 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<uint64_t>& 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<uint64_t, uint64_t>& 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<uint64_t, uint64_t>& 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<uint64_t> timestamps, const block& b)const;
|
||||
std::vector<uint64_t> get_last_n_blocks_timestamps(size_t n)const;
|
||||
const std::vector<txin_etc_details_v>& 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<crypto::key_image>& 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<uint64_t>& 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<class visitor_t>
|
||||
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<class visitor_t>
|
||||
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<txout_ref_v>& key_offsets = input_to_key.key_offsets;
|
||||
uint64_t amount = get_amount_from_variant(verified_input);
|
||||
const std::vector<txout_ref_v>& 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<txout_to_key&>(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<uint32_t>(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<txout_htlc>(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<txout_to_key&>(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<uint32_t>(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<txout_htlc>(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<const crypto::public_key&>(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<uint32_t>(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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<crypto::hash, transaction> 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()
|
||||
};
|
||||
|
||||
}
|
||||
struct vote_results
|
||||
{
|
||||
uint64_t total_pos_blocks; //total pos blocks in a given range
|
||||
std::list<vote_on_proposal> votes;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(total_pos_blocks)
|
||||
KV_SERIALIZE(votes)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
} // namespace currency
|
||||
|
|
|
|||
|
|
@ -36,11 +36,11 @@ namespace currency
|
|||
if(height > blockchain_last_block_height)
|
||||
return false;
|
||||
|
||||
auto it = m_points.lower_bound(height);
|
||||
auto it = m_points.lower_bound(height); // if found, it->first >= height
|
||||
if(it == m_points.end())
|
||||
return false;
|
||||
if(it->first <= blockchain_last_block_height)
|
||||
return true;
|
||||
return true; // this is the case only if height <= it->first <= blockchain_last_block_height
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
|
@ -68,4 +68,27 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
uint64_t checkpoints::get_checkpoint_before_height(uint64_t height) const
|
||||
{
|
||||
// returns height of the leftmost CP with height that is LESS than the given height
|
||||
// ex:
|
||||
// If there are two CP at 11 and 15:
|
||||
// get_checkpoint_before_height(10) = 0
|
||||
// get_checkpoint_before_height(11) = 0
|
||||
// get_checkpoint_before_height(12) = 11
|
||||
// get_checkpoint_before_height(13) = 11
|
||||
// get_checkpoint_before_height(14) = 11
|
||||
// get_checkpoint_before_height(15) = 11
|
||||
// get_checkpoint_before_height(16) = 15
|
||||
|
||||
uint64_t top_cp = get_top_checkpoint_height();
|
||||
if (height > top_cp)
|
||||
return top_cp;
|
||||
|
||||
auto it = m_points.lower_bound(height); // if found, it->first >= height
|
||||
if (it == m_points.end() || it == m_points.begin())
|
||||
return 0;
|
||||
return (--it)->first;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ namespace currency
|
|||
bool is_height_passed_zone(uint64_t height, uint64_t blockchain_last_block_height) const;
|
||||
bool check_block(uint64_t height, const crypto::hash& h) const;
|
||||
uint64_t get_top_checkpoint_height() const;
|
||||
|
||||
uint64_t get_checkpoint_before_height(uint64_t height) const;
|
||||
private:
|
||||
std::map<uint64_t, crypto::hash> m_points;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ namespace currency
|
|||
ADD_CHECKPOINT(600000, "d9fe316086e1aaea07d94082973ec764eff5fc5a05ed6e1eca273cee59daeeb4");
|
||||
ADD_CHECKPOINT(900000, "2205b73cd79d4937b087b02a8b001171b73c34464bc4a952834eaf7c2bd63e86");
|
||||
ADD_CHECKPOINT(1161000, "96990d851b484e30190678756ba2a4d3a2f92b987e2470728ac1e38b2bf35908");
|
||||
ADD_CHECKPOINT(1480000, "5dd3381eec35e8b4eba4518bfd8eec682a4292761d92218fd59b9f0ffedad3fe");
|
||||
ADD_CHECKPOINT(2000000, "7b6698a8cc279aa78d6263f01fef186bd16f5b1ea263a7f4714abc1d506b9cb3");
|
||||
ADD_CHECKPOINT(2390000, "10797d34349d0ef1d1ab4b41ada6f8f2c2f86a7f7eebe44dd2ba06067cb47e0a");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -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<uint64_t, m_total_count> 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);
|
||||
|
|
|
|||
43
src/currency_core/crypto_config.h
Normal file
|
|
@ -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__"
|
||||
|
|
@ -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<crypto::hash>("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<signed_parts, extra_attachment_info> txin_etc_details_v;
|
||||
|
||||
struct txin_to_key
|
||||
|
||||
struct referring_input
|
||||
{
|
||||
std::vector<txout_ref_v> key_offsets;
|
||||
};
|
||||
|
||||
struct txin_to_key : public referring_input
|
||||
{
|
||||
uint64_t amount;
|
||||
std::vector<txout_ref_v> key_offsets;
|
||||
crypto::key_image k_image; // double spending protection
|
||||
std::vector<txin_etc_details_v> 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<txin_etc_details_v> 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_gen, txin_to_key, txin_multisig, txin_htlc> txin_v;
|
||||
|
||||
typedef boost::variant<txout_to_key, txout_multisig, txout_htlc> txout_target_v;
|
||||
|
||||
//typedef std::pair<uint64_t, txout> out_t;
|
||||
struct tx_out
|
||||
struct tx_out_bare
|
||||
{
|
||||
uint64_t amount;
|
||||
txout_target_v target;
|
||||
|
|
@ -294,6 +312,189 @@ 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<txin_etc_details_v> 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<crypto::BGE_proof_s> 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()
|
||||
};
|
||||
|
||||
// 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))
|
||||
struct zc_balance_proof
|
||||
{
|
||||
crypto::generic_schnorr_sig_s ss;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(ss)
|
||||
END_SERIALIZE()
|
||||
|
||||
BEGIN_BOOST_SERIALIZATION()
|
||||
BOOST_SERIALIZE(ss)
|
||||
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_gen, txin_to_key, txin_multisig, txin_htlc, txin_zc_input> txin_v;
|
||||
|
||||
typedef boost::variant<tx_out_bare, tx_out_zarcanum> tx_out_v;
|
||||
|
||||
|
||||
struct tx_comment
|
||||
{
|
||||
|
|
@ -470,8 +671,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 +693,130 @@ 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<asset_descriptor_base>(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<crypto::signature> opt_proof; // operation proof - for update/emit
|
||||
boost::optional<crypto::public_key> 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_proof)
|
||||
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_proof)
|
||||
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<crypto::linear_composition_proof_s> opt_amount_commitment_composition_proof; // for hidden supply
|
||||
boost::optional<crypto::signature> 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 extra_padding
|
||||
{
|
||||
|
|
@ -558,10 +882,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<all_payload_types>::type payload_items_v;
|
||||
|
|
@ -569,26 +893,57 @@ namespace currency
|
|||
typedef payload_items_v attachment_v;
|
||||
|
||||
|
||||
|
||||
|
||||
//classic CryptoNote signature by Nicolas Van Saberhagen
|
||||
struct NLSAG_sig
|
||||
{
|
||||
std::vector<crypto::signature> 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<NLSAG_sig, void_sig, ZC_sig, zarcanum_sig> signature_v;
|
||||
|
||||
typedef boost::variant<zc_asset_surjection_proof, zc_outs_range_proof, zc_balance_proof, asset_operation_proof> 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_v> extra;
|
||||
uint64_t version = 0;
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out> vout;
|
||||
std::vector<extra_v> extra;
|
||||
std::vector<tx_out_v> 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 +959,23 @@ namespace currency
|
|||
class transaction: public transaction_prefix
|
||||
{
|
||||
public:
|
||||
std::vector<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
|
||||
std::vector<attachment_v> attachment;
|
||||
|
||||
transaction();
|
||||
std::vector<signature_v> signatures;
|
||||
std::vector<proof_v> proofs;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELDS(*static_cast<transaction_prefix *>(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 +1037,6 @@ namespace currency
|
|||
*/
|
||||
//-------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct stake_modifier_type
|
||||
{
|
||||
|
|
@ -725,7 +1046,6 @@ namespace currency
|
|||
|
||||
struct stake_kernel
|
||||
{
|
||||
|
||||
stake_modifier_type stake_modifier;
|
||||
uint64_t block_timestamp; //this block timestamp
|
||||
crypto::key_image kimage;
|
||||
|
|
@ -735,22 +1055,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 +1106,9 @@ 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);
|
||||
|
||||
|
||||
// txin_v variant currency
|
||||
SET_VARIANT_TAGS(currency::txin_gen, 0, "gen");
|
||||
|
|
@ -814,6 +1160,26 @@ 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");
|
||||
|
||||
|
||||
|
||||
|
||||
#undef SET_VARIANT_TAGS
|
||||
|
|
|
|||
118
src/currency_core/currency_basic_backward_comp.inl
Normal file
|
|
@ -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_v> extra;
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out_bare> vout;//std::vector<tx_out> 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_v> extra;
|
||||
std::vector<txin_v> vin;
|
||||
std::vector<tx_out_old> vout;//std::vector<tx_out> vout;
|
||||
|
||||
BEGIN_SERIALIZE()
|
||||
VARINT_FIELD(version)
|
||||
if (TRANSACTION_VERSION_PRE_HF4 < version) return false;
|
||||
FIELD(vin)
|
||||
FIELD(vout)
|
||||
FIELD(extra)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename transaction_prefix_current_t>
|
||||
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<tx_out_bare>(v));
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("Unexpected type in tx_out_v");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template<typename transaction_prefix_current_t>
|
||||
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<std::vector<crypto::signature> > signatures; //count signatures always the same as inputs count
|
||||
std::vector<attachment_v> attachment;
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(signatures)
|
||||
FIELD(attachment)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
template<typename transaction_current_t>
|
||||
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<NLSAG_sig>(s).s);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error(std::string("Unexpected type in tx.signatures during transition_convert: ") + s.type().name());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename transaction_current_t>
|
||||
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<NLSAG_sig>(to.signatures[i]).s = from.signatures[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
#include <boost/serialization/is_bitwise_serializable.hpp>
|
||||
#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 <class Archive>
|
||||
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 <class Archive>
|
||||
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 <class Archive>
|
||||
inline void serialize(Archive &a, currency::tx_comment &x, const boost::serialization::version_type ver)
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#ifndef TESTNET
|
||||
#define CURRENCY_FORMATION_VERSION 84
|
||||
#else
|
||||
#define CURRENCY_FORMATION_VERSION 88
|
||||
#define CURRENCY_FORMATION_VERSION 94
|
||||
#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
|
||||
|
|
@ -211,8 +233,10 @@
|
|||
#define MINER_CONFIG_FILENAME "miner_conf.json"
|
||||
#define GUI_SECURE_CONFIG_FILENAME "gui_secure_conf.bin"
|
||||
#define GUI_CONFIG_FILENAME "gui_settings.json"
|
||||
#define GUI_INTERNAL_CONFIG "gui_internal_config.bin"
|
||||
#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
|
||||
|
|
@ -226,9 +250,11 @@
|
|||
#define BC_OFFERS_CURRENCY_MARKET_FILENAME "market.bin"
|
||||
|
||||
#ifndef TESTNET
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION 153
|
||||
#define WALLET_FILE_SERIALIZATION_VERSION 161
|
||||
#define WALLET_FILE_LAST_SUPPORTED_VERSION 161
|
||||
#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)
|
||||
|
|
@ -241,14 +267,36 @@
|
|||
#define ZANO_HARDFORK_01_AFTER_HEIGHT 194624
|
||||
#define ZANO_HARDFORK_02_AFTER_HEIGHT 999999
|
||||
#define ZANO_HARDFORK_03_AFTER_HEIGHT 1082577
|
||||
#define ZANO_HARDFORK_04_AFTER_HEIGHT 999999999
|
||||
#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
|
||||
|
||||
#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@#@
|
||||
|
|
@ -89,6 +89,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 +355,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)
|
||||
|
|
@ -499,15 +504,29 @@ namespace currency
|
|||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::add_new_block(const block& b, block_verification_context& bvc)
|
||||
{
|
||||
uint64_t h = m_blockchain_storage.get_top_block_height();
|
||||
if (m_stop_after_height != 0 && h >= m_stop_after_height)
|
||||
{
|
||||
LOG_PRINT_YELLOW("Blockchain top block height is " << 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;
|
||||
}
|
||||
|
||||
bool r = m_blockchain_storage.add_new_block(b, bvc);
|
||||
if (r && bvc.m_added_to_main_chain)
|
||||
{
|
||||
uint64_t 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); }
|
||||
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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<bool> m_starter_message_showed;
|
||||
|
||||
critical_section m_blockchain_update_listeners_lock;
|
||||
epee::critical_section m_blockchain_update_listeners_lock;
|
||||
std::vector<i_blockchain_update_listener*> m_blockchain_update_listeners;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------------------------------------------------------
|
||||
|
|
@ -143,6 +142,7 @@ namespace currency
|
|||
|
||||
struct finalize_tx_param
|
||||
{
|
||||
|
||||
uint64_t unlock_time;
|
||||
std::vector<currency::extra_v> extra;
|
||||
std::vector<currency::attachment_v> attachments;
|
||||
|
|
@ -156,6 +156,12 @@ namespace currency
|
|||
std::vector<currency::tx_destination_entry> 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;
|
||||
crypto::secret_key asset_control_key = currency::null_skey;
|
||||
epee::misc_utils::events_dispatcher* pevents_dispatcher;
|
||||
|
||||
tx_generation_context gen_context{}; // solely for consolidated txs
|
||||
|
||||
BEGIN_SERIALIZE_OBJECT()
|
||||
FIELD(unlock_time)
|
||||
|
|
@ -171,6 +177,11 @@ namespace currency
|
|||
FIELD(prepared_destinations)
|
||||
FIELD(expiration_time)
|
||||
FIELD(spend_pub_key)
|
||||
FIELD(tx_version)
|
||||
FIELD(mode_separate_fee)
|
||||
FIELD(asset_control_key)
|
||||
if (flags & TX_FLAG_SIGNATURE_MODE_SEPARATE)
|
||||
FIELD(gen_context);
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
|
|
@ -181,6 +192,8 @@ namespace currency
|
|||
finalize_tx_param ftp;
|
||||
std::string htlc_origin;
|
||||
std::vector<serializable_pair<uint64_t, crypto::key_image>> 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 +201,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<crypto::point_t>& 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<crypto::point_t> 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_descriptor_operation> > asset_op_history;
|
||||
};
|
||||
|
||||
bool verify_multiple_zc_outs_range_proofs(const std::vector<zc_outs_range_proofs_with_commitments>& 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<tx_out_v>& 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_proof(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<tx_destination_entry>& 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<tx_destination_entry>& destinations = std::vector<tx_destination_entry>()
|
||||
);
|
||||
//---------------------------------------------------------------
|
||||
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<uint16_t>& 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<uint16_t>& 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<uint16_t>& 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_v>& attachment, extra_attachment_info& eai);
|
||||
|
|
@ -227,6 +297,7 @@ namespace currency
|
|||
const std::vector<tx_destination_entry>& destinations,
|
||||
const std::vector<attachment_v>& 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 +307,7 @@ namespace currency
|
|||
const std::vector<extra_v>& extra,
|
||||
const std::vector<attachment_v>& 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 +320,7 @@ namespace currency
|
|||
const std::vector<extra_v>& extra,
|
||||
const std::vector<attachment_v>& 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 +329,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);
|
||||
|
||||
void calculate_asset_id(const crypto::public_key& asset_owner, 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 +343,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<size_t>& 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<size_t>& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<size_t>& 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<wallet_out_info>& 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<wallet_out_info>& outs, crypto::key_derivation& derivation, std::list<htlc_info>& htlc_info_list);
|
||||
bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector<wallet_out_info>& 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<payload_items_v>& 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<tx_out>& 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<tx_out_v>& outs);
|
||||
size_t get_multisig_in_index(const std::vector<txin_v>& inputs);
|
||||
|
||||
uint64_t get_reward_from_miner_tx(const transaction& tx);
|
||||
|
|
@ -304,7 +387,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,11 +408,13 @@ namespace currency
|
|||
uint64_t get_block_height(const transaction& coinbase);
|
||||
uint64_t get_block_height(const block& b);
|
||||
std::vector<txout_ref_v> relative_output_offsets_to_absolute(const std::vector<txout_ref_v>& off);
|
||||
std::vector<txout_ref_v> absolute_output_offsets_to_relative(const std::vector<txout_ref_v>& off);
|
||||
bool absolute_sorted_output_offsets_to_relative_in_place(std::vector<txout_ref_v>& 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);
|
||||
|
||||
|
|
@ -339,15 +424,15 @@ namespace currency
|
|||
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<const crypto::public_key*>& output_keys_ptrs, const std::vector<crypto::signature>& 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 +442,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<uint64_t, uint32_t>& 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<std::pair<std::string, bool>>& 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<class t_txin_v>
|
||||
typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type& get_txin_etc_options(t_txin_v& in)
|
||||
{
|
||||
static typename std::conditional<std::is_const<t_txin_v>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type stub;
|
||||
|
||||
|
||||
//static stub;
|
||||
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
return boost::get<txin_to_key>(in).etc_details;
|
||||
else if (in.type() == typeid(txin_htlc))
|
||||
return boost::get<txin_htlc>(in).etc_details;
|
||||
else if (in.type() == typeid(txin_multisig))
|
||||
return boost::get<txin_multisig>(in).etc_details;
|
||||
else
|
||||
else if (in.type() == typeid(txin_htlc))
|
||||
return boost::get<txin_htlc>(in).etc_details;
|
||||
else if (in.type() == typeid(txin_zc_input))
|
||||
return boost::get<txin_zc_input>(in).etc_details;
|
||||
else
|
||||
return stub;
|
||||
}
|
||||
|
||||
template<typename out_t>
|
||||
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<bool>
|
||||
{
|
||||
template<typename T>
|
||||
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<class t_extra_container>
|
||||
bool add_attachments_info_to_extra(t_extra_container& extra_container, const std::vector<attachment_v>& attachments)
|
||||
{
|
||||
|
|
@ -410,6 +520,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<attachment_v>& 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 +583,34 @@ namespace currency
|
|||
return true;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// outputs "1391306.970000000000"
|
||||
template<typename t_number>
|
||||
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<typename t_number>
|
||||
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<typename t_number>
|
||||
std::string print_money(t_number amount, uint64_t decimals = CURRENCY_DISPLAY_DECIMAL_POINT)
|
||||
{
|
||||
return print_fixed_decimal_point(amount, decimals);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
|
||||
template<typename t_number>
|
||||
std::string print_asset_money(t_number amount, size_t decimal_point)
|
||||
{
|
||||
return print_fixed_decimal_point(amount, decimal_point);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class alias_rpc_details_t>
|
||||
|
|
@ -531,36 +660,6 @@ namespace currency
|
|||
return get_or_add_field_to_variant_vector<extra_t>(extra);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class variant_t, class variant_type_t>
|
||||
void update_or_add_field_to_extra(std::vector<variant_t>& variant_container, const variant_type_t& v)
|
||||
{
|
||||
for (auto& ev : variant_container)
|
||||
{
|
||||
if (ev.type() == typeid(variant_type_t))
|
||||
{
|
||||
boost::get<variant_type_t>(ev) = v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
variant_container.push_back(v);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class variant_type_t, class variant_t>
|
||||
void remove_field_of_type_from_extra(std::vector<variant_t>& 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<typename t_container>
|
||||
bool get_payment_id_from_tx(const t_container& att, std::string& payment_id)
|
||||
{
|
||||
|
|
@ -647,59 +746,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<typename chunk_handler_t>
|
||||
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<uint64_t>() % (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>
|
||||
{
|
||||
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<txin_etc_details_v>* 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<txin_to_key>(in).etc_details;
|
||||
if (in.type().hash_code() == typeid(txin_htlc).hash_code())
|
||||
return &boost::get<txin_htlc>(in).etc_details;
|
||||
if (in.type().hash_code() == typeid(txin_multisig).hash_code())
|
||||
return &boost::get<txin_multisig>(in).etc_details;
|
||||
return nullptr;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
inline std::vector<txin_etc_details_v>* get_input_etc_details(txin_v& in)
|
||||
{
|
||||
if (in.type().hash_code() == typeid(txin_to_key).hash_code())
|
||||
return &boost::get<txin_to_key>(in).etc_details;
|
||||
if (in.type().hash_code() == typeid(txin_htlc).hash_code())
|
||||
return &boost::get<txin_htlc>(in).etc_details;
|
||||
if (in.type().hash_code() == typeid(txin_multisig).hash_code())
|
||||
return &boost::get<txin_multisig>(in).etc_details;
|
||||
return nullptr;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
struct txin_signature_size_visitor : public boost::static_visitor<size_t>
|
||||
{
|
||||
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<class txin_t>
|
||||
typename std::conditional<std::is_const<txin_t>::value, const std::vector<txin_etc_details_v>, std::vector<txin_etc_details_v> >::type*
|
||||
get_input_etc_details(txin_t& in)
|
||||
{
|
||||
if (in.type() == typeid(txin_to_key))
|
||||
return &boost::get<txin_to_key>(in).etc_details;
|
||||
if (in.type() == typeid(txin_multisig))
|
||||
return &boost::get<txin_multisig>(in).etc_details;
|
||||
if (in.type() == typeid(txin_htlc))
|
||||
return &boost::get<txin_htlc>(in).etc_details;
|
||||
if (in.type() == typeid(txin_zc_input))
|
||||
return &boost::get<txin_zc_input>(in).etc_details;
|
||||
return nullptr;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
struct input_amount_getter : public boost::static_visitor<uint64_t>
|
||||
{
|
||||
template<class t_input>
|
||||
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<uint64_t>
|
||||
{
|
||||
template<class out_t>
|
||||
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<tx_out_bare>(o);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template <typename container_t>
|
||||
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 +897,7 @@ namespace currency
|
|||
template <typename container_t>
|
||||
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 +937,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<bool>
|
||||
{
|
||||
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<const extra_alias_entry&>(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<const char*>(&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<tx_payer>(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<tx_payer>(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<typename t_type>
|
||||
bool operator()(const t_type& t_t)
|
||||
{
|
||||
tv.type = typeid(t_t).name();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
//------------------------------------------------------------------
|
||||
|
||||
|
||||
template<class t_container>
|
||||
bool fill_tx_rpc_payload_items(std::vector<tx_extra_rpc_entry>& 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
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ namespace currency
|
|||
/* */
|
||||
/************************************************************************/
|
||||
template<class t_array>
|
||||
struct array_hasher : std::unary_function<t_array&, std::size_t>
|
||||
struct array_hasher
|
||||
{
|
||||
std::size_t operator()(const t_array& val) const
|
||||
{
|
||||
|
|
@ -91,22 +91,66 @@ namespace currency
|
|||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specific_type_t, typename variant_t_container>
|
||||
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<specific_type_t>(ai);
|
||||
return true;
|
||||
return &boost::get<specific_type_t>(ai);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename specific_type_t, typename variant_t_container>
|
||||
bool get_type_in_variant_container(variant_t_container& av, specific_type_t& a)
|
||||
{
|
||||
const specific_type_t* pa = get_type_in_variant_container<const specific_type_t>(av);
|
||||
if (pa)
|
||||
{
|
||||
a = *pa;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
//---------------------------------------------------------------
|
||||
template<typename specific_type_t, typename variant_t_container>
|
||||
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<specific_type_t>(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<typename specific_type_t, typename variant_container_t, typename callback_t>
|
||||
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<specific_type_t>(ai)))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
return true;
|
||||
return return_value_if_none_found;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
// callback should return true to continue iterating through the container
|
||||
template <typename A, typename B, typename container_t, typename callback_t>
|
||||
bool handle_2_alternative_types_in_variant_container(const container_t& container, callback_t cb)
|
||||
|
|
@ -129,21 +173,160 @@ namespace currency
|
|||
}
|
||||
return found;
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
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<txin_to_key>(in_v).k_image;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_v.type() == typeid(txin_htlc))
|
||||
{
|
||||
result = boost::get<txin_htlc>(in_v).k_image;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_v.type() == typeid(txin_zc_input))
|
||||
{
|
||||
result = boost::get<txin_zc_input>(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<txin_to_key>(in_v).k_image;
|
||||
|
||||
if (in_v.type() == typeid(txin_htlc))
|
||||
return boost::get<txin_htlc>(in_v).k_image;
|
||||
|
||||
if (in_v.type() == typeid(txin_zc_input))
|
||||
return boost::get<txin_zc_input>(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<currency::txout_ref_v>& get_key_offsets_from_txin_v(const txin_v& in_v)
|
||||
{
|
||||
if (in_v.type() == typeid(txin_to_key))
|
||||
return boost::get<txin_to_key>(in_v).key_offsets;
|
||||
|
||||
if (in_v.type() == typeid(txin_htlc))
|
||||
return boost::get<txin_htlc>(in_v).key_offsets;
|
||||
|
||||
if (in_v.type() == typeid(txin_zc_input))
|
||||
return boost::get<txin_zc_input>(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<txin_to_key>(in_v);
|
||||
if (out_v.type() == typeid(tx_out_bare))
|
||||
{
|
||||
const tx_out_bare& ob = boost::get<tx_out_bare>(out_v);
|
||||
if (ob.target.type() == typeid(txout_to_key))
|
||||
{
|
||||
result = boost::get<txout_to_key>(ob.target).mix_attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (out_v.type() == typeid(tx_out_zarcanum))
|
||||
{
|
||||
result = boost::get<tx_out_zarcanum>(out_v).mix_attr;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (in_v.type() == typeid(txin_htlc))
|
||||
catch(...)
|
||||
{
|
||||
const txin_htlc& in = boost::get<txin_htlc>(in_v);
|
||||
return static_cast<const txin_to_key&>(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<typename type_with_kimage_t>
|
||||
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<typename t_type_left, typename t_type_right>
|
||||
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<true> bin_archive;
|
||||
typedef variant_serialization_traits<bin_archive, t_type_left> traits_left;
|
||||
typedef variant_serialization_traits<bin_archive, t_type_right> traits_right;
|
||||
return (traits_left::get_tag() < traits_right::get_tag());
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<typename t_type_left>
|
||||
struct right_visitor : public boost::static_visitor<bool>
|
||||
{
|
||||
const t_type_left& m_rleft;
|
||||
|
||||
right_visitor(const t_type_left& left) : m_rleft(left)
|
||||
{}
|
||||
|
||||
template<typename t_type_right>
|
||||
bool operator()(const t_type_right& right)const
|
||||
{
|
||||
return compare_variant_by_types(m_rleft, right);
|
||||
}
|
||||
};
|
||||
|
||||
struct left_visitor : public boost::static_visitor<bool>
|
||||
{
|
||||
const txin_v& m_rright;
|
||||
|
||||
left_visitor(const txin_v& right) : m_rright(right)
|
||||
{}
|
||||
template<typename t_type_left>
|
||||
bool operator()(const t_type_left& left)const
|
||||
{
|
||||
return boost::apply_visitor(right_visitor<t_type_left>(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<typename variant_container_t>
|
||||
|
|
@ -246,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 <typename T, typename... Types>
|
||||
void put_t_to_buff(std::string& buff, const T& var1, Types&... var2)
|
||||
{
|
||||
static_assert(std::is_pod<T>::value, "T must be a POD type.");
|
||||
buff.append((const char*)&var1, sizeof(var1));
|
||||
put_t_to_buff(buff, var2...);
|
||||
}
|
||||
|
||||
template <typename... Types>
|
||||
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()); \
|
||||
|
|
|
|||
|
|
@ -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<txout_to_key>(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<txout_to_key>(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<size_t>
|
||||
{
|
||||
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<crypto::key_image>& kil)
|
||||
{
|
||||
std::unordered_set<crypto::key_image> 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<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& outputs, size_t old_real_index, size_t& new_real_index) noexcept
|
||||
{
|
||||
TRY_ENTRY()
|
||||
|
||||
std::vector<tx_source_entry::output_entry> 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<uint64_t>(lhs.out_reference) < boost::get<uint64_t>(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<uint64_t>(result[i].out_reference) -= boost::get<uint64_t>(result[i - 1].out_reference);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
CATCH_ENTRY2(std::vector<tx_source_entry::output_entry>{});
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key)
|
||||
{
|
||||
//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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -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<txout_ref_v, crypto::public_key> 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<output_entry> 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<txout_ref_v, crypto::public_key> output_entry; // txout_ref_v is either global output index or ref_by_id; public_key - is output's stealth address
|
||||
|
||||
std::vector<output_entry> 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<account_public_address> 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<account_public_address> 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<account_public_address>& 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<account_public_address>& addr) : amount(a), addr(addr), minimum_sigs(addr.size()){}
|
||||
tx_destination_entry(uint64_t a, const std::list<account_public_address>& 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<class variant_t, class variant_type_t>
|
||||
void update_or_add_field_to_extra(std::vector<variant_t>& variant_container, const variant_type_t& v)
|
||||
{
|
||||
for (auto& ev : variant_container)
|
||||
{
|
||||
if (ev.type() == typeid(variant_type_t))
|
||||
{
|
||||
boost::get<variant_type_t>(ev) = v;
|
||||
return;
|
||||
}
|
||||
}
|
||||
variant_container.push_back(v);
|
||||
}
|
||||
//---------------------------------------------------------------
|
||||
template<class variant_type_t, class variant_t>
|
||||
void remove_field_of_type_from_extra(std::vector<variant_t>& 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<class extra_type_t>
|
||||
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<class extra_type_t>
|
||||
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,129 @@ 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<crypto::key_image>& kil);
|
||||
bool validate_inputs_sorting(const transaction& tx);
|
||||
bool is_asset_emitting_transaction(const transaction& tx, asset_descriptor_operation* p_ado = nullptr);
|
||||
|
||||
std::vector<tx_source_entry::output_entry> prepare_outputs_entries_for_key_offsets(const std::vector<tx_source_entry::output_entry>& 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;
|
||||
}
|
||||
|
||||
// per output data
|
||||
std::vector<crypto::point_t> asset_ids;
|
||||
std::vector<crypto::point_t> blinded_asset_ids; // generate_zc_outs_range_proof
|
||||
std::vector<crypto::point_t> 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<crypto::point_t> 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<crypto::point_t> real_zc_ins_asset_ids; // H_i // generate_asset_surjection_proof
|
||||
std::vector<uint64_t> 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;
|
||||
|
||||
// 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)
|
||||
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<crypto::scalar_t>&)(asset_id_blinding_masks))
|
||||
FIELD((std::vector<crypto::scalar_t>&)(amounts))
|
||||
FIELD((std::vector<crypto::scalar_t>&)(amount_blinding_masks))
|
||||
FIELD(pseudo_outs_blinded_asset_ids)
|
||||
FIELD((std::vector<crypto::scalar_t>&)(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
|
||||
END_SERIALIZE()
|
||||
}; // struct tx_generation_context
|
||||
|
||||
bool validate_tx_output_details_againt_tx_generation_context(const transaction& tx, const tx_generation_context& gen_context, const crypto::secret_key& onet_time_key);
|
||||
std::string transform_tx_to_str(const transaction& tx);
|
||||
transaction transform_str_to_tx(const std::string& tx_str);
|
||||
|
||||
|
||||
|
||||
} // namespace currency
|
||||
|
|
|
|||
|
|
@ -179,7 +179,7 @@ namespace currency {
|
|||
return res.convert_to<wide_difficulty_type>();
|
||||
}
|
||||
|
||||
wide_difficulty_type next_difficulty_1(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
wide_difficulty_type next_difficulty_1(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& 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<uint64_t>& timestamps, vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds)
|
||||
wide_difficulty_type next_difficulty_2(vector<uint64_t>& timestamps, vector<wide_difficulty_type>& 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");
|
||||
|
||||
|
|
|
|||
|
|
@ -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<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
wide_difficulty_type next_difficulty_2(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds);
|
||||
wide_difficulty_type next_difficulty_1(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& cumulative_difficulties, size_t target_seconds, const wide_difficulty_type& difficulty_starter);
|
||||
wide_difficulty_type next_difficulty_2(std::vector<std::uint64_t>& timestamps, std::vector<wide_difficulty_type>& 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);
|
||||
}
|
||||
|
|
|
|||