1
0
Fork 0
forked from lthn/blockchain

merge from develop

This commit is contained in:
cryptozoidberg 2022-04-20 19:12:16 +02:00
commit 5c42da0a84
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
19 changed files with 1975 additions and 858 deletions

View file

@ -693,7 +693,7 @@ bool boosted_tcp_server<t_protocol_handler>::connect(const std::string& adr, con
shared_context->cond.notify_one();
};
sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, _1, local_shared_context));
sock_.async_connect(remote_endpoint, boost::bind<void>(connect_callback, boost::placeholders::_1, local_shared_context));
while(local_shared_context->ec == boost::asio::error::would_block) {
bool r = false;
try {

View file

@ -27,6 +27,7 @@
#pragma once
#include <boost/mpl/vector.hpp>
#include <boost/mpl/contains.hpp>
#include <deque>
namespace epee

View file

@ -267,20 +267,20 @@ namespace epee
#define HANDLE_INVOKE2(command_id, func, type_name_in, typename_out) \
if(!is_notify && command_id == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in, typename_out>(this, command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);}
#define HANDLE_INVOKE_T2(COMMAND, func) \
if(!is_notify && COMMAND::ID == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, _1, _2, _3, _4), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename COMMAND::request, typename COMMAND::response>(command, in_buff, buff_out, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3, boost::placeholders::_4), context);}
#define HANDLE_NOTIFY2(command_id, func, type_name_in) \
if(is_notify && command_id == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, type_name_in>(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);}
#define HANDLE_NOTIFY_T2(NOTIFY, func) \
if(is_notify && NOTIFY::ID == command) \
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, _1, _2, _3), context);}
{handled=true;return epee::net_utils::buff_to_t_adapter<internal_owner_type_name, typename NOTIFY::request>(this, command, in_buff, boost::bind(func, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3), context);}
#define CHAIN_INVOKE_MAP2(func) \

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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<public_key> L; // size = ceil( log_2(m * n) )
std::vector<public_key> R;
public_key A0;
public_key A;
public_key B;
scalar_t r;
scalar_t s;
scalar_t delta;
};
#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 scalar_vec_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; }
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<CT::c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
aLs.zero();
aRs.zero();
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
for (size_t i = 0; i < values.size(); ++i)
{
const scalar_t& v = values[i];
for (uint8_t j = 0; j < CT::c_bpp_n; ++j)
{
if (v.get_bit(j))
aLs(i, j) = c_scalar_1; // aL = 1, aR = 0
else
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
}
}
for (size_t i = values.size(); i < c_bpp_m; ++i)
for (size_t j = 0; j < CT::c_bpp_n; ++j)
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
// using e as Fiat-Shamir transcript
scalar_t e = CT::get_initial_transcript();
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, commitments);
// 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<CT::c_bpp_n> d(c_bpp_mn);
d(0, 0) = z_sq;
// first row
for (size_t i = 1; i < c_bpp_m; ++i)
d(i, 0) = d(i - 1, 0) * z_sq;
// all rows
for (size_t j = 1; j < CT::c_bpp_n; ++j)
for (size_t i = 0; i < c_bpp_m; ++i)
d(i, j) = d(i, j - 1) + d(i, j - 1);
DBG_PRINT("Hs(d): " << d.calc_hs());
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
// (calculate two more elements (1 and y^(mn+1)) for convenience)
scalar_vec_t y_powers(c_bpp_mn + 2);
y_powers[0] = 1;
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
y_powers[i] = y_powers[i - 1] * y;
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
// aL_hat = aL - 1*z
scalar_vec_t aLs_hat = aLs - z;
// 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<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()
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() . . . . ");
static_assert(CT::c_bpp_n <= 255, "too big N");
const size_t kn = sigs.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
struct intermediate_element_t
{
scalar_t y;
scalar_t z;
scalar_t z_sq;
scalar_vec_t e;
scalar_vec_t e_sq;
scalar_t e_final;
scalar_t e_final_sq;
size_t inv_e_offset; // offset in batch_for_inverse
size_t inv_y_offset; // offset in batch_for_inverse
size_t c_bpp_log2_m;
size_t c_bpp_m;
size_t c_bpp_mn;
point_t A;
point_t A0;
point_t B;
std::vector<point_t> L;
std::vector<point_t> R;
};
std::vector<intermediate_element_t> interms(kn);
size_t c_bpp_log2_m_max = 0;
for (size_t k = 0; k < kn; ++k)
{
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4);
intermediate_element_t& interm = interms[k];
interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size());
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
c_bpp_log2_m_max = interm.c_bpp_log2_m;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5);
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
interm.L.resize(sig.L.size());
interm.R.resize(sig.R.size());
for (size_t i = 0; i < interm.L.size(); ++i)
{
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
}
}
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n;
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n;
//
// prepare stuff
//
/*
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
for (size_t i = 0; i < c_bpp_mn_max; ++i)
{
g[i] = CT::get_generator(false, i);
h[i] = CT::get_generator(true, i);
}
*/
scalar_vec_t batch_for_inverse;
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// restore y and z
// using e as Fiat-Shamir transcript
scalar_t e = CT::get_initial_transcript();
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, bsc.commitments);
// calculate scalar challenges y and z
hsc.add_scalar(e);
hsc.add_pub_key(sig.A0);
hsc.assign_calc_hash(interm.y);
interm.z = hash_helper_t::hs(interm.y);
interm.z_sq = interm.z * interm.z;
DBG_VAL_PRINT(interm.y);
DBG_VAL_PRINT(interm.z);
e = interm.z; // transcript for further steps
interm.inv_y_offset = batch_for_inverse.size();
batch_for_inverse.push_back(interm.y);
interm.inv_e_offset = batch_for_inverse.size();
interm.e.resize(sig.L.size());
interm.e_sq.resize(sig.L.size());
for (size_t i = 0; i < sig.L.size(); ++i)
{
hsc.add_scalar(e);
hsc.add_pub_key(sig.L[i]);
hsc.add_pub_key(sig.R[i]);
hsc.assign_calc_hash(e);
interm.e[i] = e;
interm.e_sq[i] = e * e;
DBG_PRINT("e[" << i << "]: " << e);
batch_for_inverse.push_back(e);
}
hsc.add_scalar(e);
hsc.add_pub_key(sig.A);
hsc.add_pub_key(sig.B);
hsc.assign_calc_hash(interm.e_final);
interm.e_final_sq = interm.e_final * interm.e_final;
DBG_VAL_PRINT(interm.e_final);
}
batch_for_inverse.invert();
// Notation:
// 1_vec ^ n = (1, 1, 1, ..., 1)
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
// y<^n = (y^n, y^(n-1), ..., y^1)
// y>^n = (y^1, y^2, ..., y^n)
// from page 13, Fig 1:
// Verifier outputs Accept IFF the following equality holds (single proof):
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'
// (where g and h are calculated in each round)
// The same equation in additive notation:
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H
// <=>
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*)
// where A, B, r', s', delta' is taken from the signature
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
//
// from page 18, Fig 3:
// P and V computes:
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// (calculated once)
//
// As suggested in Section 6.1 "Practical Optimizations":
// 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20):
//
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
// - e^2 * A_hat
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0 (**)
//
// where:
// g, h - vector of fixed generators
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
//
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
// insert A_hat into (**) =>
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// )
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0
// =>
// (for single signature)
//
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
// + delta' * H | the signatures
//
// - e^2 * A0
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
// - e * A - B = 0 (***)
//
// All (***) will be muptiplied by random weightning factor and then summed up.
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
scalar_vec_t g_scalars;
g_scalars.resize(c_bpp_mn_max, 0);
scalar_vec_t h_scalars;
h_scalars.resize(c_bpp_mn_max, 0);
scalar_t G_scalar = 0;
scalar_t H_scalar = 0;
point_t summand = c_point_0;
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// random weightning factor for speed-optimized batch verification (preprint page 20)
const scalar_t rwf = scalar_t::random();
DBG_PRINT("rwf: " << rwf);
// prepare d vector (see also d structure description in proof function)
scalar_mat_t<CT::c_bpp_n> d(interm.c_bpp_mn);
d(0, 0) = interm.z_sq;
// first row
for (size_t i = 1; i < interm.c_bpp_m; ++i)
d(i, 0) = d(i - 1, 0) * interm.z_sq;
// all rows
for (size_t j = 1; j < CT::c_bpp_n; ++j)
for (size_t i = 0; i < interm.c_bpp_m; ++i)
d(i, j) = d(i, j - 1) + d(i, j - 1);
// sum(d) (see also note in proof function for this)
const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
DBG_PRINT("Hs(d): " << d.calc_hs());
DBG_PRINT("sum(d): " << sum_d);
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
// complexity (sc_mul's): MN+2*log2(MN)-2
// the idea is the following:
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
scalar_vec_t s_vec(interm.c_bpp_mn);
s_vec[0] = get_e_inv(0);
for (size_t i = 1; i < log2_mn; ++i)
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
DBG_PRINT("[0] " << s_vec[0]);
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
{
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
}
// prepare y_inv vector
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
y_inverse_powers[0] = 1;
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
// y^(mn+1)
scalar_t y_power_mnp1 = interm.y;
for (size_t i = 0; i < log2_mn; ++i)
y_power_mnp1 *= y_power_mnp1;
y_power_mnp1 *= interm.y;
DBG_VAL_PRINT(y_power_mnp1);
// now calculate all multiplicands for common generators
// g vector multiplicands:
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
// h vector multiplicands:
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
{
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
rwf_e_sq_y *= interm.y;
}
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
// G point multiplicands:
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
DBG_PRINT("G_scalar: " << G_scalar);
// H point multiplicands:
// rwf * delta
H_scalar += rwf * sig.delta;
DBG_PRINT("H_scalar: " << H_scalar);
// uncommon generators' multiplicands
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
// - rwf * e^2 * A0
summand_8 -= rwf * interm.e_final_sq * interm.A0;
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
for (size_t j = 0; j < bsc.commitments.size(); ++j)
{
e_sq_y_mn1_z_sq_power *= interm.z_sq;
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
}
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
for (size_t j = 0; j < log2_mn; ++j)
{
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
}
// - rwf * e * A - rwf * B = 0
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
summand_8.modify_mul8();
summand += summand_8;
}
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
bool result = 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

View file

