script/interpreter: make script_verify_flag_name an ordinary enum
What changed, and why it matters
This commit is a straightforward internal code cleanup in Bitcoin Core. It changes how script verification flags are defined from being bit-shifted numbers directly in the enum to plain sequential numbers, with the bit shifting done later when converting to the actual flags type. There is no security vulnerability or behavior change intended here.
No security action required. Treat as normal code-quality refactor.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors script_verify_flag_name from a bitmask-style enum (SCRIPT_VERIFY_FOO = (1U << n)) to an ordinary enum where values are sequential indices (0, 1, 2, ...). The bit-shift to produce actual flag bits is moved into the script_verify_flags constructor. The underlying type is narrowed from uint32_t to uint8_t. Constants like MAX_SCRIPT_VERIFY_FLAGS_BITS and MAX_SCRIPT_VERIFY_FLAGS are recomputed accordingly. The change preserves the same external bit values for each flag and the same static_assert guard that there is still a spare bit below 31.
Changed components
src/script/interpreter.hsrc/script/verify_flags.hInspect captured patch +28 / −28
diff --git a/src/script/interpreter.h b/src/script/interpreter.h
index 9ae29e0f..15f37fba 100644
--- a/src/script/interpreter.h
+++ b/src/script/interpreter.h
@@ -14,7 +14,6 @@
#include <span.h>
#include <uint256.h>
-#include <bit>
#include <cstddef>
#include <cstdint>
#include <optional>
@@ -47,33 +46,33 @@ enum
static constexpr script_verify_flags SCRIPT_VERIFY_NONE{0};
-enum class script_verify_flag_name : uint32_t {
+enum class script_verify_flag_name : uint8_t {
// Evaluate P2SH subscripts (BIP16).
- SCRIPT_VERIFY_P2SH = (1U << 0),
+ SCRIPT_VERIFY_P2SH,
// 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.
// (not used or intended as a consensus rule).
- SCRIPT_VERIFY_STRICTENC = (1U << 1),
+ SCRIPT_VERIFY_STRICTENC,
// Passing a non-strict-DER signature to a checksig operation causes script failure (BIP62 rule 1)
- SCRIPT_VERIFY_DERSIG = (1U << 2),
+ SCRIPT_VERIFY_DERSIG,
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
// (BIP62 rule 5).
- SCRIPT_VERIFY_LOW_S = (1U << 3),
+ SCRIPT_VERIFY_LOW_S,
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (BIP62 rule 7).
- SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
+ SCRIPT_VERIFY_NULLDUMMY,
// Using a non-push operator in the scriptSig causes script failure (BIP62 rule 2).
- SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
+ SCRIPT_VERIFY_SIGPUSHONLY,
// 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).
- SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
+ SCRIPT_VERIFY_MINIMALDATA,
// Discourage use of NOPs reserved for upgrades (NOP1-10)
//
@@ -85,7 +84,7 @@ enum class script_verify_flag_name : uint32_t {
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
// NOPs that have associated forks to give them new meaning (CLTV, CSV)
// are not subject to this rule.
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS,
// 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
@@ -94,57 +93,57 @@ enum class script_verify_flag_name : uint32_t {
// Note: CLEANSTACK should never be used without P2SH or WITNESS.
// Note: WITNESS_V0 and TAPSCRIPT script execution have behavior similar to CLEANSTACK as part of their
// consensus rules. It is automatic there and does not need this flag.
- SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
+ SCRIPT_VERIFY_CLEANSTACK,
// Verify CHECKLOCKTIMEVERIFY
//
// See BIP65 for details.
- SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9),
+ SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY,
// support CHECKSEQUENCEVERIFY opcode
//
// See BIP112 for details
- SCRIPT_VERIFY_CHECKSEQUENCEVERIFY = (1U << 10),
+ SCRIPT_VERIFY_CHECKSEQUENCEVERIFY,
// Support segregated witness
//
- SCRIPT_VERIFY_WITNESS = (1U << 11),
+ SCRIPT_VERIFY_WITNESS,
// Making v1-v16 witness program non-standard
//
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM = (1U << 12),
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM,
// Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector
//
// Note: TAPSCRIPT script execution has behavior similar to MINIMALIF as part of its consensus
// rules. It is automatic there and does not depend on this flag.
- SCRIPT_VERIFY_MINIMALIF = (1U << 13),
+ SCRIPT_VERIFY_MINIMALIF,
// Signature(s) must be empty vector if a CHECK(MULTI)SIG operation failed
//
- SCRIPT_VERIFY_NULLFAIL = (1U << 14),
+ SCRIPT_VERIFY_NULLFAIL,
// Public keys in segregated witness scripts must be compressed
//
- SCRIPT_VERIFY_WITNESS_PUBKEYTYPE = (1U << 15),
+ SCRIPT_VERIFY_WITNESS_PUBKEYTYPE,
// Making OP_CODESEPARATOR and FindAndDelete fail any non-segwit scripts
//
- SCRIPT_VERIFY_CONST_SCRIPTCODE = (1U << 16),
+ SCRIPT_VERIFY_CONST_SCRIPTCODE,
// Taproot/Tapscript validation (BIPs 341 & 342)
//
- SCRIPT_VERIFY_TAPROOT = (1U << 17),
+ SCRIPT_VERIFY_TAPROOT,
// Making unknown Taproot leaf versions non-standard
//
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION = (1U << 18),
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION,
// Making unknown OP_SUCCESS non-standard
- SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS = (1U << 19),
+ SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS,
// Making unknown public key versions (in BIP 342 scripts) non-standard
- SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE = (1U << 20),
+ SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE,
// Constants to point to the highest flag in use. Add new flags above this line.
//
@@ -152,11 +151,12 @@ enum class script_verify_flag_name : uint32_t {
};
using enum script_verify_flag_name;
+static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = static_cast<int>(SCRIPT_VERIFY_END_MARKER);
+
// assert there is still a spare bit
-static_assert(static_cast<script_verify_flags::value_type>(SCRIPT_VERIFY_END_MARKER) < (1u << 31));
+static_assert(0 < MAX_SCRIPT_VERIFY_FLAGS_BITS && MAX_SCRIPT_VERIFY_FLAGS_BITS <= 31);
-static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((static_cast<script_verify_flags::value_type>(SCRIPT_VERIFY_END_MARKER) - 1) << 1) - 1;
-static constexpr int MAX_SCRIPT_VERIFY_FLAGS_BITS = std::bit_width(MAX_SCRIPT_VERIFY_FLAGS);
+static constexpr script_verify_flags::value_type MAX_SCRIPT_VERIFY_FLAGS = ((script_verify_flags::value_type{1} << MAX_SCRIPT_VERIFY_FLAGS_BITS) - 1);
bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, script_verify_flags flags, ScriptError* serror);
diff --git a/src/script/verify_flags.h b/src/script/verify_flags.h
index ba75f089..0d34174e 100644
--- a/src/script/verify_flags.h
+++ b/src/script/verify_flags.h
@@ -9,7 +9,7 @@
#include <compare>
#include <cstdint>
-enum class script_verify_flag_name : uint32_t;
+enum class script_verify_flag_name : uint8_t;
class script_verify_flags
{
@@ -22,7 +22,7 @@ public:
consteval explicit(false) script_verify_flags(value_type f) : m_value{f} { if (f != 0) throw 0; }
// implicit construction from a hard-coded SCRIPT_VERIFY_* constant is also okay
- constexpr explicit(false) script_verify_flags(script_verify_flag_name f) : m_value{static_cast<value_type>(f)} { }
+ constexpr explicit(false) script_verify_flags(script_verify_flag_name f) : m_value{value_type{1} << static_cast<uint8_t>(f)} { }
// rule of 5
constexpr script_verify_flags(const script_verify_flags&) = default;
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.