1
0
Fork 0
forked from lthn/blockchain

Merge branch 'zarcanum' into zarcanum_wallet

This commit is contained in:
cryptozoidberg 2022-07-06 22:14:07 +02:00
commit 87e7905be1
No known key found for this signature in database
GPG key ID: 22DEB97A54C6FDEC
6 changed files with 112 additions and 40 deletions

View file

@ -23,16 +23,18 @@ namespace crypto
scalar_t delta;
};
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) std::cout << x << ENDL
#define DBG_VAL_PRINT(x) (void(0)) // std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) (void(0)) // 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; }
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; }
template<typename CT = bpp_crypto_trait_zano<>>
bool bpp_gen(const scalar_vec_t& values, const scalar_vec_t& masks, const std::vector<const crypto::public_key*>& commitments_1div8, bpp_signature& sig, uint8_t* p_err = nullptr)
{
// Note: commitments_1div8 are supposed to be already calculated
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);
@ -42,15 +44,6 @@ namespace crypto
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
@ -85,7 +78,7 @@ namespace crypto
DBG_PRINT("initial transcript: " << e);
hash_helper_t::hs_t hsc;
CT::update_transcript(hsc, e, commitments);
CT::update_transcript(hsc, e, commitments_1div8);
// 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)
@ -96,7 +89,8 @@ namespace crypto
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
// 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())
A0 *= c_scalar_1div8;
A0.to_public_key(sig.A0);
@ -147,7 +141,7 @@ namespace crypto
// 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)
// aR_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];
@ -339,7 +333,7 @@ namespace crypto
};
template<typename CT>
template<typename CT = bpp_crypto_trait_zano<>>
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) \
@ -696,4 +690,7 @@ namespace crypto
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
#undef DBG_VAL_PRINT
#undef DBG_PRINT
} // namespace crypto

View file

@ -24,8 +24,8 @@ namespace crypto
scalar_t delta_2;
};
#define DBG_VAL_PRINT(x) std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) std::cout << x << ENDL
#define DBG_VAL_PRINT(x) (void(0)) // std::cout << #x ": " << x << ENDL
#define DBG_PRINT(x) (void(0)) // 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)
@ -149,7 +149,7 @@ namespace crypto
// 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)
// aR_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];
@ -716,4 +716,7 @@ namespace crypto
#undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE
}
#undef DBG_VAL_PRINT
#undef DBG_PRINT
} // namespace crypto

View file

