From f3be3e1f82d43b7574f72f2c7244a10955864211 Mon Sep 17 00:00:00 2001 From: gladcow Date: Wed, 12 Feb 2020 18:28:13 +0300 Subject: [PATCH] Digest fix --- .../peerplays_sidechain/bitcoin_utils.cpp | 62 +++++++++++++++++-- .../bitcoin_utils_test.cpp | 8 +-- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp index 10708c88..c3fcf371 100644 --- a/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp +++ b/libraries/plugins/peerplays_sidechain/bitcoin_utils.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace graphene { namespace peerplays_sidechain { @@ -477,7 +478,7 @@ bytes hash_prevouts(const btc_tx& unsigned_tx) for(const auto& in: unsigned_tx.vin) { bytes data; - in.to_bytes(data); + in.prevout.to_bytes(data); hasher.write(reinterpret_cast(&data[0]), data.size()); } fc::sha256 res = fc::sha256::hash(hasher.result()); @@ -508,6 +509,47 @@ bytes hash_outputs(const btc_tx& unsigned_tx) return bytes(res.data(), res.data() + res.data_size()); } +bytes get_r(const fc::ecc::compact_signature& s) +{ + const unsigned char* start = s.begin(); + const unsigned char* end = s.begin() + 32; + while(*start++ == 0); + bytes res; + if(*start & 0x80) + res.push_back(0); + res.insert(res.end(), start, end); + return res; +} + +bytes get_s(const fc::ecc::compact_signature& s) +{ + const unsigned char* start = s.begin() + 32; + const unsigned char* end = s.begin() + 64; + while(*start++ == 0); + bytes res; + if(*start & 0x80) + res.push_back(0); + res.insert(res.end(), start, end); + return res; +} + +bytes to_DER_format(const fc::ecc::compact_signature& s) +{ + bytes r_value = get_r(s); + bytes s_value = get_s(s); + bytes der_signature; + der_signature.push_back(0x30); + der_signature.push_back(r_value.size() + s_value.size() + 4); // total len + der_signature.push_back(0x02); + der_signature.push_back(r_value.size()); + der_signature.insert(der_signature.end(), r_value.begin(), r_value.end()); + der_signature.push_back(0x02); + der_signature.push_back(s_value.size()); + der_signature.insert(der_signature.end(), s_value.begin(), s_value.end()); + der_signature.push_back(1); // SIGHASH_ALL + return der_signature; +} + std::vector signature_for_raw_transaction(const bytes& unsigned_tx, std::vector in_amounts, const bytes& redeem_script, @@ -522,8 +564,11 @@ std::vector signature_for_raw_transaction(const bytes& unsigned_tx, auto cur_amount = in_amounts.begin(); // pre-calc reused values bytes hashPrevouts = hash_prevouts(tx); + ilog("hashPrevouts ${h}", ("h", fc::to_hex(reinterpret_cast(&hashPrevouts[0]), hashPrevouts.size()))); bytes hashSequence = hash_sequence(tx); + ilog("hashSequence ${h}", ("h", fc::to_hex(reinterpret_cast(&hashSequence[0]), hashSequence.size()))); bytes hashOutputs = hash_outputs(tx); + ilog("hashOutputs ${h}", ("h", fc::to_hex(reinterpret_cast(&hashOutputs[0]), hashOutputs.size()))); // calc digest for every input according to BIP143 // implement SIGHASH_ALL scheme for(const auto& in: tx.vin) @@ -538,6 +583,7 @@ std::vector signature_for_raw_transaction(const bytes& unsigned_tx, bytes serializedScript; WriteBytesStream stream(serializedScript); stream.writedata(redeem_script); + ilog("Script size: ${s}", ("s", redeem_script.size())); hasher.write(reinterpret_cast(&serializedScript[0]), serializedScript.size()); uint64_t amount = *cur_amount++; hasher.write(reinterpret_cast(&amount), sizeof(amount)); @@ -545,11 +591,14 @@ std::vector signature_for_raw_transaction(const bytes& unsigned_tx, hasher.write(reinterpret_cast(&hashOutputs[0]), hashOutputs.size()); hasher.write(reinterpret_cast(&tx.nLockTime), sizeof(tx.nLockTime)); // add sigtype SIGHASH_ALL - hasher.put(1); + uint32_t sigtype = 1; + hasher.write(reinterpret_cast(&sigtype), sizeof(sigtype)); fc::sha256 digest = fc::sha256::hash(hasher.result()); - fc::ecc::compact_signature res = priv_key.sign_compact(digest); - results.push_back(bytes(res.begin(), res.begin() + res.size())); + ilog("Digest ${d}", ("d", fc::to_hex(digest.data(), digest.data_size()))); + fc::ecc::compact_signature res = priv_key.sign_compact(digest, false); + results.push_back(to_DER_format(res)); + ilog("Signature ${s}", ("s", fc::to_hex(reinterpret_cast(&results.back()[0]), results.back().size()))); } return results; } @@ -566,9 +615,10 @@ bytes sign_pw_transfer_transaction(const bytes &unsigned_tx, std::vector signatures = signature_for_raw_transaction(unsigned_tx, in_amounts, redeem_script, *key); - FC_ASSERT(signatures.size() == tx.vin.size(), "Invaid signatures number"); + FC_ASSERT(signatures.size() == tx.vin.size(), "Invalid signatures number"); + // push signatures in reverse order because script starts to check the top signature on the stack first for(unsigned int i = 0; i < tx.vin.size(); i++) - tx.vin[i].scriptWitness.push_back(signatures[i]); + tx.vin[i].scriptWitness.insert(tx.vin[i].scriptWitness.begin(), signatures[i]); } else { diff --git a/tests/peerplays_sidechain/bitcoin_utils_test.cpp b/tests/peerplays_sidechain/bitcoin_utils_test.cpp index 690e45e8..b7e42c70 100644 --- a/tests/peerplays_sidechain/bitcoin_utils_test.cpp +++ b/tests/peerplays_sidechain/bitcoin_utils_test.cpp @@ -48,7 +48,7 @@ BOOST_AUTO_TEST_CASE(pw_transfer) // Old PW address std::string old_pw = p2wsh_address_from_redeem_script(redeem_old, bitcoin_network::testnet); - ilog(old_pw); + ilog("First wallet address ${a}", ("a", old_pw)); // This address was filled with testnet transaction dc66f205a1bb03cd544c832f1d50e6746860c1223b08213f3cc793742e69c07d BOOST_REQUIRE(old_pw == "tb1qr2m64awu34wv8l69449ukl4atqylxh77ppdq862kuvfcp740hm7s3a0g6r"); @@ -71,7 +71,7 @@ BOOST_AUTO_TEST_CASE(pw_transfer) bytes redeem_new =generate_redeem_script(weights_new); // New PW address std::string new_pw = p2wsh_address_from_redeem_script(redeem_new, bitcoin_network::testnet); - ilog(new_pw); + ilog("Second wallet address ${a}", ("a", new_pw)); BOOST_REQUIRE(new_pw == "tb1qd6qfa9cu0gexk2y5xarlw56j542uultr7pepszc6473ksyrtna2q006kzc"); // try to move funds from old wallet to new one @@ -102,11 +102,11 @@ BOOST_AUTO_TEST_CASE(pw_transfer) tx.vout.push_back(output); bytes unsigned_tx; tx.to_bytes(unsigned_tx); - ilog(fc::to_hex(reinterpret_cast(&unsigned_tx[0]), unsigned_tx.size())); + ilog("Unsigned tx: [${tx}]", ("tx", fc::to_hex(reinterpret_cast(&unsigned_tx[0]), unsigned_tx.size()))); std::vector in_amounts({20000}); std::vector> keys_to_sign; for(auto key: priv_old) keys_to_sign.push_back(fc::optional(key)); bytes signed_tx =sign_pw_transfer_transaction(unsigned_tx, in_amounts, redeem_old, keys_to_sign); - ilog(fc::to_hex(reinterpret_cast(&signed_tx[0]), signed_tx.size())); + ilog("Signed tx: [${tx}]", ("tx", fc::to_hex(reinterpret_cast(&signed_tx[0]), signed_tx.size()))); }