Closed shohu closed 5 years ago
SigHashType sigHashType = SigHashType().withForkId();
:
:
ProduceSignature(MutableTransactionSignatureCreator(
&keystore, &mergedTx, i, amount, sigHashType),
prevPubKey, sigdata);
ProduceSignature
bool ProduceSignature(const BaseSignatureCreator &creator,
const CScript &fromPubKey, SignatureData &sigdata) {
CScript script = fromPubKey;
bool solved = true;
std::vector<valtype> result;
txnouttype whichType;
solved = SignStep(creator, script, result, whichType);
CScript subscript;
if (solved && whichType == TX_SCRIPTHASH) {
// Solver returns the subscript that needs to be evaluated; the final
// scriptSig is the signatures from that and then the serialized
// subscript:
script = subscript = CScript(result[0].begin(), result[0].end());
solved = solved && SignStep(creator, script, result, whichType) &&
whichType != TX_SCRIPTHASH;
result.push_back(
std::vector<uint8_t>(subscript.begin(), subscript.end()));
}
sigdata.scriptSig = PushAll(result);
// Test solution
return solved &&
VerifyScript(sigdata.scriptSig, fromPubKey,
STANDARD_SCRIPT_VERIFY_FLAGS, creator.Checker());
}
CreateSig
bool TransactionSignatureCreator::CreateSig(std::vector<uint8_t> &vchSig,
:
:
uint256 hash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount);
if (!key.Sign(hash, vchSig)) {
return false;
}
vchSig.push_back(uint8_t(sigHashType.getRawSigHashType()));
return true;
}
Detail SignatureHash.
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo,
unsigned int nIn, SigHashType sigHashType,
const Amount amount,
const PrecomputedTransactionData *cache, uint32_t flags) {
if (flags & SCRIPT_ENABLE_REPLAY_PROTECTION) {
// Legacy chain's value for fork id must be of the form 0xffxxxx.
// By xoring with 0xdead, we ensure that the value will be different
// from the original one, even if it already starts with 0xff.
uint32_t newForkValue = sigHashType.getForkValue() ^ 0xdead;
sigHashType = sigHashType.withForkValue(0xff0000 | newForkValue);
}
if (sigHashType.hasForkId() && (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) {
uint256 hashPrevouts;
uint256 hashSequence;
uint256 hashOutputs;
if (!sigHashType.hasAnyoneCanPay()) {
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
}
if (!sigHashType.hasAnyoneCanPay() &&
(sigHashType.getBaseType() != BaseSigHashType::SINGLE) &&
(sigHashType.getBaseType() != BaseSigHashType::NONE)) {
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
}
if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) &&
(sigHashType.getBaseType() != BaseSigHashType::NONE)) {
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
} else if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) &&
(nIn < txTo.vout.size())) {
CHashWriter ss(SER_GETHASH, 0);
ss << txTo.vout[nIn];
hashOutputs = ss.GetHash();
}
CHashWriter ss(SER_GETHASH, 0);
// Version
ss << txTo.nVersion;
// Input prevouts/nSequence (none/all, depending on flags)
ss << hashPrevouts;
ss << hashSequence;
// The input being signed (replacing the scriptSig with scriptCode +
// amount). The prevout may already be contained in hashPrevout, and the
// nSequence may already be contain in hashSequence.
ss << txTo.vin[nIn].prevout;
ss << scriptCode;
ss << amount.GetSatoshis();
ss << txTo.vin[nIn].nSequence;
// Outputs (none/one/all, depending on flags)
ss << hashOutputs;
// Locktime
ss << txTo.nLockTime;
// Sighash type
ss << sigHashType;
return ss.GetHash();
}
static const uint256 one(uint256S(
"0000000000000000000000000000000000000000000000000000000000000001"));
if (nIn >= txTo.vin.size()) {
// nIn out of range
return one;
}
// Check for invalid use of SIGHASH_SINGLE
if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) &&
(nIn >= txTo.vout.size())) {
// nOut out of range
return one;
}
// Wrapper to serialize only the necessary parts of the transaction being
// signed
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType);
// Serialize and hash
CHashWriter ss(SER_GETHASH, 0);
ss << txTmp << sigHashType;
return ss.GetHash();
}
ss << txTmp << sigHashType;
return ss.GetHash();
or
// Sighash type
ss << sigHashType;
return ss.GetHash();
affect fork signature.
Over threshold height when fork flag is on by GetBlockScriptFlags.
const uint32_t flags = GetBlockScriptFlags(config, pindex->pprev);
:
:
if (!CheckInputs(tx, state, view, fScriptChecks, flags,
fCacheResults, fCacheResults,
PrecomputedTransactionData(tx), &vChecks)) {
return error("ConnectBlock(): CheckInputs on %s failed with %s",
tx.GetId().ToString(), FormatStateMessage(state));
}
// Returns the script flags which should be checked for a given block
static uint32_t GetBlockScriptFlags(const Config &config,
const CBlockIndex *pChainTip) {
:
// If the UAHF is enabled, we start accepting replay protected txns
if (IsUAHFenabled(config, pChainTip)) {
flags |= SCRIPT_VERIFY_STRICTENC;
flags |= SCRIPT_ENABLE_SIGHASH_FORKID;
}
:
return flags;
}
static bool IsUAHFenabled(const Config &config, int nHeight) {
return nHeight >= config.GetChainParams().GetConsensus().uahfHeight;
}
bool IsUAHFenabled(const Config &config, const CBlockIndex *pindexPrev) {
if (pindexPrev == nullptr) {
return false;
}
return IsUAHFenabled(config, pindexPrev->nHeight);
}
bool CheckInputs(const CTransaction &tx, CValidationState &state,
const CCoinsViewCache &inputs, bool fScriptChecks,
const uint32_t flags, bool sigCacheStore,
bool scriptCacheStore,
const PrecomputedTransactionData &txdata,
std::vector<CScriptCheck> *pvChecks) {
:
:
// Verify signature
CScriptCheck check(scriptPubKey, amount, tx, i, flags, sigCacheStore,
txdata);
if (pvChecks) {
pvChecks->push_back(std::move(check));
} else if (!check()) {
:
bool CScriptCheck::operator()() {
const CScript &scriptSig = ptxTo->vin[nIn].scriptSig;
return VerifyScript(scriptSig, scriptPubKey, nFlags,
CachingTransactionSignatureChecker(ptxTo, nIn, amount,
cacheStore, txdata),
&error);
}
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey,
uint32_t flags, const BaseSignatureChecker &checker,
ScriptError *serror) {
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
:
:
std::vector<valtype> stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker, serror)) {
// serror is set
return false;
}
:
bool EvalScript(std::vector<valtype> &stack, const CScript &script,
uint32_t flags, const BaseSignatureChecker &checker,
ScriptError *serror) {
:
:
case OP_CHECKSIG:
case OP_CHECKSIGVERIFY: {
// (sig pubkey -- bool)
if (stack.size() < 2) {
return set_error(
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
}
valtype &vchSig = stacktop(-2);
valtype &vchPubKey = stacktop(-1);
if (!CheckSignatureEncoding(vchSig, flags, serror) ||
!CheckPubKeyEncoding(vchPubKey, flags, serror)) {
// serror is set
return false;
}
:
case OP_CHECKMULTISIG:
case OP_CHECKMULTISIGVERIFY: {
:
:
if (!CheckSignatureEncoding(vchSig, flags,
serror) ||
!CheckPubKeyEncoding(vchPubKey, flags,
serror)) {
// serror is set
return false;
}
bool CheckSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags,
ScriptError *serror) {
// Empty signature. Not strictly DER encoded, but allowed to provide a
// compact way to provide an invalid signature for use with CHECK(MULTI)SIG
if (vchSig.size() == 0) {
return true;
}
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S |
SCRIPT_VERIFY_STRICTENC)) != 0 &&
!IsValidSignatureEncoding(vchSig)) {
return set_error(serror, SCRIPT_ERR_SIG_DER);
}
if ((flags & SCRIPT_VERIFY_LOW_S) != 0 &&
!IsLowDERSignature(vchSig, serror)) {
// serror is set
return false;
}
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0) {
if (!GetHashType(vchSig).isDefined()) {
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
}
bool usesForkId = GetHashType(vchSig).hasForkId();
bool forkIdEnabled = flags & SCRIPT_ENABLE_SIGHASH_FORKID;
if (!forkIdEnabled && usesForkId) {
return set_error(serror, SCRIPT_ERR_ILLEGAL_FORKID);
}
if (forkIdEnabled && !usesForkId) {
return set_error(serror, SCRIPT_ERR_MUST_USE_FORKID);
}
}
return true;
}
I realized that it is possible to attack replay attack for c0ban when c0ban is forked. So I try to implement for Replay Attack by reffering to Bitcoin Cash source
Requirements