@ -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<public_key> L; // size = log_2(m * n)
std::vector<public_key> R;
public_key A0;
public_key A;
public_key B;
scalar_t r;
scalar_t s;
scalar_t delta_1;
scalar_t delta_2;
};
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) std::cout << x << ENDL
template<typename CT>
bool bppe_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const scalar_vec_t& masks2, bppe_signature& sig, std::vector<point_t>& commitments, 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<CT::c_bpp_n> aLs(c_bpp_mn), aRs(c_bpp_mn);
aLs.zero();
aRs.zero();
// m >= values.size, first set up [0..values.size-1], then -- [values.size..m-1] (padding area)
for (size_t i = 0; i < values.size(); ++i)
{
const scalar_t& v = values[i];
for (uint8_t j = 0; j < CT::c_bpp_n; ++j)
{
if (v.get_bit(j))
aLs(i, j) = c_scalar_1; // aL = 1, aR = 0
else
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
}
}
for (size_t i = values.size(); i < c_bpp_m; ++i)
for (size_t j = 0; j < CT::c_bpp_n; ++j)
aRs(i, j) = c_scalar_Lm1; // aL = 0, aR = -1
// using e as Fiat-Shamir transcript
scalar_t e = CT::get_initial_transcript();
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, commitments);
// Zarcanum paper, page 33, Fig. D.3: The prover chooses alpha_1, alpha_2 and computes A = g^aL h^aR h_1^alpha_1 h_2^alpha_2
// so we calculate A0 = alpha_1 * H + alpha_2 * H_2 + SUM(aL_i * G_i) + SUM(aR_i * H_i)
scalar_t alpha_1 = scalar_t::random(), alpha_2 = scalar_t::random();
point_t A0 = alpha_1 * CT::bpp_H + alpha_2 * CT::bpp_H2;
for (size_t i = 0; i < c_bpp_mn; ++i)
A0 += aLs[i] * CT::get_generator(false, i) + aRs[i] * CT::get_generator(true, i);
// part of 1/8 defense scheme
A0 *= c_scalar_1div8;
A0.to_public_key(sig.A0);
DBG_VAL_PRINT(alpha_1);
DBG_VAL_PRINT(alpha_2);
DBG_VAL_PRINT(A0);
// calculate scalar challenges y and z
hsc.add_scalar(e);
hsc.add_pub_key(sig.A0);
scalar_t y = hsc.calc_hash();
scalar_t z = hash_helper_t::hs(y);
e = z; // transcript for further steps
DBG_VAL_PRINT(y);
DBG_VAL_PRINT(z);
// Computing vector d for aggregated version of the protocol (BP+ paper, page 17)
// (note: elements are stored column-by-column in memory)
// d = | 1 * z^(2*1), 1 * z^(2*2), 1 * z^(2*3), ..., 1 * z^(2*m) |
// | 2 * z^(2*1), 2 * z^(2*2), 2 * z^(2*3), ..., 2 * z^(2*m) |
// | 4 * z^(2*1), 4 * z^(2*2), 4 * z^(2*3), ..., 4 * z^(2*m) |
// | ....................................................................................... |
// | 2^(n-1) * z^(2*1), 2^(n-1) * z^(2*2), 2^(n-1) * z^(2*3), ..., 2^(n-1) * z^(2*m)) |
// Note: sum(d_i) = (2^n - 1) * ((z^2)^1 + (z^2)^2 + ... (z^2)^m)) = (2^n-1) * sum_of_powers(x^2, log(m))
scalar_t z_sq = z * z;
scalar_mat_t<CT::c_bpp_n> d(c_bpp_mn);
d(0, 0) = z_sq;
// first row
for (size_t i = 1; i < c_bpp_m; ++i)
d(i, 0) = d(i - 1, 0) * z_sq;
// all rows
for (size_t j = 1; j < CT::c_bpp_n; ++j)
for (size_t i = 0; i < c_bpp_m; ++i)
d(i, j) = d(i, j - 1) + d(i, j - 1);
DBG_PRINT("Hs(d): " << d.calc_hs());
// calculate extended Vandermonde vector y = (1, y, y^2, ..., y^(mn+1)) (BP+ paper, page 18, Fig. 3)
// (calculate two more elements (1 and y^(mn+1)) for convenience)
scalar_vec_t y_powers(c_bpp_mn + 2);
y_powers[0] = 1;
for (size_t i = 1; i <= c_bpp_mn + 1; ++i)
y_powers[i] = y_powers[i - 1] * y;
const scalar_t& y_mn_p1 = y_powers[c_bpp_mn + 1];
DBG_PRINT("Hs(y_powers): " << y_powers.calc_hs());
// aL_hat = aL - 1*z
scalar_vec_t aLs_hat = aLs - z;
// 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<point_t> g(c_bpp_mn), h(c_bpp_mn);
for (size_t i = 0; i < c_bpp_mn; ++i)
{
g[i] = CT::get_generator(false, i);
h[i] = CT::get_generator(true, i);
}
// WIP zk-argument called with zk-WIP(g, h, G, H, H2, A_hat, aL_hat, aR_hat, alpha_hat_1, alpha_hat_2)
scalar_vec_t& a = aLs_hat;
scalar_vec_t& b = aRs_hat;
sig.L.resize(c_bpp_log2_mn);
sig.R.resize(c_bpp_log2_mn);
// zk-WIP reduction rounds (s.a. Zarcanum preprint page 24 Fig. D.1)
for (size_t n = c_bpp_mn / 2, ni = 0; n >= 1; n /= 2, ++ni)
{
DBG_PRINT(ENDL << "#" << ni);
// zk-WIP(g, h, G, H, H2, P, a, b, alpha_1, alpha_2)
scalar_t dL = scalar_t::random(), dL2 = scalar_t::random();
DBG_VAL_PRINT(dL); DBG_VAL_PRINT(dL2);
scalar_t dR = scalar_t::random(), dR2 = scalar_t::random();
DBG_VAL_PRINT(dR); DBG_VAL_PRINT(dR2);
// a = (a1, a2), b = (b1, b2) -- vectors of scalars
// cL = <a1, ((y, y^2, ...) o b2)> -- scalar
scalar_t cL = 0;
for (size_t i = 0; i < n; ++i)
cL += a[i] * y_powers[i + 1] * b[n + i];
DBG_VAL_PRINT(cL);
// cR = <a2, ((y, y^2, ...) o b1)> * y^n -- scalar
scalar_t cR = 0;
for (size_t i = 0; i < n; ++i)
cR += a[n + i] * y_powers[i + 1] * b[i];
cR *= y_powers[n];
DBG_VAL_PRINT(cR);
// L = y^-n * a1 * g2 + b2 * h1 + cL * G + dL * H + dL2 * H2 -- point
point_t sum = c_point_0;
for (size_t i = 0; i < n; ++i)
sum += a[i] * g[n + i];
point_t L;
CT::calc_pedersen_commitment_2(cL, dL, dL2, L);
for (size_t i = 0; i < n; ++i)
L += b[n + i] * h[i];
L += y_inverse_powers[n] * sum;
L *= c_scalar_1div8;
DBG_VAL_PRINT(L);
// R = y^n * a2 * g1 + b1 * h2 + cR * G + dR * H + dR2 * H2 -- point
sum.zero();
for (size_t i = 0; i < n; ++i)
sum += a[n + i] * g[i];
point_t R;
CT::calc_pedersen_commitment_2(cR, dR, dR2, R);
for (size_t i = 0; i < n; ++i)
R += b[i] * h[n + i];
R += y_powers[n] * sum;
R *= c_scalar_1div8;
DBG_VAL_PRINT(R);
// put L, R to the sig
L.to_public_key(sig.L[ni]);
R.to_public_key(sig.R[ni]);
// update the transcript
hsc.add_scalar(e);
hsc.add_pub_key(sig.L[ni]);
hsc.add_pub_key(sig.R[ni]);
e = hsc.calc_hash();
DBG_VAL_PRINT(e);
// recalculate arguments for the next round
scalar_t e_squared = e * e;
scalar_t e_inverse = e.reciprocal();
scalar_t e_inverse_squared = e_inverse * e_inverse;
scalar_t e_y_inv_n = e * y_inverse_powers[n];
scalar_t e_inv_y_n = e_inverse * y_powers[n];
// g_hat = e^-1 * g1 + (e * y^-n) * g2 -- vector of points
for (size_t i = 0; i < n; ++i)
g[i] = e_inverse * g[i] + e_y_inv_n * g[n + i];
// h_hat = e * h1 + e^-1 * h2 -- vector of points
for (size_t i = 0; i < n; ++i)
h[i] = e * h[i] + e_inverse * h[n + i];
// P_hat = e^2 * L + P + e^-2 * R -- point
// a_hat = e * a1 + e^-1 * y^n * a2 -- vector of scalars
for (size_t i = 0; i < n; ++i)
a[i] = e * a[i] + e_inv_y_n * a[n + i];
// b_hat = e^-1 * b1 + e * b2 -- vector of scalars
for (size_t i = 0; i < n; ++i)
b[i] = e_inverse * b[i] + e * b[n + i];
// alpha_hat_1 = e^2 * dL + alpha_1 + e^-2 * dR -- scalar
// alpha_hat_2 = e^2 * dL2 + alpha_2 + e^-2 * dR2 -- scalar
alpha_hat_1 += e_squared * dL + e_inverse_squared * dR;
alpha_hat_2 += e_squared * dL2 + e_inverse_squared * dR2;
// run next iteraton zk-WIP(g_hat, h_hat, G, H, H2, P_hat, a_hat, b_hat, alpha_hat_1, alpha_hat_2)
}
DBG_PRINT("");
// zk-WIP last round
scalar_t r = scalar_t::random();
scalar_t s = scalar_t::random();
scalar_t delta_1 = scalar_t::random(), delta_2 = scalar_t::random();
scalar_t eta_1 = scalar_t::random(), eta_2 = scalar_t::random();
DBG_VAL_PRINT(r);
DBG_VAL_PRINT(s);
DBG_VAL_PRINT(delta_1); DBG_VAL_PRINT(delta_2);
DBG_VAL_PRINT(eta_1); DBG_VAL_PRINT(eta_2);
// A = r * g + s * h + (r y b + s y a) * G + delta_1 * H + delta_2 * H2 -- point
point_t A = c_point_0;
CT::calc_pedersen_commitment_2(y * (r * b[0] + s * a[0]), delta_1, delta_2, A);
A += r * g[0] + s * h[0];
A *= c_scalar_1div8;
A.to_public_key(sig.A);
DBG_VAL_PRINT(A);
// B = (r * y * s) * G + eta_1 * H + eta_2 * H2
point_t B = c_point_0;
CT::calc_pedersen_commitment_2(r * y * s, eta_1, eta_2, B);
B *= c_scalar_1div8;
B.to_public_key(sig.B);
DBG_VAL_PRINT(B);
// update the transcript
hsc.add_scalar(e);
hsc.add_pub_key(sig.A);
hsc.add_pub_key(sig.B);
e = hsc.calc_hash();
DBG_VAL_PRINT(e);
// finalize the signature
sig.r = r + e * a[0];
sig.s = s + e * b[0];
sig.delta_1 = eta_1 + e * delta_1 + e * e * alpha_hat_1;
sig.delta_2 = eta_2 + e * delta_2 + e * e * alpha_hat_2;
DBG_VAL_PRINT(sig.r);
DBG_VAL_PRINT(sig.s);
DBG_VAL_PRINT(sig.delta_1);
DBG_VAL_PRINT(sig.delta_2);
return true;
#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<point_t>& commitments)
: sig(sig)
, commitments(commitments)
{}
const bppe_signature& sig;
const std::vector<point_t>& commitments;
};
template<typename CT>
bool bppe_verify(const std::vector<bppe_sig_commit_ref_t>& sigs, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bppe_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
DBG_PRINT(ENDL << " . . . . bppe_verify() . . . . ");
static_assert(CT::c_bpp_n <= 255, "too big N");
const size_t kn = sigs.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
struct intermediate_element_t
{
scalar_t y;
scalar_t z;
scalar_t z_sq;
scalar_vec_t e;
scalar_vec_t e_sq;
scalar_t e_final;
scalar_t e_final_sq;
size_t inv_e_offset; // offset in batch_for_inverse
size_t inv_y_offset; // offset in batch_for_inverse
size_t c_bpp_log2_m;
size_t c_bpp_m;
size_t c_bpp_mn;
point_t A;
point_t A0;
point_t B;
std::vector<point_t> L;
std::vector<point_t> R;
};
std::vector<intermediate_element_t> interms(kn);
size_t c_bpp_log2_m_max = 0;
for (size_t k = 0; k < kn; ++k)
{
const bppe_sig_commit_ref_t& bsc = sigs[k];
const bppe_signature& sig = bsc.sig;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta_1.is_reduced() && sig.delta_2.is_reduced(), 4);
intermediate_element_t& interm = interms[k];
interm.c_bpp_log2_m = constexpr_ceil_log2(bsc.commitments.size());
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
c_bpp_log2_m_max = interm.c_bpp_log2_m;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + CT::c_bpp_log2_n, 5);
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
interm.c_bpp_mn = interm.c_bpp_m * CT::c_bpp_n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
interm.L.resize(sig.L.size());
interm.R.resize(sig.R.size());
for (size_t i = 0; i < interm.L.size(); ++i)
{
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
}
}
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
const size_t c_bpp_mn_max = c_bpp_m_max * CT::c_bpp_n;
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + CT::c_bpp_log2_n;
//
// prepare stuff
//
/*
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
for (size_t i = 0; i < c_bpp_mn_max; ++i)
{
g[i] = CT::get_generator(false, i);
h[i] = CT::get_generator(true, i);
}
*/
scalar_vec_t batch_for_inverse;
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bppe_sig_commit_ref_t& bsc = sigs[k];
const bppe_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// restore y and z
// using e as Fiat-Shamir transcript
scalar_t e = CT::get_initial_transcript();
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, bsc.commitments);
// calculate scalar challenges y and z
hsc.add_scalar(e);
hsc.add_pub_key(sig.A0);
hsc.assign_calc_hash(interm.y);
interm.z = hash_helper_t::hs(interm.y);
interm.z_sq = interm.z * interm.z;
DBG_VAL_PRINT(interm.y);
DBG_VAL_PRINT(interm.z);
e = interm.z; // transcript for further steps
interm.inv_y_offset = batch_for_inverse.size();
batch_for_inverse.push_back(interm.y);
interm.inv_e_offset = batch_for_inverse.size();
interm.e.resize(sig.L.size());
interm.e_sq.resize(sig.L.size());
for (size_t i = 0; i < sig.L.size(); ++i)
{
hsc.add_scalar(e);
hsc.add_pub_key(sig.L[i]);
hsc.add_pub_key(sig.R[i]);
hsc.assign_calc_hash(e);
interm.e[i] = e;
interm.e_sq[i] = e * e;
DBG_PRINT("e[" << i << "]: " << e);
batch_for_inverse.push_back(e);
}
hsc.add_scalar(e);
hsc.add_pub_key(sig.A);
hsc.add_pub_key(sig.B);
hsc.assign_calc_hash(interm.e_final);
interm.e_final_sq = interm.e_final * interm.e_final;
DBG_VAL_PRINT(interm.e_final);
}
batch_for_inverse.invert();
// Notation:
// 1_vec ^ n = (1, 1, 1, ..., 1)
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
// y<^n = (y^n, y^(n-1), ..., y^1)
// y>^n = (y^1, y^2, ..., y^n)
// from Zarcanum page 24, Fig D.1:
// Verifier outputs Accept IFF the following holds:
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'_1 * H2 ^ delta'_2
// (where g and h are calculated in each round)
// The same equation in additive notation:
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2
// <=>
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 - e^2 * P - e * A - B == 0 (*)
// where A, B, r', s', delta'_1, delta'_2 is taken from the signature
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
//
// from Zarcanum preprint page 33, Fig D.3:
// P and V computes:
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// (calculated once)
//
// As suggested in BPP preprint Section 6.1 "Practical Optimizations":
// 1) g and h exponentianions can be optimized in order not to be calculated at each round
// as the following (page 20, with delta'_2 and H2 added):
//
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 -
// - e^2 * A_hat
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0 (**)
//
// where:
// g, h - vector of fixed generators
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
//
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
// insert A_hat into (**) =>
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta'_1 * H + delta'_2 * H2 -
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// )
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0
// =>
// (for single signature)
//
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
// + delta'_1 * H | the signatures
// + delta'_2 * H2 | the signatures
//
// - e^2 * A0
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
// - e * A - B = 0 (***)
//
// All (***) will be muptiplied by random weightning factor and then summed up.
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
scalar_vec_t g_scalars;
g_scalars.resize(c_bpp_mn_max, 0);
scalar_vec_t h_scalars;
h_scalars.resize(c_bpp_mn_max, 0);
scalar_t G_scalar = 0;
scalar_t H_scalar = 0;
scalar_t H2_scalar = 0;
point_t summand = c_point_0;
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bppe_sig_commit_ref_t& bsc = sigs[k];
const bppe_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// random weightning factor for speed-optimized batch verification (preprint page 20)
const scalar_t rwf = scalar_t::random();
DBG_PRINT("rwf: " << rwf);
// prepare d vector (see also d structure description in proof function)
scalar_mat_t<CT::c_bpp_n> d(interm.c_bpp_mn);
d(0, 0) = interm.z_sq;
// first row
for (size_t i = 1; i < interm.c_bpp_m; ++i)
d(i, 0) = d(i - 1, 0) * interm.z_sq;
// all rows
for (size_t j = 1; j < CT::c_bpp_n; ++j)
for (size_t i = 0; i < interm.c_bpp_m; ++i)
d(i, j) = d(i, j - 1) + d(i, j - 1);
// sum(d) (see also note in proof function for this)
const scalar_t sum_d = CT::get_2_to_the_power_of_N_minus_1() * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
DBG_PRINT("Hs(d): " << d.calc_hs());
DBG_PRINT("sum(d): " << sum_d);
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
// complexity (sc_mul's): MN+2*log2(MN)-2
// the idea is the following:
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
scalar_vec_t s_vec(interm.c_bpp_mn);
s_vec[0] = get_e_inv(0);
for (size_t i = 1; i < log2_mn; ++i)
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
DBG_PRINT("[0] " << s_vec[0]);
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
{
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
}
// prepare y_inv vector
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
y_inverse_powers[0] = 1;
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
// y^(mn+1)
scalar_t y_power_mnp1 = interm.y;
for (size_t i = 0; i < log2_mn; ++i)
y_power_mnp1 *= y_power_mnp1;
y_power_mnp1 *= interm.y;
DBG_VAL_PRINT(y_power_mnp1);
// now calculate all multiplicands for common generators
// g vector multiplicands:
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
// h vector multiplicands:
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
{
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
rwf_e_sq_y *= interm.y;
}
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
// G point multiplicands:
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
DBG_PRINT("G_scalar: " << G_scalar);
// H point multiplicands:
// rwf * delta_1
H_scalar += rwf * sig.delta_1;
DBG_PRINT("H_scalar: " << H_scalar);
// H2 point multiplicands:
// rwf * delta_2
H2_scalar += rwf * sig.delta_2;
DBG_PRINT("H2_scalar: " << H2_scalar);
// uncommon generators' multiplicands
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
// - rwf * e^2 * A0
summand_8 -= rwf * interm.e_final_sq * interm.A0;
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
for (size_t j = 0; j < bsc.commitments.size(); ++j)
{
e_sq_y_mn1_z_sq_power *= interm.z_sq;
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
}
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
for (size_t j = 0; j < log2_mn; ++j)
{
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
}
// - rwf * e * A - rwf * B = 0
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
summand_8.modify_mul8();
summand += summand_8;
}
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment_2(G_scalar, H_scalar, H2_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bppe_verify() -- SUCCEEDED!!!" << ENDL);
return result;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
} // namespace crypto

