13 changes: 13 additions & 0 deletions src/chainparams.cpp
Expand Up @@ -82,6 +82,10 @@ class CMainParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008

consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].bit = 25;
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nStartTime = 1577836800; // January 1, 2020
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nTimeout = 1609459200; // January 1, 2021

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000051dc8b82f450202ecb3d471");

Expand Down Expand Up @@ -188,6 +192,11 @@ class CTestNetParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 1199145601; // January 1, 2008
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = 1230767999; // December 31, 2008


consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].bit = 25;
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000007dbe94253893cbd463");

Expand Down Expand Up @@ -272,6 +281,10 @@ class CRegTestParams : public CChainParams {
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;

consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].bit = 25;
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
consensus.vDeployments[Consensus::DEPLOYMENT_SECURETHEBAG].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;

// The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00");

Expand Down
1 change: 1 addition & 0 deletions src/consensus/params.h
Expand Up @@ -17,6 +17,7 @@ enum DeploymentPos
{
DEPLOYMENT_TESTDUMMY,
// NOTE: Also add new deployments to VersionBitsDeploymentInfo in versionbits.cpp
DEPLOYMENT_SECURETHEBAG,
MAX_VERSION_BITS_DEPLOYMENTS
};

Expand Down
10 changes: 10 additions & 0 deletions src/hash.cpp
Expand Up @@ -6,6 +6,7 @@
#include <crypto/common.h>
#include <crypto/hmac_sha512.h>

#include <string>

inline uint32_t ROTL32(uint32_t x, int8_t r)
{
Expand Down Expand Up @@ -77,3 +78,12 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
num[3] = (nChild >> 0) & 0xFF;
CHMAC_SHA512(chainCode.begin(), chainCode.size()).Write(&header, 1).Write(data, 32).Write(num, 4).Finalize(output);
}

CHashWriter TaggedHash(const std::string& tag)
{
CHashWriter writer(SER_GETHASH, 0);
uint256 taghash;
CSHA256().Write((unsigned char*)tag.data(), tag.size()).Finalize(taghash.begin());
writer << taghash << taghash;
return writer;
}
26 changes: 21 additions & 5 deletions src/hash.h
Expand Up @@ -14,6 +14,7 @@
#include <uint256.h>
#include <version.h>

#include <string>
#include <vector>

typedef uint256 ChainCode;
Expand Down Expand Up @@ -117,7 +118,7 @@ inline uint160 Hash160(const prevector<N, unsigned char>& vch)
class CHashWriter
{
private:
CHash256 ctx;
CSHA256 ctx;

const int nType;
const int nVersion;
Expand All @@ -135,17 +136,24 @@ class CHashWriter
// invalidates the object
uint256 GetHash() {
uint256 result;
ctx.Finalize((unsigned char*)&result);
ctx.Finalize(result.begin());
ctx.Reset().Write(result.begin(), CSHA256::OUTPUT_SIZE).Finalize(result.begin());
return result;
}

// invalidates the object
uint256 GetSHA256() {
uint256 result;
ctx.Finalize(result.begin());
return result;
}

/**
* Returns the first 64 bits from the resulting hash.
*/
inline uint64_t GetCheapHash() {
unsigned char result[CHash256::OUTPUT_SIZE];
ctx.Finalize(result);
return ReadLE64(result);
uint256 result = GetHash();
return ReadLE64(result.begin());
}

template<typename T>
Expand Down Expand Up @@ -204,4 +212,12 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char

void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char header, const unsigned char data[32], unsigned char output[64]);

/** Return a CHashWriter primed for computing bip-schnorr compatible tagged hashes.
*
* The returned object will have SHA256(tag) written to it twice (= 64 bytes).
* A tagged hash can be computed by feeding the message into this object, and
* then calling CHashWriter::GetSHA256().
*/
CHashWriter TaggedHash(const std::string& tag);

