Skip to content

Commit

Permalink
Port script
Browse files Browse the repository at this point in the history
  • Loading branch information
timemarkovqtum committed Feb 2, 2024
1 parent b905e2a commit 3693f1d
Show file tree
Hide file tree
Showing 12 changed files with 504 additions and 22 deletions.
8 changes: 4 additions & 4 deletions src/crypto/muhash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ void Num3072::Divide(const Num3072& a)
if (this->IsOverflow()) this->FullReduce();
}

Num3072::Num3072(const unsigned char (&data)[BYTE_SIZE]) {
Num3072::Num3072(const unsigned char (&data)[DATA_BYTE_SIZE]) {
for (int i = 0; i < LIMBS; ++i) {
if (sizeof(limb_t) == 4) {
this->limbs[i] = ReadLE32(data + 4 * i);
Expand All @@ -285,7 +285,7 @@ Num3072::Num3072(const unsigned char (&data)[BYTE_SIZE]) {
}
}

void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
void Num3072::ToBytes(unsigned char (&out)[DATA_BYTE_SIZE]) {
for (int i = 0; i < LIMBS; ++i) {
if (sizeof(limb_t) == 4) {
WriteLE32(out + i * 4, this->limbs[i]);
Expand All @@ -296,7 +296,7 @@ void Num3072::ToBytes(unsigned char (&out)[BYTE_SIZE]) {
}

Num3072 MuHash3072::ToNum3072(Span<const unsigned char> in) {
unsigned char tmp[Num3072::BYTE_SIZE];
unsigned char tmp[Num3072::DATA_BYTE_SIZE];

uint256 hashed_in{(HashWriter{} << in).GetSHA256()};
static_assert(sizeof(tmp) % ChaCha20Aligned::BLOCKLEN == 0);
Expand All @@ -316,7 +316,7 @@ void MuHash3072::Finalize(uint256& out) noexcept
m_numerator.Divide(m_denominator);
m_denominator.SetToOne(); // Needed to keep the MuHash object valid

unsigned char data[Num3072::BYTE_SIZE];
unsigned char data[Num3072::DATA_BYTE_SIZE];
m_numerator.ToBytes(data);

out = (HashWriter{} << data).GetSHA256();
Expand Down
6 changes: 3 additions & 3 deletions src/crypto/muhash.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Num3072
Num3072 GetInverse() const;

public:
static constexpr size_t BYTE_SIZE = 384;
static constexpr size_t DATA_BYTE_SIZE = 384;

#ifdef __SIZEOF_INT128__
typedef unsigned __int128 double_limb_t;
Expand All @@ -49,10 +49,10 @@ class Num3072
void Divide(const Num3072& a);
void SetToOne();
void Square();
void ToBytes(unsigned char (&out)[BYTE_SIZE]);
void ToBytes(unsigned char (&out)[DATA_BYTE_SIZE]);

Num3072() { this->SetToOne(); };
Num3072(const unsigned char (&data)[BYTE_SIZE]);
Num3072(const unsigned char (&data)[DATA_BYTE_SIZE]);

SERIALIZE_METHODS(Num3072, obj)
{
Expand Down
2 changes: 1 addition & 1 deletion src/init/bitcoin-gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace init {
namespace {
const char* EXE_NAME = "bitcoin-gui";
const char* EXE_NAME = "qtum-gui";

class BitcoinGuiInit : public interfaces::Init
{
Expand Down
2 changes: 1 addition & 1 deletion src/init/bitcoin-node.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

namespace init {
namespace {
const char* EXE_NAME = "bitcoin-node";
const char* EXE_NAME = "qtum-node";

class BitcoinNodeInit : public interfaces::Init
{
Expand Down
179 changes: 169 additions & 10 deletions src/script/interpreter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
#include <script/script.h>
#include <uint256.h>

typedef std::vector<unsigned char> valtype;

namespace {

Expand Down Expand Up @@ -60,7 +59,7 @@ static inline void popstack(std::vector<valtype>& stack)
stack.pop_back();
}

bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
if (vchPubKey.size() < CPubKey::COMPRESSED_SIZE) {
// Non-canonical public key: too short
return false;
Expand Down Expand Up @@ -104,7 +103,7 @@ bool static IsCompressedPubKey(const valtype &vchPubKey) {
*
* This function is consensus-critical since BIP66.
*/
bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig, bool haveHashType = true) {
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S] [sighash]
// * total-length: 1-byte length descriptor of everything that follows,
// excluding the sighash byte.
Expand All @@ -125,7 +124,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
if (sig[0] != 0x30) return false;

// Make sure the length covers the entire signature.
if (sig[1] != sig.size() - 3) return false;
if (sig[1] != sig.size() - (haveHashType ? 3 : 2)) return false;

// Extract the length of the R element.
unsigned int lenR = sig[3];
Expand All @@ -138,7 +137,7 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {

// Verify that the length of the signature matches the sum of the length
// of the elements.
if ((size_t)(lenR + lenS + 7) != sig.size()) return false;
if ((size_t)(lenR + lenS + (haveHashType ? 7 : 6)) != sig.size()) return false;

// Check whether the R element is an integer.
if (sig[2] != 0x02) return false;
Expand Down Expand Up @@ -169,14 +168,14 @@ bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {
return true;
}

bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
if (!IsValidSignatureEncoding(vchSig)) {
bool IsLowDERSignature(const valtype &vchSig, ScriptError* serror, bool haveHashType) {
if (!IsValidSignatureEncoding(vchSig, haveHashType)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
// https://bitcoin.stackexchange.com/a/12556:
// Also note that inside transaction signatures, an extra hashtype byte
// follows the actual signature data.
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - 1);
std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size() - (haveHashType ? 1 : 0));
// If the S value is above the order of the curve divided by two, its
// complement modulo the order could have been used instead, which is
// one byte shorter when encoded correctly.
Expand All @@ -186,6 +185,13 @@ bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
return true;
}

bool IsDERSignature(const valtype &vchSig, ScriptError* serror, bool haveHashType) {
if (!IsValidSignatureEncoding(vchSig, haveHashType)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
return true;
}

bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
if (vchSig.size() == 0) {
return false;
Expand Down Expand Up @@ -1213,6 +1219,27 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
}
break;

//////////////////////////////////////////////////////// qtum
case OP_SENDER:
{
if(!(flags & SCRIPT_OUTPUT_SENDER))
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
break;
case OP_SPEND:
{
return true; // temp
}
break;
case OP_CREATE:
case OP_CALL:
{
valtype scriptRest(pc - 1, pend);
stack.push_back(scriptRest);
return true; // temp
}
break;
////////////////////////////////////////////////////////
default:
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
}
Expand Down Expand Up @@ -1360,6 +1387,22 @@ uint256 GetSequencesSHA256(const T& txTo)
return ss.GetSHA256();
}

template <class T>
uint256 GetFirstPrevoutSHA256(const T& txTo)
{
HashWriter ss{};
ss << txTo.vin[0].prevout;
return ss.GetSHA256();
}

template <class T>
uint256 GetFirstSequenceSHA256(const T& txTo)
{
HashWriter ss{};
ss << txTo.vin[0].nSequence;
return ss.GetSHA256();
}

/** Compute the (single) SHA256 of the concatenation of all txouts of a tx. */
template <class T>
uint256 GetOutputsSHA256(const T& txTo)
Expand Down Expand Up @@ -1391,6 +1434,27 @@ uint256 GetSpentScriptsSHA256(const std::vector<CTxOut>& outputs_spent)
return ss.GetSHA256();
}

CTxOut GetOutputWithoutSenderSig(const CTxOut& output)
{
return CTxOut(output.nValue, output.scriptPubKey.WithoutSenderSig());
}

template <class T>
uint256 GetOutputsOpSenderSHA256(const T& txTo)
{
HashWriter ss{};
for (const auto& txout : txTo.vout) {
if(txout.scriptPubKey.HasOpSender())
{
ss << GetOutputWithoutSenderSig(txout);
}
else
{
ss << txout;
}
}
return ss.GetSHA256();
}

} // namespace

Expand All @@ -1408,6 +1472,7 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
// Determine which precomputation-impacting features this transaction uses.
bool uses_bip143_segwit = force;
bool uses_bip341_taproot = force;
bool uses_op_sender = txTo.HasOpSender();
for (size_t inpos = 0; inpos < txTo.vin.size() && !(uses_bip143_segwit && uses_bip341_taproot); ++inpos) {
if (!txTo.vin[inpos].scriptWitness.IsNull()) {
if (m_spent_outputs_ready && m_spent_outputs[inpos].scriptPubKey.size() == 2 + WITNESS_V1_TAPROOT_SIZE &&
Expand All @@ -1427,16 +1492,24 @@ void PrecomputedTransactionData::Init(const T& txTo, std::vector<CTxOut>&& spent
if (uses_bip341_taproot && uses_bip143_segwit) break; // No need to scan further if we already need all.
}

if (uses_bip143_segwit || uses_bip341_taproot) {
if (uses_bip143_segwit || uses_bip341_taproot || uses_op_sender) {
// Computations shared between both sighash schemes.
m_prevouts_single_hash = GetPrevoutsSHA256(txTo);
m_sequences_single_hash = GetSequencesSHA256(txTo);
m_outputs_single_hash = GetOutputsSHA256(txTo);
if(uses_op_sender)
{
m_outputs_opsender_single_hash = GetOutputsOpSenderSHA256(txTo);
}
}
if (uses_bip143_segwit) {
if (uses_bip143_segwit || uses_op_sender) {
hashPrevouts = SHA256Uint256(m_prevouts_single_hash);
hashSequence = SHA256Uint256(m_sequences_single_hash);
hashOutputs = SHA256Uint256(m_outputs_single_hash);
if(uses_op_sender)
{
hashOutputsOpSender = SHA256Uint256(m_outputs_opsender_single_hash);
}
m_bip143_segwit_ready = true;
}
if (uses_bip341_taproot && m_spent_outputs_ready) {
Expand Down Expand Up @@ -1564,6 +1637,60 @@ bool SignatureHashSchnorr(uint256& hash_out, ScriptExecutionData& execdata, cons
return true;
}

template <class T>
uint256 SignatureHashOutput(const CScript& scriptCode, const T& txTo, unsigned int nOut, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
assert(nOut < txTo.vout.size());

uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
const bool cacheready = cache && cache->m_bip143_segwit_ready;

if (nHashType & SIGHASH_ANYONECANPAY) {
assert(0 < txTo.vin.size());
hashPrevouts = SHA256Uint256(GetFirstPrevoutSHA256(txTo));
hashSequence = SHA256Uint256(GetFirstSequenceSHA256(txTo));
}

if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cacheready ? cache->hashPrevouts : SHA256Uint256(GetPrevoutsSHA256(txTo));
}

if (!(nHashType & SIGHASH_ANYONECANPAY) && (nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashSequence = cacheready ? cache->hashSequence : SHA256Uint256(GetSequencesSHA256(txTo));
}


if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cacheready ? cache->hashOutputsOpSender : SHA256Uint256(GetOutputsOpSenderSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nOut < txTo.vout.size()) {
HashWriter ss{};
ss << GetOutputWithoutSenderSig(txTo.vout[nOut]);
hashOutputs = ss.GetHash();
}

HashWriter ss{};

// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/first/all, depending on flags)
ss << hashPrevouts;
ss << hashSequence;
// The output being signed
ss << GetOutputWithoutSenderSig(txTo.vout[nOut]);
ss << scriptCode;
ss << amount;
// Outputs (none/one/all, depending on flags)
ss << hashOutputs;
// Locktime
ss << txTo.nLockTime;
// Sighash type
ss << nHashType;

return ss.GetHash();
}

template <class T>
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache)
{
Expand Down Expand Up @@ -1785,6 +1912,38 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;

template <class T>
bool GenericTransactionSignatureOutputChecker<T>::VerifyECDSASignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
{
return pubkey.Verify(sighash, vchSig);
}

template <class T>
bool GenericTransactionSignatureOutputChecker<T>::CheckECDSASignature(const std::vector<unsigned char>& vchSigIn, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const
{
CPubKey pubkey(vchPubKey);
if (!pubkey.IsValid())
return false;

// Hash type is one byte tacked on to the end of the signature
std::vector<unsigned char> vchSig(vchSigIn);
if (vchSig.empty())
return false;
int nHashType = vchSig.back();
vchSig.pop_back();

uint256 sighash = SignatureHashOutput(scriptCode, *txTo, nOut, nHashType, amount, sigversion, this->txdata);

if (!VerifyECDSASignature(vchSig, pubkey, sighash))
return false;

return true;
}

// explicit instantiation
template class GenericTransactionSignatureOutputChecker<CTransaction>;
template class GenericTransactionSignatureOutputChecker<CMutableTransaction>;

static bool ExecuteWitnessScript(const Span<const valtype>& stack_span, const CScript& exec_script, unsigned int flags, SigVersion sigversion, const BaseSignatureChecker& checker, ScriptExecutionData& execdata, ScriptError* serror)
{
std::vector<valtype> stack{stack_span.begin(), stack_span.end()};
Expand Down
Loading

0 comments on commit 3693f1d

Please sign in to comment.