View file

@ -6,7 +6,4 @@
namespace crypto
{
const point_t& bpp_crypto_trait_zano::bpp_H = c_point_H;
}

View file

@ -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<size_t N = 64, size_t values_max = 16>
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<size_t N, size_t values_max>
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H = c_point_H;
template<size_t N, size_t values_max>
const point_t& bpp_crypto_trait_zano<N, values_max>::bpp_H2 = c_point_H2;
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");
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<point_t>& commitments)
: sig(sig)
, commitments(commitments)
{}
const bpp_signature& sig;
const std::vector<point_t>& commitments;
};
template<typename CT>
bool bpp_verify(const std::vector<bpp_sig_commit_ref_t>& sigs, uint8_t* p_err = nullptr)
{
#define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \
if (!(cond)) { LOG_PRINT_RED("bpp_verify: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \
if (p_err) { *p_err = err_code; } return false; }
DBG_PRINT(ENDL << " . . . . bpp_verify() . . . . ");
const size_t kn = sigs.size();
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(kn > 0, 1);
struct intermediate_element_t
{
scalar_t y;
scalar_t z;
scalar_t z_sq;
scalar_vec_t e;
scalar_vec_t e_sq;
scalar_t e_final;
scalar_t e_final_sq;
size_t inv_e_offset; // offset in batch_for_inverse
size_t inv_y_offset; // offset in batch_for_inverse
size_t c_bpp_log2_m;
size_t c_bpp_m;
size_t c_bpp_mn;
point_t A;
point_t A0;
point_t B;
std::vector<point_t> L;
std::vector<point_t> R;
};
std::vector<intermediate_element_t> interms(kn);
size_t c_bpp_log2_m_max = 0;
for (size_t k = 0; k < kn; ++k)
{
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bsc.commitments.size() > 0, 2);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() > 0 && sig.L.size() == sig.R.size(), 3);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.r.is_reduced() && sig.s.is_reduced() && sig.delta.is_reduced(), 4);
intermediate_element_t& interm = interms[k];
interm.c_bpp_log2_m = calc_exp_power_of_2_upper_bound(bsc.commitments.size());
if (c_bpp_log2_m_max < interm.c_bpp_log2_m)
c_bpp_log2_m_max = interm.c_bpp_log2_m;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(sig.L.size() == interm.c_bpp_log2_m + c_bpp_log2_n, 5);
interm.c_bpp_m = 1ull << interm.c_bpp_log2_m;
interm.c_bpp_mn = interm.c_bpp_m * c_bpp_n;
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A0.from_public_key(sig.A0), 6);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.A.from_public_key(sig.A), 7);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.B.from_public_key(sig.B), 8);
interm.L.resize(sig.L.size());
interm.R.resize(sig.R.size());
for (size_t i = 0; i < interm.L.size(); ++i)
{
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.L[i].from_public_key(sig.L[i]), 9);
CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(interm.R[i].from_public_key(sig.R[i]), 10);
}
}
const size_t c_bpp_m_max = 1ull << c_bpp_log2_m_max;
const size_t c_bpp_mn_max = c_bpp_m_max * c_bpp_n;
const size_t c_bpp_LR_size_max = c_bpp_log2_m_max + c_bpp_log2_n;
//
// prepare stuff
//
/*
std::vector<point_t> g(c_bpp_mn_max), h(c_bpp_mn_max);
for (size_t i = 0; i < c_bpp_mn_max; ++i)
{
g[i] = CT::get_generator(false, i);
h[i] = CT::get_generator(true, i);
}
*/
scalar_vec_t batch_for_inverse;
batch_for_inverse.reserve(kn + kn * c_bpp_LR_size_max);
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// restore y and z
// using e as Fiat-Shamir transcript
scalar_t e = CT::get_initial_transcript();
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, bsc.commitments);
// calculate scalar challenges y and z
hsc.add_scalar(e);
hsc.add_pub_key(sig.A0);
hsc.assign_calc_hash(interm.y);
interm.z = hash_helper_t::hs(interm.y);
interm.z_sq = interm.z * interm.z;
DBG_VAL_PRINT(interm.y);
DBG_VAL_PRINT(interm.z);
e = interm.z; // transcript for further steps
interm.inv_y_offset = batch_for_inverse.size();
batch_for_inverse.push_back(interm.y);
interm.inv_e_offset = batch_for_inverse.size();
interm.e.resize(sig.L.size());
interm.e_sq.resize(sig.L.size());
for (size_t i = 0; i < sig.L.size(); ++i)
{
hsc.add_scalar(e);
hsc.add_pub_key(sig.L[i]);
hsc.add_pub_key(sig.R[i]);
hsc.assign_calc_hash(e);
interm.e[i] = e;
interm.e_sq[i] = e * e;
DBG_PRINT("e[" << i << "]: " << e);
batch_for_inverse.push_back(e);
}
hsc.add_scalar(e);
hsc.add_pub_key(sig.A);
hsc.add_pub_key(sig.B);
hsc.assign_calc_hash(interm.e_final);
interm.e_final_sq = interm.e_final * interm.e_final;
DBG_VAL_PRINT(interm.e_final);
}
batch_for_inverse.invert();
// Notation:
// 1_vec ^ n = (1, 1, 1, ..., 1)
// 2_vec ^ n = (2^0, 2^1, 2^2, ..., 2^(n-1))
// -1_vec ^ n = ((-1)^0, (-1)^1, (-1)^2, ... (-1)^(n-1)) = (1, -1, 1, -1, ...)
// y<^n = (y^n, y^(n-1), ..., y^1)
// y>^n = (y^1, y^2, ..., y^n)
// from page 13, Fig 1:
// Verifier outputs Accept IFF the following equality holds (single proof):
// P^e^2 * A^e * B == g ^ (r' e) * h ^ (s' e) * G ^ (r' y s') * H ^ delta'
// (where g and h are calculated in each round)
// The same equation in additive notation:
// e^2 * P + e * A + B == (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H
// <=>
// (r' * e) * g + (s' * e) * h + (r' y s') * G + delta' * H - e^2 * P - e * A - B == 0 (*)
// where A, B, r', s', delta' is taken from the signature
// and P_{k+1} = e^2 * L_k + P_k + e^-2 * R_k for all rounds
//
// from page 18, Fig 3:
// P and V computes:
// A_hat = A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// (calculated once)
//
// As suggested in Section 6.1 "Practical Optimizations":
// 1) g and h exponentianions can be optimized in order not to be calculated at each round as the following (page 20):
//
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
// - e^2 * A_hat
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0 (**)
//
// where:
// g, h - vector of fixed generators
// s_vec_i = y^(1-i) * PROD{j=1..log(n)}(e_j ^ b(i,j))
// s'_vec_i = PROD{j=1..log(n)}(e_j ^ -b(i,j))
// b(i, j) = { 2 * ((1<<(j-1)) & (i-1)) - 1) (counting both from 1) (page 20)
// b(i, j) = { 2 * ((1<<j) & i) - 1) (counting both from 0)
//
// 2) we gonna aggregate all (**) for each round by multiplying them to a random weights and then sum up
// insert A_hat into (**) =>
// (r' * e * s_vec) * g + (s' * e * s'_vec) * h + (r' y s') * G + delta' * H -
// - e^2 * (A0 + (- 1^(mn) * z) * g + (d o y<^(mn) + 1^(mn) * z) * h +
// + y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j) +
// + (z*SUM(y^>mn) - z*y^(mn+1)*SUM(d) - z^2 * SUM(y^>mn)) * G
// )
// - SUM{j=1..log(n)}(e_final^2 * e_j^2 * L_j + e_final^2 * e_j^-2 * R_j)
// - e * A - B = 0
// =>
// (for single signature)
//
// (r' * e * s_vec - e^2 * (- 1_vec^(mn) * z)) * g | these are
// + (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z)) * h | fixed generators
// + (r' y s' - e^2 * ((z - z^2)*SUM(y^>mn) - z*y^(mn+1)*SUM(d)) * G | across all
// + delta' * H | the signatures
//
// - e^2 * A0
// - e^2 * y^(mn+1) * (SUM{j=1..m} z^(2j) * V_j))
// - e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
// - e * A - B = 0 (***)
//
// All (***) will be muptiplied by random weightning factor and then summed up.
// Calculate cummulative sclalar multiplicand for fixed generators across all the sigs.
scalar_vec_t g_scalars;
g_scalars.resize(c_bpp_mn_max, 0);
scalar_vec_t h_scalars;
h_scalars.resize(c_bpp_mn_max, 0);
scalar_t G_scalar = 0;
scalar_t H_scalar = 0;
point_t summand = c_point_0;
for (size_t k = 0; k < kn; ++k)
{
DBG_PRINT(ENDL << "SIG #" << k);
const bpp_sig_commit_ref_t& bsc = sigs[k];
const bpp_signature& sig = bsc.sig;
intermediate_element_t& interm = interms[k];
// random weightning factor for speed-optimized batch verification (preprint page 20)
const scalar_t rwf = scalar_t::random();
DBG_PRINT("rwf: " << rwf);
// prepare d vector (see also d structure description in proof function)
scalar_mat_t<c_bpp_n> d(interm.c_bpp_mn);
d(0, 0) = interm.z_sq;
// first row
for (size_t i = 1; i < interm.c_bpp_m; ++i)
d(i, 0) = d(i - 1, 0) * interm.z_sq;
// all rows
for (size_t j = 1; j < c_bpp_n; ++j)
for (size_t i = 0; i < interm.c_bpp_m; ++i)
d(i, j) = d(i, j - 1) + d(i, j - 1);
// sum(d) (see also note in proof function for this)
static const scalar_t c_scalar_2_power_n_minus_1 = { 0xffffffffffffffff, 0x0000000000000000, 0x0000000000000000, 0x0000000000000000 };
const scalar_t sum_d = c_scalar_2_power_n_minus_1 * sum_of_powers(interm.z_sq, interm.c_bpp_log2_m);
DBG_PRINT("Hs(d): " << d.calc_hs());
DBG_PRINT("sum(d): " << sum_d);
const scalar_t& y_inv = batch_for_inverse[interm.inv_y_offset];
auto get_e_inv = [&](size_t i) { return batch_for_inverse[interm.inv_e_offset + i]; }; // i belongs to [0; L.size()-1]
// prepare s_vec (unlike the paper here we moved y-component out of s_vec for convenience, so s_vec'[x] = s_vec[~x & (MN-1)])
// complexity (sc_mul's): MN+2*log2(MN)-2
// the idea is the following:
// s_vec[00000b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^-1 * (e_1)^-1 * (e_0)^-1
// s_vec[00101b] = ... * (e_4)^-1 * (e_3)^-1 * (e_2)^+1 * (e_1)^-1 * (e_0)^+1
const size_t log2_mn = sig.L.size(); // at the beginning we made sure that sig.L.size() == c_bpp_log2_m + c_bpp_log2_n
scalar_vec_t s_vec(interm.c_bpp_mn);
s_vec[0] = get_e_inv(0);
for (size_t i = 1; i < log2_mn; ++i)
s_vec[0] *= get_e_inv(i); // s_vec[0] = (e_0)^-1 * (e_1)^-1 * .. (e_{log2_mn-1})^-1
DBG_PRINT("[0] " << s_vec[0]);
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
{
size_t base_el_index = i & (i - 1); // base element index: 0, 0, 2, 0, 4, 4, 6, 0, 8, 8, 10... base element differs in one bit (0) from the current one (1)
size_t bit_index = log2_mn - calc_lsb_32((uint32_t)i) - 1; // the bit index where current element has the difference with the base
s_vec[i] = s_vec[base_el_index] * interm.e_sq[bit_index]; // (e_j)^-1 * (e_j)^2 = (e_j)^+1
DBG_PRINT("[" << i << "] " << " " << base_el_index << ", " << bit_index << " : " << s_vec[i]);
}
// prepare y_inv vector
scalar_vec_t y_inverse_powers(interm.c_bpp_mn);
y_inverse_powers[0] = 1;
for (size_t i = 1; i < interm.c_bpp_mn; ++i)
y_inverse_powers[i] = y_inverse_powers[i - 1] * y_inv;
// y^(mn+1)
scalar_t y_power_mnp1 = interm.y;
for (size_t i = 0; i < log2_mn; ++i)
y_power_mnp1 *= y_power_mnp1;
y_power_mnp1 *= interm.y;
DBG_VAL_PRINT(y_power_mnp1);
// now calculate all multiplicands for common generators
// g vector multiplicands:
// rwf * (r' * e * (1, y^-1, y^-2, ...) o s_vec + e^2 * z) =
// rwf * r' * e * ((1, y^-1, ...) o s_vec) + rwf * e^2 * z * (1, 1, ...)
scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_r_e = rwf * interm.e_final * sig.r;
for (size_t i = 0; i < interm.c_bpp_mn; ++i)
g_scalars[i] += rwf_r_e * y_inverse_powers[i] * s_vec[i] + rwf_e_sq_z;
DBG_PRINT("Hs(g_scalars): " << g_scalars.calc_hs());
// h vector multiplicands:
// rwf * (s' * e * s'_vec - e^2 * (d o y<^(mn) + 1_vec^(mn) * z))
// rwf * s' * e * s'_vec - rwf * e^2 * z * (1, 1...) - rwf * e^2 * (d o y<^(mn))
//scalar_t rwf_e_sq_z = rwf * interm.e_final_sq * interm.z;
scalar_t rwf_s_e = rwf * sig.s * interm.e_final;
scalar_t rwf_e_sq_y = rwf * interm.e_final_sq * interm.y;
for (size_t i = interm.c_bpp_mn - 1; i != SIZE_MAX; --i)
{
h_scalars[i] += rwf_s_e * s_vec[interm.c_bpp_mn - 1 - i] - rwf_e_sq_z - rwf_e_sq_y * d[i];
rwf_e_sq_y *= interm.y;
}
DBG_PRINT("Hs(h_scalars): " << h_scalars.calc_hs());
// G point multiplicands:
// rwf * (r' y s' - e ^ 2 * ((z - z ^ 2)*SUM(y^>mn) - z * y^(mn+1) * SUM(d)) =
// = rwf * r' y s' - rwf * e^2 * (z - z ^ 2)*SUM(y^>mn) + rwf * e^2 * z * y^(mn+1) * SUM(d)
G_scalar += rwf * sig.r * interm.y * sig.s + rwf_e_sq_y * sum_d * interm.z;
G_scalar -= rwf * interm.e_final_sq * (interm.z - interm.z_sq) * sum_of_powers(interm.y, log2_mn);
DBG_PRINT("sum_y: " << sum_of_powers(interm.y, log2_mn));
DBG_PRINT("G_scalar: " << G_scalar);
// H point multiplicands:
// rwf * delta
H_scalar += rwf * sig.delta;
DBG_PRINT("H_scalar: " << H_scalar);
// uncommon generators' multiplicands
point_t summand_8 = c_point_0; // this summand to be multiplied by 8 before adding to the main summand
// - rwf * e^2 * A0
summand_8 -= rwf * interm.e_final_sq * interm.A0;
DBG_PRINT("A0_scalar: " << c_scalar_Lm1 * interm.e_final_sq * rwf);
// - rwf * e^2 * y^(mn+1) * (SUM{j=1..m} (z^2)^j * V_j))
scalar_t e_sq_y_mn1_z_sq_power = rwf * interm.e_final_sq * y_power_mnp1;
for (size_t j = 0; j < bsc.commitments.size(); ++j)
{
e_sq_y_mn1_z_sq_power *= interm.z_sq;
summand_8 -= e_sq_y_mn1_z_sq_power * bsc.commitments[j];
DBG_PRINT("V_scalar[" << j << "]: " << c_scalar_Lm1 * e_sq_y_mn1_z_sq_power);
}
// - rwf * e^2 * SUM{j=1..log(n)}(e_j^2 * L_j + e_j^-2 * R_j)
scalar_t rwf_e_sq = rwf * interm.e_final_sq;
for (size_t j = 0; j < log2_mn; ++j)
{
summand_8 -= rwf_e_sq * (interm.e_sq[j] * interm.L[j] + get_e_inv(j) * get_e_inv(j) * interm.R[j]);
DBG_PRINT("L_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * interm.e_sq[j]);
DBG_PRINT("R_scalar[" << j << "]: " << c_scalar_Lm1 * rwf_e_sq * get_e_inv(j) * get_e_inv(j));
}
// - rwf * e * A - rwf * B = 0
summand_8 -= rwf * interm.e_final * interm.A + rwf * interm.B;
DBG_PRINT("A_scalar: " << c_scalar_Lm1 * rwf * interm.e_final);
DBG_PRINT("B_scalar: " << c_scalar_Lm1 * rwf);
summand_8.modify_mul8();
summand += summand_8;
}
point_t GH_exponents = c_point_0;
CT::calc_pedersen_commitment(G_scalar, H_scalar, GH_exponents);
bool result = multiexp_and_check_being_zero<CT>(g_scalars, h_scalars, summand + GH_exponents);
if (result)
DBG_PRINT(ENDL << " . . . . bpp_verify() -- SUCCEEDED!!!" << ENDL);
return result;
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
} // namespace crypto
#include "range_proof_bpp.h"
#include "range_proof_bppe.h"

