Skip to content

Commit 360a79e

Browse files
committed
64bit arith cscriptnum no new opcodes
1 parent 5471428 commit 360a79e

File tree

13 files changed

+473
-89
lines changed

13 files changed

+473
-89
lines changed

src/script/interpreter.cpp

Lines changed: 62 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,20 @@ int FindAndDelete(CScript& script, const CScript& b)
254254
return nFound;
255255
}
256256

257+
CScriptNum GetCScriptNum(const valtype& num, const bool fRequireMinimal, const SigVersion& sigversion)
258+
{
259+
switch (sigversion)
260+
{
261+
case SigVersion::BASE:
262+
case SigVersion::WITNESS_V0:
263+
case SigVersion::TAPROOT:
264+
case SigVersion::TAPSCRIPT:
265+
return CScriptNum(num,fRequireMinimal,/*nMaximumSize=*/4);
266+
case SigVersion::TAPSCRIPT_64BIT:
267+
return CScriptNum(num,fRequireMinimal,/*nMaximumSize=*/8);
268+
}
269+
}
270+
257271
namespace {
258272
/** A data type to abstract out the condition stack during script execution.
259273
*
@@ -396,6 +410,7 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
396410
case SigVersion::WITNESS_V0:
397411
return EvalChecksigPreTapscript(sig, pubkey, pbegincodehash, pend, flags, checker, sigversion, serror, success);
398412
case SigVersion::TAPSCRIPT:
413+
case SigVersion::TAPSCRIPT_64BIT:
399414
return EvalChecksigTapscript(sig, pubkey, execdata, flags, checker, sigversion, serror, success);
400415
case SigVersion::TAPROOT:
401416
// Key path spending in Taproot has no script, so this is unreachable.
@@ -404,6 +419,39 @@ static bool EvalChecksig(const valtype& sig, const valtype& pubkey, CScript::con
404419
assert(false);
405420
}
406421

422+
static bool IsOpCodeDisabled(const opcodetype& opcode, const SigVersion& sigVersion, ScriptError* serror)
423+
{
424+
switch(sigVersion)
425+
{
426+
case SigVersion::BASE:
427+
case SigVersion::WITNESS_V0:
428+
case SigVersion::TAPROOT:
429+
case SigVersion::TAPSCRIPT:
430+
case SigVersion::TAPSCRIPT_64BIT:
431+
{
432+
if (opcode == OP_CAT ||
433+
opcode == OP_SUBSTR ||
434+
opcode == OP_LEFT ||
435+
opcode == OP_RIGHT ||
436+
opcode == OP_INVERT ||
437+
opcode == OP_AND ||
438+
opcode == OP_OR ||
439+
opcode == OP_XOR ||
440+
opcode == OP_2MUL ||
441+
opcode == OP_2DIV ||
442+
opcode == OP_MUL ||
443+
opcode == OP_DIV ||
444+
opcode == OP_MOD ||
445+
opcode == OP_LSHIFT ||
446+
opcode == OP_RSHIFT)
447+
return !set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes (CVE-2010-5137).
448+
break;
449+
}
450+
}
451+
//should we default to disabled is false?
452+
return false;
453+
}
454+
407455
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptExecutionData& execdata, ScriptError* serror)
408456
{
409457
static const CScriptNum bnZero(0);
@@ -415,7 +463,7 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
415463
static const valtype vchTrue(1, 1);
416464

417465
// sigversion cannot be TAPROOT here, as it admits no script execution.
418-
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT);
466+
assert(sigversion == SigVersion::BASE || sigversion == SigVersion::WITNESS_V0 || sigversion == SigVersion::TAPSCRIPT || sigversion == SigVersion::TAPSCRIPT_64BIT);
419467

420468
CScript::const_iterator pc = script.begin();
421469
CScript::const_iterator pend = script.end();
@@ -454,22 +502,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
454502
}
455503
}
456504

457-
if (opcode == OP_CAT ||
458-
opcode == OP_SUBSTR ||
459-
opcode == OP_LEFT ||
460-
opcode == OP_RIGHT ||
461-
opcode == OP_INVERT ||
462-
opcode == OP_AND ||
463-
opcode == OP_OR ||
464-
opcode == OP_XOR ||
465-
opcode == OP_2MUL ||
466-
opcode == OP_2DIV ||
467-
opcode == OP_MUL ||
468-
opcode == OP_DIV ||
469-
opcode == OP_MOD ||
470-
opcode == OP_LSHIFT ||
471-
opcode == OP_RSHIFT)
472-
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes (CVE-2010-5137).
505+
if (IsOpCodeDisabled(opcode,sigversion,serror))
506+
return false;
473507

474508
// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in non-segwit script is rejected even in an unexecuted branch
475509
if (opcode == OP_CODESEPARATOR && sigversion == SigVersion::BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))
@@ -926,7 +960,8 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
926960
// (in -- out)
927961
if (stack.size() < 1)
928962
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
929-
CScriptNum bn(stacktop(-1), fRequireMinimal);
963+
964+
CScriptNum bn = GetCScriptNum(stacktop(-1), fRequireMinimal, sigversion);
930965
switch (opcode)
931966
{
932967
case OP_1ADD: bn += bnOne; break;
@@ -959,19 +994,17 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
959994
// (x1 x2 -- out)
960995
if (stack.size() < 2)
961996
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
962-
CScriptNum bn1(stacktop(-2), fRequireMinimal);
963-
CScriptNum bn2(stacktop(-1), fRequireMinimal);
997+
CScriptNum bn1 = GetCScriptNum(stacktop(-2), fRequireMinimal, sigversion);
998+
CScriptNum bn2 = GetCScriptNum(stacktop(-1), fRequireMinimal, sigversion);
964999
CScriptNum bn(0);
9651000
switch (opcode)
9661001
{
9671002
case OP_ADD:
9681003
bn = bn1 + bn2;
9691004
break;
970-
9711005
case OP_SUB:
9721006
bn = bn1 - bn2;
9731007
break;
974-
9751008
case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
9761009
case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
9771010
case OP_NUMEQUAL: bn = (bn1 == bn2); break;
@@ -988,7 +1021,6 @@ bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript&
9881021
popstack(stack);
9891022
popstack(stack);
9901023
stack.push_back(bn.getvch());
991-
9921024
if (opcode == OP_NUMEQUALVERIFY)
9931025
{
9941026
if (CastToBool(stacktop(-1)))
@@ -1939,6 +1971,13 @@ static bool VerifyWitnessProgram(const CScriptWitness& witness, int witversion,
19391971
execdata.m_validation_weight_left_init = true;
19401972
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT, checker, execdata, serror);
19411973
}
1974+
if ((control[0] & TAPROOT_LEAF_MASK) == TAPROOT_LEAF_TAPSCRIPT_64BIT) {
1975+
// Tapscript (leaf version 0x66)
1976+
exec_script = CScript(script.begin(), script.end());
1977+
execdata.m_validation_weight_left = ::GetSerializeSize(witness.stack) + VALIDATION_WEIGHT_OFFSET;
1978+
execdata.m_validation_weight_left_init = true;
1979+
return ExecuteWitnessScript(stack, exec_script, flags, SigVersion::TAPSCRIPT_64BIT, checker, execdata, serror);
1980+
}
19421981
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION) {
19431982
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION);
19441983
}

src/script/interpreter.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ static constexpr size_t WITNESS_V1_TAPROOT_SIZE = 32;
222222

223223
static constexpr uint8_t TAPROOT_LEAF_MASK = 0xfe;
224224
static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT = 0xc0;
225+
static constexpr uint8_t TAPROOT_LEAF_TAPSCRIPT_64BIT = 0x66;
225226
static constexpr size_t TAPROOT_CONTROL_BASE_SIZE = 33;
226227
static constexpr size_t TAPROOT_CONTROL_NODE_SIZE = 32;
227228
static constexpr size_t TAPROOT_CONTROL_MAX_NODE_COUNT = 128;
@@ -232,7 +233,7 @@ extern const HashWriter HASHER_TAPLEAF; //!< Hasher with tag "TapLeaf" pre-fe
232233
extern const HashWriter HASHER_TAPBRANCH; //!< Hasher with tag "TapBranch" pre-fed to it.
233234

234235
template <class T>
235-
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int32_t nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
236+
uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn, int nHashType, const CAmount& amount, SigVersion sigversion, const PrecomputedTransactionData* cache = nullptr);
236237

237238
class BaseSignatureChecker
238239
{

src/script/script.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,7 @@ bool IsOpSuccess(const opcodetype& opcode, SigVersion sigversion)
361361
switch (sigversion)
362362
{
363363
case SigVersion::TAPSCRIPT:
364+
case SigVersion::TAPSCRIPT_64BIT:
364365
return opcode == 80 || opcode == 98 || (opcode >= 126 && opcode <= 129) ||
365366
(opcode >= 131 && opcode <= 134) || (opcode >= 137 && opcode <= 138) ||
366367
(opcode >= 141 && opcode <= 142) || (opcode >= 149 && opcode <= 153) ||

src/script/script.h

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,6 @@
1313
#include <uint256.h>
1414
#include <util/hash_type.h>
1515

16-
#include <cassert>
17-
#include <cstdint>
18-
#include <cstring>
19-
#include <limits>
20-
#include <span>
21-
#include <stdexcept>
22-
#include <string>
23-
#include <type_traits>
24-
#include <utility>
25-
#include <vector>
26-
2716
enum class SigVersion;
2817

2918
// Maximum number of bytes pushable to the stack
@@ -237,7 +226,7 @@ class CScriptNum
237226
*/
238227
public:
239228

240-
explicit CScriptNum(const int64_t& n)
229+
explicit CScriptNum(const __int128_t& n)
241230
{
242231
m_value = n;
243232
}
@@ -298,9 +287,15 @@ class CScriptNum
298287

299288
inline CScriptNum& operator&=( const CScriptNum& rhs) { return operator&=(rhs.m_value); }
300289

290+
inline CScriptNum operator*(const __int128_t& rhs) const { return CScriptNum(m_value * rhs);}
291+
inline CScriptNum operator*(const CScriptNum& rhs) const { return operator*(rhs.m_value);}
292+
293+
inline CScriptNum operator/(const __int128_t& rhs) const { return CScriptNum(m_value / rhs);}
294+
inline CScriptNum operator/(const CScriptNum& rhs) const { return operator/(rhs.m_value);}
295+
301296
inline CScriptNum operator-() const
302297
{
303-
assert(m_value != std::numeric_limits<int64_t>::min());
298+
assert(m_value != std::numeric_limits<__int128_t>::min());
304299
return CScriptNum(-m_value);
305300
}
306301

@@ -312,16 +307,16 @@ class CScriptNum
312307

313308
inline CScriptNum& operator+=( const int64_t& rhs)
314309
{
315-
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
316-
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
310+
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<__int128_t>::max() - rhs) ||
311+
(rhs < 0 && m_value >= std::numeric_limits<__int128_t>::min() - rhs));
317312
m_value += rhs;
318313
return *this;
319314
}
320315

