forked from lthn/blockchain
191 lines
6 KiB
C++
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"
|