View file

@ -7,6 +7,7 @@
#pragma once
#include <boost/lexical_cast.hpp>
#include <boost/bind/placeholders.hpp>
#include "console_handler.h"
#include "p2p/net_node.h"
@ -18,6 +19,8 @@
#include "serialization/binary_utils.h"
#include "simplewallet/password_container.h"
namespace ph = boost::placeholders;
PUSH_VS_WARNINGS
DISABLE_VS_WARNINGS(4100)
@ -31,49 +34,49 @@ class daemon_commands_handler
public:
daemon_commands_handler(nodetool::node_server<currency::t_currency_protocol_handler<currency::core> >& srv, currency::core_rpc_server& rpc) :m_srv(srv), m_rpc(rpc)
{
m_cmd_binder.set_handler("help", boost::bind(&console_handlers_binder::help, &m_cmd_binder, _1), "Show this help");
m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_commands_handler::print_pl, this, _1), "Print peer list");
m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_commands_handler::print_cn, this, _1), "Print connections");
m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_commands_handler::print_bc, this, _1), "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]");
m_cmd_binder.set_handler("print_bc_tx", boost::bind(&daemon_commands_handler::print_bc_tx, this, _1), "Print blockchain info with trnsactions in a given blocks range, print_bc <begin_height> [<end_height>]");
//m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_commands_handler::print_bci, this, _1));
m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_commands_handler::print_bc_outs, this, _1));
m_cmd_binder.set_handler("print_market", boost::bind(&daemon_commands_handler::print_market, this, _1));
m_cmd_binder.set_handler("print_bc_outs_stats", boost::bind(&daemon_commands_handler::print_bc_outs_stats, this, _1));
m_cmd_binder.set_handler("print_block", boost::bind(&daemon_commands_handler::print_block, this, _1), "Print block, print_block <block_hash> | <block_height>");
m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_commands_handler::print_block_info, this, _1), "Print block info, print_block <block_hash> | <block_height>");
m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, _1), "Print tx prunning info");
m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, _1), "Print transaction, print_tx <transaction_hash>");
m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, _1), "Start mining for specified address, start_mining <addr> [threads=1]");
m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, _1), "Stop mining");
m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, _1), "Print transaction pool (long format)");
m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, _1), "Print transaction pool (short format)");
m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_commands_handler::show_hr, this, _1), "Start showing hash rate");
m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_commands_handler::hide_hr, this, _1), "Stop showing hash rate");
m_cmd_binder.set_handler("save", boost::bind(&daemon_commands_handler::save, this, _1), "Save blockchain");
m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_commands_handler::print_daemon_stat, this, _1), "Print daemon stat");
m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_commands_handler::print_debug_stat, this, _1), "Print debug stat info");
m_cmd_binder.set_handler("get_transactions_statics", boost::bind(&daemon_commands_handler::get_transactions_statistics, this, _1), "Calculates transactions statistics");
m_cmd_binder.set_handler("force_relay_tx_pool", boost::bind(&daemon_commands_handler::force_relay_tx_pool, this, _1), "re-relay all transactions from pool");
m_cmd_binder.set_handler("enable_channel", boost::bind(&daemon_commands_handler::enable_channel, this, _1), "Enable specified log channel");
m_cmd_binder.set_handler("disable_channel", boost::bind(&daemon_commands_handler::disable_channel, this, _1), "Enable specified log channel");
m_cmd_binder.set_handler("clear_cache", boost::bind(&daemon_commands_handler::clear_cache, this, _1), "Clear blockchain storage cache");
m_cmd_binder.set_handler("clear_altblocks", boost::bind(&daemon_commands_handler::clear_altblocks, this, _1), "Clear blockchain storage cache");
m_cmd_binder.set_handler("truncate_bc", boost::bind(&daemon_commands_handler::truncate_bc, this, _1), "Truncate blockchain to specified height");
m_cmd_binder.set_handler("inspect_block_index", boost::bind(&daemon_commands_handler::inspect_block_index, this, _1), "Inspects block index for internal errors");
m_cmd_binder.set_handler("print_db_performance_data", boost::bind(&daemon_commands_handler::print_db_performance_data, this, _1), "Dumps all db containers performance counters");
m_cmd_binder.set_handler("search_by_id", boost::bind(&daemon_commands_handler::search_by_id, this, _1), "Search all possible elemets by given id");
m_cmd_binder.set_handler("find_key_image", boost::bind(&daemon_commands_handler::find_key_image, this, _1), "Try to find tx related to key_image");
m_cmd_binder.set_handler("rescan_aliases", boost::bind(&daemon_commands_handler::rescan_aliases, this, _1), "Debug function");
m_cmd_binder.set_handler("forecast_difficulty", boost::bind(&daemon_commands_handler::forecast_difficulty, this, _1), "Prints PoW and PoS difficulties for as many future blocks as possible based on current conditions");
m_cmd_binder.set_handler("print_deadlock_guard", boost::bind(&daemon_commands_handler::print_deadlock_guard, this, _1), "Print all threads which is blocked or involved in mutex ownership");
m_cmd_binder.set_handler("print_block_from_hex_blob", boost::bind(&daemon_commands_handler::print_block_from_hex_blob, this, _1), "Unserialize block from hex binary data to json-like representation");
m_cmd_binder.set_handler("print_tx_from_hex_blob", boost::bind(&daemon_commands_handler::print_tx_from_hex_blob, this, _1), "Unserialize transaction from hex binary data to json-like representation");
m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, _1), "Analyse if tx outputs for involved in subsequent transactions");
m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, _1), "Print difficulties of last n blocks");
m_cmd_binder.set_handler("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, _1), "<ip-address> - If node got connected put node into 'debug mode' i.e. no sync process of other communication except ping responses, maintenance secrete key will be requested");
m_cmd_binder.set_handler("help", boost::bind(&console_handlers_binder::help, &m_cmd_binder, ph::_1), "Show this help");
m_cmd_binder.set_handler("print_pl", boost::bind(&daemon_commands_handler::print_pl, this, ph::_1), "Print peer list");
m_cmd_binder.set_handler("print_cn", boost::bind(&daemon_commands_handler::print_cn, this, ph::_1), "Print connections");
m_cmd_binder.set_handler("print_bc", boost::bind(&daemon_commands_handler::print_bc, this, ph::_1), "Print blockchain info in a given blocks range, print_bc <begin_height> [<end_height>]");
m_cmd_binder.set_handler("print_bc_tx", boost::bind(&daemon_commands_handler::print_bc_tx, this, ph::_1), "Print blockchain info with trnsactions in a given blocks range, print_bc <begin_height> [<end_height>]");
//m_cmd_binder.set_handler("print_bci", boost::bind(&daemon_commands_handler::print_bci, this, ph::_1));
m_cmd_binder.set_handler("print_bc_outs", boost::bind(&daemon_commands_handler::print_bc_outs, this, ph::_1));
m_cmd_binder.set_handler("print_market", boost::bind(&daemon_commands_handler::print_market, this, ph::_1));
m_cmd_binder.set_handler("print_bc_outs_stats", boost::bind(&daemon_commands_handler::print_bc_outs_stats, this, ph::_1));
m_cmd_binder.set_handler("print_block", boost::bind(&daemon_commands_handler::print_block, this, ph::_1), "Print block, print_block <block_hash> | <block_height>");
m_cmd_binder.set_handler("print_block_info", boost::bind(&daemon_commands_handler::print_block_info, this, ph::_1), "Print block info, print_block <block_hash> | <block_height>");
m_cmd_binder.set_handler("print_tx_prun_info", boost::bind(&daemon_commands_handler::print_tx_prun_info, this, ph::_1), "Print tx prunning info");
m_cmd_binder.set_handler("print_tx", boost::bind(&daemon_commands_handler::print_tx, this, ph::_1), "Print transaction, print_tx <transaction_hash>");
m_cmd_binder.set_handler("start_mining", boost::bind(&daemon_commands_handler::start_mining, this, ph::_1), "Start mining for specified address, start_mining <addr> [threads=1]");
m_cmd_binder.set_handler("stop_mining", boost::bind(&daemon_commands_handler::stop_mining, this, ph::_1), "Stop mining");
m_cmd_binder.set_handler("print_pool", boost::bind(&daemon_commands_handler::print_pool, this, ph::_1), "Print transaction pool (long format)");
m_cmd_binder.set_handler("print_pool_sh", boost::bind(&daemon_commands_handler::print_pool_sh, this, ph::_1), "Print transaction pool (short format)");
m_cmd_binder.set_handler("show_hr", boost::bind(&daemon_commands_handler::show_hr, this, ph::_1), "Start showing hash rate");
m_cmd_binder.set_handler("hide_hr", boost::bind(&daemon_commands_handler::hide_hr, this, ph::_1), "Stop showing hash rate");
m_cmd_binder.set_handler("save", boost::bind(&daemon_commands_handler::save, this, ph::_1), "Save blockchain");
m_cmd_binder.set_handler("print_daemon_stat", boost::bind(&daemon_commands_handler::print_daemon_stat, this, ph::_1), "Print daemon stat");
m_cmd_binder.set_handler("print_debug_stat", boost::bind(&daemon_commands_handler::print_debug_stat, this, ph::_1), "Print debug stat info");
m_cmd_binder.set_handler("get_transactions_statics", boost::bind(&daemon_commands_handler::get_transactions_statistics, this, ph::_1), "Calculates transactions statistics");
m_cmd_binder.set_handler("force_relay_tx_pool", boost::bind(&daemon_commands_handler::force_relay_tx_pool, this, ph::_1), "re-relay all transactions from pool");
m_cmd_binder.set_handler("enable_channel", boost::bind(&daemon_commands_handler::enable_channel, this, ph::_1), "Enable specified log channel");
m_cmd_binder.set_handler("disable_channel", boost::bind(&daemon_commands_handler::disable_channel, this, ph::_1), "Enable specified log channel");
m_cmd_binder.set_handler("clear_cache", boost::bind(&daemon_commands_handler::clear_cache, this, ph::_1), "Clear blockchain storage cache");
m_cmd_binder.set_handler("clear_altblocks", boost::bind(&daemon_commands_handler::clear_altblocks, this, ph::_1), "Clear blockchain storage cache");
m_cmd_binder.set_handler("truncate_bc", boost::bind(&daemon_commands_handler::truncate_bc, this, ph::_1), "Truncate blockchain to specified height");
m_cmd_binder.set_handler("inspect_block_index", boost::bind(&daemon_commands_handler::inspect_block_index, this, ph::_1), "Inspects block index for internal errors");
m_cmd_binder.set_handler("print_db_performance_data", boost::bind(&daemon_commands_handler::print_db_performance_data, this, ph::_1), "Dumps all db containers performance counters");
m_cmd_binder.set_handler("search_by_id", boost::bind(&daemon_commands_handler::search_by_id, this, ph::_1), "Search all possible elemets by given id");
m_cmd_binder.set_handler("find_key_image", boost::bind(&daemon_commands_handler::find_key_image, this, ph::_1), "Try to find tx related to key_image");
m_cmd_binder.set_handler("rescan_aliases", boost::bind(&daemon_commands_handler::rescan_aliases, this, ph::_1), "Debug function");
m_cmd_binder.set_handler("forecast_difficulty", boost::bind(&daemon_commands_handler::forecast_difficulty, this, ph::_1), "Prints PoW and PoS difficulties for as many future blocks as possible based on current conditions");
m_cmd_binder.set_handler("print_deadlock_guard", boost::bind(&daemon_commands_handler::print_deadlock_guard, this, ph::_1), "Print all threads which is blocked or involved in mutex ownership");
m_cmd_binder.set_handler("print_block_from_hex_blob", boost::bind(&daemon_commands_handler::print_block_from_hex_blob, this, ph::_1), "Unserialize block from hex binary data to json-like representation");
m_cmd_binder.set_handler("print_tx_from_hex_blob", boost::bind(&daemon_commands_handler::print_tx_from_hex_blob, this, ph::_1), "Unserialize transaction from hex binary data to json-like representation");
m_cmd_binder.set_handler("print_tx_outputs_usage", boost::bind(&daemon_commands_handler::print_tx_outputs_usage, this, ph::_1), "Analyse if tx outputs for involved in subsequent transactions");
m_cmd_binder.set_handler("print_difficulties_of_last_n_blocks", boost::bind(&daemon_commands_handler::print_difficulties_of_last_n_blocks, this, ph::_1), "Print difficulties of last n blocks");
m_cmd_binder.set_handler("debug_remote_node_mode", boost::bind(&daemon_commands_handler::debug_remote_node_mode, this, ph::_1), "<ip-address> - If node got connected put node into 'debug mode' i.e. no sync process of other communication except ping responses, maintenance secrete key will be requested");
#ifdef _DEBUG
m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, _1), "DEBUG: set core time adjustment");
m_cmd_binder.set_handler("debug_set_time_adj", boost::bind(&daemon_commands_handler::debug_set_time_adj, this, ph::_1), "DEBUG: set core time adjustment");
#endif
}