321316
inline CScriptNum& operator-=( const int64_t& rhs)
322317
{
323-
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
324-
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
318+
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<__int128_t>::min() + rhs) ||
319+
(rhs < 0 && m_value <= std::numeric_limits<__int128_t>::max() + rhs));
325320
m_value -= rhs;
326321
return *this;
327322
}
@@ -342,20 +337,21 @@ class CScriptNum
342337
}
343338

344339
int64_t GetInt64() const { return m_value; }
345-
340+
__int128_t GetInt128() const {return m_value; }
346341
std::vector<unsigned char> getvch() const
347342
{
348343
return serialize(m_value);
349344
}
350345

351-
static std::vector<unsigned char> serialize(const int64_t& value)
346+
static std::vector<unsigned char> serialize(const __int128_t& value)
352347
{
353-
if(value == 0)
348+
if(value == 0) {
354349
return std::vector<unsigned char>();
350+
}
355351

356352
std::vector<unsigned char> result;
357353
const bool neg = value < 0;
358-
uint64_t absvalue = neg ? ~static_cast<uint64_t>(value) + 1 : static_cast<uint64_t>(value);
354+
__uint128_t absvalue = neg ? ~static_cast<__uint128_t>(value) + 1 : static_cast<__uint128_t>(value);
359355

360356
while(absvalue)
361357
{
@@ -373,33 +369,35 @@ class CScriptNum
373369
// 0x80 to it, since it will be subtracted and interpreted as a negative when
374370
// converting to an integral.
375371

376-
if (result.back() & 0x80)
372+
if (result.back() & 0x80) {
377373
result.push_back(neg ? 0x80 : 0);
378-
else if (neg)
374+
}
375+
else if (neg) {
379376
result.back() |= 0x80;
377+
}
380378

381379
return result;
382380
}
383381

384382
private:
385-
static int64_t set_vch(const std::vector<unsigned char>& vch)
383+
static __int128_t set_vch(const std::vector<unsigned char>& vch)
386384
{
387385
if (vch.empty())
388386
return 0;
389387

390-
int64_t result = 0;
388+
__int128_t result = 0;
391389
for (size_t i = 0; i != vch.size(); ++i)
392-
result |= static_cast<int64_t>(vch[i]) << 8*i;
390+
result |= static_cast<__int128_t>(vch[i]) << 8*i;
393391

394392
// If the input vector's most significant byte is 0x80, remove it from
395393
// the result's msb and return a negative.
396394
if (vch.back() & 0x80)
397-
return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));
395+
return -((__int128_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));
398396

