1
0
Fork 0
forked from lthn/blockchain
blockchain/src/crypto/range_proofs.h

191 lines
6 KiB
C++

// 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
#include "epee/include/misc_log_ex.h"
#include "crypto-sugar.h"
namespace crypto
{
// returns x + x^2 + x^3 + ... + x^(2^f)
// == x * (x + 1) * (x^2 + 1) * (x^4 + 1) * ...(x^(f+1) + 1)
inline scalar_t sum_of_powers(scalar_t x, size_t f)
{
scalar_t result = x;
for (size_t i = 0; i < f; ++i)
{
result.assign_muladd(result, x, result);
x *= x;
}
return result;
}
// returns greatest k, s.t. n**k <= v
// tests in crypto_tests_range_proofs.h
constexpr size_t constexpr_floor_log_n(size_t v, size_t n)
{
return (v < n || n <= 1) ? 0 : constexpr_floor_log_n(v / n, n) + 1;
}
// returns smallest k, s.t. v <= n**k
// tests in crypto_tests_range_proofs.h
constexpr size_t constexpr_ceil_log_n(size_t v, size_t n)
{
return (v <= 1 || n <= 1) ? 0 : constexpr_floor_log_n(v - 1, n) + 1;
}
// returns smallest k, s.t. v <= 2**k
// tests in crypto_tests_range_proofs.h
constexpr size_t constexpr_ceil_log2(size_t v)
{
return constexpr_ceil_log_n(v, 2);
}
// returns least significant bit uing de Bruijn sequence
// http://graphics.stanford.edu/~seander/bithacks.html
inline uint8_t calc_lsb_32(uint32_t v)
{
static const uint8_t multiply_de_bruijn_bit_position[32] =
{
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
};
return multiply_de_bruijn_bit_position[((uint32_t)((v & -(int32_t)v) * 0x077CB531U)) >> 27];
}
////////////////////////////////////////
// crypto trait for Zano
////////////////////////////////////////
struct bpp_ct_generators_HGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
};
struct bpp_ct_generators_UGX
{
// NOTE! This notation follows the original BP+ whitepaper, see mapping to Zano's generators below
static const point_t& bpp_G;
static const point_t& bpp_H;
static const point_t& bpp_H2;
};
template<typename gen_trait_t, size_t N = 64, size_t values_max = 16>
struct bpp_crypto_trait_zano : gen_trait_t
{
static constexpr size_t c_bpp_n = N; // the upper bound for the witness's range
static constexpr size_t c_bpp_values_max = values_max; // maximum number of elements in BP+ proof, i.e. max allowed BP+ outputs
static constexpr size_t c_bpp_log2_n = constexpr_ceil_log2(c_bpp_n);
static constexpr size_t c_bpp_mn_max = c_bpp_n * c_bpp_values_max;
static void calc_pedersen_commitment(const scalar_t& value, const scalar_t& mask, point_t& commitment)
{
commitment = value * bpp_G + mask * bpp_H;
}
static void calc_pedersen_commitment_2(const scalar_t& value, const scalar_t& mask1, const scalar_t& mask2, point_t& commitment)
{
commitment = value * bpp_G + mask1 * bpp_H + mask2 * bpp_H2;
}
static const scalar_t& get_initial_transcript()
{
static scalar_t value = hash_helper_t::hs("Zano BP+ initial transcript");
return value;
}
// assumes hsc is cleared
static void update_transcript(hash_helper_t::hs_t& hsc, scalar_t& e, const std::vector<point_t>& points)
{
hsc.add_scalar(e);
hsc.add_points_array(points);
e = hsc.calc_hash();
}
// assumes hsc is cleared
static void update_transcript(hash_helper_t::hs_t& hsc, scalar_t& e, const std::vector<const public_key*>& pub_keys)
{
hsc.add_scalar(e);
for(auto p : pub_keys)
hsc.add_pub_key(*p);
e = hsc.calc_hash();
}
// TODO: refactor with proper OOB handling
// TODO: @#@# add domain separation
static const point_t& get_generator(bool select_H, size_t index)
{
if (index >= c_bpp_mn_max)
return c_point_0; // out of bound
static std::vector<point_t> generators(2 * c_bpp_mn_max);
static bool calculated = false;
if (!calculated)
{
scalar_t hash_buf[2] = { hash_helper_t::hs("Zano BP+ generator"), 0 };
for (size_t i = 0; i < 2 * c_bpp_mn_max; ++i)
{
hash_buf[1].m_u64[0] = i;
ge_bytes_hash_to_ec(&generators[i].m_p3, &hash_buf, sizeof hash_buf);
}
calculated = true;
}
return generators[2 * index + (select_H ? 1 : 0)];
}
static const 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;
}
using typename gen_trait_t::bpp_G;
using typename gen_trait_t::bpp_H;
using typename gen_trait_t::bpp_H2;
}; // struct bpp_crypto_trait_zano
typedef bpp_crypto_trait_zano<bpp_ct_generators_UGX, 64, 16> bpp_crypto_trait_ZC_out;
typedef bpp_crypto_trait_zano<bpp_ct_generators_HGX, 128, 16> bpp_crypto_trait_Zarcanum;
// 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() <= CT::c_bpp_mn_max, false, "g_scalars oversized");
CHECK_AND_ASSERT_MES(h_scalars.size() <= CT::c_bpp_mn_max, false, "h_scalars oversized");
point_t result = summand;
for (size_t i = 0; i < g_scalars.size(); ++i)
result += g_scalars[i] * CT::get_generator(false, i);
for (size_t i = 0; i < h_scalars.size(); ++i)
result += h_scalars[i] * CT::get_generator(true, i);
if (!result.is_zero())
{
LOG_PRINT_L0("multiexp result is non zero: " << result);
return false;
}
return true;
}
} // namespace crypto
#include "range_proof_bpp.h"
#include "range_proof_bppe.h"