View file

@ -33,6 +33,7 @@ using namespace epee;
using namespace currency;
using boost::lexical_cast;
namespace po = boost::program_options;
namespace ph = boost::placeholders;
#define EXTENDED_LOGS_FILE "wallet_details.log"
@ -179,49 +180,49 @@ simple_wallet::simple_wallet()
m_refresh_progress_reporter(*this),
m_offline_mode(false)
{
m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, _1), "start_mining <threads_count> - Start mining in daemon");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, _1), "Stop mining in daemon");
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, _1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, _1), "Show current wallet balance");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, _1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, _1), "incoming_transfers counts");
m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, _1), "list_recent_transfers [offset] [count] - Show recent maximum 1000 transfers, offset default = 0, count default = 100 ");
m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, _1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, _1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs");
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, _1), "dump_transfers - Write transfers in json to dump_transfers.txt");
m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, _1), "dump_keyimages - Write key_images in json to dump_key_images.txt");
m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, _1), "payments <payment_id_1> [<payment_id_2> ... <payment_id_N>] - Show payments <payment_id_1>, ... <payment_id_N>");
m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this, _1), "Show blockchain height");
m_cmd_binder.set_handler("wallet_bc_height", boost::bind(&simple_wallet::show_wallet_bcheight, this, _1), "Show blockchain height");
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this, _1), "transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available), <payment_id> is an optional HEX-encoded string");
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this, _1), "set_log <level> - Change current log detalisation level, <level> is a number 0-4");
m_cmd_binder.set_handler("enable_console_logger", boost::bind(&simple_wallet::enable_console_logger, this, _1), "Enables console logging");
m_cmd_binder.set_handler("resync", boost::bind(&simple_wallet::resync_wallet, this, _1), "Causes wallet to reset all transfers and re-synchronize wallet");
m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), "Show this help");
m_cmd_binder.set_handler("get_transfer_info", boost::bind(&simple_wallet::get_transfer_info, this, _1), "displays transfer info by key_image or index");
m_cmd_binder.set_handler("scan_for_collision", boost::bind(&simple_wallet::scan_for_key_image_collisions, this, _1), "Rescan transfers for key image collisions");
m_cmd_binder.set_handler("fix_collisions", boost::bind(&simple_wallet::fix_collisions, this, _1), "Rescan transfers for key image collisions");
m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this, _1), "Rescan transfers for tx_id");
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this, _1), "Rescan transfers for key image");
m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this, _1), "Prints utxo distribution");
m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this, _1), "sweep_below <mixin_count> <address> <amount_lower_limit> [payment_id] - Tries to transfers all coins with amount below the given limit to the given address");
m_cmd_binder.set_handler("start_mining", boost::bind(&simple_wallet::start_mining, this, ph::_1), "start_mining <threads_count> - Start mining in daemon");
m_cmd_binder.set_handler("stop_mining", boost::bind(&simple_wallet::stop_mining, this, ph::_1), "Stop mining in daemon");
m_cmd_binder.set_handler("refresh", boost::bind(&simple_wallet::refresh, this, ph::_1), "Resynchronize transactions and balance");
m_cmd_binder.set_handler("balance", boost::bind(&simple_wallet::show_balance, this, ph::_1), "Show current wallet balance");
m_cmd_binder.set_handler("incoming_transfers", boost::bind(&simple_wallet::show_incoming_transfers, this, ph::_1), "incoming_transfers [available|unavailable] - Show incoming transfers - all of them or filter them by availability");
m_cmd_binder.set_handler("incoming_counts", boost::bind(&simple_wallet::show_incoming_transfers_counts, this, ph::_1), "incoming_transfers counts");
m_cmd_binder.set_handler("list_recent_transfers", boost::bind(&simple_wallet::list_recent_transfers, this, ph::_1), "list_recent_transfers [offset] [count] - Show recent maximum 1000 transfers, offset default = 0, count default = 100 ");
m_cmd_binder.set_handler("export_recent_transfers", boost::bind(&simple_wallet::export_recent_transfers, this, ph::_1), "list_recent_transfers_tx - Write recent transfer in json to wallet_recent_transfers.txt");
m_cmd_binder.set_handler("list_outputs", boost::bind(&simple_wallet::list_outputs, this, ph::_1), "list_outputs [spent|unspent] - Lists all the outputs that have ever been sent to this wallet if called without arguments, otherwise it lists only the spent or unspent outputs");
m_cmd_binder.set_handler("dump_transfers", boost::bind(&simple_wallet::dump_trunsfers, this, ph::_1), "dump_transfers - Write transfers in json to dump_transfers.txt");
m_cmd_binder.set_handler("dump_keyimages", boost::bind(&simple_wallet::dump_key_images, this, ph::_1), "dump_keyimages - Write key_images in json to dump_key_images.txt");
m_cmd_binder.set_handler("payments", boost::bind(&simple_wallet::show_payments, this, ph::_1), "payments <payment_id_1> [<payment_id_2> ... <payment_id_N>] - Show payments <payment_id_1>, ... <payment_id_N>");
m_cmd_binder.set_handler("bc_height", boost::bind(&simple_wallet::show_blockchain_height, this,ph::_1), "Show blockchain height");
m_cmd_binder.set_handler("wallet_bc_height", boost::bind(&simple_wallet::show_wallet_bcheight, this,ph::_1), "Show blockchain height");
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer, this,ph::_1), "transfer <mixin_count> <addr_1> <amount_1> [<addr_2> <amount_2> ... <addr_N> <amount_N>] [payment_id] - Transfer <amount_1>,... <amount_N> to <address_1>,... <address_N>, respectively. <mixin_count> is the number of transactions yours is indistinguishable from (from 0 to maximum available), <payment_id> is an optional HEX-encoded string");
m_cmd_binder.set_handler("set_log", boost::bind(&simple_wallet::set_log, this,ph::_1), "set_log <level> - Change current log detalisation level, <level> is a number 0-4");
m_cmd_binder.set_handler("enable_console_logger", boost::bind(&simple_wallet::enable_console_logger, this,ph::_1), "Enables console logging");
m_cmd_binder.set_handler("resync", boost::bind(&simple_wallet::resync_wallet, this,ph::_1), "Causes wallet to reset all transfers and re-synchronize wallet");
m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this,ph::_1), "Show this help");
m_cmd_binder.set_handler("get_transfer_info", boost::bind(&simple_wallet::get_transfer_info, this,ph::_1), "displays transfer info by key_image or index");
m_cmd_binder.set_handler("scan_for_collision", boost::bind(&simple_wallet::scan_for_key_image_collisions, this,ph::_1), "Rescan transfers for key image collisions");
m_cmd_binder.set_handler("fix_collisions", boost::bind(&simple_wallet::fix_collisions, this,ph::_1), "Rescan transfers for key image collisions");
m_cmd_binder.set_handler("scan_transfers_for_id", boost::bind(&simple_wallet::scan_transfers_for_id, this,ph::_1), "Rescan transfers for tx_id");
m_cmd_binder.set_handler("scan_transfers_for_ki", boost::bind(&simple_wallet::scan_transfers_for_ki, this,ph::_1), "Rescan transfers for key image");
m_cmd_binder.set_handler("print_utxo_distribution", boost::bind(&simple_wallet::print_utxo_distribution, this,ph::_1), "Prints utxo distribution");
m_cmd_binder.set_handler("sweep_below", boost::bind(&simple_wallet::sweep_below, this,ph::_1), "sweep_below <mixin_count> <address> <amount_lower_limit> [payment_id] - Tries to transfers all coins with amount below the given limit to the given address");
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this, _1), "Show current wallet public address");
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this, _1), "integrated_address [<payment_id>|<integrated_address] - encodes given payment_id along with wallet's address into an integrated address (random payment_id will be used if none is provided). Decodes given integrated_address into standard address");
m_cmd_binder.set_handler("show_seed", boost::bind(&simple_wallet::show_seed, this, _1), "Display secret 24 word phrase that could be used to recover this wallet");
m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), "Display secret spend key");
m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this, _1), "Display secret view key");
m_cmd_binder.set_handler("address", boost::bind(&simple_wallet::print_address, this,ph::_1), "Show current wallet public address");
m_cmd_binder.set_handler("integrated_address", boost::bind(&simple_wallet::integrated_address, this,ph::_1), "integrated_address [<payment_id>|<integrated_address] - encodes given payment_id along with wallet's address into an integrated address (random payment_id will be used if none is provided). Decodes given integrated_address into standard address");
m_cmd_binder.set_handler("show_seed", boost::bind(&simple_wallet::show_seed, this,ph::_1), "Display secret 24 word phrase that could be used to recover this wallet");
m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this,ph::_1), "Display secret spend key");
m_cmd_binder.set_handler("viewkey", boost::bind(&simple_wallet::viewkey, this,ph::_1), "Display secret view key");
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this, _1), "Get transaction one-time secret key (r) for a given <txid>");
m_cmd_binder.set_handler("get_tx_key", boost::bind(&simple_wallet::get_tx_key, this,ph::_1), "Get transaction one-time secret key (r) for a given <txid>");
m_cmd_binder.set_handler("tracking_seed", boost::bind(&simple_wallet::tracking_seed, this, _1), "For auditable wallets: prints tracking seed for wallet's audit by a third party");
m_cmd_binder.set_handler("tracking_seed", boost::bind(&simple_wallet::tracking_seed, this,ph::_1), "For auditable wallets: prints tracking seed for wallet's audit by a third party");
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this, _1), "Save wallet synchronized data");
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this, _1), "save_watch_only <filename> <password> - save as watch-only wallet file.");
m_cmd_binder.set_handler("save", boost::bind(&simple_wallet::save, this,ph::_1), "Save wallet synchronized data");
m_cmd_binder.set_handler("save_watch_only", boost::bind(&simple_wallet::save_watch_only, this,ph::_1), "save_watch_only <filename> <password> - save as watch-only wallet file.");
m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this, _1), "sign_transfer <unsgined_tx_file> <signed_tx_file> - sign unsigned tx from a watch-only wallet");
m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this, _1), "submit_transfer <signed_tx_file> - broadcast signed tx");
m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this, _1), "Export transaction history in CSV file");
m_cmd_binder.set_handler("sign_transfer", boost::bind(&simple_wallet::sign_transfer, this,ph::_1), "sign_transfer <unsgined_tx_file> <signed_tx_file> - sign unsigned tx from a watch-only wallet");
m_cmd_binder.set_handler("submit_transfer", boost::bind(&simple_wallet::submit_transfer, this,ph::_1), "submit_transfer <signed_tx_file> - broadcast signed tx");
m_cmd_binder.set_handler("export_history", boost::bind(&simple_wallet::submit_transfer, this,ph::_1), "Export transaction history in CSV file");
m_cmd_binder.set_handler("tor_enable", boost::bind(&simple_wallet::tor_enable, this, _1), "Enable relaying transactions over TOR network(enabled by default)");
m_cmd_binder.set_handler("tor_disable", boost::bind(&simple_wallet::tor_disable, this, _1), "Enable relaying transactions over TOR network(enabled by default)");
}

