forked from lthn/blockchain
Merge branch 'develop' into release
This commit is contained in:
commit
1d101ac984
30 changed files with 1257 additions and 97 deletions
84
README.md
84
README.md
|
|
@ -1,61 +1,79 @@
|
|||
[](https://scan.coverity.com/projects/zanoproject)
|
||||
[](https://discord.gg/wE3rmYY)
|
||||
|
||||
Building
|
||||
## Cloning
|
||||
|
||||
Be sure to clone the repository properly:\
|
||||
`$ git clone --recursive https://github.com/hyle-team/zano.git`
|
||||
|
||||
# Building
|
||||
--------
|
||||
|
||||
### Cloning
|
||||
|
||||
Be sure to properly clone the repository:
|
||||
|
||||
`$ git clone --recursive https://github.com/hyle-team/zano.git`
|
||||
|
||||
### Dependencies
|
||||
| component / version | minimum <br>(not recommended but may work) | recommended | most recent of what we have ever tested |
|
||||
|--|--|--|--|
|
||||
| gcc (Linux) | 5.4.0 | 7.2.0 | 8.3.0 |
|
||||
| gcc (Linux) | 5.4.0 | 7.4.0 | 8.3.0 |
|
||||
| llvm/clang (Linux) | UNKNOWN | 7.0.1 | 8.0.0 |
|
||||
| [MSVC](https://visualstudio.microsoft.com/downloads/) (Windows) | 2015 (14.0 update 1) | 2017 (15.5.7) | 2019 |
|
||||
| [XCode](https://developer.apple.com/downloads/) (macOS) | 7.3.1 | 9.2 | 9.2 |
|
||||
| [CMake](https://cmake.org/download/) | 2.8.6 | 3.15.5 | 3.15.5 |
|
||||
| [Boost](https://www.boost.org/users/download/) | 1.56 | 1.68 | 1.68 |
|
||||
| [Qt](https://download.qt.io/archive/qt/) (only for GUI) | 5.8.0 | 5.11.2 | 5.13.2 |
|
||||
| [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 |
|
||||
| [Qt](https://download.qt.io/archive/qt/) (*only for GUI*) | 5.8.0 | 5.11.2 | 5.15.2 |
|
||||
|
||||
Note:\
|
||||
[*server version*] denotes steps required for building command-line tools (daemon, simplewallet, etc.).\
|
||||
[*GUI version*] denotes steps required for building Zano executable with GUI.
|
||||
|
||||
<br />
|
||||
|
||||
### Linux
|
||||
|
||||
Recommended OS version: Ubuntu 18.04 LTS.
|
||||
|
||||
1. Prerequisites
|
||||
1. Prerequisites for server version:
|
||||
|
||||
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen
|
||||
|
||||
1. Prerequisites for 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`
|
||||
[*server version*]
|
||||
|
||||
sudo apt-get install -y build-essential g++ python-dev autotools-dev libicu-dev libbz2-dev cmake git screen
|
||||
|
||||
[*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
|
||||
|
||||
2. Download and build Boost
|
||||
|
||||
wget https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.bz2
|
||||
wget https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2
|
||||
tar -xjf boost_1_68_0.tar.bz2
|
||||
cd boost_1_68_0
|
||||
./bootstrap.sh --with-libraries=system,filesystem,thread,date_time,chrono,regex,serialization,atomic,program_options,locale,timer
|
||||
./b2
|
||||
|
||||
3. Install Qt
|
||||
3. Install Qt\
|
||||
(*GUI version only, skip this step if you're building server version*)
|
||||
|
||||
[*GUI version*]
|
||||
|
||||
wget https://download.qt.io/new_archive/qt/5.11/5.11.2/qt-opensource-linux-x64-5.11.2.run
|
||||
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 WebEngine module!
|
||||
Then follow the instructions in Wizard. Don't forget to tick the WebEngine module checkbox!
|
||||
|
||||
4. Set environment variables properly\
|
||||
For instance, by adding the following lines to `~/.bashrc`
|
||||
|
||||
[*server version*]
|
||||
|
||||
export BOOST_ROOT=/home/user/boost_1_68_0
|
||||
|
||||
|
||||
[*GUI version*]
|
||||
|
||||
4. Set `BOOST_ROOT` and `QT_PREFIX_PATH` envinorment variables\
|
||||
For instance, by adding these lines to `~/.bashrc`:
|
||||
|
||||
export BOOST_ROOT=/home/user/boost_1_68_0
|
||||
export QT_PREFIX_PATH=/home/user/Qt5.11.2/5.11.2/gcc_64
|
||||
|
||||
|
||||
|
||||
5. Building binaries
|
||||
1. Building daemon and simplewallet:
|
||||
|
||||
|
|
@ -66,7 +84,9 @@ Recommended OS version: Ubuntu 18.04 LTS.
|
|||
cmake ..
|
||||
make -j1 daemon simplewallet
|
||||
|
||||
**NOTICE**: If you are building on machine with relatively high anount of RAM or with proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution.
|
||||
**NOTICE**: If you are building on a machine with a relatively high amount of RAM or with the proper setting of virtual memory, then you can use `-j2` or `-j` option to speed up the building process. Use with caution.
|
||||
|
||||
**NOTICE 2**: If you'd like to build binaries for the testnet, use `cmake -D TESTNET=TRUE ..` instead of `cmake ..` .
|
||||
|
||||
1. Building GUI:
|
||||
|
||||
|
|
@ -75,6 +95,8 @@ Recommended OS version: Ubuntu 18.04 LTS.
|
|||
|
||||
7. Look for the binaries in `build` folder
|
||||
|
||||
<br />
|
||||
|
||||
### Windows
|
||||
Recommended OS version: Windows 7 x64.
|
||||
1. Install required prerequisites (Boost, Qt, CMake).
|
||||
|
|
@ -83,13 +105,17 @@ Recommended OS version: Windows 7 x64.
|
|||
4. Go to the build folder and open generated Zano.sln in MSVC.
|
||||
5. Build.
|
||||
|
||||
In order to correctly deploy Qt GUI application you also need to do the following:
|
||||
In order to correctly deploy Qt GUI application, you also need to do the following:
|
||||
|
||||
6. Copy Zano.exe to a folder (e.g. `depoy`).
|
||||
7. Run `PATH_TO_QT\bin\windeployqt.exe deploy/Zano.exe`.
|
||||
7. Run `PATH_TO_QT\bin\windeployqt.exe deploy\Zano.exe`.
|
||||
8. Copy folder `\src\gui\qt-daemon\html` to `deploy\html`.
|
||||
9. Now you can run `Zano.exe`
|
||||
|
||||
<br />
|
||||
|
||||
### macOS
|
||||
Recommended OS version: macOS Sierra 10.12.6 x64.
|
||||
Recommended OS version: macOS Sierra 10.15.4 x64.
|
||||
1. Install required prerequisites.
|
||||
2. Set environment variables as stated in `utils/macosx_build_config.command`.
|
||||
3. `mkdir build` <br> `cd build` <br> `cmake ..` <br> `make`
|
||||
|
|
@ -104,7 +130,7 @@ To build GUI application:
|
|||
e. Press “Create”, then “Done”.\
|
||||
f. Make sure the certificate was added to keychain "System". If not—move it to "System".\
|
||||
g. Double click the certificate you've just added, enter the trust section and under "When using this certificate" select "Always trust".\
|
||||
h. Unfold the certificate in Keychain Access window and double click underlying private key "Zano". Select "Access Control" tab, then select "Allow all applications to access this item". Click "Save Changes".
|
||||
h. Unfold the certificate in Keychain Access window and double click the underlying private key "Zano". Select "Access Control" tab, then select "Allow all applications to access this item". Click "Save Changes".
|
||||
2. Revise building script, comment out unwanted steps and run it: `utils/build_script_mac_osx.sh`
|
||||
3. The application should be here: `/buid_mac_osx_64/release/src`
|
||||
|
||||
|
|
|
|||
|
|
@ -340,7 +340,7 @@ namespace eos {
|
|||
// we choose to use little endian because this way we just
|
||||
// save the first size bytes to the stream and skip the rest
|
||||
#if BOOST_VERSION >= 106900
|
||||
temp = endian::native_to_little(temp);
|
||||
temp = endian::native_to_little(t);
|
||||
#else
|
||||
endian::store_little_endian<T, sizeof(T)>(&temp, t);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ namespace epee
|
|||
}
|
||||
|
||||
|
||||
#define STD_TRY_CATCH_LOCATION(return_val) STD_TRY_CATCH(LOCATION_SS, return_val)
|
||||
|
||||
/* helper class, to make able get namespace via decltype()::*/
|
||||
template<class base_class>
|
||||
class namespace_accessor: public base_class{};
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/mpl/vector.hpp>
|
||||
#include <deque>
|
||||
|
||||
namespace epee
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/mpl/contains.hpp>
|
||||
#include "misc_language.h"
|
||||
#include "portable_storage_base.h"
|
||||
#include "portable_storage_to_bin.h"
|
||||
|
|
|
|||
|
|
@ -50,7 +50,8 @@ namespace tools
|
|||
|
||||
boost::system::error_code ec;
|
||||
uint64_t sz = boost::filesystem::file_size(db_main_file_path, ec);
|
||||
if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || command_line::has_arg(vm, command_line::arg_force_predownload)) )
|
||||
bool flag_force_predownload = command_line::has_arg(vm, command_line::arg_force_predownload);
|
||||
if (pre_download.unpacked_size == 0 || !(ec || (pre_download.unpacked_size > sz && pre_download.unpacked_size - sz > pre_download_min_size_difference) || flag_force_predownload) )
|
||||
{
|
||||
LOG_PRINT_MAGENTA("Pre-downloading not needed (db file size = " << sz << ")", LOG_LEVEL_0);
|
||||
return true;
|
||||
|
|
@ -92,15 +93,15 @@ namespace tools
|
|||
r = cl.download_and_unzip(cb, downloading_file_path, url, 5000 /* timout */, "GET", std::string(), 30 /* fails count */);
|
||||
if (!r)
|
||||
{
|
||||
LOG_PRINT_RED("Download failed", LOG_LEVEL_0);
|
||||
return false;
|
||||
LOG_PRINT_RED("Downloading failed", LOG_LEVEL_0);
|
||||
return !flag_force_predownload; // fatal error only if force-predownload
|
||||
}
|
||||
|
||||
crypto::hash data_hash = hash_stream.calculate_hash();
|
||||
if (epee::string_tools::pod_to_hex(data_hash) != pre_download.hash)
|
||||
{
|
||||
LOG_ERROR("hash missmatch in downloaded file, got: " << epee::string_tools::pod_to_hex(data_hash) << ", expected: " << pre_download.hash);
|
||||
return false;
|
||||
return !flag_force_predownload; // fatal error only if force-predownload
|
||||
}
|
||||
|
||||
LOG_PRINT_GREEN("Download succeeded, hash " << pre_download.hash << " is correct" , LOG_LEVEL_0);
|
||||
|
|
|
|||
|
|
@ -593,6 +593,7 @@ bool handle_get_daemon_info(po::variables_map& vm)
|
|||
PRINT_FIELD_NAME(res.performance_data, "", tx_append_time)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_append_rl_wait)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_append_is_expired)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_mixin_count)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_prefix_hash)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_attachment_check)
|
||||
PRINT_FIELD_NAME(res.performance_data, "", tx_check_inputs_loop)
|
||||
|
|
|
|||
|
|
@ -315,6 +315,13 @@ namespace crypto
|
|||
return *this;
|
||||
}
|
||||
|
||||
// returns this = a * b
|
||||
scalar_t& assign_mul(const scalar_t& a, const scalar_t& b)
|
||||
{
|
||||
sc_mul(m_s, a.m_s, b.m_s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*
|
||||
I think it has bad symantic (operator-like), consider rename/reimplement -- sowle
|
||||
*/
|
||||
|
|
@ -426,6 +433,17 @@ namespace crypto
|
|||
|
||||
}; // struct scalar_t
|
||||
|
||||
//
|
||||
// Global constants
|
||||
//
|
||||
|
||||
extern const scalar_t c_scalar_1;
|
||||
extern const scalar_t c_scalar_L;
|
||||
extern const scalar_t c_scalar_Lm1;
|
||||
extern const scalar_t c_scalar_P;
|
||||
extern const scalar_t c_scalar_Pm1;
|
||||
extern const scalar_t c_scalar_256m1;
|
||||
extern const scalar_t c_scalar_1div8;
|
||||
|
||||
//
|
||||
//
|
||||
|
|
@ -479,6 +497,7 @@ namespace crypto
|
|||
zero();
|
||||
}
|
||||
|
||||
// as we're using additive notation, zero means identity group element here and after
|
||||
void zero()
|
||||
{
|
||||
ge_p3_0(&m_p3);
|
||||
|
|
@ -490,6 +509,11 @@ namespace crypto
|
|||
return fe_isnonzero(m_p3.X) * fe_cmp(m_p3.Y, m_p3.Z) == 0;
|
||||
}
|
||||
|
||||
bool is_in_main_subgroup() const
|
||||
{
|
||||
return (c_scalar_L * *this).is_zero();
|
||||
}
|
||||
|
||||
bool from_public_key(const crypto::public_key& pk)
|
||||
{
|
||||
return ge_frombytes_vartime(&m_p3, reinterpret_cast<const unsigned char*>(&pk)) == 0;
|
||||
|
|
@ -710,19 +734,151 @@ namespace crypto
|
|||
}; // struct point_g_t
|
||||
|
||||
|
||||
//
|
||||
// vector of scalars
|
||||
//
|
||||
struct scalar_vec_t : public std::vector<scalar_t>
|
||||
{
|
||||
typedef std::vector<scalar_t> super_t;
|
||||
|
||||
scalar_vec_t() {}
|
||||
scalar_vec_t(size_t n) : super_t(n) {}
|
||||
scalar_vec_t(std::initializer_list<scalar_t> init_list) : super_t(init_list) {}
|
||||
|
||||
bool is_reduced() const
|
||||
{
|
||||
for (auto& el : *this)
|
||||
if (!el.is_reduced())
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// add a scalar rhs to each element
|
||||
scalar_vec_t operator+(const scalar_t& rhs) const
|
||||
{
|
||||
scalar_vec_t result(size());
|
||||
for (size_t i = 0, n = size(); i < n; ++i)
|
||||
result[i] = at(i) + rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
// subtract a scalar rhs to each element
|
||||
scalar_vec_t operator-(const scalar_t& rhs) const
|
||||
{
|
||||
scalar_vec_t result(size());
|
||||
for (size_t i = 0, n = size(); i < n; ++i)
|
||||
result[i] = at(i) - rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
// multiply each element of the vector by a scalar
|
||||
scalar_vec_t operator*(const scalar_t& rhs) const
|
||||
{
|
||||
scalar_vec_t result(size());
|
||||
for (size_t i = 0, n = size(); i < n; ++i)
|
||||
result[i] = at(i) * rhs;
|
||||
return result;
|
||||
}
|
||||
|
||||
// component-wise multiplication (a.k.a the Hadamard product) (only if their sizes match)
|
||||
scalar_vec_t operator*(const scalar_vec_t& rhs) const
|
||||
{
|
||||
scalar_vec_t result;
|
||||
const size_t n = size();
|
||||
if (n != rhs.size())
|
||||
return result;
|
||||
|
||||
result.resize(size());
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
result[i] = at(i) * rhs[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
// add each element of two vectors, but only if their sizes match
|
||||
scalar_vec_t operator+(const scalar_vec_t& rhs) const
|
||||
{
|
||||
scalar_vec_t result;
|
||||
const size_t n = size();
|
||||
if (n != rhs.size())
|
||||
return result;
|
||||
|
||||
result.resize(size());
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
result[i] = at(i) + rhs[i];
|
||||
return result;
|
||||
}
|
||||
|
||||
// zeroes all elements
|
||||
void zero()
|
||||
{
|
||||
size_t size_bytes = sizeof(scalar_t) * size();
|
||||
memset(data(), 0, size_bytes);
|
||||
}
|
||||
|
||||
// invert all elements in-place efficiently: 4*N muptiplications + 1 inversion
|
||||
void invert()
|
||||
{
|
||||
// muls muls_rev
|
||||
// 0: 1 2 3 .. n-1
|
||||
// 1: 0 2 3 .. n-1
|
||||
// 2: 0 1 3 .. n-1
|
||||
//
|
||||
// n-1: 0 1 2 3 .. n-2
|
||||
|
||||
const size_t size = this->size();
|
||||
|
||||
if (size < 2)
|
||||
{
|
||||
if (size == 1)
|
||||
at(0) = at(0).reciprocal();
|
||||
return;
|
||||
}
|
||||
|
||||
scalar_vec_t muls(size), muls_rev(size);
|
||||
muls[0] = 1;
|
||||
for (size_t i = 0; i < size - 1; ++i)
|
||||
muls[i + 1] = at(i) * muls[i];
|
||||
|
||||
muls_rev[size - 1] = 1;
|
||||
for (size_t i = size - 1; i != 0; --i)
|
||||
muls_rev[i - 1] = at(i) * muls_rev[i];
|
||||
|
||||
scalar_t inv = (muls[size - 1] * at(size - 1)).reciprocal();
|
||||
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
at(i) = muls[i] * inv * muls_rev[i];
|
||||
}
|
||||
|
||||
scalar_t calc_hs() const;
|
||||
|
||||
}; // scalar_vec_t
|
||||
|
||||
|
||||
// treats vector of scalars as an M x N matrix just for convenience
|
||||
template<size_t N>
|
||||
struct scalar_mat_t : public scalar_vec_t
|
||||
{
|
||||
typedef scalar_vec_t super_t;
|
||||
static_assert(N > 0, "invalid N value");
|
||||
|
||||
scalar_mat_t() {}
|
||||
scalar_mat_t(size_t n) : super_t(n) {}
|
||||
scalar_mat_t(std::initializer_list<scalar_t> init_list) : super_t(init_list) {}
|
||||
|
||||
// matrix accessor M rows x N cols
|
||||
scalar_t& operator()(size_t row, size_t col)
|
||||
{
|
||||
return at(row * N + col);
|
||||
}
|
||||
}; // scalar_mat_t
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Global constants
|
||||
//
|
||||
|
||||
extern const point_g_t c_point_G;
|
||||
|
||||
extern const scalar_t c_scalar_1;
|
||||
extern const scalar_t c_scalar_L;
|
||||
extern const scalar_t c_scalar_Lm1;
|
||||
extern const scalar_t c_scalar_P;
|
||||
extern const scalar_t c_scalar_Pm1;
|
||||
extern const scalar_t c_scalar_256m1;
|
||||
extern const scalar_t c_scalar_1div8;
|
||||
|
||||
extern const point_t c_point_H;
|
||||
extern const point_t c_point_0;
|
||||
|
|
@ -901,4 +1057,11 @@ namespace crypto
|
|||
}; // hash_helper_t struct
|
||||
|
||||
|
||||
inline scalar_t scalar_vec_t::calc_hs() const
|
||||
{
|
||||
// hs won't touch memory if size is 0, so it's safe
|
||||
return hash_helper_t::hs(data(), sizeof(scalar_t) * size());
|
||||
}
|
||||
|
||||
|
||||
} // namespace crypto
|
||||
|
|
|
|||
12
src/crypto/range_proofs.cpp
Normal file
12
src/crypto/range_proofs.cpp
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2021 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2021 sowle (val@zano.org, crypto.sowle@gmail.com)
|
||||
// Distributed under the MIT/X11 software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
#include "range_proofs.h"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H;
|
||||
|
||||
|
||||
}
|
||||
823
src/crypto/range_proofs.h
Normal file
823
src/crypto/range_proofs.h
Normal file
|
|
@ -0,0 +1,823 @@
|
|||
// Copyright (c) 2021 Zano Project (https://zano.org/)
|
||||
// Copyright (c) 2021 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"
|
||||
|
||||
namespace crypto
|
||||
{
|
||||
|
||||
// returns x + x^2 + x^3 + ... + x^(2^f)
|
||||
// == x * (x + 1) * (x^2 + 1) * (x^4 + 1) * ...(x^(f+1) + 1)
|
||||
inline scalar_t sum_of_powers(scalar_t x, size_t f)
|
||||
{
|
||||
scalar_t result = x;
|
||||
for (size_t i = 0; i < f; ++i)
|
||||
{
|
||||
result.assign_muladd(result, x, result);
|
||||
x *= x;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr size_t c_bpp_log2_n = 6;
|
||||
constexpr size_t c_bpp_n = 64; // 2^64 is the upper bound for the witness's range
|
||||
constexpr size_t c_bpp_values_max = 16; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs
|
||||
constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max;
|
||||
|
||||
// returns smallest k, s.t. v <= 2**k
|
||||
inline size_t calc_exp_power_of_2_upper_bound(size_t v)
|
||||
{
|
||||
constexpr size_t max_v = (SIZE_MAX >> 1) + 1;
|
||||
//if (v > max_v)
|
||||
// return 0;
|
||||
|
||||
size_t pow = 1, result = 0;
|
||||
while (v > pow)
|
||||
{
|
||||
pow <<= 1;
|
||||
++result;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// returns least significant bit uing de Bruijn sequence
|
||||
// http://graphics.stanford.edu/~seander/bithacks.html
|
||||
inline uint8_t calc_lsb_32(uint32_t v)
|
||||
{
|
||||
static const uint8_t multiply_de_bruijn_bit_position[32] =
|
||||
{
|
||||
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
|
||||
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
|
||||
};
|
||||
return multiply_de_bruijn_bit_position[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27];
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////
|
||||
// crypto trait for Zano
|
||||
////////////////////////////////////////
|
||||
struct bpp_crypto_trait_zano
|
||||
{
|
||||
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 const scalar_t& get_initial_transcript()
|
||||
{
|
||||
static scalar_t value = hash_helper_t::hs("Zano BP+ initial transcript");
|
||||
return value;
|
||||
}
|
||||
|
||||
// assumes hsc is cleared
|
||||
static void update_transcript(hash_helper_t::hs_t& hsc, scalar_t& e, const std::vector<point_t>& points)
|
||||
{
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_points_array(points);
|
||||
e = hsc.calc_hash();
|
||||
}
|
||||
|
||||
static const point_t& get_generator(bool select_H, size_t index)
|
||||
{
|
||||
if (index >= c_bpp_mn_max)
|
||||
return c_point_0; // out of bound
|
||||
|
||||
static std::vector<point_t> generators(2 * c_bpp_mn_max);
|
||||
static bool calculated = false;
|
||||
if (!calculated)
|
||||
{
|
||||
scalar_t hash_buf[2] = { hash_helper_t::hs("Zano BP+ generator"), 0 };
|
||||
for (size_t i = 0; i < 2 * c_bpp_mn_max; ++i)
|
||||
{
|
||||
hash_buf[1].m_u64[0] = i;
|
||||
ge_bytes_hash_to_ec(&generators[i].m_p3, &hash_buf, sizeof hash_buf);
|
||||
}
|
||||
calculated = true;
|
||||
}
|
||||
|
||||
return generators[2 * index + (select_H ? 1 : 0)];
|
||||
}
|
||||
|
||||
static const point_t& bpp_H;
|
||||
};
|
||||
|
||||
|
||||
struct bpp_signature
|
||||
{
|
||||
std::vector<public_key> L; // size = log_2(m * n)
|
||||
std::vector<public_key> R;
|
||||
public_key A0;
|
||||
public_key A;
|
||||
public_key B;
|
||||
scalar_t r;
|
||||
scalar_t s;
|
||||
scalar_t delta;
|
||||
};
|
||||
|
||||
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
|
||||
#define DBG_PRINT(x) std::cout << x << ENDL
|
||||
|
||||
template<typename CT>
|
||||
bool bpp_gen(const std::vector<uint64_t>& values, const scalar_vec_t& masks, bpp_signature& sig, std::vector<point_t>& commitments, uint8_t* p_err = nullptr)
|
||||
{
|
||||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
if (!(cond)) { LOG_PRINT_RED("bpp_gen: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(values.size() > 0 && values.size() <= c_bpp_values_max && values.size() == masks.size(), 1);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(masks.is_reduced(), 3);
|
||||
|
||||
const size_t c_bpp_log2_m = calc_exp_power_of_2_upper_bound(values.size());
|
||||
const size_t c_bpp_m = 1ull << c_bpp_log2_m;
|
||||
const size_t c_bpp_mn = c_bpp_m * c_bpp_n;
|
||||
const size_t c_bpp_log2_mn = c_bpp_log2_m + c_bpp_log2_n;
|
||||
|
||||
// pre-multiply all output points by c_scalar_1div8
|
||||
// in order to enforce these points to be in the prime-order subgroup (after mul by 8 in bpp_verify())
|
||||
|
||||
// calc commitments vector as commitments[i] = 1/8 * values[i] * G + 1/8 * masks[i] * H
|
||||
commitments.resize(values.size());
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
CT::calc_pedersen_commitment(scalar_t(values[i]) * c_scalar_1div8, masks[i] * c_scalar_1div8, commitments[i]);
|
||||
|
||||
|
||||
// s.a. BP+ paper, page 15, eq. 11
|
||||
// decompose v into aL and aR:
|
||||
// v = aL o (1, 2, 2^2, ..., 2^n-1), o - component-wise product aka Hadamard product
|
||||
// aR = aL - (1, 1, ... 1)
|
||||
// aR o aL = 0
|
||||
|
||||
// aLs = (aL_0, aL_1, ..., aL_m-1) -- `bit` matrix of c_bpp_m x c_bpp_n, each element is a scalar
|
||||
|
||||
scalar_mat_t<c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
|
||||
aLs.zero();
|
||||
aRs.zero();
|
||||
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
|
||||
for (size_t i = 0; i < values.size(); ++i)
|
||||
{
|
||||
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<c_bpp_n> d(c_bpp_mn);
|
||||
d(0, 0) = z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
|
||||
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
|
||||
// (calculate two more elements (1 and y^(mn+1)) for convenience)
|
||||
scalar_vec_t y_powers(c_bpp_mn + 2);
|
||||
y_powers[0] = 1;
|
||||
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
|
||||
y_powers[i] = y_powers[i - 1] * y;
|
||||
|
||||
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
|
||||
|
||||
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
|
||||
|
||||
// aL_hat = aL - 1*z
|
||||
scalar_vec_t aLs_hat = aLs - z;
|
||||
// aL_hat = aR + d o y^leftarr + 1*z where y^leftarr = (y^n, y^(n-1), ..., y) (BP+ paper, page 18, Fig. 3)
|
||||
scalar_vec_t aRs_hat = aRs + z;
|
||||
for (size_t i = 0; i < c_bpp_mn; ++i)
|
||||
aRs_hat[i] += d[i] * y_powers[c_bpp_mn - i];
|
||||
|
||||
DBG_PRINT("Hs(aLs_hat): " << aLs_hat.calc_hs());
|
||||
DBG_PRINT("Hs(aRs_hat): " << aRs_hat.calc_hs());
|
||||
|
||||
// calculate alpha_hat
|
||||
// alpha_hat = alpha + SUM(z^(2j) * gamma_j * y^(mn+1)) for j = 1..m
|
||||
// i.e. \hat{\alpha} = \alpha + y^{m n+1} \sum_{j = 1}^{m} z^{2j} \gamma_j
|
||||
scalar_t alpha_hat = 0;
|
||||
for (size_t i = 0; i < masks.size(); ++i)
|
||||
alpha_hat += d(i, 0) * masks[i];
|
||||
alpha_hat = alpha + y_mn_p1 * alpha_hat;
|
||||
|
||||
DBG_VAL_PRINT(alpha_hat);
|
||||
|
||||
// calculate y^-1, y^-2, ...
|
||||
const scalar_t y_inverse = y.reciprocal();
|
||||
scalar_vec_t y_inverse_powers(c_bpp_mn / 2 + 1); // the greatest power we need is c_bpp_mn/2 (at the first reduction round)
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1, size = y_inverse_powers.size(); i < size; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inverse;
|
||||
|
||||
// prepare generator's vector
|
||||
std::vector<point_t> g(c_bpp_mn), h(c_bpp_mn);
|
||||
for (size_t i = 0; i < c_bpp_mn; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
|
||||
// WIP zk-argument called with zk-WIP(g, h, G, H, A_hat, aL_hat, aR_hat, alpha_hat)
|
||||
|
||||
scalar_vec_t& a = aLs_hat;
|
||||
scalar_vec_t& b = aRs_hat;
|
||||
|
||||
sig.L.resize(c_bpp_log2_mn);
|
||||
sig.R.resize(c_bpp_log2_mn);
|
||||
|
||||
// zk-WIP reduction rounds (s.a. the preprint page 13 Fig. 1)
|
||||
for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni)
|
||||
{
|
||||
DBG_PRINT(ENDL << "#" << ni);
|
||||
|
||||
// zk-WIP(g, h, G, H, P, a, b, alpha)
|
||||
|
||||
scalar_t dL = scalar_t::random();
|
||||
DBG_VAL_PRINT(dL);
|
||||
scalar_t dR = scalar_t::random();
|
||||
DBG_VAL_PRINT(dR);
|
||||
|
||||
// a = (a1, a2), b = (b1, b2) -- vectors of scalars
|
||||
// cL = <a1, ((y, y^2, ...) o b2)> -- scalar
|
||||
scalar_t cL = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cL += a[i] * y_powers[i + 1] * b[n + i];
|
||||
|
||||
DBG_VAL_PRINT(cL);
|
||||
|
||||
// cR = <a2, ((y, y^2, ...) o b1)> * y^n -- scalar
|
||||
scalar_t cR = 0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
cR += a[n + i] * y_powers[i + 1] * b[i];
|
||||
cR *= y_powers[n];
|
||||
|
||||
DBG_VAL_PRINT(cR);
|
||||
|
||||
// L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H -- point
|
||||
point_t sum = c_point_0;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[i] * g[n + i];
|
||||
point_t L;
|
||||
CT::calc_pedersen_commitment(cL, dL, L);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
L += b[n + i] * h[i];
|
||||
L += y_inverse_powers[n] * sum;
|
||||
L *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(L);
|
||||
|
||||
// R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H -- point
|
||||
sum.zero();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
sum += a[n + i] * g[i];
|
||||
point_t R;
|
||||
CT::calc_pedersen_commitment(cR, dR, R);
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
R += b[i] * h[n + i];
|
||||
R += y_powers[n] * sum;
|
||||
R *= c_scalar_1div8;
|
||||
DBG_VAL_PRINT(R);
|
||||
|
||||
// put L, R to the sig
|
||||
L.to_public_key(sig.L[ni]);
|
||||
R.to_public_key(sig.R[ni]);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[ni]);
|
||||
hsc.add_pub_key(sig.R[ni]);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// recalculate arguments for the next round
|
||||
scalar_t e_squared = e * e;
|
||||
scalar_t e_inverse = e.reciprocal();
|
||||
scalar_t e_inverse_squared = e_inverse * e_inverse;
|
||||
scalar_t e_y_inv_n = e * y_inverse_powers[n];
|
||||
scalar_t e_inv_y_n = e_inverse * y_powers[n];
|
||||
|
||||
// g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i];
|
||||
|
||||
// h_hat = e * h1 + e^-1 * h2 -- vector of points
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
h[i] = e * h[i] + e_inverse * h[n + i];
|
||||
|
||||
// P_hat = e^2 * L + P + e^-2 * R -- point
|
||||
|
||||
// a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
a[i] = e * a[i] + e_inv_y_n * a[n + i];
|
||||
|
||||
// b_hat = e^-1 * b1 + e * b2 -- vector of scalars
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
b[i] = e_inverse * b[i] + e * b[n + i];
|
||||
|
||||
// alpha_hat = e^2 * dL + alpha + e^-2 * dR -- scalar
|
||||
alpha_hat += e_squared * dL + e_inverse_squared * dR;
|
||||
|
||||
// run next iteraton zk-WIP(g_hat, h_hat, G, H, P_hat, a_hat, b_hat, alpha_hat)
|
||||
}
|
||||
DBG_PRINT("");
|
||||
|
||||
// zk-WIP last round
|
||||
scalar_t r = scalar_t::random();
|
||||
scalar_t s = scalar_t::random();
|
||||
scalar_t delta = scalar_t::random();
|
||||
scalar_t eta = scalar_t::random();
|
||||
DBG_VAL_PRINT(r);
|
||||
DBG_VAL_PRINT(s);
|
||||
DBG_VAL_PRINT(delta);
|
||||
DBG_VAL_PRINT(eta);
|
||||
|
||||
// A = r * g + s * h + (r y b + s y a) * G + delta * H -- point
|
||||
point_t A = c_point_0;
|
||||
CT::calc_pedersen_commitment(y * (r * b[0] + s * a[0]), delta, A);
|
||||
A += r * g[0] + s * h[0];
|
||||
A *= c_scalar_1div8;
|
||||
A.to_public_key(sig.A);
|
||||
DBG_VAL_PRINT(A);
|
||||
|
||||
// B = (r * y * s) * G + eta * H
|
||||
point_t B = c_point_0;
|
||||
CT::calc_pedersen_commitment(r * y * s, eta, B);
|
||||
B *= c_scalar_1div8;
|
||||
B.to_public_key(sig.B);
|
||||
DBG_VAL_PRINT(B);
|
||||
|
||||
// update the transcript
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
e = hsc.calc_hash();
|
||||
DBG_VAL_PRINT(e);
|
||||
|
||||
// finalize the signature
|
||||
sig.r = r + e * a[0];
|
||||
sig.s = s + e * b[0];
|
||||
sig.delta = eta + e * delta + e * e * alpha_hat;
|
||||
DBG_VAL_PRINT(sig.r);
|
||||
DBG_VAL_PRINT(sig.s);
|
||||
DBG_VAL_PRINT(sig.delta);
|
||||
|
||||
return true;
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
} // bpp_gen()
|
||||
|
||||
|
||||
// efficient multiexponentiation (naive stub implementation atm, TODO)
|
||||
template<typename CT>
|
||||
bool multiexp_and_check_being_zero(const scalar_vec_t& g_scalars, const scalar_vec_t& h_scalars, const point_t& summand)
|
||||
{
|
||||
CHECK_AND_ASSERT_MES(g_scalars.size() < c_bpp_mn_max, false, "g_scalars oversized");
|
||||
CHECK_AND_ASSERT_MES(h_scalars.size() < c_bpp_mn_max, false, "h_scalars oversized");
|
||||
|
||||
point_t result = summand;
|
||||
|
||||
for (size_t i = 0; i < g_scalars.size(); ++i)
|
||||
result += g_scalars[i] * CT::get_generator(false, i);
|
||||
|
||||
for (size_t i = 0; i < h_scalars.size(); ++i)
|
||||
result += h_scalars[i] * CT::get_generator(true, i);
|
||||
|
||||
if (!result.is_zero())
|
||||
{
|
||||
LOG_PRINT_L0("multiexp result is non zero: " << result);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct bpp_sig_commit_ref_t
|
||||
{
|
||||
bpp_sig_commit_ref_t(const bpp_signature& sig, const std::vector<point_t>& commitments)
|
||||
: sig(sig)
|
||||
, commitments(commitments)
|
||||
{}
|
||||
const bpp_signature& sig;
|
||||
const std::vector<point_t>& commitments;
|
||||
};
|
||||
|
||||
|
||||
template<typename CT>
|
||||
bool bpp_verify(const std::vector<bpp_sig_commit_ref_t>& sigs, uint8_t* p_err = nullptr)
|
||||
{
|
||||
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
|
||||
if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
|
||||
if (p_err) { *p_err = err_code; } return false; }
|
||||
|
||||
DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . ");
|
||||
|
||||
const size_t kn = sigs.size();
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
|
||||
|
||||
struct intermediate_element_t
|
||||
{
|
||||
scalar_t y;
|
||||
scalar_t z;
|
||||
scalar_t z_sq;
|
||||
scalar_vec_t e;
|
||||
scalar_vec_t e_sq;
|
||||
scalar_t e_final;
|
||||
scalar_t e_final_sq;
|
||||
size_t inv_e_offset; // offset in batch_for_inverse
|
||||
size_t inv_y_offset; // offset in batch_for_inverse
|
||||
size_t c_bpp_log2_m;
|
||||
size_t c_bpp_m;
|
||||
size_t c_bpp_mn;
|
||||
point_t A;
|
||||
point_t A0;
|
||||
point_t B;
|
||||
std::vector<point_t> L;
|
||||
std::vector<point_t> R;
|
||||
};
|
||||
std::vector<intermediate_element_t> interms(kn);
|
||||
|
||||
size_t c_bpp_log2_m_max = 0;
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4);
|
||||
|
||||
intermediate_element_t& interm = interms[k];
|
||||
interm.c_bpp_log2_m = calc_exp_power_of_2_upper_bound(bsc.commitments.size());
|
||||
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
|
||||
c_bpp_log2_m_max = interm.c_bpp_log2_m;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + c_bpp_log2_n, 5);
|
||||
|
||||
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
|
||||
interm.c_bpp_mn = interm.c_bpp_m * c_bpp_n;
|
||||
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
|
||||
interm.L.resize(sig.L.size());
|
||||
interm.R.resize(sig.R.size());
|
||||
for (size_t i = 0; i < interm.L.size(); ++i)
|
||||
{
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
|
||||
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
|
||||
}
|
||||
}
|
||||
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
|
||||
const size_t c_bpp_mn_max = c_bpp_m_max * c_bpp_n;
|
||||
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + c_bpp_log2_n;
|
||||
|
||||
|
||||
//
|
||||
// prepare stuff
|
||||
//
|
||||
/*
|
||||
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
|
||||
for (size_t i = 0; i < c_bpp_mn_max; ++i)
|
||||
{
|
||||
g[i] = CT::get_generator(false, i);
|
||||
h[i] = CT::get_generator(true, i);
|
||||
}
|
||||
*/
|
||||
|
||||
scalar_vec_t batch_for_inverse;
|
||||
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
|
||||
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// restore y and z
|
||||
// using e as Fiat-Shamir transcript
|
||||
scalar_t e = CT::get_initial_transcript();
|
||||
DBG_PRINT("initial transcript: " << e);
|
||||
hash_helper_t::hs_t hsc;
|
||||
CT::update_transcript(hsc, e, bsc.commitments);
|
||||
// calculate scalar challenges y and z
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A0);
|
||||
hsc.assign_calc_hash(interm.y);
|
||||
interm.z = hash_helper_t::hs(interm.y);
|
||||
interm.z_sq = interm.z * interm.z;
|
||||
DBG_VAL_PRINT(interm.y);
|
||||
DBG_VAL_PRINT(interm.z);
|
||||
e = interm.z; // transcript for further steps
|
||||
|
||||
interm.inv_y_offset = batch_for_inverse.size();
|
||||
batch_for_inverse.push_back(interm.y);
|
||||
interm.inv_e_offset = batch_for_inverse.size();
|
||||
|
||||
interm.e.resize(sig.L.size());
|
||||
interm.e_sq.resize(sig.L.size());
|
||||
|
||||
for (size_t i = 0; i < sig.L.size(); ++i)
|
||||
{
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.L[i]);
|
||||
hsc.add_pub_key(sig.R[i]);
|
||||
hsc.assign_calc_hash(e);
|
||||
interm.e[i] = e;
|
||||
interm.e_sq[i] = e * e;
|
||||
DBG_PRINT("e[" << i << "]: " << e);
|
||||
batch_for_inverse.push_back(e);
|
||||
}
|
||||
|
||||
hsc.add_scalar(e);
|
||||
hsc.add_pub_key(sig.A);
|
||||
hsc.add_pub_key(sig.B);
|
||||
hsc.assign_calc_hash(interm.e_final);
|
||||
interm.e_final_sq = interm.e_final * interm.e_final;
|
||||
DBG_VAL_PRINT(interm.e_final);
|
||||
}
|
||||
|
||||
batch_for_inverse.invert();
|
||||
|
||||
// Notation:
|
||||
// 1_vec ^ n = (1, 1, 1, ..., 1)
|
||||
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
|
||||
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
|
||||
// y<^n = (y^n, y^(n-1), ..., y^1)
|
||||
// y>^n = (y^1, y^2, ..., y^n)
|
||||
|
||||
// from page 13, Fig 1:
|
||||
// Verifier outputs Accept IFF the following equality holds (single proof):
|
||||
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'
|
||||
// (where g and h are calculated in each round)
|
||||
// The same equation in additive notation:
|
||||
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H
|
||||
// <=>
|
||||
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*)
|
||||
// where A, B, r', s', delta' is taken from the signature
|
||||
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
|
||||
//
|
||||
// from page 18, Fig 3:
|
||||
// P and V computes:
|
||||
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// (calculated once)
|
||||
//
|
||||
// As suggested in Section 6.1 "Practical Optimizations":
|
||||
// 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20):
|
||||
//
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * A_hat
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (**)
|
||||
//
|
||||
// where:
|
||||
// g, h - vector of fixed generators
|
||||
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
|
||||
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
|
||||
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
|
||||
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
|
||||
//
|
||||
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
|
||||
// insert A_hat into (**) =>
|
||||
|
||||
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
|
||||
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
|
||||
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
|
||||
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
|
||||
// )
|
||||
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
|
||||
// - e * A - B = 0
|
||||
|
||||
// =>
|
||||
|
||||
// (for single signature)
|
||||
//
|
||||
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
|
||||
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
|
||||
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
|
||||
// + delta' * H | the signatures
|
||||
//
|
||||
// - e^2 * A0
|
||||
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
|
||||
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
// - e * A - B = 0 (***)
|
||||
//
|
||||
// All (***) will be muptiplied by random weightning factor and then summed up.
|
||||
|
||||
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
|
||||
scalar_vec_t g_scalars;
|
||||
g_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_vec_t h_scalars;
|
||||
h_scalars.resize(c_bpp_mn_max, 0);
|
||||
scalar_t G_scalar = 0;
|
||||
scalar_t H_scalar = 0;
|
||||
point_t summand = c_point_0;
|
||||
|
||||
for (size_t k = 0; k < kn; ++k)
|
||||
{
|
||||
DBG_PRINT(ENDL << "SIG #" << k);
|
||||
const bpp_sig_commit_ref_t& bsc = sigs[k];
|
||||
const bpp_signature& sig = bsc.sig;
|
||||
intermediate_element_t& interm = interms[k];
|
||||
|
||||
// random weightning factor for speed-optimized batch verification (preprint page 20)
|
||||
const scalar_t rwf = scalar_t::random();
|
||||
DBG_PRINT("rwf: " << rwf);
|
||||
|
||||
// prepare d vector (see also d structure description in proof function)
|
||||
scalar_mat_t<c_bpp_n> d(interm.c_bpp_mn);
|
||||
d(0, 0) = interm.z_sq;
|
||||
// first row
|
||||
for (size_t i = 1; i < interm.c_bpp_m; ++i)
|
||||
d(i, 0) = d(i - 1, 0) * interm.z_sq;
|
||||
// all rows
|
||||
for (size_t j = 1; j < c_bpp_n; ++j)
|
||||
for (size_t i = 0; i < interm.c_bpp_m; ++i)
|
||||
d(i, j) = d(i, j - 1) + d(i, j - 1);
|
||||
// sum(d) (see also note in proof function for this)
|
||||
static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 };
|
||||
const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
|
||||
|
||||
DBG_PRINT("Hs(d): " << d.calc_hs());
|
||||
DBG_PRINT("sum(d): " << sum_d);
|
||||
|
||||
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
|
||||
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
|
||||
|
||||
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
|
||||
// complexity (sc_mul's): MN+2*log2(MN)-2
|
||||
// the idea is the following:
|
||||
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
|
||||
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
|
||||
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
|
||||
scalar_vec_t s_vec(interm.c_bpp_mn);
|
||||
s_vec[0] = get_e_inv(0);
|
||||
for (size_t i = 1; i < log2_mn; ++i)
|
||||
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
|
||||
DBG_PRINT("[0] " << s_vec[0]);
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
{
|
||||
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
|
||||
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
|
||||
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
|
||||
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
|
||||
}
|
||||
|
||||
// prepare y_inv vector
|
||||
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
|
||||
y_inverse_powers[0] = 1;
|
||||
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
|
||||
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
|
||||
|
||||
// y^(mn+1)
|
||||
scalar_t y_power_mnp1 = interm.y;
|
||||
for (size_t i = 0; i < log2_mn; ++i)
|
||||
y_power_mnp1 *= y_power_mnp1;
|
||||
y_power_mnp1 *= interm.y;
|
||||
DBG_VAL_PRINT(y_power_mnp1);
|
||||
|
||||
// now calculate all multiplicands for common generators
|
||||
|
||||
// g vector multiplicands:
|
||||
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
|
||||
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
|
||||
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
|
||||
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
|
||||
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
|
||||
|
||||
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
|
||||
|
||||
// h vector multiplicands:
|
||||
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
|
||||
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
|
||||
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
|
||||
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
|
||||
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
|
||||
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
|
||||
{
|
||||
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
|
||||
rwf_e_sq_y *= interm.y;
|
||||
}
|
||||
|
||||
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
|
||||
|
||||
// G point multiplicands:
|
||||
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
|
||||
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
|
||||
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
|
||||
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
|
||||
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
|
||||
DBG_PRINT("G_scalar: " << G_scalar);
|
||||
|
||||
// H point multiplicands:
|
||||
// rwf * delta
|
||||
H_scalar += rwf * sig.delta;
|
||||
DBG_PRINT("H_scalar: " << H_scalar);
|
||||
|
||||
// uncommon generators' multiplicands
|
||||
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
|
||||
// - rwf * e^2 * A0
|
||||
summand_8 -= rwf * interm.e_final_sq * interm.A0;
|
||||
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
|
||||
|
||||
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
|
||||
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
|
||||
for (size_t j = 0; j < bsc.commitments.size(); ++j)
|
||||
{
|
||||
e_sq_y_mn1_z_sq_power *= interm.z_sq;
|
||||
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
|
||||
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
|
||||
}
|
||||
|
||||
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
|
||||
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
|
||||
for (size_t j = 0; j < log2_mn; ++j)
|
||||
{
|
||||
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
|
||||
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
|
||||
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
|
||||
}
|
||||
|
||||
// - rwf * e * A - rwf * B = 0
|
||||
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
|
||||
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
|
||||
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
|
||||
|
||||
summand_8.modify_mul8();
|
||||
summand += summand_8;
|
||||
}
|
||||
|
||||
point_t GH_exponents = c_point_0;
|
||||
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
|
||||
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
|
||||
if (result)
|
||||
DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
|
||||
return result;
|
||||
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
|
@ -3816,12 +3816,14 @@ namespace currency
|
|||
const crypto::hash& m_tx_id;
|
||||
const crypto::hash& m_bl_id;
|
||||
const uint64_t m_bl_height;
|
||||
add_transaction_input_visitor(blockchain_storage& bcs, blockchain_storage::key_images_container& m_db_spent_keys, const crypto::hash& tx_id, const crypto::hash& bl_id, const uint64_t bl_height) :
|
||||
uint64_t &m_mixins_count;
|
||||
add_transaction_input_visitor(blockchain_storage& bcs, blockchain_storage::key_images_container& m_db_spent_keys, const crypto::hash& tx_id, const crypto::hash& bl_id, const uint64_t bl_height, uint64_t& mixins_count) :
|
||||
m_bcs(bcs),
|
||||
m_db_spent_keys(m_db_spent_keys),
|
||||
m_tx_id(tx_id),
|
||||
m_bl_id(bl_id),
|
||||
m_bl_height(bl_height)
|
||||
m_bl_height(bl_height),
|
||||
m_mixins_count(mixins_count)
|
||||
{}
|
||||
bool operator()(const txin_to_key& in) const
|
||||
{
|
||||
|
|
@ -3846,7 +3848,8 @@ namespace currency
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_mixins_count < in.key_offsets.size())
|
||||
m_mixins_count = in.key_offsets.size();
|
||||
return true;
|
||||
}
|
||||
bool operator()(const txin_htlc& in) const
|
||||
|
|
@ -3896,11 +3899,11 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
|
|||
process_blockchain_tx_attachments(tx, bl_height, bl_id, timestamp);
|
||||
TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_attachment);
|
||||
|
||||
|
||||
uint64_t mixins_count = 0;
|
||||
TIME_MEASURE_START_PD(tx_process_inputs);
|
||||
for(const txin_v& in : tx.vin)
|
||||
{
|
||||
if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height), in))
|
||||
if(!boost::apply_visitor(add_transaction_input_visitor(*this, m_db_spent_keys, tx_id, bl_id, bl_height, mixins_count), in))
|
||||
{
|
||||
LOG_ERROR("critical internal error: add_transaction_input_visitor failed. but key_images should be already checked");
|
||||
purge_transaction_keyimages_from_blockchain(tx, false);
|
||||
|
|
@ -3913,6 +3916,13 @@ bool blockchain_storage::add_transaction_from_block(const transaction& tx, const
|
|||
}
|
||||
}
|
||||
TIME_MEASURE_FINISH_PD_COND(need_to_profile, tx_process_inputs);
|
||||
if (need_to_profile && mixins_count > 0)
|
||||
{
|
||||
m_performance_data.tx_mixin_count.push(mixins_count);
|
||||
#ifdef _DEBUG
|
||||
LOG_PRINT_L0("[TX_MIXINS]: " << mixins_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
//check if there is already transaction with this hash
|
||||
TIME_MEASURE_START_PD(tx_check_exist);
|
||||
|
|
|
|||
|
|
@ -73,33 +73,35 @@ namespace currency
|
|||
epee::math_helper::average<uint64_t, 5> target_calculating_calc;
|
||||
|
||||
//tx processing zone
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_time;
|
||||
epee::math_helper::average<uint64_t, 5> tx_add_one_tx_time;
|
||||
epee::math_helper::average<uint64_t, 5> tx_process_extra;
|
||||
epee::math_helper::average<uint64_t, 5> tx_process_attachment;
|
||||
epee::math_helper::average<uint64_t, 5> tx_process_inputs ;
|
||||
epee::math_helper::average<uint64_t, 5> tx_push_global_index;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_exist;
|
||||
epee::math_helper::average<uint64_t, 5> tx_print_log;
|
||||
epee::math_helper::average<uint64_t, 5> tx_prapare_append;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_time;
|
||||
epee::math_helper::average<uint64_t, 1> tx_add_one_tx_time;
|
||||
epee::math_helper::average<uint64_t, 1> tx_process_extra;
|
||||
epee::math_helper::average<uint64_t, 1> tx_process_attachment;
|
||||
epee::math_helper::average<uint64_t, 1> tx_process_inputs ;
|
||||
epee::math_helper::average<uint64_t, 1> tx_push_global_index;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_exist;
|
||||
epee::math_helper::average<uint64_t, 1> tx_print_log;
|
||||
epee::math_helper::average<uint64_t, 1> tx_prapare_append;
|
||||
|
||||
epee::math_helper::average<uint64_t, 5> tx_append_time;
|
||||
epee::math_helper::average<uint64_t, 5> tx_append_rl_wait;
|
||||
epee::math_helper::average<uint64_t, 5> tx_append_is_expired;
|
||||
epee::math_helper::average<uint64_t, 1> tx_append_time;
|
||||
epee::math_helper::average<uint64_t, 1> tx_append_rl_wait;
|
||||
epee::math_helper::average<uint64_t, 1> tx_append_is_expired;
|
||||
|
||||
epee::math_helper::average<uint64_t, 5> tx_store_db;
|
||||
epee::math_helper::average<uint64_t, 1> tx_store_db;
|
||||
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_prefix_hash;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_attachment_check;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_kimage_check;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_ch_in_val_sig;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_get_item_size;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_relative_to_absolute;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_loop;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_loop_get_subitem;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_loop_find_tx;
|
||||
epee::math_helper::average<uint64_t, 5> tx_check_inputs_loop_scan_outputkeys_loop_handle_output;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_prefix_hash;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_attachment_check;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_kimage_check;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_ch_in_val_sig;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_get_item_size;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_relative_to_absolute;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_loop;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_loop_get_subitem;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_loop_find_tx;
|
||||
epee::math_helper::average<uint64_t, 1> tx_check_inputs_loop_scan_outputkeys_loop_handle_output;
|
||||
|
||||
epee::math_helper::average<uint64_t, 1> tx_mixin_count;
|
||||
|
||||
|
||||
//TODO: move this to suitable place or remove it all
|
||||
|
|
|
|||
|
|
@ -66,8 +66,6 @@ POP_VS_WARNINGS
|
|||
#include <boost/serialization/variant.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include <boost/spirit/home/support/detail/endian/endian.hpp>
|
||||
#include <boost/spirit/home/support/detail/math/fpclassify.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/timer/timer.hpp>
|
||||
#include <boost/type_traits/is_arithmetic.hpp>
|
||||
|
|
|
|||
|
|
@ -210,6 +210,7 @@ namespace currency
|
|||
res.performance_data.tx_append_time = pd.tx_append_time.get_avg();
|
||||
res.performance_data.tx_append_rl_wait = pd.tx_append_rl_wait.get_avg();
|
||||
res.performance_data.tx_append_is_expired = pd.tx_append_is_expired.get_avg();
|
||||
res.performance_data.tx_mixin_count = pd.tx_mixin_count.get_avg();
|
||||
|
||||
|
||||
res.performance_data.tx_store_db = pd.tx_store_db.get_avg();
|
||||
|
|
|
|||
|
|
@ -500,6 +500,8 @@ namespace currency
|
|||
uint64_t tx_print_log;
|
||||
uint64_t tx_prapare_append;
|
||||
|
||||
uint64_t tx_mixin_count;
|
||||
|
||||
|
||||
uint64_t tx_store_db;
|
||||
|
||||
|
|
@ -547,6 +549,7 @@ namespace currency
|
|||
KV_SERIALIZE(tx_store_db)
|
||||
KV_SERIALIZE(tx_print_log)
|
||||
KV_SERIALIZE(tx_prapare_append)
|
||||
KV_SERIALIZE(tx_mixin_count)
|
||||
|
||||
KV_SERIALIZE(tx_check_inputs_prefix_hash)
|
||||
KV_SERIALIZE(tx_check_inputs_attachment_check)
|
||||
|
|
|
|||
|
|
@ -95,21 +95,21 @@ namespace plain_wallet
|
|||
std::string get_wallets_folder()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return "";
|
||||
std::string path = get_bundle_working_dir() + "/" + WALLETS_FOLDER_NAME + "/";
|
||||
#else
|
||||
std::string path = get_bundle_working_dir() + "/" + WALLETS_FOLDER_NAME + "/";
|
||||
return path;
|
||||
#endif // WIN32
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string get_app_config_folder()
|
||||
{
|
||||
#ifdef WIN32
|
||||
return "";
|
||||
std::string path = get_bundle_working_dir() + "/" + APP_CONFIG_FOLDER + "/";
|
||||
#else
|
||||
std::string path = get_bundle_working_dir() + "/" + APP_CONFIG_FOLDER + "/";
|
||||
return path;
|
||||
#endif // WIN32
|
||||
return path;
|
||||
}
|
||||
#ifdef ANDROID_BUILD
|
||||
class android_logger : public log_space::ibase_log_stream
|
||||
|
|
|
|||
|
|
@ -2389,10 +2389,6 @@ bool wallet2::deinit()
|
|||
bool wallet2::clear()
|
||||
{
|
||||
reset_all();
|
||||
//currency::block b;
|
||||
//currency::generate_genesis_block(b);
|
||||
m_chain.clear();
|
||||
//m_blockchain.push_back(get_block_hash(b));
|
||||
return true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
|
|
@ -2666,6 +2662,7 @@ void wallet2::load(const std::wstring& wallet_, const std::string& password)
|
|||
bool need_to_resync = false;
|
||||
if (wbh.m_ver == 1000)
|
||||
{
|
||||
// old WALLET_FILE_BINARY_HEADER_VERSION version means no encryption
|
||||
need_to_resync = !tools::portable_unserialize_obj_from_stream(*this, data_file);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -707,7 +707,7 @@ namespace tools
|
|||
|
||||
if (ver < 149)
|
||||
{
|
||||
WLT_LOG_MAGENTA("Wallet file truncated due to old version", LOG_LEVEL_0);
|
||||
WLT_LOG_MAGENTA("Wallet file truncated due to old version: " << ver, LOG_LEVEL_0);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@ namespace tools
|
|||
result.require_password = false;
|
||||
result.hash_sum_matched = false;
|
||||
result.syntax_correct = acc.restore_from_tracking_seed(seed_phrase);
|
||||
if (result.syntax_correct)
|
||||
result.tracking = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -188,11 +188,13 @@ namespace wallet_public
|
|||
bool syntax_correct;
|
||||
bool require_password;
|
||||
bool hash_sum_matched;
|
||||
bool tracking;
|
||||
|
||||
BEGIN_KV_SERIALIZE_MAP()
|
||||
KV_SERIALIZE(syntax_correct)
|
||||
KV_SERIALIZE(require_password)
|
||||
KV_SERIALIZE(hash_sum_matched)
|
||||
KV_SERIALIZE(tracking)
|
||||
END_KV_SERIALIZE_MAP()
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "currency_core/difficulty.h"
|
||||
|
||||
#include "crypto/crypto-sugar.h"
|
||||
#include "crypto/range_proofs.h"
|
||||
|
||||
using namespace crypto;
|
||||
|
||||
|
|
@ -1096,6 +1097,52 @@ TEST(crypto, point_basics)
|
|||
return true;
|
||||
}
|
||||
|
||||
TEST(crypto, neg_identity)
|
||||
{
|
||||
point_t z = c_point_0; // 0 group element (identity)
|
||||
public_key z_pk = z.to_public_key(); // pub key, corresponding to 0 ge (pub key is not zero bitwise)
|
||||
public_key z_neg_pk = z_pk;
|
||||
((unsigned char*)&z_neg_pk)[31] = 0x80; // set sign bit manually
|
||||
std::cout << "-Identity = " << z_pk << ENDL;
|
||||
point_t z_neg;
|
||||
ASSERT_FALSE(z_neg.from_public_key(z_neg_pk)); // negative identity should not be loaded
|
||||
|
||||
key_image z_ki;
|
||||
memset(&z_ki, 0, sizeof(z_ki));
|
||||
((unsigned char*)&z_ki)[00] = 0x01; // y = 1
|
||||
|
||||
ASSERT_TRUE(validate_key_image(z_ki));
|
||||
|
||||
key_image z_neg_ki = z_ki;
|
||||
((unsigned char*)&z_neg_ki)[31] = 0x80; // set sign bit manually
|
||||
|
||||
ASSERT_FALSE(validate_key_image(z_neg_ki)); // negative identity should not be loaded
|
||||
|
||||
|
||||
// also do zero-byte pub key / key image checks
|
||||
|
||||
public_key zzz_pk;
|
||||
memset(&zzz_pk, 0, sizeof public_key);
|
||||
|
||||
ASSERT_TRUE(check_key(zzz_pk));
|
||||
|
||||
point_t zzz;
|
||||
ASSERT_TRUE(zzz.from_public_key(zzz_pk));
|
||||
ASSERT_FALSE(zzz.is_in_main_subgroup());
|
||||
|
||||
key_image zzz_ki;
|
||||
memset(&zzz_ki, 0, sizeof key_image);
|
||||
|
||||
ASSERT_FALSE(validate_key_image(zzz_ki));
|
||||
|
||||
point_t zzz2;
|
||||
ASSERT_TRUE(zzz2.from_key_image(zzz_ki));
|
||||
ASSERT_FALSE(zzz2.is_in_main_subgroup());
|
||||
ASSERT_EQ(zzz, zzz2);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(crypto, scalar_reciprocal)
|
||||
{
|
||||
int64_t test_nums[] = { 1, 2, 10 };
|
||||
|
|
@ -1551,6 +1598,30 @@ TEST(crypto, hex_tools)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
TEST(crypto, calc_lsb_32)
|
||||
{
|
||||
auto local_calc_lsb = [](uint32_t v) {
|
||||
uint8_t r = 0;
|
||||
while (v != 0 && (v & 1) == 0)
|
||||
{
|
||||
v >>= 1;
|
||||
++r;
|
||||
}
|
||||
return r;
|
||||
};
|
||||
|
||||
for (uint32_t x = 0; x < UINT32_MAX; ++x)
|
||||
{
|
||||
if (x % 10000000 == 0)
|
||||
std::cout << x << ENDL;
|
||||
ASSERT_EQ((int)local_calc_lsb(x), (int)calc_lsb_32(x));
|
||||
}
|
||||
ASSERT_EQ((int)local_calc_lsb(UINT32_MAX), (int)calc_lsb_32(UINT32_MAX));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// test's runner
|
||||
//
|
||||
|
|
|
|||
|
|
@ -31,17 +31,29 @@ struct try_pull_result_open_response
|
|||
void run_plain_wallet_api_test()
|
||||
{
|
||||
LOG_PRINT_L0("Creating instance...");
|
||||
std::string s = plain_wallet::init("195.201.107.230", "11211", boost::dll::program_location().parent_path().string(), 1);
|
||||
s = plain_wallet::get_export_private_info("E:\\tmp\\check_export");
|
||||
|
||||
std::string key = plain_wallet::generate_random_key(10);
|
||||
std::string test_data = "1234567890 test test ";
|
||||
std::string res = plain_wallet::set_appconfig(test_data, key);
|
||||
std::string test_data2 = plain_wallet::get_appconfig(key);
|
||||
if (test_data2 != test_data)
|
||||
{
|
||||
LOG_ERROR("Error");
|
||||
}
|
||||
//plain_wallet::set_bundle_working_dir("E:\\tmp\\check_export");
|
||||
std::string s = plain_wallet::init("195.201.107.230", "33333", boost::dll::program_location().parent_path().string(), 1);
|
||||
//s = plain_wallet::get_export_private_info("E:\\tmp\\check_export");
|
||||
|
||||
|
||||
std::string res = plain_wallet::sync_call("get_seed_phrase_info", 0, "{\"seed_phrase\":\"aZxat4HAWriVQ3enkGcVsrZRdMseAJswG3CSEwTqZS246VsFQ53w26eZstYsu1jWE74Atz9ajLxFnBsVTafncWNH5SMv4zHFaTS:1780c4d5dd7e97cc4a75ea8baa7977d12ef948b9a6dddc2a9a37e5e22ac7180e:1599495055\"}");
|
||||
|
||||
|
||||
res = plain_wallet::restore("footstep knowledge fur capture honey minute carefully peaceful lovely crawl lunch government nightmare friendship myself sign possibly plan flower depression bread rainbow wrong hardly dark chest",
|
||||
"test_wall2.zan", "111", "");
|
||||
|
||||
|
||||
epee::misc_utils::sleep_no_w(10000000);
|
||||
|
||||
//std::string key = plain_wallet::generate_random_key(10);
|
||||
//std::string test_data = "1234567890 test test ";
|
||||
//std::string res = plain_wallet::set_appconfig(test_data, key);
|
||||
//std::string test_data2 = plain_wallet::get_appconfig(key);
|
||||
//if (test_data2 != test_data)
|
||||
//{
|
||||
// LOG_ERROR("Error");
|
||||
//}
|
||||
return;
|
||||
//std::string fres = plain_wallet::get_logs_buffer();
|
||||
//std::string fres2 = plain_wallet::truncate_log();
|
||||
|
|
|
|||
8
utils/configure_local_paths_msvs2019.cmd
Normal file
8
utils/configure_local_paths_msvs2019.cmd
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@echo off
|
||||
rem
|
||||
rem This file contains local path settings for your own personal dev environment.
|
||||
rem Rename to configure_local_paths.cmd and do not commit.
|
||||
rem
|
||||
|
||||
set QT_PREFIX_PATH=C:\dev\_sdk\Qt5.15.2\5.15.2
|
||||
set BOOST_ROOT=C:\dev\_sdk\boost_1_76_0
|
||||
7
utils/configure_win64_msvs2019_gui_testnet.cmd
Normal file
7
utils/configure_win64_msvs2019_gui_testnet.cmd
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
call configure_local_paths_msvs2019.cmd
|
||||
|
||||
cd ..
|
||||
@mkdir build_msvc2019_64_tn
|
||||
cd build_msvc2019_64_tn
|
||||
|
||||
cmake -D TESTNET=TRUE -D USE_PCH=TRUE -D BUILD_TESTS=TRUE -D CMAKE_PREFIX_PATH="%QT_PREFIX_PATH%"\msvc2019_64 -D BUILD_GUI=TRUE -D STATIC=FALSE -DBOOST_ROOT="%BOOST_ROOT%" -DBOOST_LIBRARYDIR="%BOOST_ROOT%\lib64-msvc-14.2" -G "Visual Studio 16 2019" -A x64 -T host=x64 ".."
|
||||
|
|
@ -46,7 +46,7 @@ RUN curl https://github.com/Kitware/CMake/releases/download/v3.15.5/cmake-3.15.5
|
|||
|
||||
# Boost 1.68
|
||||
|
||||
RUN curl https://dl.bintray.com/boostorg/release/1.68.0/source/boost_1_68_0.tar.bz2 -OL &&\
|
||||
RUN curl https://boostorg.jfrog.io/artifactory/main/release/1.68.0/source/boost_1_68_0.tar.bz2 -OL &&\
|
||||
echo '7f6130bc3cf65f56a618888ce9d5ea704fa10b462be126ad053e80e553d6d8b7 boost_1_68_0.tar.bz2' | sha256sum -c - &&\
|
||||
tar -xjf boost_1_68_0.tar.bz2 &&\
|
||||
rm boost_1_68_0.tar.bz2 &&\
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ case $1 in
|
|||
cat <<'EOM'
|
||||
graph_title performance_transactions
|
||||
graph_vlabel mcs
|
||||
graph_category daemon
|
||||
graph_category transactions
|
||||
tx_add_one_tx_time.label tx_add_one_tx_time
|
||||
tx_add_one_tx_time.draw LINE
|
||||
tx_append_time.label tx_append_time
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ case $1 in
|
|||
cat <<'EOM'
|
||||
graph_title performance_tranactions_inp
|
||||
graph_vlabel mcs
|
||||
graph_category daemon.inp
|
||||
graph_category transactions.inp
|
||||
tx_check_inputs_prefix_hash.label prefix_hash
|
||||
tx_check_inputs_prefix_hash.draw AREA
|
||||
tx_check_inputs_attachment_check.label attachment_check
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ case $1 in
|
|||
cat <<'EOM'
|
||||
graph_title performance_tranactions_inp.every_inp
|
||||
graph_vlabel mcs
|
||||
graph_category daemon.inp
|
||||
graph_category transactions.inp
|
||||
tx_check_inputs_loop_kimage_check.label kimage_check
|
||||
tx_check_inputs_loop_kimage_check.draw AREA
|
||||
tx_check_inputs_loop_ch_in_val_sig.label ch_in_val_sig
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ case $1 in
|
|||
cat <<'EOM'
|
||||
graph_title performance_tranactions_inp.every_inp.every_key
|
||||
graph_vlabel mcs
|
||||
graph_category daemon.inp
|
||||
graph_category transactions.inp
|
||||
tx_check_inputs_loop_scan_outputkeys_loop_get_subitem.label get_subitem
|
||||
tx_check_inputs_loop_scan_outputkeys_loop_get_subitem.draw AREA
|
||||
tx_check_inputs_loop_scan_outputkeys_loop_find_tx.label find_tx
|
||||
|
|
|
|||
17
utils/munin_plugins/tx_mixins_count
Executable file
17
utils/munin_plugins/tx_mixins_count
Executable file
|
|
@ -0,0 +1,17 @@
|
|||
#!/bin/bash
|
||||
|
||||
case $1 in
|
||||
config)
|
||||
cat <<'EOM'
|
||||
graph_args --alt-autoscale
|
||||
graph_title mixins
|
||||
graph_vlabel mixins
|
||||
graph_category transactions
|
||||
mixins.label mixins
|
||||
|
||||
EOM
|
||||
exit 0;;
|
||||
esac
|
||||
|
||||
printf "mixins.value "
|
||||
connectivity_tool --ip=127.0.0.1 --rpc-port=$ZANO_RPC_PORT --timeout=1000 --rpc-get-daemon-info --getinfo-flags-hex="0x0000000000010000" | grep tx_mixin_count | cut -d ' ' -f2
|
||||
Loading…
Add table
Reference in a new issue