@ -88,6 +88,15 @@ namespace crypto
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
static const point_t& get_generator(bool select_H, size_t index)
{

View file

@ -1026,6 +1026,7 @@ SET_VARIANT_TAGS(crypto::bppe_signature_serialized, 41, "bppe_signature_serializ
SET_VARIANT_TAGS(currency::NLSAG_sig, 42, "NLSAG_sig");
SET_VARIANT_TAGS(currency::zarcanum_sig, 43, "zarcanum_sig");
SET_VARIANT_TAGS(currency::void_sig, 44, "void_sig");
SET_VARIANT_TAGS(currency::zarcanum_outs_range_proof, 45, "zarcanum_outs_range_proof");

View file

@ -609,10 +609,12 @@ namespace currency
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr)
{
finalized_tx result = AUTO_VAL_INIT(result);
return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, result, tx_outs_attr);
crypto::scalar_t out_blinding_mask = AUTO_VAL_INIT(out_blinding_mask);
return construct_tx_out(de, tx_sec_key, output_index, tx, deriv_cache, self, out_blinding_mask, result, tx_outs_attr);
}
//---------------------------------------------------------------
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, finalized_tx& result, uint8_t tx_outs_attr)
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache,
const account_keys& self, crypto::scalar_t& out_blinding_mask, finalized_tx& result, uint8_t tx_outs_attr)
{
if (tx.version > TRANSACTION_VERSION_PRE_HF4)
{
@ -634,8 +636,8 @@ namespace currency
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
crypto::scalar_t blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
out.amount_commitment = (de.amount * crypto::c_point_H + blinding_mask * crypto::c_point_G).to_public_key();
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
out.amount_commitment = (crypto::c_scalar_1div8 * de.amount * crypto::c_point_H + crypto::c_scalar_1div8 * out_blinding_mask * crypto::c_point_G).to_public_key();
out.mix_attr = tx_outs_attr; // TODO @#@# @CZ check this
}
@ -648,11 +650,11 @@ namespace currency
out.stealth_address = (h * crypto::c_point_G + crypto::point_t(apa.spend_public_key)).to_public_key();
out.concealing_point = (crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_CONCEALING_POINT, h) * crypto::point_t(apa.view_public_key)).to_public_key(); // Q = Hs(domain_sep, h) * V
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h);
out.encrypted_amount = de.amount ^ amount_mask.m_u64[0];
crypto::scalar_t blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
out.amount_commitment = (de.amount * crypto::c_point_H + blinding_mask * crypto::c_point_G).to_public_key();
out_blinding_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_BLINDING_MASK, h); // f = Hs(domain_sep, d, i)
out.amount_commitment = (crypto::c_scalar_1div8 * de.amount * crypto::c_point_H + crypto::c_scalar_1div8 * out_blinding_mask * crypto::c_point_G).to_public_key();
if (de.addr.front().is_auditable())
out.mix_attr = CURRENCY_TO_KEY_OUT_FORCED_NO_MIX; // override mix_attr to 1 for auditable target addresses
@ -1524,11 +1526,14 @@ namespace currency
//fill outputs
size_t output_index = tx.vout.size(); // in case of append mode we need to start output indexing from the last one + 1
std::set<uint16_t> deriv_cache;
crypto::scalar_vec_t blinding_masks(destinations.size()); // vector of secret blinging masks for each output. For range proof generation
crypto::scalar_vec_t amounts(destinations.size()); // vector of amounts, converted to scalars. For rnage proof generation
for(const tx_destination_entry& dst_entr : shuffled_dsts)
{
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount);
bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys, result, tx_outs_attr);
CHECK_AND_ASSERT_MES(r, false, "Failed to construc tx out");
CHECK_AND_ASSERT_MES(dst_entr.amount > 0, false, "Destination with wrong amount: " << dst_entr.amount); // <<-- TODO @#@# consider removing this check
bool r = construct_tx_out(dst_entr, txkey.sec, output_index, tx, deriv_cache, sender_account_keys, blinding_masks[output_index], result, tx_outs_attr);
CHECK_AND_ASSERT_MES(r, false, "Failed to construct tx out");
amounts[output_index] = dst_entr.amount;
output_index++;
summary_outs_money += dst_entr.amount;
}
@ -2868,6 +2873,12 @@ namespace currency
tv.details_view = tv.short_view;
return true;
}
bool operator()(const zarcanum_outs_range_proof& rp)
{
tv.type = "zarcanum_outs_range_proof";
tv.short_view = "outputs_count = " + std::to_string(rp.outputs_count);
return true;
}
};
//------------------------------------------------------------------
template<class t_container>
@ -3446,6 +3457,57 @@ namespace currency
return false;
}
//--------------------------------------------------------------------------------
bool generate_zarcanum_outs_range_proof(size_t out_index_start, size_t outs_count, const crypto::scalar_vec_t& amounts, const crypto::scalar_vec_t& blinding_masks,
const std::vector<tx_out_v>& vouts, zarcanum_outs_range_proof& result)
{
CHECK_AND_ASSERT_MES(amounts.size() == outs_count, false, "");
CHECK_AND_ASSERT_MES(blinding_masks.size() == outs_count, false, "");
CHECK_AND_ASSERT_MES(out_index_start + outs_count == vouts.size(), false, "");
std::vector<const crypto::public_key*> commitments_1div8;
for(size_t out_index = out_index_start, i = 0; i < outs_count; ++out_index, ++i)
{
const tx_out_zarcanum& toz = boost::get<tx_out_zarcanum>(vouts[out_index]); // may throw an exception, only zarcanum outputs are exprected
const crypto::public_key* p = &toz.amount_commitment;
commitments_1div8.push_back(p);
}
uint8_t err = 0;
bool r = crypto::bpp_gen<>(amounts, blinding_masks, commitments_1div8, result.bpp, &err);
CHECK_AND_ASSERT_MES(r, false, "bpp_gen failed with error " << err);
return true;
}
//--------------------------------------------------------------------------------
struct zarcanum_outs_range_proof_commit_ref_t
{
zarcanum_outs_range_proof_commit_ref_t(const zarcanum_outs_range_proof& range_proof, const std::vector<crypto::point_t>& amount_commitments)
: range_proof(range_proof)
, amount_commitments(amount_commitments)
{}
const zarcanum_outs_range_proof& range_proof;
const std::vector<crypto::point_t>& amount_commitments;
};
bool verify_multiple_zarcanum_outs_range_proofs(const std::vector<zarcanum_outs_range_proof_commit_ref_t>& range_proofs)
{
std::vector<crypto::bpp_sig_commit_ref_t> sigs;
for(auto el : range_proofs)
sigs.emplace_back(el.range_proof.bpp, el.amount_commitments);
uint8_t err = 0;
bool r = crypto::bpp_verify<>(sigs, &err);
CHECK_AND_ASSERT_MES(r, false, "bpp_vefiry failed with error " << err);
return true;
}
//--------------------------------------------------------------------------------
bool generate_zarcanum_signature(const crypto::hash& prefix_hash, const std::vector<tx_source_entry>& sources, const txin_zarcanum_inputs& zins, zarcanum_sig& result)
{
return true;
}
//--------------------------------------------------------------------------------
boost::multiprecision::uint1024_t get_a_to_b_relative_cumulative_difficulty(const wide_difficulty_type& difficulty_pos_at_split_point,
const wide_difficulty_type& difficulty_pow_at_split_point,

View file

@ -235,7 +235,7 @@ namespace currency
//---------------------------------------------------------------
uint64_t get_string_uint64_hash(const std::string& str);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, crypto::scalar_t& out_blinding_mask, finalized_tx& result, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool construct_tx_out(const tx_destination_entry& de, const crypto::secret_key& tx_sec_key, size_t output_index, transaction& tx, std::set<uint16_t>& deriv_cache, const account_keys& self, uint8_t tx_outs_attr = CURRENCY_TO_KEY_OUT_RELAXED);
bool validate_alias_name(const std::string& al);
bool validate_password(const std::string& password);
@ -406,20 +406,20 @@ namespace currency
}
template<typename out_t>
bool is_out_burned(const out_t& out) { CHECK_AND_ASSERT_THROW_MES(false, "incorrect out type: " << typeid(out).name()); }
bool is_out_burned(const tx_out_bare& o) { return is_out_burned(o.target); }
bool is_out_burned(const txout_to_key& o) { return o.key == null_pkey; }
bool is_out_burned(const tx_out_zarcanum& o) { return o.stealth_address == null_pkey; }
inline bool is_out_burned(const out_t& out) { CHECK_AND_ASSERT_THROW_MES(false, "incorrect out type: " << typeid(out).name()); }
inline bool is_out_burned(const tx_out_bare& o) { return is_out_burned(o.target); }
inline bool is_out_burned(const txout_to_key& o) { return o.key == null_pkey; }
inline bool is_out_burned(const tx_out_zarcanum& o) { return o.stealth_address == null_pkey; }
struct zz_is_out_burned_helper_visitor : boost::static_visitor<bool>
{
template<typename T>
bool operator()(const T& v) const { return is_out_burned(v); }
};
bool is_out_burned(const tx_out_v& v)
inline bool is_out_burned(const tx_out_v& v)
{
return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v);
}
bool is_out_burned(const txout_target_v& v)
inline bool is_out_burned(const txout_target_v& v)
{
return boost::apply_visitor(zz_is_out_burned_helper_visitor(), v);
}