#endif // BITCOIN_HASH_H
2 changes: 2 additions & 0 deletions src/policy/policy.cpp
Expand Up @@ -177,6 +177,8 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs)
if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) {
return false;
}
} else if (whichType == TX_SECURETHEBAG) {
if (tx.vin[i].scriptSig.size() != 0) return false;
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/policy/policy.h
Expand Up @@ -68,7 +68,8 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
SCRIPT_VERIFY_WITNESS |
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
SCRIPT_VERIFY_CONST_SCRIPTCODE;
SCRIPT_VERIFY_CONST_SCRIPTCODE |
SCRIPT_VERIFY_SECURETHEBAG;

/** For convenience, standard but not mandatory verify flags. */
static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
Expand Down
48 changes: 48 additions & 0 deletions src/primitives/transaction.h
Expand Up @@ -8,6 +8,7 @@

#include <stdint.h>
#include <amount.h>
#include <hash.h>
#include <script/script.h>
#include <serialize.h>
#include <uint256.h>
Expand Down Expand Up @@ -263,6 +264,53 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
s << tx.nLockTime;
}

template <class T>
uint256 GetPrevoutSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
return ss.GetSHA256();
}

template <class T>
uint256 GetSequenceSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
return ss.GetSHA256();
}

template <class T>
uint256 GetOutputsSHA256(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : txTo.vout) {
ss << txout;
}
return ss.GetSHA256();
}

template<typename TxType>
uint256 GetSecuredBagHash(const TxType& tx) {
return GetSecuredBagHash(tx, GetOutputsSHA256(tx), GetSequenceSHA256(tx));
}

static const CHashWriter BagHash = TaggedHash("BagHash");
template<typename TxType>
uint256 GetSecuredBagHash(const TxType& tx, const uint256& outputs_hash, const uint256& sequences_hash) {
auto h = CHashWriter(BagHash)
<< tx.nVersion << tx.nLockTime
<< outputs_hash << sequences_hash
<< uint64_t(tx.vin.size());
for (const auto& in : tx.vin) {
h << in.scriptSig;
}
return h.GetSHA256();
}

