diff --git a/src/currency_core/blockchain_storage.cpp b/src/currency_core/blockchain_storage.cpp index 420a9f36..ce804515 100644 --- a/src/currency_core/blockchain_storage.cpp +++ b/src/currency_core/blockchain_storage.cpp @@ -6673,7 +6673,7 @@ bool blockchain_storage::is_output_allowed_for_input(const output_key_or_htlc_v& } } //------------------------------------------------------------------ -bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, const signature_v& input_sigs_v, uint64_t split_height, const alt_chain_type& alt_chain) const +bool blockchain_storage::validate_alt_block_ms_input(const transaction& input_tx, const crypto::hash& input_tx_hash, size_t input_index, uint64_t split_height, const alt_chain_type& alt_chain) const { // Main and alt chain outline: // diff --git a/src/currency_core/currency_basic.h b/src/currency_core/currency_basic.h index 623f4117..e0ff6f82 100644 --- a/src/currency_core/currency_basic.h +++ b/src/currency_core/currency_basic.h @@ -759,7 +759,7 @@ namespace currency FIELDS(*static_cast(this)) CHAIN_TRANSITION_VER(TRANSACTION_VERSION_INITAL, transaction_v1) CHAIN_TRANSITION_VER(TRANSACTION_VERSION_PRE_HF4, transaction_v1) - FIELD(signature) + FIELD(signatures) FIELD(attachment) END_SERIALIZE() }; @@ -774,7 +774,7 @@ namespace currency vin.clear(); vout.clear(); extra.clear(); - signature = NLSAG_sig(); + signatures.clear(); attachment.clear(); } diff --git a/src/currency_core/currency_basic_backward_comp.inl b/src/currency_core/currency_basic_backward_comp.inl index 4e3bf92a..1dd09309 100644 --- a/src/currency_core/currency_basic_backward_comp.inl +++ b/src/currency_core/currency_basic_backward_comp.inl @@ -90,13 +90,15 @@ template bool transition_convert(const transaction_current_t& from, transaction_v1& to) { to.attachment = from.attachment; - if (from.signature.type() == typeid(NLSAG_sig)) + for (const auto& s : from.signatures) { - to.signatures = boost::get(from.signature).s; - } - else - { - throw std::runtime_error("Unexpected type in signature_v"); + if (s.type() == typeid(NLSAG_sig)) + { + to.signatures.push_back(boost::get(s).s); ; + }else + { + throw std::runtime_error("Unexpected type in signature_v"); + } } return true; } @@ -106,6 +108,10 @@ bool transition_convert(const transaction_v1& from, transaction_current_t& to) { // TODO: consider using move semantic for 'from' to.attachment = from.attachment; - to.signature = NLSAG_sig({from.signatures}); + to.signatures.resize(from.signatures.size()); + for (size_t i = 0; i != from.signatures.size(); i++) + { + boost::get(to.signatures[i]).s = from.signatures[i]; + } return true; } diff --git a/src/currency_core/currency_format_utils.cpp b/src/currency_core/currency_format_utils.cpp index f9ed697c..2a374c53 100644 --- a/src/currency_core/currency_format_utils.cpp +++ b/src/currency_core/currency_format_utils.cpp @@ -196,7 +196,6 @@ namespace currency posin.k_image = pe.keyimage; tx.vin.push_back(posin); //reserve place for ring signature - //tx.signature = NLSAG_sig(); tx.signatures.resize(1); tx.signatures[0] = NLSAG_sig(); boost::get(tx.signatures[0]).s.resize(posin.key_offsets.size()); diff --git a/src/currency_core/currency_format_utils.h b/src/currency_core/currency_format_utils.h index 21e0cea4..a6271037 100644 --- a/src/currency_core/currency_format_utils.h +++ b/src/currency_core/currency_format_utils.h @@ -56,7 +56,9 @@ namespace currency bool operator ==(const currency::transaction& a, const currency::transaction& b); bool operator ==(const currency::block& a, const currency::block& b); bool operator ==(const currency::extra_attachment_info& a, const currency::extra_attachment_info& b); - + bool operator ==(const currency::NLSAG_sig& a, const currency::NLSAG_sig& b); + bool operator ==(const currency::void_sig& a, const currency::void_sig& b); + bool operator ==(const currency::zarcanum_sig& a, const currency::zarcanum_sig& b); typedef boost::multiprecision::uint128_t uint128_tl; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 02a3267f..164432d9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -3507,8 +3507,9 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, return false; // to get rid of warning }else { - NLSAG_sig& signatures = boost::get(b.miner_tx.signature); - WLT_CHECK_AND_ASSERT_MES(signatures.s.size() == 1 && signatures.s[0].size() == txin.key_offsets.size(), + WLT_CHECK_AND_ASSERT_MES(b.miner_tx.signatures.size() == 1 && + b.miner_tx.signatures[0].type() == typeid(NLSAG_sig) && + boost::get(b.miner_tx.signatures[0]).s.size() == txin.key_offsets.size(), false, "Wrong signatures amount in coinbase transacton"); @@ -3536,12 +3537,12 @@ bool wallet2::prepare_and_sign_pos_block(currency::block& b, keys_ptrs, derived_secret_ephemeral_key, 0, - &signatures.s[0][0]); + &boost::get(b.miner_tx.signatures[0]).s[0]); WLT_LOG_L4("GENERATED RING SIGNATURE: block_id " << block_hash << "txin.k_image" << txin.k_image << "key_ptr:" << *keys_ptrs[0] - << "signature:" << signatures.s[0][0]); + << "signature:" << boost::get(b.miner_tx.signatures[0]).s); return true; } diff --git a/src/wallet/wallet2_escrow.cpp b/src/wallet/wallet2_escrow.cpp index af4f735e..542db5f2 100644 --- a/src/wallet/wallet2_escrow.cpp +++ b/src/wallet/wallet2_escrow.cpp @@ -234,14 +234,14 @@ bool wallet2::validate_escrow_release(const transaction& tx, bool release_type_n // (5/5) signatures - VARIANT_SWITCH_BEGIN(tx.signature); - VARIANT_CASE_CONST(NLSAG_sig, signatures) - { - LOC_CHK(signatures.s.size() == 1, "invalid singatures size: " << signatures.s.size()); // only 1 input means only 1 signature vector + LOC_CHK(tx.signatures.size() == 1, "invalid singatures size: " << tx.signatures.size()); // only 1 input means only 1 signature vector - // As we don't have b_keys we can't be sure which signature is B's and which is reserved for A (should be a null-placeholder, if present). - // Having a_keys, we determine index of A key in multisig output keys array. - // Thus it's possible to determine the order of signatures (A, B or B, A), and, eventually, validate B signature. + VARIANT_SWITCH_BEGIN(tx.signatures[0]); + VARIANT_CASE_CONST(NLSAG_sig, signature) + { + // As we don't have b_keys we can't be sure which signature is B's and which is reserved for A (should be a null-placeholder, if present). + // Having a_keys, we determine index of A key in multisig output keys array. + // Thus it's possible to determine the order of signatures (A, B or B, A), and, eventually, validate B signature. crypto::public_key source_tx_pub_key = get_tx_pub_key_from_extra(source_tx); r = crypto::generate_key_derivation(source_tx_pub_key, a_keys.view_secret_key, der); LOC_CHK(r, "generate_key_derivation failed"); @@ -250,14 +250,14 @@ bool wallet2::validate_escrow_release(const transaction& tx, bool release_type_n LOC_CHK(r, "derive_public_key failed"); LOC_CHK(source_ms_out.keys.size() == 2, "internal error: invalid ms output keys array, size: " << source_ms_out.keys.size()); - LOC_CHK(signatures.s[0].size() == 2, "internal error: invalid signature size for input #0: " << signatures.s[0].size()) + LOC_CHK(signature.size() == 2, "internal error: invalid signature size for input #0: " << signature.size()) size_t ms_out_key_a_index = std::find(source_ms_out.keys.begin(), source_ms_out.keys.end(), ephemeral_pub_key) - source_ms_out.keys.begin(); LOC_CHK(ms_out_key_a_index < source_ms_out.keys.size(), "internal error: can't find A ephemeral pub key within ms output keys"); size_t ms_out_key_b_index = 1 - ms_out_key_a_index; - // in this particular case (source_ms_out.minimum_sigs == source_ms_out.keys.size() == 2) index in 'keys' is the same as index in signatures.s[0] + // in this particular case (source_ms_out.minimum_sigs == source_ms_out.keys.size() == 2) index in 'keys' is the same as index in signature crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, 0, get_transaction_hash(tx)); - r = crypto::check_signature(tx_hash_for_signature, source_ms_out.keys[ms_out_key_b_index], signatures.s[0][ms_out_key_b_index]); + r = crypto::check_signature(tx_hash_for_signature, source_ms_out.keys[ms_out_key_b_index], signature[ms_out_key_b_index]); LOC_CHK(r, "B signature for multisig input is invalid"); } VARIANT_CASE_CONST(zarcanum_sig, s); @@ -418,17 +418,18 @@ bool wallet2::validate_escrow_cancel_release(const currency::transaction& tx, co // (5/5) signatures - VARIANT_SWITCH_BEGIN(tx.signature); + LOC_CHK(tx.signatures.size() == 1, "invalid singatures size: " << tx.signatures.size()); // only 1 input means only 1 signature vector + VARIANT_SWITCH_BEGIN(tx.signatures[0]); VARIANT_CASE_CONST(NLSAG_sig, signatures) { - LOC_CHK(signatures.s.size() == 1, "invalid singatures size: " << signatures.s.size()); // only 1 input means only 1 signature vector - LOC_CHK(signatures.s[0].size() == 2, "invalid signature[0] size: " << signatures.s[0].size()); // it's expected to contain A-party signature and null-sig placeholder + + LOC_CHK(signature.size() == 2, "invalid signature[0] size: " << signature.size()); // it's expected to contain A-party signature and null-sig placeholder LOC_CHK(source_ms_out.keys.size() == 2, "internal error: invalid source ms output keys array, size: " << source_ms_out.keys.size()); - size_t a_sign_index = (signatures.s[0][0] != null_sig) ? 0 : 1; + size_t a_sign_index = (signature[0] != null_sig) ? 0 : 1; crypto::hash tx_hash_for_signature = prepare_prefix_hash_for_sign(tx, 0, get_transaction_hash(tx)); - r = crypto::check_signature(tx_hash_for_signature, source_ms_out.keys[a_sign_index], signatures.s[0][a_sign_index]); + r = crypto::check_signature(tx_hash_for_signature, source_ms_out.keys[a_sign_index], signature[a_sign_index]); LOC_CHK(r, "A signature for multisig input is invalid"); } VARIANT_CASE_CONST(zarcanum_sig, s); diff --git a/tests/unit_tests/serialization.cpp b/tests/unit_tests/serialization.cpp index 24e950d8..ea6e9c3f 100644 --- a/tests/unit_tests/serialization.cpp +++ b/tests/unit_tests/serialization.cpp @@ -26,6 +26,12 @@ struct Struct char blob[8]; }; + +std::ostream& operator <<(std::ostream& o, const currency::signature_v& v) +{ + return o; +} + template struct serializer { @@ -270,6 +276,18 @@ namespace } return res; } + + template + std::vector linearize_vector2(const std::vector< currency::signature_v >& vec_vec) + { + std::vector res; + BOOST_FOREACH(const auto& vec, vec_vec) + { + res.insert(res.end(), vec.begin(), vec.end()); + } + return res; + } + } bool test_get_varint_packed_size_for_num(uint64_t n) @@ -330,7 +348,8 @@ TEST(Serialization, serializes_transacion_signatures_correctly) ASSERT_TRUE(false); } - ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); + ASSERT_EQ(tx.signatures, tx1.signatures); + //ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); // Miner tx without signatures txin_gen txin_gen1; @@ -344,10 +363,11 @@ TEST(Serialization, serializes_transacion_signatures_correctly) { ASSERT_TRUE(false); } - ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); + ASSERT_EQ(tx.signatures, tx1.signatures); + //ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); // Miner tx with empty signatures 2nd vector - boost::get(tx.signature).s.resize(1); + tx.signatures.resize(1); ASSERT_TRUE(serialization::dump_binary(tx, blob)); ASSERT_EQ(9, blob.size()); // 5 bytes + 2 bytes vin[0] + 0 bytes extra + 0 bytes signatures + counter ASSERT_TRUE(serialization::parse_binary(blob, tx1)); @@ -355,29 +375,30 @@ TEST(Serialization, serializes_transacion_signatures_correctly) { ASSERT_TRUE(false); } - ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); + ASSERT_EQ(tx.signatures, tx1.signatures); + //ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); //TX VALIDATION REMOVED FROM SERIALIZATION /* // Miner tx with one signature - boost::get(tx.signature).s[0].resize(1); + tx.signatures[0].resize(1); ASSERT_FALSE(serialization::dump_binary(tx, blob)); // Miner tx with 2 empty vectors - boost::get(tx.signature).s.resize(2); - boost::get(tx.signature).s[0].resize(0); - boost::get(tx.signature).s[1].resize(0); + tx.signatures.resize(2); + tx.signatures[0].resize(0); + tx.signatures[1].resize(0); ASSERT_FALSE(serialization::dump_binary(tx, blob)); // Miner tx with 2 signatures - boost::get(tx.signature).s[0].resize(1); - boost::get(tx.signature).s[1].resize(1); + tx.signatures[0].resize(1); + tx.signatures[1].resize(1); ASSERT_FALSE(serialization::dump_binary(tx, blob)); */ // Two txin_gen, no signatures tx.vin.push_back(txin_gen1); - boost::get(tx.signature).s.resize(0); + tx.signatures.resize(0); ASSERT_TRUE(serialization::dump_binary(tx, blob)); ASSERT_EQ(10, blob.size()); // 5 bytes + 2 * 2 bytes vins + 0 bytes extra + 0 bytes signatures ASSERT_TRUE(serialization::parse_binary(blob, tx1)); @@ -385,14 +406,15 @@ TEST(Serialization, serializes_transacion_signatures_correctly) { ASSERT_TRUE(false); } - ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); + ASSERT_EQ(tx.signatures, tx1.signatures); + //ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); // Two txin_gen, signatures vector contains only one empty element //signatures.resize(1); //ASSERT_FALSE(serialization::dump_binary(tx, blob)); // Two txin_gen, signatures vector contains two empty elements - boost::get(tx.signature).s.resize(2); + tx.signatures.resize(2); ASSERT_TRUE(serialization::dump_binary(tx, blob)); ASSERT_EQ(12, blob.size()); // 5 bytes + 2 * 2 bytes vins + 0 bytes extra + 0 bytes signatures ASSERT_TRUE(serialization::parse_binary(blob, tx1)); @@ -400,7 +422,9 @@ TEST(Serialization, serializes_transacion_signatures_correctly) { ASSERT_TRUE(false); } - ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); + + ASSERT_EQ(tx.signatures, tx1.signatures); + //ASSERT_EQ(linearize_vector2(boost::get(tx.signature).s), linearize_vector2(boost::get(tx1.signature).s)); // Two txin_gen, signatures vector contains three empty elements //signatures.resize(3); @@ -415,7 +439,7 @@ TEST(Serialization, serializes_transacion_signatures_correctly) // A few bytes instead of signature tx.vin.clear(); tx.vin.push_back(txin_gen1); - boost::get(tx.signature).s.clear(); + tx.signatures.clear(); ASSERT_TRUE(serialization::dump_binary(tx, blob)); blob.append(std::string(sizeof(crypto::signature) / 2, 'x')); ASSERT_FALSE(serialization::parse_binary(blob, tx1)); @@ -438,28 +462,28 @@ TEST(Serialization, serializes_transacion_signatures_correctly) /* // Too much signatures for two inputs - boost::get(tx.signature).s.resize(3); - boost::get(tx.signature).s[0].resize(2); - boost::get(tx.signature).s[1].resize(2); - boost::get(tx.signature).s[2].resize(2); + tx.signatures.resize(3); + tx.signatures[0].resize(2); + tx.signatures[1].resize(2); + tx.signatures[2].resize(2); ASSERT_FALSE(serialization::dump_binary(tx, blob)); // First signatures vector contains too little elements - boost::get(tx.signature).s.resize(2); - boost::get(tx.signature).s[0].resize(1); - boost::get(tx.signature).s[1].resize(2); + tx.signatures.resize(2); + tx.signatures[0].resize(1); + tx.signatures[1].resize(2); ASSERT_FALSE(serialization::dump_binary(tx, blob)); // First signatures vector contains too much elements - boost::get(tx.signature).s.resize(2); - boost::get(tx.signature).s[0].resize(3); - boost::get(tx.signature).s[1].resize(2); + tx.signatures.resize(2); + tx.signatures[0].resize(3); + tx.signatures[1].resize(2); ASSERT_FALSE(serialization::dump_binary(tx, blob)); // There are signatures for each input - boost::get(tx.signature).s.resize(2); - boost::get(tx.signature).s[0].resize(2); - boost::get(tx.signature).s[1].resize(2); + tx.signatures.resize(2); + tx.signatures[0].resize(2); + tx.signatures[1].resize(2); ASSERT_TRUE(serialization::dump_binary(tx, blob)); ASSERT_TRUE(serialization::parse_binary(blob, tx1)); ASSERT_EQ(tx, tx1);