From d904323f886472f531a80eb53bce219d347154c6 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Jun 2022 22:13:34 +0200 Subject: [PATCH 1/5] crypto: made point_t throwing exceptions in bad cases --- src/crypto/crypto-sugar.h | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 96c4873a..2c99153b 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -16,7 +16,9 @@ namespace crypto #include "crypto/crypto-ops.h" } // extern "C" - +#define CRYPTO_STR_(X) #X +#define CRYPTO_STR(X) CRYPTO_STR_(X) +#define CRYPTO_CHECK_AND_THROW_MES(cond, msg) if (!(cond)) { throw std::runtime_error(msg " @ " __FILE__ ":" CRYPTO_STR(__LINE__)); } // // Helpers @@ -480,27 +482,24 @@ namespace crypto { } - explicit point_t(const crypto::public_key& pk) + explicit point_t(const crypto::public_key& pk) // can throw std::runtime_error { - if (!from_public_key(pk)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key"); } - point_t(const unsigned char(&v)[32]) + point_t(const unsigned char(&v)[32]) // can throw std::runtime_error { static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch"); - if (!from_public_key(*(const crypto::public_key*)v)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (char[32])"); } - point_t(const uint64_t(&v)[4]) + point_t(const uint64_t(&v)[4]) // can throw std::runtime_error { static_assert(sizeof(crypto::public_key) == sizeof v, "size missmatch"); - if (!from_public_key(*(const crypto::public_key*)v)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(*(const crypto::public_key*)v), "invalid public key (uint64_t[4])"); } - point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) + point_t(uint64_t a0, uint64_t a1, uint64_t a2, uint64_t a3) // can throw std::runtime_error { crypto::public_key pk; ((uint64_t*)&pk)[0] = a0; @@ -508,8 +507,7 @@ namespace crypto ((uint64_t*)&pk)[2] = a2; ((uint64_t*)&pk)[3] = a3; - if (!from_public_key(pk)) - zero(); + CRYPTO_CHECK_AND_THROW_MES(from_public_key(pk), "invalid public key (four uint64_t)"); } explicit point_t(tag_zero&&) From 9d1ab22010d625e8cbc2009c64215a760d5c951b Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Jun 2022 22:14:39 +0200 Subject: [PATCH 2/5] crypto: hs_t and hs(...) made compatible with char[32] --- src/crypto/crypto-sugar.h | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/src/crypto/crypto-sugar.h b/src/crypto/crypto-sugar.h index 2c99153b..14046d61 100644 --- a/src/crypto/crypto-sugar.h +++ b/src/crypto/crypto-sugar.h @@ -933,9 +933,10 @@ namespace crypto struct hs_t { - hs_t() + hs_t(size_t size_to_reserve = 0) { static_assert(sizeof(scalar_t) == sizeof(crypto::public_key), "unexpected size of data"); + m_elements.reserve(size_to_reserve); } void reserve(size_t elements_count) @@ -1005,6 +1006,11 @@ namespace crypto m_elements.emplace_back(key_image_array[i]); } + void add_32_chars(const char(&str32)[32]) + { + m_elements.emplace_back(str32); + } + scalar_t calc_hash(bool clear = true) { size_t data_size_bytes = m_elements.size() * sizeof(item_t); @@ -1031,17 +1037,21 @@ namespace crypto item_t(const scalar_t& scalar) : scalar(scalar) {} item_t(const crypto::public_key& pk) : pk(pk) {} item_t(const crypto::key_image& ki) : ki(ki) {} + item_t(const char(&str32)[32]) { memcpy(c, str32, sizeof c); } scalar_t scalar; crypto::public_key pk; crypto::key_image ki; + char c[32]; }; + static_assert(sizeof(item_t::c) == sizeof(item_t::pk), "size missmatch"); + std::vector m_elements; }; static scalar_t hs(const scalar_t& s, const std::vector& ps0, const std::vector& ps1) { - hs_t hs_calculator; + hs_t hs_calculator(3); hs_calculator.add_scalar(s); hs_calculator.add_points_array(ps0); hs_calculator.add_points_array(ps1); @@ -1051,7 +1061,7 @@ namespace crypto static scalar_t hs(const crypto::hash& s, const std::vector& ps0, const std::vector& ps1) { static_assert(sizeof(crypto::hash) == sizeof(scalar_t), "size missmatch"); - hs_t hs_calculator; + hs_t hs_calculator(3); hs_calculator.add_scalar(*reinterpret_cast(&s)); hs_calculator.add_pub_keys_array(ps0); hs_calculator.add_key_images_array(ps1); @@ -1060,12 +1070,20 @@ namespace crypto static scalar_t hs(const std::vector& ps0, const std::vector& ps1) { - hs_t hs_calculator; + hs_t hs_calculator(2); hs_calculator.add_points_array(ps0); hs_calculator.add_points_array(ps1); return hs_calculator.calc_hash(); } + static scalar_t hs(const char(&str32)[32], const scalar_t& s) + { + hs_t hs_calculator(2); + hs_calculator.add_32_chars(str32); + hs_calculator.add_scalar(s); + return hs_calculator.calc_hash(); + } + static point_t hp(const point_t& p) { point_t result; From a23eaac73065f7b2cbc7945c22c5cc6e22b05b98 Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Jun 2022 22:15:18 +0200 Subject: [PATCH 3/5] crypto_ops: derivation_to_scalar made public --- src/crypto/crypto.cpp | 3 ++- src/crypto/crypto.h | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/crypto/crypto.cpp b/src/crypto/crypto.cpp index a1e0c64c..7210cd3c 100644 --- a/src/crypto/crypto.cpp +++ b/src/crypto/crypto.cpp @@ -187,7 +187,8 @@ namespace crypto { return true; } - static void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) { + void crypto_ops::derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &res) + { struct { key_derivation derivation; char output_index[(sizeof(size_t) * 8 + 6) / 7]; diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h index 64df2444..aa79f4e0 100644 --- a/src/crypto/crypto.h +++ b/src/crypto/crypto.h @@ -86,6 +86,8 @@ namespace crypto { friend bool secret_key_to_public_key(const secret_key &, public_key &); static bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); friend bool generate_key_derivation(const public_key &, const secret_key &, key_derivation &); + static void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &); + friend void derivation_to_scalar(const key_derivation &, size_t, ec_scalar &); static bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); friend bool derive_public_key(const key_derivation &, std::size_t, const public_key &, public_key &); static void derive_secret_key(const key_derivation &, std::size_t, const secret_key &, secret_key &); @@ -174,6 +176,10 @@ namespace crypto { inline bool generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) { return crypto_ops::generate_key_derivation(key1, key2, derivation); } + inline void derivation_to_scalar(const key_derivation &derivation, size_t output_index, ec_scalar &result) { + crypto::crypto_ops::derivation_to_scalar(derivation, output_index, result); + } + inline bool derive_public_key(const key_derivation &derivation, std::size_t output_index, const public_key &base, public_key &derived_key) { return crypto_ops::derive_public_key(derivation, output_index, base, derived_key); From 45e1bbcafad24e4106221591a9aa9f95a81d7dbb Mon Sep 17 00:00:00 2001 From: sowle Date: Tue, 28 Jun 2022 22:17:29 +0200 Subject: [PATCH 4/5] zarcanum outputs detection/decoding --- src/currency_core/crypto_config.h | 10 ++++ src/currency_core/currency_format_utils.cpp | 60 ++++++++++++++++----- src/currency_core/currency_format_utils.h | 11 +++- 3 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 src/currency_core/crypto_config.h diff --git a/src/currency_core/crypto_config.h b/src/currency_core/crypto_config.h new file mode 100644 index 00000000..24ae3d6a --- /dev/null +++ b/src/currency_core/crypto_config.h @@ -0,0 +1,10 @@ +// Copyright (c) 2022 Zano Project +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +// +#pragma once + +// hash domain separation strings, 32 bytes long (31 chars + \0) +// +#define CRYPTO_HDS_OUT_AMOUNT_MASK "ZANO_HDS_OUT_AMOUNT_MASK_______" +#define CRYPTO_HDS_OUT_BLINDING_MASK "ZANO_HDS_OUT_BLINDING_MASK_____" diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index df66336a..aa7a44fd 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -31,6 +31,7 @@ using namespace epee; #include "genesis_acc.h" #include "common/mnemonic-encoding.h" #include "crypto/bitcoin/sha256_helper.h" +#include "crypto_config.h" namespace currency { @@ -1960,6 +1961,33 @@ namespace currency return false; return true; } + + bool is_out_to_acc(const account_keys& acc, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount) + { + crypto::scalar_t h = {}; + crypto::derivation_to_scalar(derivation, output_index, h.as_secret_key()); // h = Hs(r * V, i) + + crypto::point_t P_prime = h * crypto::c_point_G + crypto::point_t(acc.account_address.spend_public_key); // P =? Hs(rV, i) * G + S + if (P_prime.to_public_key() != zo.stealth_address) + return false; + + crypto::point_t Q_prime = h * crypto::point_t(acc.account_address.view_public_key); // Q =? v * Hs(rv, i) * G + if (Q_prime.to_public_key() != zo.concealing_point) + return false; + + crypto::scalar_t amount_mask = crypto::hash_helper_t::hs(CRYPTO_HDS_OUT_AMOUNT_MASK, h); + decoded_amount = zo.encrypted_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, h) + + crypto::point_t A_prime; + A_prime.assign_mul_plus_G(decoded_amount, crypto::c_point_H, blinding_mask); // A =? a * H + f * G + if (A_prime.to_public_key() != zo.amount_commitment) + return false; + + return true; + } + //--------------------------------------------------------------- bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation) { @@ -2009,7 +2037,7 @@ namespace currency CHECK_AND_ASSERT_MES(o.target.type() == typeid(txout_to_key), false, "condition failed: o.target.type() == typeid(txout_to_key)"); if (is_out_to_acc(acc, boost::get(o.target), derivation, offset)) { - outs.push_back(offset); + outs.emplace_back(offset, o.amount); money_transfered += o.amount; } return true; @@ -2036,7 +2064,7 @@ namespace currency if (!check_tx_derivation_hint(tx, derivation)) return true; - size_t i = 0; + size_t output_index = 0; for(const auto& ov : tx.vout) { VARIANT_SWITCH_BEGIN(ov); @@ -2044,40 +2072,44 @@ namespace currency { VARIANT_SWITCH_BEGIN(o.target); VARIANT_CASE_CONST(txout_to_key, t) - if (is_out_to_acc(acc, t, derivation, i)) + if (is_out_to_acc(acc, t, derivation, output_index)) { - outs.push_back(i); + outs.emplace_back(output_index, o.amount); money_transfered += o.amount; } VARIANT_CASE_CONST(txout_multisig, t) - if (is_out_to_acc(acc, t, derivation, i)) + if (is_out_to_acc(acc, t, derivation, output_index)) { - outs.push_back(i); - //don't count this money + outs.emplace_back(output_index, 0); // TODO: @#@# consider this + //don't cout this money } VARIANT_CASE_CONST(txout_htlc, htlc) htlc_info hi = AUTO_VAL_INIT(hi); - if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, i)) + if (is_out_to_acc(acc, htlc.pkey_redeem, derivation, output_index)) { hi.hltc_our_out_is_before_expiration = true; htlc_info_list.push_back(hi); - outs.push_back(i); } - else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, i)) + else if (is_out_to_acc(acc, htlc.pkey_refund, derivation, output_index)) { hi.hltc_our_out_is_before_expiration = false; htlc_info_list.push_back(hi); - outs.push_back(i); } + outs.emplace_back(output_index, o.amount); VARIANT_CASE_OTHER() LOG_ERROR("Wrong type at lookup_acc_outs, unexpected type is: " << o.target.type().name()); return false; VARIANT_SWITCH_END(); } - VARIANT_CASE_CONST(tx_out_zarcanum, o) - //@#@ + VARIANT_CASE_CONST(tx_out_zarcanum, zo) + //@#@ + wallet_out_info woi(output_index, 0); + if (is_out_to_acc(acc, zo, derivation, output_index, woi.amount)) + { + outs.emplace_back(woi); + } VARIANT_SWITCH_END(); - i++; + output_index++; } return true; } diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 28353fdb..7e28632a 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -197,8 +197,14 @@ namespace currency struct wallet_out_info { - size_t index; - uint64_t amount; + wallet_out_info() = default; + wallet_out_info(size_t index, uint64_t amount) + : index(index) + , amount(amount) + {} + + size_t index = SIZE_MAX; + uint64_t amount = 0; //todo: additional input info }; @@ -289,6 +295,7 @@ namespace currency crypto::hash get_multisig_out_id(const transaction& tx, size_t n); bool is_out_to_acc(const account_keys& acc, const txout_to_key& out_key, const crypto::key_derivation& derivation, size_t output_index); bool is_out_to_acc(const account_keys& acc, const txout_multisig& out_multisig, const crypto::key_derivation& derivation, size_t output_index); + bool is_out_to_acc(const account_keys& acc, const tx_out_zarcanum& zo, const crypto::key_derivation& derivation, size_t output_index, uint64_t& decoded_amount); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, const crypto::public_key& tx_pub_key, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation, std::list& htlc_info_list); bool lookup_acc_outs(const account_keys& acc, const transaction& tx, std::vector& outs, uint64_t& money_transfered, crypto::key_derivation& derivation); From fc01b6a0998a894aa6ea71b7a4271e9de4501147 Mon Sep 17 00:00:00 2001 From: sowle Date: Thu, 30 Jun 2022 18:42:13 +0200 Subject: [PATCH 5/5] tx_out_zarcanum: mix_attr added --- src/currency_core/currency_basic.h | 3 +++ src/currency_core/currency_boost_serialization.h | 1 + 2 files changed, 4 insertions(+) diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index b7c1de14..902265a5 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -358,6 +358,7 @@ namespace currency crypto::public_key concealing_point; // group element Q, see also Zarcanum paper crypto::public_key amount_commitment; uint64_t encrypted_amount; + uint8_t mix_attr; //crypto::public_key token_masked_generator; BEGIN_SERIALIZE_OBJECT() @@ -365,6 +366,7 @@ namespace currency FIELD(concealing_point) FIELD(amount_commitment) FIELD(encrypted_amount) + FIELD(mix_attr) END_SERIALIZE() BEGIN_BOOST_SERIALIZATION() @@ -372,6 +374,7 @@ namespace currency BOOST_SERIALIZE(concealing_point) BOOST_SERIALIZE(amount_commitment) BOOST_SERIALIZE(encrypted_amount) + BOOST_SERIALIZE(mix_attr) END_BOOST_SERIALIZATION() }; diff --git a/src/currency_core/currency_boost_serialization.h b/src/currency_core/currency_boost_serialization.h index 5d52d2ff..9a09dce1 100644 --- a/src/currency_core/currency_boost_serialization.h +++ b/src/currency_core/currency_boost_serialization.h @@ -117,6 +117,7 @@ namespace boost a & x.concealing_point; a & x.amount_commitment; a & x.encrypted_amount; + a & x.mix_attr; } template