diff --git a/.gitmodules b/.gitmodules
index e68cde5e..191af28d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -5,3 +5,7 @@
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
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index f21fb093..99243a7d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,18 +56,23 @@ if(APPLE)
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")
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(DISABLE_TOR)
+ message("NOTICE: Building with disabled TOR support!")
+ add_definitions(-DDISABLE_TOR)
+endif()
set(STATIC ${MSVC} CACHE BOOL "Link libraries statically")
@@ -197,7 +202,7 @@ 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")
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()
diff --git a/README.md b/README.md
index 189c88cf..c6ad2f56 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,8 @@ Be sure to clone the repository properly:\
| [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 |
+| [Boost](https://www.boost.org/users/download/) | 1.70 | 1.70 | 1.76 |
+| [OpenSSL](https://www.openssl.org/source/) [(win)](https://slproweb.com/products/Win32OpenSSL.html) | - | 1.1.1n | 1.1.1n |
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 |
Note:\
@@ -35,18 +36,18 @@ Recommended OS version: Ubuntu 18.04 LTS.
[*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++ python-dev 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
- 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
+ curl -OL https://boostorg.jfrog.io/artifactory/main/release/1.70.0/source/boost_1_70_0.tar.bz2
+ tar -xjf boost_1_70_0.tar.bz2
+ cd boost_1_70_0
+ ./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer,log
./b2
3. Install Qt\
@@ -54,28 +55,44 @@ Recommended OS version: Ubuntu 18.04 LTS.
[*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\
+
+4. Install OpenSSL
+
+ We recommend installing OpenSSL v1.1.1n locally unless you would like to use the same version system-wide.
+
+ curl -OL https://www.openssl.org/source/openssl-1.1.1n.tar.gz
+ tar xaf openssl-1.1.1n.tar.gz
+ cd openssl-1.1.1n/
+ ./config --prefix=/home/user/openssl --openssldir=/home/user/openssl shared zlib
+ make
+ make test
+ make install
+
+
+5. Set environment variables properly\
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:
+6. Build the binaries
+ 1. Build daemon and simplewallet:
cd zano/ && make -j1
or
@@ -88,7 +105,7 @@ For instance, by adding the following lines to `~/.bashrc`
**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
@@ -99,9 +116,9 @@ For instance, by adding the following lines to `~/.bashrc`
### Windows
Recommended OS version: Windows 7 x64.
-1. Install required prerequisites (Boost, Qt, CMake).
+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 +132,7 @@ In order to correctly deploy Qt GUI application, you also need to do the followi
### 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`
`cd build`
`cmake ..`
`make`
diff --git a/contrib/CMakeLists.txt b/contrib/CMakeLists.txt
index 779876a1..601672d5 100644
--- a/contrib/CMakeLists.txt
+++ b/contrib/CMakeLists.txt
@@ -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)
diff --git a/contrib/db/libmdbx/src/elements/version.c.in b/contrib/db/libmdbx/src/elements/version.c.in
index 2854bd5d..356b1857 100644
--- a/contrib/db/libmdbx/src/elements/version.c.in
+++ b/contrib/db/libmdbx/src/elements/version.c.in
@@ -3,10 +3,10 @@
#include "internals.h"
-#if MDBX_VERSION_MAJOR != ${MDBX_VERSION_MAJOR} || \
- MDBX_VERSION_MINOR != ${MDBX_VERSION_MINOR}
-#error "API version mismatch! Had `git fetch --tags` done?"
-#endif
+//#if MDBX_VERSION_MAJOR != ${MDBX_VERSION_MAJOR} || \
+// MDBX_VERSION_MINOR != ${MDBX_VERSION_MINOR}
+//#error "API version mismatch! Had `git fetch --tags` done?"
+//#endif
static const char sourcery[] = STRINGIFY(MDBX_BUILD_SOURCERY);
diff --git a/contrib/epee/include/misc_language.h b/contrib/epee/include/misc_language.h
index 276dfe02..1389ba03 100644
--- a/contrib/epee/include/misc_language.h
+++ b/contrib/epee/include/misc_language.h
@@ -31,6 +31,8 @@
#include
#include
#include
+#include
+#include
#include
#include "include_base_utils.h"
#include "auto_val_init.h"
@@ -111,17 +113,6 @@ namespace misc_utils
return (std::numeric_limits::max)();
}
- // TEMPLATE STRUCT less
- template
- 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
bool is_less_as_pod(const _Ty& _Left, const _Ty& _Right)
{ // apply operator< to operands
diff --git a/contrib/epee/include/net/abstract_tcp_server2.inl b/contrib/epee/include/net/abstract_tcp_server2.inl
index 2bb45f69..6829b645 100644
--- a/contrib/epee/include/net/abstract_tcp_server2.inl
+++ b/contrib/epee/include/net/abstract_tcp_server2.inl
@@ -693,7 +693,7 @@ bool boosted_tcp_server::connect(const std::string& adr, con
shared_context->cond.notify_one();
};
- sock_.async_connect(remote_endpoint, boost::bind(connect_callback, _1, local_shared_context));
+ sock_.async_connect(remote_endpoint, boost::bind(connect_callback, boost::placeholders::_1, local_shared_context));
while(local_shared_context->ec == boost::asio::error::would_block) {
bool r = false;
try {
diff --git a/contrib/epee/include/net/http_client.h b/contrib/epee/include/net/http_client.h
index be81ba41..c0b57596 100644
--- a/contrib/epee/include/net/http_client.h
+++ b/contrib/epee/include/net/http_client.h
@@ -831,7 +831,7 @@ using namespace std;
return false;
}else
{ //Apparently there are no signs of the form of transfer, will receive data until the connection is closed
- m_state = reciev_machine_state_error;
+ m_state = reciev_machine_state_body_connection_close;
LOG_PRINT("Undefinded transfer type, consider http_body_transfer_connection_close method. header: " << m_header_cache, LOG_LEVEL_2);
return false;
}
diff --git a/contrib/epee/include/net/levin_client.h b/contrib/epee/include/net/levin_client.h
index 335f6ba0..cc656e9d 100644
--- a/contrib/epee/include/net/levin_client.h
+++ b/contrib/epee/include/net/levin_client.h
@@ -46,11 +46,12 @@ namespace levin
/************************************************************************/
/* */
/************************************************************************/
- class levin_client_impl
+ template
+ 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
+ class levin_client_impl2: public levin_client_impl_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 levin_client;
+ typedef levin::levin_client_impl2 levin_client2;
}
}
diff --git a/contrib/epee/include/net/levin_client.inl b/contrib/epee/include/net/levin_client.inl
index 6f7c473e..62089afa 100644
--- a/contrib/epee/include/net/levin_client.inl
+++ b/contrib/epee/include/net/levin_client.inl
@@ -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(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
+ bool levin_client_impl_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
+ bool levin_client_impl_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(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
+ bool levin_client_impl_t::is_connected()
+ {
+ return m_transport.is_connected();
+ }
+ //------------------------------------------------------------------------------
+ template
+ bool levin_client_impl_t::disconnect()
+ {
+ return m_transport.disconnect();
+ }
+ //------------------------------------------------------------------------------
+ template
+ levin_client_impl_t::levin_client_impl_t()
+ {
+ }
+ //------------------------------------------------------------------------------
+ template
+ levin_client_impl_t::~levin_client_impl_t()
+ {
+ disconnect();
+ }
+ //------------------------------------------------------------------------------
+ template
+ int levin_client_impl_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
+ int levin_client_impl_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
+ int levin_client_impl2::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(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(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
+ int levin_client_impl2::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;
-}
-
-}
}
//------------------------------------------------------------------------------
\ No newline at end of file
diff --git a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
index 01f9e257..d33d5ad1 100644
--- a/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
+++ b/contrib/epee/include/serialization/keyvalue_serialization_overloads.h
@@ -27,6 +27,7 @@
#pragma once
#include
+#include
#include
namespace epee
diff --git a/contrib/epee/include/storages/levin_abstract_invoke2.h b/contrib/epee/include/storages/levin_abstract_invoke2.h
index 1b2c74a4..4c1c5569 100644
--- a/contrib/epee/include/storages/levin_abstract_invoke2.h
+++ b/contrib/epee/include/storages/levin_abstract_invoke2.h
@@ -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(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(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(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter(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(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter(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(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
+ {handled=true;return epee::net_utils::buff_to_t_adapter(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);}
#define CHAIN_INVOKE_MAP2(func) \
diff --git a/contrib/tor-connect b/contrib/tor-connect
new file mode 160000
index 00000000..aa509880
--- /dev/null
+++ b/contrib/tor-connect
@@ -0,0 +1 @@
+Subproject commit aa509880f06292ac8078046f3d49ff854e400716
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a044fab8..da31da22 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -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)
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,7 +162,7 @@ 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})
ENABLE_SHARED_PCH(daemon DAEMON)
ENABLE_SHARED_PCH_EXECUTABLE(daemon)
@@ -170,8 +173,9 @@ ENABLE_SHARED_PCH(connectivity_tool CONN_TOOL)
ENABLE_SHARED_PCH_EXECUTABLE(connectivity_tool)
add_executable(simplewallet ${SIMPLEWALLET})
-add_dependencies(simplewallet version)
+add_dependencies(simplewallet version)
target_link_libraries(simplewallet wallet rpc currency_core crypto common zlibstatic ethash ${CMAKE_THREAD_LIBS_INIT} ${Boost_LIBRARIES})
+
ENABLE_SHARED_PCH(simplewallet SIMPLEWALLET)
ENABLE_SHARED_PCH_EXECUTABLE(simplewallet)
diff --git a/src/common/command_line.cpp b/src/common/command_line.cpp
index 6595763f..0474f9cd 100644
--- a/src/common/command_line.cpp
+++ b/src/common/command_line.cpp
@@ -10,36 +10,36 @@
namespace command_line
{
- const arg_descriptor arg_help = {"help", "Produce help message"};
- const arg_descriptor arg_version = {"version", "Output version information"};
- const arg_descriptor arg_data_dir = {"data-dir", "Specify data directory", ""};
+ const arg_descriptor arg_help ("help", "Produce help message");
+ const arg_descriptor arg_version ("version", "Output version information");
+ const arg_descriptor arg_data_dir ("data-dir", "Specify data directory", "");
- const arg_descriptor 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 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 arg_config_file = { "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") };
- const arg_descriptor arg_os_version = { "os-version", "" };
+ const arg_descriptor arg_config_file ( "config-file", "Specify configuration file", std::string(CURRENCY_NAME_SHORT ".conf") );
+ const arg_descriptor arg_os_version ( "os-version", "" );
- const arg_descriptor arg_log_dir = { "log-dir", "", "", true};
- const arg_descriptor arg_log_file = { "log-file", "", "" };
- const arg_descriptor arg_log_level = { "log-level", "", LOG_LEVEL_0, true };
+ const arg_descriptor arg_log_dir ( "log-dir", "");
+ const arg_descriptor arg_log_file ( "log-file", "", "");
+ const arg_descriptor arg_log_level ( "log-level", "");
- const arg_descriptor arg_console = { "no-console", "Disable daemon console commands" };
- const arg_descriptor arg_show_details = { "currency-details", "Display currency details" };
- const arg_descriptor arg_show_rpc_autodoc = { "show_rpc_autodoc", "Display rpc auto-generated documentation template" };
+ const arg_descriptor arg_console ( "no-console", "Disable daemon console commands" );
+ const arg_descriptor arg_show_details ( "currency-details", "Display currency details" );
+ const arg_descriptor arg_show_rpc_autodoc ( "show_rpc_autodoc", "Display rpc auto-generated documentation template" );
- const arg_descriptor arg_disable_upnp = { "disable-upnp", "Disable UPnP (enhances local network privacy)", false, true };
- const arg_descriptor 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", false, true };
+ const arg_descriptor arg_disable_upnp ( "disable-upnp", "Disable UPnP (enhances local network privacy)");
+ const arg_descriptor 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 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 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 arg_enable_offers_service = { "enable-offers-service", "Enables marketplace feature", false, false};
- const arg_descriptor arg_db_engine = { "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB, false };
+ const arg_descriptor 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 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 arg_enable_offers_service ( "enable-offers-service", "Enables marketplace feature", false);
+ const arg_descriptor arg_db_engine ( "db-engine", "Specify database engine for storage. May be \"lmdb\"(default) or \"mdbx\"", ARG_DB_ENGINE_LMDB );
- const arg_descriptor arg_no_predownload = { "no-predownload", "Do not pre-download blockchain database", };
- const arg_descriptor arg_force_predownload = { "force-predownload", "Pre-download blockchain database regardless of it's status", };
- const arg_descriptor arg_validate_predownload = { "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database", };
- const arg_descriptor arg_predownload_link = { "predownload-link", "Override url for blockchain database pre-downloading", "", true };
+ const arg_descriptor arg_no_predownload ( "no-predownload", "Do not pre-download blockchain database");
+ const arg_descriptor arg_force_predownload ( "force-predownload", "Pre-download blockchain database regardless of it's status");
+ const arg_descriptor arg_validate_predownload ( "validate-predownload", "Paranoid mode, re-validate each block from pre-downloaded database and rebuild own database");
+ const arg_descriptor arg_predownload_link ( "predownload-link", "Override url for blockchain database pre-downloading");
- const arg_descriptor arg_deeplink = { "deeplink-params", "Deeplink parameter, in that case app just forward params to running app", "", true };
+ const arg_descriptor arg_deeplink ( "deeplink-params", "Deeplink parameter, in that case app just forward params to running app");
}
diff --git a/src/common/command_line.h b/src/common/command_line.h
index 652d1777..2c147d20 100644
--- a/src/common/command_line.h
+++ b/src/common/command_line.h
@@ -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
struct arg_descriptor, false>
{
+ arg_descriptor(const char* _name, const char* _description) :
+ name(_name),
+ description(_description)
+ {}
+
typedef std::vector value_type;
const char* name;
@@ -79,7 +85,7 @@ namespace command_line
boost::program_options::typed_value* make_semantic(const arg_descriptor& arg)
{
auto semantic = boost::program_options::value();
- 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* make_semantic(const arg_descriptor& arg, const T& def)
{
auto semantic = boost::program_options::value();
- if (!arg.not_use_default)
+ if (arg.use_default)
semantic->default_value(def);
return semantic;
}
diff --git a/src/common/ntp.cpp b/src/common/ntp.cpp
index fdbc2a5b..db55610a 100644
--- a/src/common/ntp.cpp
+++ b/src/common/ntp.cpp
@@ -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;
diff --git a/src/common/pre_download.h b/src/common/pre_download.h
index b6d4a74d..3a3e8666 100644
--- a/src/common/pre_download.h
+++ b/src/common/pre_download.h
@@ -21,8 +21,8 @@ namespace tools
};
#ifndef TESTNET
- static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_1480000.pak", "2b664de02450cc0082efb6c75824d33ffe694b9b17b21fc7966bcb9be9ac31f7", 1570460883, 3221176320 };
- static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_1480000.pak", "67770faa7db22dfe97982611d7471ba5673145589e81e02ed99832644ae328f6", 2042582638, 2968252416 };
+ static constexpr pre_download_entry c_pre_download_mdbx = { "http://95.217.42.247/pre-download/zano_mdbx_95_1569000.pak", "c2aff6fb65c2d7a40492738c75d1d04f2f35388d3c1a664aeb77420f2d90d644", 1740147926, 3221176320 };
+ static constexpr pre_download_entry c_pre_download_lmdb = { "http://95.217.42.247/pre-download/zano_lmdb_95_1569000.pak", "f673636638b666b36c976168a3c64b2fd1fcf071c41b5d9cf01ed58a5924f80a", 2244905636, 3216977920 };
#else
static constexpr pre_download_entry c_pre_download_mdbx = { "", "", 0, 0 };
static constexpr pre_download_entry c_pre_download_lmdb = { "", "", 0, 0 };
diff --git a/src/common/threads_pool.h b/src/common/threads_pool.h
index 4e4e3905..461e8843 100644
--- a/src/common/threads_pool.h
+++ b/src/common/threads_pool.h
@@ -51,11 +51,11 @@ namespace utils
int num_threads = std::thread::hardware_concurrency();
this->init(num_threads);
}
- void init(unsigned int num_threads)
+ void init(size_t num_threads)
{
m_is_stop = false;
- for (int i = 0; i < num_threads; i++)
+ for (size_t i = 0; i < num_threads; i++)
{
m_threads.push_back(std::thread([this]() {this->worker_func(); }));
}
@@ -81,7 +81,7 @@ namespace utils
std::mutex batch_mutex;
- std::atomic cnt = 0;
+ std::atomic cnt(0);
for (const auto& jb : cntr)
{
call_executor_base* pjob = jb.get();
diff --git a/src/common/tor_helper.h b/src/common/tor_helper.h
new file mode 100644
index 00000000..48cabba1
--- /dev/null
+++ b/src/common/tor_helper.h
@@ -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 levin_over_tor_client;
+
+}
+
+
diff --git a/src/connectivity_tool/conn_tool.cpp b/src/connectivity_tool/conn_tool.cpp
index d1f2115b..1ee022b3 100644
--- a/src/connectivity_tool/conn_tool.cpp
+++ b/src/connectivity_tool/conn_tool.cpp
@@ -38,32 +38,32 @@ using namespace nodetool;
namespace
{
- const command_line::arg_descriptor arg_ip = {"ip", "set ip", "127.0.0.1", false};
- const command_line::arg_descriptor arg_port = {"port", "set port"};
- const command_line::arg_descriptor arg_rpc_port = {"rpc-port", "set rpc port", RPC_DEFAULT_PORT, false};
- const command_line::arg_descriptor arg_timeout = {"timeout", "set timeout", 5000, false};
- const command_line::arg_descriptor arg_priv_key = {"private-key", "private key to subscribe debug command", "", true};
- const command_line::arg_descriptor arg_peer_id = {"peer-id", "peerid if known(if not - will be requested)", 0};
- const command_line::arg_descriptor arg_generate_keys = {"generate-keys-pair", "generate private and public keys pair"};
- const command_line::arg_descriptor arg_request_stat_info = {"request-stat-info", "request statistics information"};
- const command_line::arg_descriptor arg_log_journal_len = { "log-journal-len", "Specify length of list of last error messages in log", 0, true };
- const command_line::arg_descriptor arg_request_net_state = {"request-net-state", "request network state information (peer list, connections count)"};
- const command_line::arg_descriptor 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 arg_get_aliases = {"rpc-get-aliases", "request daemon aliases all list", "", true};
- const command_line::arg_descriptor arg_increment_build_no = { "increment-build-no", "Increment build nimber", "", true };
- const command_line::arg_descriptor 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 arg_update_build_no = {"update-build-no", "Updated version number in version template file", "", true};
- const command_line::arg_descriptor arg_generate_genesis = {"generate-genesis", "Generate genesis coinbase based on config file", "", true };
- const command_line::arg_descriptor arg_genesis_split_amount = { "genesis-split-amount", "Set split amount for generating genesis block", 0, true };
- const command_line::arg_descriptor arg_get_info_flags = { "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "", true };
- const command_line::arg_descriptor arg_set_peer_log_level = { "set-peer-log-level", "Set log level for remote peer", 0, true };
- const command_line::arg_descriptor arg_download_peer_log = { "download-peer-log", "Download log from remote peer [,]", "", true };
- const command_line::arg_descriptor arg_do_consloe_log = { "do-console-log", "Tool generates debug console output(debug purposes)", "", true };
- const command_line::arg_descriptor arg_generate_integrated_address = { "generate-integrated-address", "Tool create integrated address from simple address and payment_id", "", true };
- const command_line::arg_descriptor arg_pack_file = {"pack-file", "perform gzip-packing and calculate hash for a given file", "", true };
- const command_line::arg_descriptor arg_unpack_file = {"unpack-file", "Perform gzip-unpacking and calculate hash for a given file", "", true };
- const command_line::arg_descriptor arg_target_file = {"target-file", "Specify target file for pack-file and unpack-file commands", "", true };
- //const command_line::arg_descriptor arg_send_ipc = {"send-ipc", "Send IPC request to UI", "", true };
+ const command_line::arg_descriptor arg_ip ("ip", "set ip", "127.0.0.1");
+ const command_line::arg_descriptor arg_port ("port", "set port");
+ const command_line::arg_descriptor arg_rpc_port ("rpc-port", "set rpc port", RPC_DEFAULT_PORT);
+ const command_line::arg_descriptor arg_timeout ("timeout", "set timeout", 5000);
+ const command_line::arg_descriptor arg_priv_key ("private-key", "private key to subscribe debug command");
+ const command_line::arg_descriptor arg_peer_id ("peer-id", "peerid if known(if not - will be requested)", 0);
+ const command_line::arg_descriptor arg_generate_keys ("generate-keys-pair", "generate private and public keys pair");
+ const command_line::arg_descriptor arg_request_stat_info ("request-stat-info", "request statistics information");
+ const command_line::arg_descriptor arg_log_journal_len ( "log-journal-len", "Specify length of list of last error messages in log");
+ const command_line::arg_descriptor arg_request_net_state ("request-net-state", "request network state information (peer list, connections count)");
+ const command_line::arg_descriptor 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 arg_get_aliases ("rpc-get-aliases", "request daemon aliases all list");
+ const command_line::arg_descriptor arg_increment_build_no ( "increment-build-no", "Increment build nimber");
+ const command_line::arg_descriptor 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 arg_update_build_no ("update-build-no", "Updated version number in version template file");
+ const command_line::arg_descriptor arg_generate_genesis ("generate-genesis", "Generate genesis coinbase based on config file");
+ const command_line::arg_descriptor arg_genesis_split_amount ( "genesis-split-amount", "Set split amount for generating genesis block");
+ const command_line::arg_descriptor arg_get_info_flags ( "getinfo-flags-hex", "Set of bits for rpc-get-daemon-info", "");
+ const command_line::arg_descriptor arg_set_peer_log_level ( "set-peer-log-level", "Set log level for remote peer");
+ const command_line::arg_descriptor arg_download_peer_log ( "download-peer-log", "Download log from remote peer [,]");
+ const command_line::arg_descriptor arg_do_consloe_log ( "do-console-log", "Tool generates debug console output(debug purposes)");
+ const command_line::arg_descriptor arg_generate_integrated_address ( "generate-integrated-address", "Tool create integrated address from simple address and payment_id");
+ const command_line::arg_descriptor arg_pack_file ("pack-file", "perform gzip-packing and calculate hash for a given file");
+ const command_line::arg_descriptor arg_unpack_file ("unpack-file", "Perform gzip-unpacking and calculate hash for a given file");
+ const command_line::arg_descriptor arg_target_file ("target-file", "Specify target file for pack-file and unpack-file commands");
+ //const command_line::arg_descriptor arg_send_ipc ("send-ipc", "Send IPC request to UI");
}
typedef COMMAND_REQUEST_STAT_INFO_T::stat_info> COMMAND_REQUEST_STAT_INFO;
@@ -640,7 +640,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(command_line::get_arg(vm, arg_port)), static_cast(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;
@@ -878,7 +878,7 @@ bool generate_and_print_keys()
}
//---------------------------------------------------------------------------------------------------------------
template
-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())
{
@@ -933,7 +933,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);
@@ -982,7 +982,7 @@ bool handle_download_peer_log(po::variables_map& vm)
}
uint64_t start_offset = static_cast(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);
diff --git a/src/crypto/crypto-sugar.cpp b/src/crypto/crypto-sugar.cpp
index 4774e9b7..8b8779ae 100644
--- a/src/crypto/crypto-sugar.cpp
+++ b/src/crypto/crypto-sugar.cpp
@@ -21,6 +21,7 @@ namespace crypto
const scalar_t c_scalar_1div8 = { 0x6106e529e2dc2f79, 0x07d39db37d1cdad0, 0x0, 0x0600000000000000 };
const point_t c_point_H = { 0x05087c1f5b9b32d6, 0x00547595f445c3b5, 0x764df64578552f2a, 0x8a49a651e0e0da45 }; // == Hp(G), this is being checked in bpp_basics
+ const point_t c_point_H2 = { 0x70c8d1ab9dbf1cc0, 0xc561bb12639a8516, 0x3cfff1def9e5b268, 0xe0936386f3bcce1a }; // == Hp("h2_generator"), cheched in bpp_basics
const point_t c_point_0 = point_t(point_t::tag_zero());
} // namespace crypto
diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h
index 5542b9fb..a2681642 100644
--- a/src/crypto/crypto-sugar.h
+++ b/src/crypto/crypto-sugar.h
@@ -431,6 +431,31 @@ 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));
+ }
+
+ static scalar_t power_of_2(uint8_t exponent)
+ {
+ scalar_t result = 0;
+ result.set_bit(exponent);
+ return result;
+ }
+
}; // struct scalar_t
//
@@ -890,6 +915,7 @@ namespace crypto
extern const point_g_t c_point_G;
extern const point_t c_point_H;
+ extern const point_t c_point_H2;
extern const point_t c_point_0;
//
@@ -1063,6 +1089,21 @@ 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;
+ }
+
}; // hash_helper_t struct
diff --git a/src/crypto/range_proof_bpp.h b/src/crypto/range_proof_bpp.h
new file mode 100644
index 00000000..cd61ca85
--- /dev/null
+++ b/src/crypto/range_proof_bpp.h
@@ -0,0 +1,699 @@
+// 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 L; // size = ceil( log_2(m * n) )
+ std::vector 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
+ bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& 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; }
+
+ static_assert(CT::c_bpp_n <= 255, "too big N");
+ CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size(), 1);
+ CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(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;
+
+ // pre-multiply all output points by c_scalar_1div8
+ // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
+
+ // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H
+ commitments.resize(values.size());
+ for (size_t i = 0; i < values.size(); ++i)
+ CT::calc_pedersen_commitment(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]);
+
+
+ // 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 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);
+
+ // 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 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 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;
+ // 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 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 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 = -- 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 = * 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()
+
+
+ struct bpp_sig_commit_ref_t
+ {
+ bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector& commitments)
+ : sig(sig)
+ , commitments(commitments)
+ {}
+ const bpp_signature& sig;
+ const std::vector& commitments;
+ };
+
+
+ template
+ bool bpp_verify(const std::vector& sigs, uint8_t* p_err = nullptr)
+ {
+#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
+ if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
+ if (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 L;
+ std::vector R;
+ };
+ std::vector 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 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<
+
+ // (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 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 = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents);
+ if (result)
+ DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
+ return result;
+#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
+ }
+
+} // namespace crypto
diff --git a/src/crypto/range_proof_bppe.h b/src/crypto/range_proof_bppe.h
new file mode 100644
index 00000000..7aaed80c
--- /dev/null
+++ b/src/crypto/range_proof_bppe.h
@@ -0,0 +1,719 @@
+// 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 L; // size = log_2(m * n)
+ std::vector R;
+ public_key A0;
+ public_key A;
+ public_key B;
+ scalar_t r;
+ scalar_t s;
+ scalar_t delta_1;
+ scalar_t delta_2;
+ };
+
+#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
+#define DBG_PRINT(x) std::cout << x << ENDL
+
+ template
+ bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector& commitments, uint8_t* p_err = nullptr)
+ {
+#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
+ if (!(cond)) { LOG_PRINT_RED("bppe_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
+ if (p_err) { *p_err = err_code; } return false; }
+
+ static_assert(CT::c_bpp_n <= 255, "too big N");
+ CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= CT::c_bpp_values_max && values.size() == masks.size() && masks.size() == masks2.size(), 1);
+ CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(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;
+
+ // pre-multiply all output points by c_scalar_1div8
+ // in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
+
+ // calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H + 1/8 * masks2[i] * H2
+ commitments.resize(values.size());
+ for (size_t i = 0; i < values.size(); ++i)
+ CT::calc_pedersen_commitment_2(values[i] * c_scalar_1div8, masks[i] * c_scalar_1div8, masks2[i] * c_scalar_1div8, commitments[i]);
+
+
+ // 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 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);
+
+ // 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 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;
+ // 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_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 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 = -- 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 = * 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;
+#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
+ } // bppe_gen()
+
+
+ struct bppe_sig_commit_ref_t
+ {
+ bppe_sig_commit_ref_t(const bppe_signature& sig, const std::vector& commitments)
+ : sig(sig)
+ , commitments(commitments)
+ {}
+ const bppe_signature& sig;
+ const std::vector& commitments;
+ };
+
+
+ template
+ bool bppe_verify(const std::vector& sigs, uint8_t* p_err = nullptr)
+ {
+#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
+ if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
+ if (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 L;
+ std::vector R;
+ };
+ std::vector 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 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<
+
+ // (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 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 = multiexp_and_check_being_zero(g_scalars, h_scalars, summand + GH_exponents);
+ if (result)
+ DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL);
+ return result;
+#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
+ }
+
+} // namespace crypto
diff --git a/src/crypto/range_proofs.cpp b/src/crypto/range_proofs.cpp
index b6750a09..783a0c2b 100644
--- a/src/crypto/range_proofs.cpp
+++ b/src/crypto/range_proofs.cpp
@@ -6,7 +6,4 @@
namespace crypto
{
- const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H;
-
-
}
diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h
index b3d04d68..bcd03393 100644
--- a/src/crypto/range_proofs.h
+++ b/src/crypto/range_proofs.h
@@ -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-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.pdf
-//
-
#include "epee/include/misc_log_ex.h"
#include "crypto-sugar.h"
@@ -28,27 +23,23 @@ 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 greatest k, s.t. 2**k <= v
+ // tests in crypto_tests_range_proofs.h
+ constexpr size_t constexpr_floor_log2(size_t v)
+ {
+ return v <= 1 ? 0 : constexpr_floor_log2(v >> 1) + 1;
+ }
// returns smallest k, s.t. v <= 2**k
- inline size_t calc_exp_power_of_2_upper_bound(size_t v)
+ // tests in crypto_tests_range_proofs.h
+ constexpr size_t constexpr_ceil_log2(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;
+ return v <= 1 ? 0 : constexpr_floor_log2(v - 1) + 1;
}
+
+
// returns least significant bit uing de Bruijn sequence
// http://graphics.stanford.edu/~seander/bithacks.html
inline uint8_t calc_lsb_32(uint32_t v)
@@ -61,17 +52,28 @@ namespace crypto
return multiply_de_bruijn_bit_position[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27];
}
-
+
////////////////////////////////////////
// crypto trait for Zano
////////////////////////////////////////
+ template
struct bpp_crypto_trait_zano
{
+ 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;
}
+ static void calc_pedersen_commitment_2(const scalar_t& value, const scalar_t& mask1, const scalar_t& mask2, point_t& commitment)
+ {
+ commitment = value * c_point_G + mask1 * c_point_H + mask2 * c_point_H2;
+ }
+
static const scalar_t& get_initial_transcript()
{
static scalar_t value = hash_helper_t::hs("Zano BP+ initial transcript");
@@ -86,6 +88,7 @@ namespace crypto
e = hsc.calc_hash();
}
+ // TODO: refactor with proper OOB handling
static const point_t& get_generator(bool select_H, size_t index)
{
if (index >= c_bpp_mn_max)
@@ -107,333 +110,29 @@ namespace crypto
return generators[2 * index + (select_H ? 1 : 0)];
}
+ static const scalar_t& get_2_to_the_power_of_N_minus_1()
+ {
+ static scalar_t result = scalar_t::power_of_2(c_bpp_n) - 1;
+ return result;
+ }
+
static const point_t& bpp_H;
- };
+ static const point_t& bpp_H2;
+ }; // struct bpp_crypto_trait_zano
+
+ template
+ const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H;
+
+ template
+ const point_t& bpp_crypto_trait_zano::bpp_H2 = c_point_H2;
- struct bpp_signature
- {
- std::vector L; // size = log_2(m * n)
- std::vector 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
- bool bpp_gen(const std::vector& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector& 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 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)
- {
- 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;
- }
- }
-
- 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 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);
-
- // 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 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 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 = -- 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 = * 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
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");
+ 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;
@@ -452,372 +151,7 @@ namespace crypto
}
- struct bpp_sig_commit_ref_t
- {
- bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector& commitments)
- : sig(sig)
- , commitments(commitments)
- {}
- const bpp_signature& sig;
- const std::vector& commitments;
- };
-
-
- template
- bool bpp_verify(const std::vector& sigs, uint8_t* p_err = nullptr)
- {
-#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
- if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
- if (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 L;
- std::vector R;
- };
- std::vector 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 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<
-
- // (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 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(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 "range_proof_bpp.h"
+#include "range_proof_bppe.h"
diff --git a/src/currency_core/bc_offers_service.cpp b/src/currency_core/bc_offers_service.cpp
index 59064632..b6349e90 100644
--- a/src/currency_core/bc_offers_service.cpp
+++ b/src/currency_core/bc_offers_service.cpp
@@ -13,7 +13,7 @@
#include "storages/portable_storage_template_helper.h"
-command_line::arg_descriptor arg_market_disable = { "disable-market", "Start GUI with market service disabled", false, true };
+command_line::arg_descriptor arg_market_disable ( "disable-market", "Start GUI with market service disabled");
namespace bc_services
diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp
index 6bb47719..9ab636f5 100644
--- a/src/currency_core/blockchain_storage.cpp
+++ b/src/currency_core/blockchain_storage.cpp
@@ -80,8 +80,8 @@ DISABLE_VS_WARNINGS(4267)
namespace
{
- const command_line::arg_descriptor arg_db_cache_l1 = { "db-cache-l1", "Specify size of memory mapped db cache file", 0, true };
- const command_line::arg_descriptor arg_db_cache_l2 = { "db-cache-l2", "Specify cached elements in db helpers", 0, true };
+ const command_line::arg_descriptor arg_db_cache_l1 ( "db-cache-l1", "Specify size of memory mapped db cache file");
+ const command_line::arg_descriptor arg_db_cache_l2 ( "db-cache-l2", "Specify cached elements in db helpers");
}
//------------------------------------------------------------------
diff --git a/src/currency_core/currency_config.h b/src/currency_core/currency_config.h
index 29e76ab1..18e38c67 100644
--- a/src/currency_core/currency_config.h
+++ b/src/currency_core/currency_config.h
@@ -250,6 +250,8 @@
+
static_assert(CURRENCY_MINER_TX_MAX_OUTS <= CURRENCY_TX_MAX_ALLOWED_OUTS, "Miner tx must obey normal tx max outs limit");
static_assert(PREMINE_AMOUNT / WALLET_MAX_ALLOWED_OUTPUT_AMOUNT < CURRENCY_MINER_TX_MAX_OUTS, "Premine can't be divided into reasonable number of outs");
+#define CURRENCY_RELAY_TXS_MAX_COUNT 5
\ No newline at end of file
diff --git a/src/currency_core/miner.cpp b/src/currency_core/miner.cpp
index 005c274c..d52e51e2 100644
--- a/src/currency_core/miner.cpp
+++ b/src/currency_core/miner.cpp
@@ -33,10 +33,10 @@ namespace currency
namespace
{
- const command_line::arg_descriptor arg_extra_messages = {"extra-messages-file", "Specify file for extra messages to include into coinbase transactions", "", true};
- const command_line::arg_descriptor arg_start_mining = {"start-mining", "Specify wallet address to mining for", "", true};
- const command_line::arg_descriptor arg_mining_threads = {"mining-threads", "Specify mining threads count", 0, true};
- const command_line::arg_descriptor arg_block_template_extra_text = { "miner-text-info", "Set block extra text info", "", true };
+ const command_line::arg_descriptor arg_extra_messages ("extra-messages-file", "Specify file for extra messages to include into coinbase transactions");
+ const command_line::arg_descriptor arg_start_mining ("start-mining", "Specify wallet address to mining for");
+ const command_line::arg_descriptor arg_mining_threads ("mining-threads", "Specify mining threads count");
+ const command_line::arg_descriptor arg_block_template_extra_text ( "miner-text-info", "Set block extra text info");
}
diff --git a/src/currency_core/tx_pool.cpp b/src/currency_core/tx_pool.cpp
index 7a65990e..581dfdb8 100644
--- a/src/currency_core/tx_pool.cpp
+++ b/src/currency_core/tx_pool.cpp
@@ -666,7 +666,7 @@ namespace currency
bool tx_memory_pool::force_relay_pool() const
{
LOG_PRINT_GREEN("Preparing relay message...", LOG_LEVEL_0);
- NOTIFY_NEW_TRANSACTIONS::request r = AUTO_VAL_INIT(r);
+ NOTIFY_OR_INVOKE_NEW_TRANSACTIONS::request r = AUTO_VAL_INIT(r);
m_db_transactions.enumerate_items([&](uint64_t i, const crypto::hash& k, const tx_details& v)
{
diff --git a/src/currency_protocol/currency_protocol_defs.h b/src/currency_protocol/currency_protocol_defs.h
index 48f09e21..2a0eead6 100644
--- a/src/currency_protocol/currency_protocol_defs.h
+++ b/src/currency_protocol/currency_protocol_defs.h
@@ -71,7 +71,7 @@ namespace currency
/************************************************************************/
/* */
/************************************************************************/
- struct NOTIFY_NEW_TRANSACTIONS
+ struct NOTIFY_OR_INVOKE_NEW_TRANSACTIONS
{
const static int ID = BC_COMMANDS_POOL_BASE + 2;
@@ -83,6 +83,16 @@ namespace currency
KV_SERIALIZE(txs)
END_KV_SERIALIZE_MAP()
};
+
+ struct response
+ {
+ std::string code;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(code)
+ END_KV_SERIALIZE_MAP()
+ };
+
};
/************************************************************************/
/* */
diff --git a/src/currency_protocol/currency_protocol_handler.h b/src/currency_protocol/currency_protocol_handler.h
index cae17241..1e420919 100644
--- a/src/currency_protocol/currency_protocol_handler.h
+++ b/src/currency_protocol/currency_protocol_handler.h
@@ -35,14 +35,15 @@ namespace currency
typedef core_stat_info stat_info;
typedef t_currency_protocol_handler currency_protocol_handler;
typedef CORE_SYNC_DATA payload_type;
- typedef std::pair relay_que_entry;
+ typedef std::pair