399397
return result;
400398
}
401399

402-
int64_t m_value;
400+
__int128_t m_value;
403401
};
404402

405403
/**

src/script/script_error.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ std::string ScriptErrorString(const ScriptError serror)
115115
return "Using OP_CODESEPARATOR in non-witness script";
116116
case SCRIPT_ERR_SIG_FINDANDDELETE:
117117
return "Signature is found in scriptCode";
118+
case SCRIPT_ERR_ARITHMETIC64:
119+
return "Arithmetic opcode error";
118120
case SCRIPT_ERR_UNKNOWN_ERROR:
119121
case SCRIPT_ERR_ERROR_COUNT:
120122
default: break;

src/script/script_error.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ typedef enum ScriptError_t
8282
SCRIPT_ERR_OP_CODESEPARATOR,
8383
SCRIPT_ERR_SIG_FINDANDDELETE,
8484

85-
SCRIPT_ERR_ERROR_COUNT
85+
SCRIPT_ERR_ERROR_COUNT,
86+
87+
/* 64bit arithmetic opcode errors */
88+
SCRIPT_ERR_ARITHMETIC64
89+
8690
} ScriptError;
8791

8892
#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT

src/script/sigversion.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ enum class SigVersion
66
WITNESS_V0 = 1, //!< Witness v0 (P2WPKH and P2WSH); see BIP 141
77
TAPROOT = 2, //!< Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, key path spending; see BIP 341
88
TAPSCRIPT = 3, //!< Witness v1 with 32-byte program, not BIP16 P2SH-wrapped, script path spending, leaf version 0xc0; see BIP 342
9+
TAPSCRIPT_64BIT = 4, //!< Witness v1 with 32 byte program script path spending with 64bit arithmetic
910
};
1011
#endif // BITCOIN_SCRIPT_SIGVERSION_H

src/test/script_tests.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1701,8 +1701,9 @@ BOOST_AUTO_TEST_CASE(bip341_keypath_test_vectors)
17011701
BOOST_CHECK_EQUAL(HexStr(sighash), input["intermediary"]["sigHash"].get_str());
17021702

17031703
// To verify the sigmsg, hash the expected sigmsg, and compare it with the (expected) sighash.
1704-
BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << std::span<const uint8_t>{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
1704+
BOOST_CHECK_EQUAL(HexStr((HashWriter{HASHER_TAPSIGHASH} << Span{ParseHex(input["intermediary"]["sigMsg"].get_str())}).GetSHA256()), input["intermediary"]["sigHash"].get_str());
17051705
}
1706+
17061707
}
17071708
}
17081709

src/wallet/feebumper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ struct SignatureWeights
9393
break;
9494
case SigVersion::TAPROOT:
9595
case SigVersion::TAPSCRIPT:
96+
case SigVersion::TAPSCRIPT_64BIT:
9697
assert(false);
9798
}
9899
}

0 commit comments

Comments
 (0)