Page MenuHomePhabricator

D1565.diff
No OneTemporary

D1565.diff

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -164,6 +164,7 @@
script/interpreter.cpp
script/script.cpp
script/script_error.cpp
+ script/sigencoding.cpp
uint256.cpp
utilstrencodings.cpp
)
diff --git a/src/Makefile.am b/src/Makefile.am
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -317,6 +317,9 @@
script/script.h \
script/script_error.cpp \
script/script_error.h \
+ script/script_flags.h \
+ script/sigencoding.cpp \
+ script/sigencoding.h \
serialize.h \
tinyformat.h \
uint256.cpp \
diff --git a/src/core_write.cpp b/src/core_write.cpp
--- a/src/core_write.cpp
+++ b/src/core_write.cpp
@@ -7,6 +7,7 @@
#include "dstencode.h"
#include "primitives/transaction.h"
#include "script/script.h"
+#include "script/sigencoding.h"
#include "script/standard.h"
#include "serialize.h"
#include "streams.h"
diff --git a/src/policy/policy.h b/src/policy/policy.h
--- a/src/policy/policy.h
+++ b/src/policy/policy.h
@@ -7,12 +7,12 @@
#define BITCOIN_POLICY_POLICY_H
#include "consensus/consensus.h"
-#include "script/interpreter.h"
#include "script/standard.h"
#include <string>
class CCoinsViewCache;
+class CTransaction;
/** Default for -blockmaxsize, which controls the maximum size of block the
* mining code will create **/
diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp
--- a/src/policy/policy.cpp
+++ b/src/policy/policy.cpp
@@ -8,6 +8,7 @@
#include "policy/policy.h"
+#include "script/interpreter.h"
#include "tinyformat.h"
#include "util.h"
#include "utilstrencodings.h"
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -7,6 +8,7 @@
#define BITCOIN_SCRIPT_INTERPRETER_H
#include "primitives/transaction.h"
+#include "script/script_flags.h"
#include "script_error.h"
#include "sighashtype.h"
@@ -19,98 +21,6 @@
class CTransaction;
class uint256;
-/** Script verification flags */
-enum {
- SCRIPT_VERIFY_NONE = 0,
-
- // Evaluate P2SH subscripts (softfork safe, BIP16).
- SCRIPT_VERIFY_P2SH = (1U << 0),
-
- // Passing a non-strict-DER signature or one with undefined hashtype to a
- // checksig operation causes script failure. Evaluating a pubkey that is not
- // (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script
- // failure.
- SCRIPT_VERIFY_STRICTENC = (1U << 1),
-
- // Passing a non-strict-DER signature to a checksig operation causes script
- // failure (softfork safe, BIP62 rule 1)
- SCRIPT_VERIFY_DERSIG = (1U << 2),
-
- // Passing a non-strict-DER signature or one with S > order/2 to a checksig
- // operation causes script failure
- // (softfork safe, BIP62 rule 5).
- SCRIPT_VERIFY_LOW_S = (1U << 3),
-
- // verify dummy stack item consumed by CHECKMULTISIG is of zero-length
- // (softfork safe, BIP62 rule 7).
- SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
-
- // Using a non-push operator in the scriptSig causes script failure
- // (softfork safe, BIP62 rule 2).
- SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
-
- // Require minimal encodings for all push operations (OP_0... OP_16,
- // OP_1NEGATE where possible, direct pushes up to 75 bytes, OP_PUSHDATA up
- // to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating any other
- // push causes the script to fail (BIP62 rule 3). In addition, whenever a
- // stack element is interpreted as a number, it must be of minimal length
- // (BIP62 rule 4).
- // (softfork safe)
- SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
-
- // Discourage use of NOPs reserved for upgrades (NOP1-10)
- //
- // Provided so that nodes can avoid accepting or mining transactions
- // containing executed NOP's whose meaning may change after a soft-fork,
- // thus rendering the script invalid; with this flag set executing
- // discouraged NOPs fails the script. This verification flag will never be a
- // mandatory flag applied to scripts in a block. NOPs that are not executed,
- // e.g. within an unexecuted IF ENDIF block, are *not* rejected.
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
-
- // Require that only a single stack element remains after evaluation. This
- // changes the success criterion from "At least one stack element must
- // remain, and when interpreted as a boolean, it must be true" to "Exactly
- // one stack element must remain, and when interpreted as a boolean, it must
- // be true".
- // (softfork safe, BIP62 rule 6)
- // Note: CLEANSTACK should never be used without P2SH or WITNESS.
- SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
-
- // Verify CHECKLOCKTIMEVERIFY
- //
- // See BIP65 for details.
- SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
-
- // support CHECKSEQUENCEVERIFY opcode
- //
- // See BIP112 for details
- SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
-
- // Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
- //
- SCRIPT_VERIFY_MINIMALIF = (1U << 13),
-
- // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed
- //
- SCRIPT_VERIFY_NULLFAIL = (1U << 14),
-
- // Public keys in scripts must be compressed
- //
- SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE = (1U << 15),
-
- // Do we accept signature using SIGHASH_FORKID
- //
- SCRIPT_ENABLE_SIGHASH_FORKID = (1U << 16),
-
- // Do we accept activate replay protection using a different fork id.
- //
- SCRIPT_ENABLE_REPLAY_PROTECTION = (1U << 17),
-};
-
-bool CheckSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags,
- ScriptError *serror);
-
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo,
unsigned int nIn, SigHashType sigHashType,
const Amount amount,
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp
--- a/src/script/interpreter.cpp
+++ b/src/script/interpreter.cpp
@@ -1,5 +1,6 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -11,28 +12,10 @@
#include "primitives/transaction.h"
#include "pubkey.h"
#include "script/script.h"
+#include "script/script_flags.h"
+#include "script/sigencoding.h"
#include "uint256.h"
-typedef std::vector<uint8_t> valtype;
-
-namespace {
-
-inline bool set_success(ScriptError *ret) {
- if (ret) {
- *ret = SCRIPT_ERR_OK;
- }
- return true;
-}
-
-inline bool set_error(ScriptError *ret, const ScriptError serror) {
- if (ret) {
- *ret = serror;
- }
- return false;
-}
-
-} // namespace
-
bool CastToBool(const valtype &vch) {
for (size_t i = 0; i < vch.size(); i++) {
if (vch[i] != 0) {
@@ -59,140 +42,6 @@
stack.pop_back();
}
-static bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
- if (vchPubKey.size() < 33) {
- // Non-canonical public key: too short
- return false;
- }
- if (vchPubKey[0] == 0x04) {
- if (vchPubKey.size() != 65) {
- // Non-canonical public key: invalid length for uncompressed key
- return false;
- }
- } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
- if (vchPubKey.size() != 33) {
- // Non-canonical public key: invalid length for compressed key
- return false;
- }
- } else {
- // Non-canonical public key: neither compressed nor uncompressed
- return false;
- }
- return true;
-}
-
-static bool IsCompressedPubKey(const valtype &vchPubKey) {
- if (vchPubKey.size() != 33) {
- // Non-canonical public key: invalid length for compressed key
- return false;
- }
- if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
- // Non-canonical public key: invalid prefix for compressed key
- return false;
- }
- return true;
-}
-
-/**
- * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len
- * S> <S> <hashtype>, where R and S are not negative (their first byte has its
- * highest bit not set), and not excessively padded (do not start with a 0 byte,
- * unless an otherwise negative number follows, in which case a single 0 byte is
- * necessary and even required).
- *
- * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
- *
- * This function is consensus-critical since BIP66.
- */
-static bool IsValidSignatureEncoding(const std::vector<uint8_t> &sig) {
- // 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.
- // * R-length: 1-byte length descriptor of the R value that follows.
- // * R: arbitrary-length big-endian encoded R value. It must use the
- // shortest possible encoding for a positive integers (which means no null
- // bytes at the start, except a single one when the next byte has its
- // highest bit set).
- // * S-length: 1-byte length descriptor of the S value that follows.
- // * S: arbitrary-length big-endian encoded S value. The same rules apply.
- // * sighash: 1-byte value indicating what data is hashed (not part of the
- // DER signature)
-
- // Minimum and maximum size constraints.
- if (sig.size() < 9) return false;
- if (sig.size() > 73) return false;
-
- // A signature is of type 0x30 (compound).
- if (sig[0] != 0x30) return false;
-
- // Make sure the length covers the entire signature.
- if (sig[1] != sig.size() - 3) return false;
-
- // Extract the length of the R element.
- unsigned int lenR = sig[3];
-
- // Make sure the length of the S element is still inside the signature.
- if (5 + lenR >= sig.size()) return false;
-
- // Extract the length of the S element.
- unsigned int lenS = sig[5 + lenR];
-
- // 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;
-
- // Check whether the R element is an integer.
- if (sig[2] != 0x02) return false;
-
- // Zero-length integers are not allowed for R.
- if (lenR == 0) return false;
-
- // Negative numbers are not allowed for R.
- if (sig[4] & 0x80) return false;
-
- // Null bytes at the start of R are not allowed, unless R would otherwise be
- // interpreted as a negative number.
- if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
-
- // Check whether the S element is an integer.
- if (sig[lenR + 4] != 0x02) return false;
-
- // Zero-length integers are not allowed for S.
- if (lenS == 0) return false;
-
- // Negative numbers are not allowed for S.
- if (sig[lenR + 6] & 0x80) return false;
-
- // Null bytes at the start of S are not allowed, unless S would otherwise be
- // interpreted as a negative number.
- if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) {
- return false;
- }
-
- return true;
-}
-
-static bool IsLowDERSignature(const valtype &vchSig, ScriptError *serror) {
- if (!IsValidSignatureEncoding(vchSig)) {
- return set_error(serror, SCRIPT_ERR_SIG_DER);
- }
- std::vector<uint8_t> vchSigCopy(vchSig.begin(),
- vchSig.begin() + vchSig.size() - 1);
- if (!CPubKey::CheckLowS(vchSigCopy)) {
- return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
- }
- return true;
-}
-
-static SigHashType GetHashType(const valtype &vchSig) {
- if (vchSig.size() == 0) {
- return SigHashType(0);
- }
-
- return SigHashType(vchSig[vchSig.size() - 1]);
-}
-
static void CleanupScriptCode(CScript &scriptCode,
const std::vector<uint8_t> &vchSig,
uint32_t flags) {
@@ -203,54 +52,6 @@
}
}
-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;
-}
-
-static bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags,
- ScriptError *serror) {
- if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 &&
- !IsCompressedOrUncompressedPubKey(vchPubKey)) {
- return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
- }
- // Only compressed keys are accepted when
- // SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is enabled.
- if (flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE &&
- !IsCompressedPubKey(vchPubKey)) {
- return set_error(serror, SCRIPT_ERR_NONCOMPRESSED_PUBKEY);
- }
- return true;
-}
-
static bool CheckMinimalPush(const valtype &data, opcodetype opcode) {
if (data.size() == 0) {
// Could have used OP_0.
diff --git a/src/script/script_error.h b/src/script/script_error.h
--- a/src/script/script_error.h
+++ b/src/script/script_error.h
@@ -77,4 +77,22 @@
const char *ScriptErrorString(const ScriptError error);
+namespace {
+
+inline bool set_success(ScriptError *ret) {
+ if (ret) {
+ *ret = SCRIPT_ERR_OK;
+ }
+ return true;
+}
+
+inline bool set_error(ScriptError *ret, const ScriptError serror) {
+ if (ret) {
+ *ret = serror;
+ }
+ return false;
+}
+
+} // namespace
+
#endif // BITCOIN_SCRIPT_SCRIPT_ERROR_H
diff --git a/src/script/interpreter.h b/src/script/script_flags.h
copy from src/script/interpreter.h
copy to src/script/script_flags.h
--- a/src/script/interpreter.h
+++ b/src/script/script_flags.h
@@ -1,23 +1,11 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
-#ifndef BITCOIN_SCRIPT_INTERPRETER_H
-#define BITCOIN_SCRIPT_INTERPRETER_H
-
-#include "primitives/transaction.h"
-#include "script_error.h"
-#include "sighashtype.h"
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-class CPubKey;
-class CScript;
-class CTransaction;
-class uint256;
+#ifndef BITCOIN_SCRIPT_SCRIPTFLAGS_H
+#define BITCOIN_SCRIPT_SCRIPTFLAGS_H
/** Script verification flags */
enum {
@@ -108,76 +96,4 @@
SCRIPT_ENABLE_REPLAY_PROTECTION = (1U << 17),
};
-bool CheckSignatureEncoding(const std::vector<uint8_t> &vchSig, uint32_t flags,
- ScriptError *serror);
-
-uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo,
- unsigned int nIn, SigHashType sigHashType,
- const Amount amount,
- const PrecomputedTransactionData *cache = nullptr,
- uint32_t flags = SCRIPT_ENABLE_SIGHASH_FORKID);
-
-class BaseSignatureChecker {
-public:
- virtual bool CheckSig(const std::vector<uint8_t> &scriptSig,
- const std::vector<uint8_t> &vchPubKey,
- const CScript &scriptCode, uint32_t flags) const {
- return false;
- }
-
- virtual bool CheckLockTime(const CScriptNum &nLockTime) const {
- return false;
- }
-
- virtual bool CheckSequence(const CScriptNum &nSequence) const {
- return false;
- }
-
- virtual ~BaseSignatureChecker() {}
-};
-
-class TransactionSignatureChecker : public BaseSignatureChecker {
-private:
- const CTransaction *txTo;
- unsigned int nIn;
- const Amount amount;
- const PrecomputedTransactionData *txdata;
-
-protected:
- virtual bool VerifySignature(const std::vector<uint8_t> &vchSig,
- const CPubKey &vchPubKey,
- const uint256 &sighash) const;
-
-public:
- TransactionSignatureChecker(const CTransaction *txToIn, unsigned int nInIn,
- const Amount amountIn)
- : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(nullptr) {}
- TransactionSignatureChecker(const CTransaction *txToIn, unsigned int nInIn,
- const Amount amountIn,
- const PrecomputedTransactionData &txdataIn)
- : txTo(txToIn), nIn(nInIn), amount(amountIn), txdata(&txdataIn) {}
- bool CheckSig(const std::vector<uint8_t> &scriptSig,
- const std::vector<uint8_t> &vchPubKey,
- const CScript &scriptCode, uint32_t flags) const override;
- bool CheckLockTime(const CScriptNum &nLockTime) const override;
- bool CheckSequence(const CScriptNum &nSequence) const override;
-};
-
-class MutableTransactionSignatureChecker : public TransactionSignatureChecker {
-private:
- const CTransaction txTo;
-
-public:
- MutableTransactionSignatureChecker(const CMutableTransaction *txToIn,
- unsigned int nInIn, const Amount amount)
- : TransactionSignatureChecker(&txTo, nInIn, amount), txTo(*txToIn) {}
-};
-
-bool EvalScript(std::vector<std::vector<uint8_t>> &stack, const CScript &script,
- uint32_t flags, const BaseSignatureChecker &checker,
- ScriptError *error = nullptr);
-bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey,
- uint32_t flags, const BaseSignatureChecker &checker,
- ScriptError *serror = nullptr);
-
-#endif // BITCOIN_SCRIPT_INTERPRETER_H
+#endif // BITCOIN_SCRIPT_SCRIPTFLAGS_H
diff --git a/src/script/sigencoding.h b/src/script/sigencoding.h
new file mode 100644
--- /dev/null
+++ b/src/script/sigencoding.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#ifndef BITCOIN_SCRIPT_SIGENCODING_H
+#define BITCOIN_SCRIPT_SIGENCODING_H
+
+#include "script_error.h"
+#include "sighashtype.h"
+
+#include <cstdint>
+#include <vector>
+
+typedef std::vector<uint8_t> valtype;
+
+namespace {
+
+inline SigHashType GetHashType(const valtype &vchSig) {
+ if (vchSig.size() == 0) {
+ return SigHashType(0);
+ }
+
+ return SigHashType(vchSig[vchSig.size() - 1]);
+}
+
+} // namespace
+
+bool CheckSignatureEncoding(const valtype &vchSig, uint32_t flags,
+ ScriptError *serror);
+bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags,
+ ScriptError *serror);
+
+#endif // BITCOIN_SCRIPT_SIGENCODING_H
diff --git a/src/script/sigencoding.cpp b/src/script/sigencoding.cpp
new file mode 100644
--- /dev/null
+++ b/src/script/sigencoding.cpp
@@ -0,0 +1,184 @@
+// Copyright (c) 2009-2010 Satoshi Nakamoto
+// Copyright (c) 2009-2016 The Bitcoin Core developers
+// Copyright (c) 2017-2018 The Bitcoin developers
+// Distributed under the MIT software license, see the accompanying
+// file COPYING or http://www.opensource.org/licenses/mit-license.php.
+
+#include "sigencoding.h"
+
+#include "pubkey.h"
+#include "script_flags.h"
+
+/**
+ * A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len
+ * S> <S> <hashtype>, where R and S are not negative (their first byte has its
+ * highest bit not set), and not excessively padded (do not start with a 0 byte,
+ * unless an otherwise negative number follows, in which case a single 0 byte is
+ * necessary and even required).
+ *
+ * See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
+ *
+ * This function is consensus-critical since BIP66.
+ */
+static bool IsValidSignatureEncoding(const valtype &sig) {
+ // 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.
+ // * R-length: 1-byte length descriptor of the R value that follows.
+ // * R: arbitrary-length big-endian encoded R value. It must use the
+ // shortest possible encoding for a positive integers (which means no null
+ // bytes at the start, except a single one when the next byte has its
+ // highest bit set).
+ // * S-length: 1-byte length descriptor of the S value that follows.
+ // * S: arbitrary-length big-endian encoded S value. The same rules apply.
+ // * sighash: 1-byte value indicating what data is hashed (not part of the
+ // DER signature)
+
+ // Minimum and maximum size constraints.
+ if (sig.size() < 9) return false;
+ if (sig.size() > 73) return false;
+
+ // A signature is of type 0x30 (compound).
+ if (sig[0] != 0x30) return false;
+
+ // Make sure the length covers the entire signature.
+ if (sig[1] != sig.size() - 3) return false;
+
+ // Extract the length of the R element.
+ unsigned int lenR = sig[3];
+
+ // Make sure the length of the S element is still inside the signature.
+ if (5 + lenR >= sig.size()) return false;
+
+ // Extract the length of the S element.
+ unsigned int lenS = sig[5 + lenR];
+
+ // 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;
+
+ // Check whether the R element is an integer.
+ if (sig[2] != 0x02) return false;
+
+ // Zero-length integers are not allowed for R.
+ if (lenR == 0) return false;
+
+ // Negative numbers are not allowed for R.
+ if (sig[4] & 0x80) return false;
+
+ // Null bytes at the start of R are not allowed, unless R would otherwise be
+ // interpreted as a negative number.
+ if (lenR > 1 && (sig[4] == 0x00) && !(sig[5] & 0x80)) return false;
+
+ // Check whether the S element is an integer.
+ if (sig[lenR + 4] != 0x02) return false;
+
+ // Zero-length integers are not allowed for S.
+ if (lenS == 0) return false;
+
+ // Negative numbers are not allowed for S.
+ if (sig[lenR + 6] & 0x80) return false;
+
+ // Null bytes at the start of S are not allowed, unless S would otherwise be
+ // interpreted as a negative number.
+ if (lenS > 1 && (sig[lenR + 6] == 0x00) && !(sig[lenR + 7] & 0x80)) {
+ return false;
+ }
+
+ return true;
+}
+
+static bool IsLowDERSignature(const valtype &vchSig, ScriptError *serror) {
+ if (!IsValidSignatureEncoding(vchSig)) {
+ return set_error(serror, SCRIPT_ERR_SIG_DER);
+ }
+ std::vector<uint8_t> vchSigCopy(vchSig.begin(),
+ vchSig.begin() + vchSig.size() - 1);
+ if (!CPubKey::CheckLowS(vchSigCopy)) {
+ return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
+ }
+ return true;
+}
+
+bool CheckSignatureEncoding(const valtype &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;
+}
+
+static bool IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
+ if (vchPubKey.size() < 33) {
+ // Non-canonical public key: too short
+ return false;
+ }
+ if (vchPubKey[0] == 0x04) {
+ if (vchPubKey.size() != 65) {
+ // Non-canonical public key: invalid length for uncompressed key
+ return false;
+ }
+ } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
+ if (vchPubKey.size() != 33) {
+ // Non-canonical public key: invalid length for compressed key
+ return false;
+ }
+ } else {
+ // Non-canonical public key: neither compressed nor uncompressed
+ return false;
+ }
+ return true;
+}
+
+static bool IsCompressedPubKey(const valtype &vchPubKey) {
+ if (vchPubKey.size() != 33) {
+ // Non-canonical public key: invalid length for compressed key
+ return false;
+ }
+ if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {
+ // Non-canonical public key: invalid prefix for compressed key
+ return false;
+ }
+ return true;
+}
+
+bool CheckPubKeyEncoding(const valtype &vchPubKey, uint32_t flags,
+ ScriptError *serror) {
+ if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 &&
+ !IsCompressedOrUncompressedPubKey(vchPubKey)) {
+ return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);
+ }
+ // Only compressed keys are accepted when
+ // SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE is enabled.
+ if ((flags & SCRIPT_VERIFY_COMPRESSED_PUBKEYTYPE) &&
+ !IsCompressedPubKey(vchPubKey)) {
+ return set_error(serror, SCRIPT_ERR_NONCOMPRESSED_PUBKEY);
+ }
+ return true;
+}
diff --git a/src/script/standard.h b/src/script/standard.h
--- a/src/script/standard.h
+++ b/src/script/standard.h
@@ -6,7 +6,9 @@
#ifndef BITCOIN_SCRIPT_STANDARD_H
#define BITCOIN_SCRIPT_STANDARD_H
-#include "script/interpreter.h"
+#include "amount.h"
+#include "pubkey.h"
+#include "script/script_flags.h"
#include "uint256.h"
#include <boost/variant.hpp>
diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp
--- a/src/test/sigopcount_tests.cpp
+++ b/src/test/sigopcount_tests.cpp
@@ -6,6 +6,7 @@
#include "consensus/validation.h"
#include "key.h"
#include "pubkey.h"
+#include "script/interpreter.h"
#include "script/script.h"
#include "script/standard.h"
#include "test/test_bitcoin.h"

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 1, 11:45 (3 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5187690
Default Alt Text
D1565.diff (27 KB)

Event Timeline