/** The basic transaction that is broadcasted on the network and contained in
* blocks. A transaction can contain multiple inputs and outputs.
Expand Down
82 changes: 48 additions & 34 deletions src/script/interpreter.cpp
Expand Up @@ -8,6 +8,7 @@
#include <crypto/ripemd160.h>
#include <crypto/sha1.h>
#include <crypto/sha256.h>
#include <primitives/transaction.h>
#include <pubkey.h>
#include <script/script.h>
#include <uint256.h>
Expand Down Expand Up @@ -457,7 +458,26 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
break;
}

case OP_NOP1: case OP_NOP4: case OP_NOP5:
case OP_SECURETHEBAG:
{
// when not enabled; treat as a NOP4
if (!(flags & SCRIPT_VERIFY_SECURETHEBAG)) break;
// Read one step ahead; we expect to push 32 bytes
CScript::const_iterator tmp_pc = pc;
opcodetype push_op;
if (!script.GetOp(tmp_pc, push_op, vchPushValue)) return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
// If the push was not 32 bytes, ignore it:
// upgrade can add semantics for this opcode with different length args
if (vchPushValue.size() != 32) break;
// push_op should be minimal, i.e. 0x20 -- will fail later anyways
if (!CheckMinimalPush(vchPushValue, push_op)) return set_error(serror, SCRIPT_ERR_MINIMALDATA);
// Check the BagHash computed from the transaction matches the literal value
if (!checker.CheckBagSecured(vchPushValue)) return set_error(serror, SCRIPT_ERR_BAG_NOT_SECURED);
// Success
break;
}

case OP_NOP1: case OP_NOP5:
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
{
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
Expand Down Expand Up @@ -1182,34 +1202,12 @@ class CTransactionSignatureSerializer
}
};

template <class T>
uint256 GetPrevoutHash(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.prevout;
}
return ss.GetHash();
}

template <class T>
uint256 GetSequenceHash(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txin : txTo.vin) {
ss << txin.nSequence;
}
return ss.GetHash();
void RehashSHA256(uint256& hash) {
CSHA256().Write(hash.begin(), 32).Finalize(hash.begin());
}

template <class T>
uint256 GetOutputsHash(const T& txTo)
{
CHashWriter ss(SER_GETHASH, 0);
for (const auto& txout : txTo.vout) {
ss << txout;
}
return ss.GetHash();
uint256 RehashSHA256(uint256&& hash) {
CSHA256().Write(hash.begin(), 32).Finalize(hash.begin());
return hash;
}

} // namespace
Expand All @@ -1219,9 +1217,13 @@ PrecomputedTransactionData::PrecomputedTransactionData(const T& txTo)
{
// Cache is calculated only for transactions with witness
if (txTo.HasWitness()) {
hashPrevouts = GetPrevoutHash(txTo);
hashSequence = GetSequenceHash(txTo);
hashOutputs = GetOutputsHash(txTo);
hashOutputs = GetOutputsSHA256(txTo);
hashSequence = GetSequenceSHA256(txTo);
hashBag = GetSecuredBagHash(txTo, hashOutputs, hashSequence);
hashPrevouts = GetPrevoutSHA256(txTo);
RehashSHA256(hashOutputs);
RehashSHA256(hashSequence);
RehashSHA256(hashPrevouts);
ready = true;
}
}
Expand All @@ -1242,16 +1244,16 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
const bool cacheready = cache && cache->ready;

if (!(nHashType & SIGHASH_ANYONECANPAY)) {
hashPrevouts = cacheready ? cache->hashPrevouts : GetPrevoutHash(txTo);
hashPrevouts = cacheready ? cache->hashPrevouts : RehashSHA256(GetPrevoutSHA256(txTo));
}

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


if ((nHashType & 0x1f) != SIGHASH_SINGLE && (nHashType & 0x1f) != SIGHASH_NONE) {
hashOutputs = cacheready ? cache->hashOutputs : GetOutputsHash(txTo);
hashOutputs = cacheready ? cache->hashOutputs : RehashSHA256(GetOutputsSHA256(txTo));
} else if ((nHashType & 0x1f) == SIGHASH_SINGLE && nIn < txTo.vout.size()) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
Expand Down Expand Up @@ -1412,6 +1414,18 @@ bool GenericTransactionSignatureChecker<T>::CheckSequence(const CScriptNum& nSeq
return true;
}

template <class T>
bool GenericTransactionSignatureChecker<T>::CheckBagSecured(const std::vector<unsigned char>& hash) const
{
// Should already be checked before calling...
assert(hash.size() == 32);
if (txdata && txdata->ready) {
return std::equal(txdata->hashBag.begin(), txdata->hashBag.end(), hash.data());
}
assert(txTo != nullptr);
uint256 hashBag = GetSecuredBagHash(*txTo);
return std::equal(hashBag.begin(), hashBag.end(), hash.data());
}
// explicit instantiation
template class GenericTransactionSignatureChecker<CTransaction>;
template class GenericTransactionSignatureChecker<CMutableTransaction>;
Expand Down
12 changes: 11 additions & 1 deletion src/script/interpreter.h
Expand Up @@ -115,13 +115,17 @@ enum
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
//
SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),

// support OP_SECURETHEBAG
//
SCRIPT_VERIFY_SECURETHEBAG = (1U << 17),
};

bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror);

struct PrecomputedTransactionData
{
uint256 hashPrevouts, hashSequence, hashOutputs;
uint256 hashPrevouts, hashSequence, hashOutputs, hashBag;
bool ready = false;

template <class T>
Expand Down Expand Up @@ -159,6 +163,11 @@ class BaseSignatureChecker
return false;
}

virtual bool CheckBagSecured(const std::vector<unsigned char>& hash) const
{
return false;
}

virtual ~BaseSignatureChecker() {}
};

Expand All @@ -180,6 +189,7 @@ class GenericTransactionSignatureChecker : public BaseSignatureChecker
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode, SigVersion sigversion) const override;
bool CheckLockTime(const CScriptNum& nLockTime) const override;
bool CheckSequence(const CScriptNum& nSequence) const override;
bool CheckBagSecured(const std::vector<unsigned char>& hash) const override;
};

using TransactionSignatureChecker = GenericTransactionSignatureChecker<CTransaction>;
Expand Down
7 changes: 7 additions & 0 deletions src/script/script.cpp
Expand Up @@ -193,6 +193,13 @@ unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
return subscript.GetSigOpCount(true);
}

bool CScript::IsBasicSecureTheBag() const
{
// Extra-fast test for pay-to-script-hash CScripts:
return (this->size() == 34 &&
(*this)[0] == OP_SECURETHEBAG &&
(*this)[1] == 0x20);
}
bool CScript::IsPayToScriptHash() const
{
// Extra-fast test for pay-to-script-hash CScripts:
Expand Down