View file

@ -997,10 +997,10 @@ void append_vector_by_another_vector(U& dst, const V& src)
#define REGISTER_CALLBACK(CB_NAME, CLBACK) \
register_callback(CB_NAME, boost::bind(&CLBACK, this, _1, _2, _3));
register_callback(CB_NAME, boost::bind(&CLBACK, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))
#define REGISTER_CALLBACK_METHOD(CLASS, METHOD) \
register_callback(#METHOD, boost::bind(&CLASS::METHOD, this, _1, _2, _3));
register_callback(#METHOD, boost::bind(&CLASS::METHOD, this, boost::placeholders::_1, boost::placeholders::_2, boost::placeholders::_3))
#define MAKE_GENESIS_BLOCK(VEC_EVENTS, BLK_NAME, MINER_ACC, TS) \
test_generator generator; \

View file

@ -667,6 +667,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_options, arg_enable_debug_asserts);
command_line::add_arg(desc_options, command_line::arg_data_dir, std::string("."));
command_line::add_arg(desc_options, command_line::arg_stop_after_height);
command_line::add_arg(desc_options, command_line::arg_disable_ntp);
currency::core::init_options(desc_options);
tools::db::db_backend_selector::init_options(desc_options);

View file

@ -6,52 +6,6 @@
#include "chaingen.h"
#include "random_helper.h"
random_state_test_restorer::random_state_test_restorer()
{
crypto::random_prng_get_state(&m_state, sizeof m_state);
}
random_state_test_restorer::~random_state_test_restorer()
{
crypto::random_prng_set_state(&m_state, sizeof m_state);
}
void random_state_test_restorer::reset_random(uint64_t seed /* = 0 */)
{
crypto::random_prng_initialize_with_seed(seed);
}
std::string get_random_text(size_t len)
{
static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" ";
static const uint8_t text_chars_size = sizeof text_chars - 1; // to avoid '\0'
std::string result;
if (len < 1)
return result;
result.resize(len);
char* result_buf = &result[0];
uint8_t* rnd_indices = new uint8_t[len];
crypto::generate_random_bytes(len, rnd_indices);
size_t n = len / 4, i;
for (i = 0; i < n; ++i)
{
result_buf[4 * i + 0] = text_chars[rnd_indices[4 * i + 0] % text_chars_size];
result_buf[4 * i + 1] = text_chars[rnd_indices[4 * i + 1] % text_chars_size];
result_buf[4 * i + 2] = text_chars[rnd_indices[4 * i + 2] % text_chars_size];
result_buf[4 * i + 3] = text_chars[rnd_indices[4 * i + 3] % text_chars_size];
}
for (size_t j = i * 4; j < len; ++j)
{
result_buf[j] = text_chars[rnd_indices[j] % text_chars_size];
}
delete[] rnd_indices;
return result;
}
//------------------------------------------------------------------------------
bool random_state_manupulation_test()

View file

@ -13,17 +13,56 @@
// Remebers random state at ctor, restores it at dtor
struct random_state_test_restorer
{
random_state_test_restorer();
~random_state_test_restorer();
static void reset_random(uint64_t seed = 0);
random_state_test_restorer()
{
crypto::random_prng_get_state(&m_state, sizeof m_state);
}
~random_state_test_restorer()
{
crypto::random_prng_set_state(&m_state, sizeof m_state);
}
static void reset_random(uint64_t seed = 0)
{
crypto::random_prng_initialize_with_seed(seed);
}
private:
uint8_t m_state[RANDOM_STATE_SIZE];
};
#endif // #ifdef USE_INSECURE_RANDOM_RPNG_ROUTINES
std::string get_random_text(size_t len);
inline std::string get_random_text(size_t len)
{
{
static const char text_chars[] = "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "0123456789" "~!@#$%^&*()-=_+\\/?,.<>|{}[]`';:\" ";
static const uint8_t text_chars_size = sizeof text_chars - 1; // to avoid '\0'
std::string result;
if (len < 1)
return result;
result.resize(len);
char* result_buf = &result[0];
uint8_t* rnd_indices = new uint8_t[len];
crypto::generate_random_bytes(len, rnd_indices);
size_t n = len / 4, i;
for (i = 0; i < n; ++i)
{
result_buf[4 * i + 0] = text_chars[rnd_indices[4 * i + 0] % text_chars_size];
result_buf[4 * i + 1] = text_chars[rnd_indices[4 * i + 1] % text_chars_size];
result_buf[4 * i + 2] = text_chars[rnd_indices[4 * i + 2] % text_chars_size];
result_buf[4 * i + 3] = text_chars[rnd_indices[4 * i + 3] % text_chars_size];
}
for (size_t j = i * 4; j < len; ++j)
{
result_buf[j] = text_chars[rnd_indices[j] % text_chars_size];
}
delete[] rnd_indices;
return result;
}
}
bool random_state_manupulation_test();
bool random_evenness_test();

View file

@ -473,6 +473,7 @@ uint64_t hash_64(const void* data, size_t size)
#define ASSERT_TRUE(expr) CHECK_AND_ASSERT_MES(expr, false, "This is not true: " #expr)
#define ASSERT_FALSE(expr) CHECK_AND_ASSERT_MES((expr) == false, false, "This is not false: " #expr)
#define ASSERT_EQ(a, b) CHECK_AND_ASSERT_MES(a == b, false, #a " != " #b "\n " << a << " != " << b)
#define ASSERT_NEQ(a, b) CHECK_AND_ASSERT_MES(a != b, false, #a " == " #b "\n " << a)
typedef bool(*bool_func_ptr_t)();
static std::vector<std::pair<std::string, bool_func_ptr_t>> g_tests;
@ -487,6 +488,7 @@ struct test_keeper_t
////////////////////////////////////////////////////////////////////////////////
#include "L2S.h"
#include "crypto_tests_range_proofs.h"
////////////////////////////////////////////////////////////////////////////////
@ -1803,6 +1805,68 @@ TEST(crypto, point_is_zero)
}
TEST(crypto, sc_get_bit)
{
static_assert(sizeof(scalar_t) * 8 == 256, "size missmatch");
scalar_t v = 0; // all bits are 0
for (size_t n = 0; n < 256; ++n)
{
ASSERT_EQ(v.get_bit(static_cast<uint8_t>(n)), false);
}
v = c_scalar_256m1; // all bits are 1
for (size_t n = 0; n < 256; ++n)
{
ASSERT_EQ(v.get_bit(static_cast<uint8_t>(n)), true);
}
// bits out of the [0; 255] range supposed to be always 0
for (size_t n = 256; n < 2048; ++n)
{
ASSERT_EQ(v.get_bit(static_cast<uint8_t>(n)), false);
}
// check random value
const scalar_t x = scalar_t::random();
for (size_t n = 0; n < 64; ++n)
ASSERT_EQ(x.get_bit(static_cast<uint8_t>(n)), ((x.m_u64[0] & (1ull << (n - 0))) != 0));
for (size_t n = 64; n < 128; ++n)
ASSERT_EQ(x.get_bit(static_cast<uint8_t>(n)), ((x.m_u64[1] & (1ull << (n - 64))) != 0));
for (size_t n = 128; n < 192; ++n)
ASSERT_EQ(x.get_bit(static_cast<uint8_t>(n)), ((x.m_u64[2] & (1ull << (n - 128))) != 0));
for (size_t n = 192; n < 256; ++n)
ASSERT_EQ(x.get_bit(static_cast<uint8_t>(n)), ((x.m_u64[3] & (1ull << (n - 192))) != 0));
return true;
}
TEST(crypto, sc_set_bit_clear_bit)
{
static_assert(sizeof(scalar_t) * 8 == 256, "size missmatch");
// check random value
const scalar_t x = scalar_t::random();
scalar_t y = scalar_t::random();
ASSERT_NEQ(x, y);
uint8_t i = 0;
do
{
if (x.get_bit(i))
y.set_bit(i);
else
y.clear_bit(i);
} while(++i != 0);
ASSERT_EQ(x, y);
return true;
}
//
// test's runner
//

