Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F13115696
D1565.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
27 KB
Subscribers
None
D1565.diff
View Options
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
Details
Attached
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)
Attached To
D1565: Move function checking encoding of public key and signature out of interpreter.{h/cpp}
Event Timeline
Log In to Comment