diff --git a/src/crypto/clsag.cpp b/src/crypto/clsag.cpp index 5059a6fe..0b22642e 100644 --- a/src/crypto/clsag.cpp +++ b/src/crypto/clsag.cpp @@ -317,7 +317,7 @@ namespace crypto hsc.add_point(alpha_g * ki_base); hsc.add_point(alpha_x * c_point_X); hsc.add_point(alpha_x * ki_base); - DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")"); + //DBG_PRINT("c[" << secret_index << "] = Hs(ih, " << alpha_g * c_point_G << ", " << alpha_g * ki_base << ", " << alpha_x * c_point_X << ", " << alpha_x * ki_base << ")"); scalar_t c_prev = hsc.calc_hash(); // c_{secret_index + 1} sig.r_g.clear(); @@ -355,8 +355,8 @@ namespace crypto } - bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki, - const CLSAG_GGXG_signature& sig) + bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, + const key_image& ki, const CLSAG_GGXG_signature& sig) { DBG_PRINT("== verify_CLSAG_GGXG =="); size_t ring_size = ring.size(); @@ -474,7 +474,7 @@ namespace crypto hsc.add_point(sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x); c_prev = hsc.calc_hash(); // c_{i + 1} DBG_PRINT("c[" << i + 1 << "] = " << c_prev); - DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); + //DBG_PRINT("c[" << i + 1 << "] = Hs(ih, " << sig.r_g[i] * c_point_G + c_prev * W_pub_keys_g[i] << ", " << sig.r_g[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_g << ", " << sig.r_x[i] * c_point_X + c_prev * W_pub_keys_x[i] << ", " << sig.r_x[i] * hash_helper_t::hp(ring[i].stealth_address) + c_prev * W_key_image_x << ")"); } return c_prev == sig.c; diff --git a/src/crypto/clsag.h b/src/crypto/clsag.h index 140a25e1..8a4400e5 100644 --- a/src/crypto/clsag.h +++ b/src/crypto/clsag.h @@ -32,15 +32,18 @@ namespace crypto struct CLSAG_GG_input_ref_t { CLSAG_GG_input_ref_t(const public_key& stealth_address, const public_key& amount_commitment) - : stealth_address(stealth_address), amount_commitment(amount_commitment) {} + : stealth_address(stealth_address), amount_commitment(amount_commitment) + {} - const public_key& stealth_address; // not premultiplied by 1/8, TODO @#@#: make sure it's okay - const public_key& amount_commitment; // multiplied by 1/8 + const public_key& stealth_address; // P, not premultiplied by 1/8, TODO @#@#: make sure it's okay + const public_key& amount_commitment; // A, premultiplied by 1/8 }; + // pseudo_out_amount_commitment -- not premultiplied by 1/8 bool generate_CLSAG_GG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const key_image& ki, const scalar_t& secret_x, const scalar_t& secret_f, uint64_t secret_index, CLSAG_GG_signature& sig); + // pseudo_out_amount_commitment -- premultiplied by 1/8 bool verify_CLSAG_GG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const key_image& ki, const CLSAG_GG_signature& sig); @@ -71,10 +74,15 @@ namespace crypto const public_key& concealing_point; // Q, premultiplied by 1/8 }; + // pseudo_out_amount_commitment -- not premultiplied by 1/8 + // extended_amount_commitment -- not premultiplied by 1/8 bool generate_CLSAG_GGXG(const hash& m, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const point_t& extended_amount_commitment, const key_image& ki, const scalar_t& secret_0_xp, const scalar_t& secret_1_f, const scalar_t& secret_2_x, const scalar_t& secret_3_q, uint64_t secret_index, CLSAG_GGXG_signature& sig); - bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, const public_key& extended_amount_commitment, const key_image& ki, - const CLSAG_GGXG_signature& sig); + // pseudo_out_amount_commitment -- premultiplied by 1/8 + // extended_amount_commitment -- premultiplied by 1/8 + // may throw an exception TODO @#@# make sure it's okay + bool verify_CLSAG_GGXG(const hash& m, const std::vector& ring, const public_key& pseudo_out_amount_commitment, + const public_key& extended_amount_commitment, const key_image& ki, const CLSAG_GGXG_signature& sig); } // namespace crypto diff --git a/src/crypto/range_proofs.h b/src/crypto/range_proofs.h index 92980fc9..56213fcc 100644 --- a/src/crypto/range_proofs.h +++ b/src/crypto/range_proofs.h @@ -137,7 +137,7 @@ namespace crypto const point_t& bpp_crypto_trait_zano::bpp_H = c_point_G; template - const point_t& bpp_crypto_trait_zano::bpp_H2 = c_point_H2; + const point_t& bpp_crypto_trait_zano::bpp_H2 = c_point_X; // efficient multiexponentiation (naive stub implementation atm, TODO) diff --git a/src/crypto/zarcanum.cpp b/src/crypto/zarcanum.cpp index d9f1b39b..9056fda5 100644 --- a/src/crypto/zarcanum.cpp +++ b/src/crypto/zarcanum.cpp @@ -45,9 +45,8 @@ namespace crypto #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ if (!(cond)) { LOG_PRINT_RED("zarcanum_generate_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ if (p_err) { *p_err = err_code; } return false; } - - bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const point_t& pseudo_out_amount_commitment, + bool zarcanum_generate_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, const point_t& pseudo_out_amount_commitment, const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, const scalar_t& secret_x, const scalar_t& secret_q, uint64_t secret_index, const scalar_t& pseudo_out_blinding_mask, uint64_t stake_amount, const scalar_t& stake_blinding_mask, zarcanum_proof& result, uint8_t* p_err /* = nullptr */) @@ -117,7 +116,7 @@ namespace crypto const scalar_vec_t masks2 = { bx }; // X component const std::vector E_1div8_vec_ptr = { &result.E }; - CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10); + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_gen>(values, masks, masks2, E_1div8_vec_ptr, result.E_range_proof), 10); // = four-layers ring signature data outline = // (j in [0, ring_size-1]) @@ -144,6 +143,9 @@ namespace crypto // Q[j] // layer 3 secret (with respect to G) // secret_q + + result.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key(); + TRY_ENTRY() CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(generate_CLSAG_GGXG(m, ring, pseudo_out_amount_commitment, C, stake_ki, secret_x, stake_blinding_mask - pseudo_out_blinding_mask, x0, secret_q, secret_index, @@ -152,11 +154,27 @@ namespace crypto return true; } + #undef CHECK_AND_FAIL_WITH_ERROR_IF_FALSE - bool zarcanum_verify_proof(const hash& kernel_hash, const public_key& commitment_1div8, const scalar_t& last_pow_block_id_hashed, const zarcanum_proof& proof, uint8_t* p_err /* = nullptr */) + + #define CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(cond, err_code) \ + if (!(cond)) { LOG_PRINT_RED("zarcanum_verify_proof: \"" << #cond << "\" is false at " << LOCATION_SS << ENDL << "error code = " << err_code, LOG_LEVEL_3); \ + if (p_err) { *p_err = err_code; } return false; } + + bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const zarcanum_proof& sig, uint8_t* p_err /* = nullptr */) { - return false; + bool r = false; + + std::vector E_for_range_proof = { point_t(sig.E) }; + std::vector range_proofs = { bppe_sig_commit_ref_t(sig.E_range_proof, E_for_range_proof) }; + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(bppe_verify>(range_proofs), 10); + + CHECK_AND_FAIL_WITH_ERROR_IF_FALSE(verify_CLSAG_GGXG(m, ring, sig.pseudo_out_amount_commitment, sig.C, stake_ki, sig.clsag_ggxg), 1); + + return true; } diff --git a/src/crypto/zarcanum.h b/src/crypto/zarcanum.h index 9d19ce5b..b8471bc3 100644 --- a/src/crypto/zarcanum.h +++ b/src/crypto/zarcanum.h @@ -50,6 +50,8 @@ namespace crypto zarcanum_proof& result, uint8_t* p_err = nullptr); - bool zarcanum_verify_proof(const hash& kernel_hash, const public_key& commitment_1div8, const scalar_t& last_pow_block_id_hashed, const zarcanum_proof& proof, uint8_t* p_err = nullptr); + bool zarcanum_verify_proof(const hash& m, const hash& kernel_hash, const std::vector& ring, + const scalar_t& last_pow_block_id_hashed, const key_image& stake_ki, + const zarcanum_proof& sig, uint8_t* p_err = nullptr); } // namespace crypto diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 7386f044..ed388cf1 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -37,6 +37,7 @@ #include "tx_semantic_validation.h" #include "crypto/RIPEMD160_helper.h" #include "crypto/bitcoin/sha256_helper.h" +#include "crypto_config.h" #undef LOG_DEFAULT_CHANNEL @@ -1280,7 +1281,10 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t } if (pos) { - CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake transaction in the block has the wrong type"); + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_zc_input), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name()); + else + CHECK_AND_ASSERT_MES(b.miner_tx.vin[1].type() == typeid(txin_to_key), false, "coinstake tx has incorrect type of input #1: " << b.miner_tx.vin[1].type().name()); } if (m_core_runtime_config.is_hardfork_active_for_height(1, height)) @@ -1315,11 +1319,19 @@ bool blockchain_storage::prevalidate_miner_transaction(const block& b, uint64_t return false; } - if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) + if (is_hardfork_active(ZANO_HARDFORK_04_ZARCANUM)) // TODO @#@# consider moving to validate_tx_for_hardfork_specific_terms { - CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 2, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2"); - CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)"); - CHECK_AND_ASSERT_MES(b.miner_tx.attachment[1].type() == typeid(zc_balance_proof), false, "coinbase transaction wrong attachmenttype #1 (expected: zc_balance_proof)"); + if (pos) + { + CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 1, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2"); + CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)"); + } + else + { + CHECK_AND_ASSERT_MES(b.miner_tx.attachment.size() == 2, false, "coinbase transaction has incorrect number of attachments (" << b.miner_tx.attachment.size() << "), expected 2"); + CHECK_AND_ASSERT_MES(b.miner_tx.attachment[0].type() == typeid(zc_outs_range_proof), false, "coinbase transaction wrong attachment #0 type (expected: zc_outs_range_proof)"); + CHECK_AND_ASSERT_MES(b.miner_tx.attachment[1].type() == typeid(zc_balance_proof), false, "coinbase transaction wrong attachmenttype #1 (expected: zc_balance_proof)"); + } } else { @@ -5441,10 +5453,13 @@ bool blockchain_storage::validate_pos_block(const block& b, for(auto& zc_out : scan_contex.zc_outs) ring.emplace_back(zc_out.stealth_address, zc_out.amount_commitment, zc_out.concealing_point); - r = crypto::verify_CLSAG_GGXG(miner_tx_hash, ring, sig.pseudo_out_amount_commitment, sig.C, stake_input.k_image, sig.clsag_ggxg); - CHECK_AND_ASSERT_MES(r, false, "verify_CLSAG_GGXG failed"); + crypto::scalar_t last_pow_block_id_hashed = crypto::hash_helper_t::hs(CRYPTO_HDS_ZARCANUM_LAST_POW_HASH, sm.last_pow_id); + + uint8_t err = 0; + r = crypto::zarcanum_verify_proof(miner_tx_hash, kernel_hash, ring, last_pow_block_id_hashed, stake_input.k_image, sig, &err); + CHECK_AND_ASSERT_MES(r, false, "zarcanum_verify_proof failed with code " << err); - return false; // not implemented yet, TODO @#@# + return true; } else { diff --git a/src/currency_core/crypto_config.h b/src/currency_core/crypto_config.h index 3e4deffe..087c1cfd 100644 --- a/src/currency_core/crypto_config.h +++ b/src/currency_core/crypto_config.h @@ -22,7 +22,6 @@ #define CRYPTO_HDS_CLSAG_GGXG_CHALLENGE "ZANO_HDS_CLSAG_GGXG_CHALLENGE__" #define CRYPTO_HDS_ZARCANUM_LAST_POW_HASH "ZANO_HDS_ZARCANUM_LAST_POW_HASH" -#define CRYPTO_HDS_ZARCANUM_SECRET_Q "ZANO_HDS_ZARCANUM_SECRET_Q_____" #define CRYPTO_HDS_ZARCANUM_PROOF_HASH "ZANO_HDS_ZARCANUM_PROOF_HASH___" #define CRYPTO_HDS_ASSET_CONTROL_KEY "ZANO_HDS_ASSET_CONTROL_KEY_____" diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index d5b64558..015eccf4 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -387,6 +387,9 @@ namespace currency VARIANT_CASE_CONST(ZC_sig, zc_sig); sum_of_pseudo_out_amount_commitments += crypto::point_t(zc_sig.pseudo_out_amount_commitment); // *1/8 ++zc_sigs_count; + VARIANT_CASE_CONST(zarcanum_sig, sig); + sum_of_pseudo_out_amount_commitments += crypto::point_t(sig.pseudo_out_amount_commitment); // *1/8 + ++zc_sigs_count; VARIANT_SWITCH_END(); } sum_of_pseudo_out_amount_commitments.modify_mul8(); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index f7434747..2db2235c 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3796,7 +3796,6 @@ bool wallet2::prepare_and_sign_pos_block(const mining_context& cxt, currency::bl crypto::scalar_t pseudo_out_blinding_mask = crypto::scalar_t::random(); crypto::point_t pseudo_out_amount_commitment = td.m_amount * crypto::c_point_H + pseudo_out_blinding_mask * crypto::c_point_G; - sig.pseudo_out_amount_commitment = (crypto::c_scalar_1div8 * pseudo_out_amount_commitment).to_public_key(); crypto::hash tx_hash_for_sig = get_transaction_hash(b.miner_tx);