View file

@ -0,0 +1,261 @@
// 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
// calc weighted inner pruduct of av and bv w.r.t. Vandermonde vector (y, y^2, y^3, ..., y^n)
// <a, ((y, y^2, y^3, ...) o b)> = <c, (y, y^2, y^3, ...)> (<> -- standard inner product, o - componen-wise)
// s.a. BP+ paper, pages 3-4
bool wip_vandermonde(const scalar_vec_t& av, const scalar_vec_t& bv, const scalar_t& y, scalar_t& result)
{
result = 0;
size_t n = av.size();
if (n != bv.size())
return false;
scalar_t y_powered = 1;
for (size_t i = 0; i < n; ++i)
{
y_powered *= y;
result.assign_muladd(av[i] * bv[i], y_powered, result); // result.a += av[i] * bv[i] * y_powered;
}
return true;
}
static_assert(constexpr_floor_log2(0) == 0, "");
static_assert(constexpr_floor_log2(1) == 0, "");
static_assert(constexpr_floor_log2(2) == 1, "");
static_assert(constexpr_floor_log2(3) == 1, "");
static_assert(constexpr_floor_log2(4) == 2, "");
static_assert(constexpr_floor_log2(5) == 2, "");
static_assert(constexpr_floor_log2(64) == 6, "");
static_assert(constexpr_floor_log2(100) == 6, "");
static_assert(constexpr_floor_log2(100000000) == 26, "");
static_assert(constexpr_floor_log2(0x7fffffffffffffff) == 62, "");
static_assert(constexpr_floor_log2(SIZE_MAX) == 63, "");
static_assert(constexpr_ceil_log2(0) == 0, "");
static_assert(constexpr_ceil_log2(1) == 0, "");
static_assert(constexpr_ceil_log2(2) == 1, "");
static_assert(constexpr_ceil_log2(3) == 2, "");
static_assert(constexpr_ceil_log2(4) == 2, "");
static_assert(constexpr_ceil_log2(5) == 3, "");
static_assert(constexpr_ceil_log2(64) == 6, "");
static_assert(constexpr_ceil_log2(100) == 7, "");
static_assert(constexpr_ceil_log2(100000000) == 27, "");
static_assert(constexpr_ceil_log2(0x7fffffffffffffff) == 63, "");
static_assert(constexpr_ceil_log2(SIZE_MAX) == 64, "");
TEST(bpp, basics)
{
/*
srand(0);
for (size_t i = 0; i < 10; ++i)
std::cout << scalar_t::random().to_string_as_secret_key() << ENDL;
*/
point_t H = hash_helper_t::hp(c_point_G);
ASSERT_EQ(H, c_point_H);
std::string h2_hash_str("h2_generator");
point_t H2 = hash_helper_t::hp(h2_hash_str.c_str(), h2_hash_str.size());
ASSERT_EQ(H2, c_point_H2);
LOG_PRINT_L0("c_point_0 = " << c_point_0 << " = { " << c_point_0.to_hex_comma_separated_uint64_str() << " }");
LOG_PRINT_L0("Zano G = " << c_point_G << " = { " << c_point_G.to_hex_comma_separated_bytes_str() << " }");
LOG_PRINT_L0("Zano H = " << H << " = { " << H.to_hex_comma_separated_uint64_str() << " }");
LOG_PRINT_L0("Zano H2 = " << H2 << " = { " << H2.to_hex_comma_separated_uint64_str() << " }");
scalar_vec_t values = { 5 };
scalar_vec_t masks = { 0 };
bpp_signature bpp_sig;
std::vector<point_t> commitments;
uint8_t err = 0;
bool r = bpp_gen<bpp_crypto_trait_zano<>>(values, masks, bpp_sig, commitments, &err);
ASSERT_TRUE(r);
return true;
}
TEST(bpp, two)
{
std::vector<bpp_signature> signatures_vector;
signatures_vector.reserve(10);
std::vector<std::vector<point_t>> commitments_vector;
commitments_vector.reserve(10);
std::vector<bpp_sig_commit_ref_t> sigs;
uint8_t err = 0;
bool r = false;
{
signatures_vector.resize(signatures_vector.size() + 1);
bpp_signature &bpp_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77) };
r = bpp_gen<bpp_crypto_trait_zano<>>(values, masks, bpp_sig, commitments, &err);
ASSERT_TRUE(r);
sigs.emplace_back(bpp_sig, commitments);
}
{
signatures_vector.resize(signatures_vector.size() + 1);
bpp_signature &bpp_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5, 700, 8 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) };
r = bpp_gen<bpp_crypto_trait_zano<>>(values, masks, bpp_sig, commitments, &err);
ASSERT_TRUE(r);
sigs.emplace_back(bpp_sig, commitments);
}
r = bpp_verify<bpp_crypto_trait_zano<>>(sigs, &err);
ASSERT_TRUE(r);
return true;
}
TEST(bpp, power_256)
{
// make sure the BPP implementation supports values up to 2^256 (Zarcanum needs 2^170 since b_a < z * 2^64, where z = 2^106, s.a. Zarcanum preprint, page 21)
std::vector<bpp_signature> signatures_vector;
signatures_vector.reserve(10);
std::vector<std::vector<point_t>> commitments_vector;
commitments_vector.reserve(10);
std::vector<bpp_sig_commit_ref_t> sig_ñommit_refs;
uint8_t err = 0;
bool r = false;
{
signatures_vector.resize(signatures_vector.size() + 1);
bpp_signature &bpp_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77) };
r = bpp_gen<bpp_crypto_trait_zano<>>(values, masks, bpp_sig, commitments, &err);
ASSERT_TRUE(r);
sig_ñommit_refs.emplace_back(bpp_sig, commitments);
}
{
signatures_vector.resize(signatures_vector.size() + 1);
bpp_signature &bpp_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5, 700, 8 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) };
r = bpp_gen<bpp_crypto_trait_zano<>>(values, masks, bpp_sig, commitments, &err);
ASSERT_TRUE(r);
sig_ñommit_refs.emplace_back(bpp_sig, commitments);
}
r = bpp_verify<bpp_crypto_trait_zano<>>(sig_ñommit_refs, &err);
ASSERT_TRUE(r);
return true;
}
//
// tests for Bulletproofs+ Extended (with double-blinded commitments)
//
TEST(bppe, basics)
{
/*
srand(0);
for (size_t i = 0; i < 10; ++i)
std::cout << scalar_t::random().to_string_as_secret_key() << ENDL;
*/
scalar_vec_t values = { 5 };
scalar_vec_t masks = { 0 };
scalar_vec_t masks_2 = { 0 };
bppe_signature bppe_sig;
std::vector<point_t> commitments;
uint8_t err = 0;
bool r = bppe_gen<bpp_crypto_trait_zano<>>(values, masks, masks_2, bppe_sig, commitments, &err);
ASSERT_TRUE(r);
return true;
}
TEST(bppe, two)
{
std::vector<bppe_signature> signatures_vector;
signatures_vector.reserve(10);
std::vector<std::vector<point_t>> commitments_vector;
commitments_vector.reserve(10);
std::vector<bppe_sig_commit_ref_t> sigs;
uint8_t err = 0;
bool r = false;
{
signatures_vector.resize(signatures_vector.size() + 1);
bppe_signature &bppe_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77) };
scalar_vec_t masks2 = { scalar_t(88 + 256 * 88) };
r = bppe_gen<bpp_crypto_trait_zano<>>(values, masks, masks2, bppe_sig, commitments, &err);
ASSERT_TRUE(r);
sigs.emplace_back(bppe_sig, commitments);
}
{
signatures_vector.resize(signatures_vector.size() + 1);
bppe_signature &bppe_sig = signatures_vector.back();
commitments_vector.resize(commitments_vector.size() + 1);
std::vector<point_t>& commitments = commitments_vector.back();
scalar_vec_t values = { 5, 700, 8 };
scalar_vec_t masks = { scalar_t(77 + 256 * 77), scalar_t(255), scalar_t(17) };
scalar_vec_t masks2 = { scalar_t(88 + 256 * 88), scalar_t(1), scalar_t(19) };
r = bppe_gen<bpp_crypto_trait_zano<>>(values, masks, masks2, bppe_sig, commitments, &err);
ASSERT_TRUE(r);
sigs.emplace_back(bppe_sig, commitments);
}
r = bppe_verify<bpp_crypto_trait_zano<>>(sigs, &err);
ASSERT_TRUE(r);
return true;
}

View file

@ -66,9 +66,6 @@ int main(int argc, char* argv[])
TRY_ENTRY();
string_tools::set_module_name_and_folder(argv[0]);
uint64_t reward = 0;
currency::get_block_reward(false, 500000, 589313, 10300000000000000, reward, 11030);
//set up logging options
//log_space::get_set_log_detalisation_level(true, LOG_LEVEL_1);
//log_space::log_singletone::add_logger(LOGGER_CONSOLE, NULL, NULL, LOG_LEVEL_2);