


// Copyright (c) 20092010 Satoshi Nakamoto




// Copyright (c) 20092017 The Starwels developers




// Distributed under the MIT software license, see the accompanying




// file COPYING or http://www.opensource.org/licenses/mitlicense.php.








#include <script/interpreter.h>








#include <crypto/ripemd160.h>




#include <crypto/sha1.h>




#include <crypto/sha256.h>




#include <pubkey.h>




#include <script/script.h>




#include <uint256.h>








typedef std::vector<unsigned char> 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 (unsigned int i = 0; i < vch.size(); i++)




{




if (vch[i] != 0)




{




// Can be negative zero




if (i == vch.size()1 && vch[i] == 0x80)




return false;




return true;




}




}




return false;




}








/**




* Script is a stack machine (like Forth) that evaluates a predicate




* returning a bool indicating valid or not. There are no loops.




*/




#define stacktop(i) (stack.at(stack.size()+(i)))




#define altstacktop(i) (altstack.at(altstack.size()+(i)))




static inline void popstack(std::vector<valtype>& stack)




{




if (stack.empty())




throw std::runtime_error("popstack(): stack empty");




stack.pop_back();




}








bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {




if (vchPubKey.size() < 33) {




// Noncanonical public key: too short




return false;




}




if (vchPubKey[0] == 0x04) {




if (vchPubKey.size() != 65) {




// Noncanonical public key: invalid length for uncompressed key




return false;




}




} else if (vchPubKey[0] == 0x02  vchPubKey[0] == 0x03) {




if (vchPubKey.size() != 33) {




// Noncanonical public key: invalid length for compressed key




return false;




}




} else {




// Noncanonical public key: neither compressed nor uncompressed




return false;




}




return true;




}








bool static IsCompressedPubKey(const valtype &vchPubKey) {




if (vchPubKey.size() != 33) {




// Noncanonical public key: invalid length for compressed key




return false;




}




if (vchPubKey[0] != 0x02 && vchPubKey[0] != 0x03) {




// Noncanonical 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 consensuscritical since BIP66.




*/




bool static IsValidSignatureEncoding(const std::vector<unsigned char> &sig) {




// Format: 0x30 [totallength] 0x02 [Rlength] [R] 0x02 [Slength] [S] [sighash]




// * totallength: 1byte length descriptor of everything that follows,




// excluding the sighash byte.




// * Rlength: 1byte length descriptor of the R value that follows.




// * R: arbitrarylength bigendian 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).




// * Slength: 1byte length descriptor of the S value that follows.




// * S: arbitrarylength bigendian encoded S value. The same rules apply.




// * sighash: 1byte 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;








// Zerolength 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;








// Zerolength 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;




}








bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {




if (!IsValidSignatureEncoding(vchSig)) {




return set_error(serror, SCRIPT_ERR_SIG_DER);




}




// https://bitcoin.stackexchange.com/a/12556:




// Also note that inside transaction signatures, an extra hashtype byte




// follows the actual signature data.




std::vector<unsigned char> vchSigCopy(vchSig.begin(), vchSig.begin() + vchSig.size()  1);




// If the S value is above the order of the curve divided by two, its




// complement modulo the order could have been used instead, which is




// one byte shorter when encoded correctly.




if (!CPubKey::CheckLowS(vchSigCopy)) {




return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);




}




return true;




}








bool static IsDefinedHashtypeSignature(const valtype &vchSig) {




if (vchSig.size() == 0) {




return false;




}




unsigned char nHashType = vchSig[vchSig.size()  1] & (~(SIGHASH_ANYONECANPAY));




if (nHashType < SIGHASH_ALL  nHashType > SIGHASH_SINGLE)




return false;








return true;




}








bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int 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);




} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {




// serror is set




return false;




} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {




return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);




}




return true;




}








bool static CheckPubKeyEncoding(const valtype &vchPubKey, unsigned int flags, const SigVersion &sigversion, ScriptError* serror) {




if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchPubKey)) {




return set_error(serror, SCRIPT_ERR_PUBKEYTYPE);




}




// Only compressed keys are accepted in segwit




if ((flags & SCRIPT_VERIFY_WITNESS_PUBKEYTYPE) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(vchPubKey)) {




return set_error(serror, SCRIPT_ERR_WITNESS_PUBKEYTYPE);




}




return true;




}








bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {




if (data.size() == 0) {




// Could have used OP_0.




return opcode == OP_0;




} else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {




// Could have used OP_1 .. OP_16.




return opcode == OP_1 + (data[0]  1);




} else if (data.size() == 1 && data[0] == 0x81) {




// Could have used OP_1NEGATE.




return opcode == OP_1NEGATE;




} else if (data.size() <= 75) {




// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).




return opcode == data.size();




} else if (data.size() <= 255) {




// Could have used OP_PUSHDATA.




return opcode == OP_PUSHDATA1;




} else if (data.size() <= 65535) {




// Could have used OP_PUSHDATA2.




return opcode == OP_PUSHDATA2;




}




return true;




}








bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, SigVersion sigversion, ScriptError* serror)




{




static const CScriptNum bnZero(0);




static const CScriptNum bnOne(1);




// static const CScriptNum bnFalse(0);




// static const CScriptNum bnTrue(1);




static const valtype vchFalse(0);




// static const valtype vchZero(0);




static const valtype vchTrue(1, 1);








CScript::const_iterator pc = script.begin();




CScript::const_iterator pend = script.end();




CScript::const_iterator pbegincodehash = script.begin();




opcodetype opcode;




valtype vchPushValue;




std::vector<bool> vfExec;




std::vector<valtype> altstack;




set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);




if (script.size() > MAX_SCRIPT_SIZE)




return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);




int nOpCount = 0;




bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;








try




{




while (pc < pend)




{




bool fExec = !count(vfExec.begin(), vfExec.end(), false);








//




// Read instruction




//




if (!script.GetOp(pc, opcode, vchPushValue))




return set_error(serror, SCRIPT_ERR_BAD_OPCODE);




if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)




return set_error(serror, SCRIPT_ERR_PUSH_SIZE);








// Note how OP_RESERVED does not count towards the opcode limit.




if (opcode > OP_16 && ++nOpCount > MAX_OPS_PER_SCRIPT)




return set_error(serror, SCRIPT_ERR_OP_COUNT);








if (opcode == OP_CAT 




opcode == OP_SUBSTR 




opcode == OP_LEFT 




opcode == OP_RIGHT 




opcode == OP_INVERT 




opcode == OP_AND 




opcode == OP_OR 




opcode == OP_XOR 




opcode == OP_2MUL 




opcode == OP_2DIV 




opcode == OP_MUL 




opcode == OP_DIV 




opcode == OP_MOD 




opcode == OP_LSHIFT 




opcode == OP_RSHIFT)




return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.








// With SCRIPT_VERIFY_CONST_SCRIPTCODE, OP_CODESEPARATOR in nonsegwit script is rejected even in an unexecuted branch




if (opcode == OP_CODESEPARATOR && sigversion == SIGVERSION_BASE && (flags & SCRIPT_VERIFY_CONST_SCRIPTCODE))




return set_error(serror, SCRIPT_ERR_OP_CODESEPARATOR);








if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {




if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {




return set_error(serror, SCRIPT_ERR_MINIMALDATA);




}




stack.push_back(vchPushValue);




} else if (fExec  (OP_IF <= opcode && opcode <= OP_ENDIF))




switch (opcode)




{




//




// Push value




//




case OP_1NEGATE:




case OP_1:




case OP_2:




case OP_3:




case OP_4:




case OP_5:




case OP_6:




case OP_7:




case OP_8:




case OP_9:




case OP_10:




case OP_11:




case OP_12:




case OP_13:




case OP_14:




case OP_15:




case OP_16:




{




// (  value)




CScriptNum bn((int)opcode  (int)(OP_1  1));




stack.push_back(bn.getvch());




// The result of these opcodes should always be the minimal way to push the data




// they push, so no need for a CheckMinimalPush here.




}




break;












//




// Control




//




case OP_NOP:




break;








case OP_CHECKLOCKTIMEVERIFY:




{




if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {




// not enabled; treat as a NOP2




break;




}








if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);








// Note that elsewhere numeric opcodes are limited to




// operands in the range 2**31+1 to 2**311, however it is




// legal for opcodes to produce results exceeding that




// range. This limitation is implemented by CScriptNum's




// default 4byte limit.




//




// If we kept to that limit we'd have a year 2038 problem,




// even though the nLockTime field in transactions




// themselves is uint32 which only becomes meaningless




// after the year 2106.




//




// Thus as a special case we tell CScriptNum to accept up




// to 5byte bignums, which are good until 2**391, well




// beyond the 2**321 limit of the nLockTime field itself.




const CScriptNum nLockTime(stacktop(1), fRequireMinimal, 5);








// In the rare event that the argument may be < 0 due to




// some arithmetic being done first, you can always use




// 0 MAX CHECKLOCKTIMEVERIFY.




if (nLockTime < 0)




return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);








// Actually compare the specified lock time with the transaction.




if (!checker.CheckLockTime(nLockTime))




return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);








break;




}








case OP_CHECKSEQUENCEVERIFY:




{




if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {




// not enabled; treat as a NOP3




break;




}








if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);








// nSequence, like nLockTime, is a 32bit unsigned integer




// field. See the comment in CHECKLOCKTIMEVERIFY regarding




// 5byte numeric operands.




const CScriptNum nSequence(stacktop(1), fRequireMinimal, 5);








// In the rare event that the argument may be < 0 due to




// some arithmetic being done first, you can always use




// 0 MAX CHECKSEQUENCEVERIFY.




if (nSequence < 0)




return set_error(serror, SCRIPT_ERR_NEGATIVE_LOCKTIME);








// To provide for future softfork extensibility, if the




// operand has the disabled locktime flag set,




// CHECKSEQUENCEVERIFY behaves as a NOP.




if ((nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0)




break;








// Compare the specified sequence number with the input.




if (!checker.CheckSequence(nSequence))




return set_error(serror, SCRIPT_ERR_UNSATISFIED_LOCKTIME);








break;




}








case OP_NOP1: case OP_NOP4: case OP_NOP5:




case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:




{




if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)




return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);




}




break;








case OP_IF:




case OP_NOTIF:




{




// <expression> if [statements] [else [statements]] endif




bool fValue = false;




if (fExec)




{




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);




valtype& vch = stacktop(1);




if (sigversion == SIGVERSION_WITNESS_V0 && (flags & SCRIPT_VERIFY_MINIMALIF)) {




if (vch.size() > 1)




return set_error(serror, SCRIPT_ERR_MINIMALIF);




if (vch.size() == 1 && vch[0] != 1)




return set_error(serror, SCRIPT_ERR_MINIMALIF);




}




fValue = CastToBool(vch);




if (opcode == OP_NOTIF)




fValue = !fValue;




popstack(stack);




}




vfExec.push_back(fValue);




}




break;








case OP_ELSE:




{




if (vfExec.empty())




return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);




vfExec.back() = !vfExec.back();




}




break;








case OP_ENDIF:




{




if (vfExec.empty())




return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);




vfExec.pop_back();




}




break;








case OP_VERIFY:




{




// (true  ) or




// (false  false) and return




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




bool fValue = CastToBool(stacktop(1));




if (fValue)




popstack(stack);




else




return set_error(serror, SCRIPT_ERR_VERIFY);




}




break;








case OP_RETURN:




{




return set_error(serror, SCRIPT_ERR_OP_RETURN);




}




break;












//




// Stack ops




//




case OP_TOALTSTACK:




{




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




altstack.push_back(stacktop(1));




popstack(stack);




}




break;








case OP_FROMALTSTACK:




{




if (altstack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION);




stack.push_back(altstacktop(1));




popstack(altstack);




}




break;








case OP_2DROP:




{




// (x1 x2  )




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




popstack(stack);




popstack(stack);




}




break;








case OP_2DUP:




{




// (x1 x2  x1 x2 x1 x2)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch1 = stacktop(2);




valtype vch2 = stacktop(1);




stack.push_back(vch1);




stack.push_back(vch2);




}




break;








case OP_3DUP:




{




// (x1 x2 x3  x1 x2 x3 x1 x2 x3)




if (stack.size() < 3)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch1 = stacktop(3);




valtype vch2 = stacktop(2);




valtype vch3 = stacktop(1);




stack.push_back(vch1);




stack.push_back(vch2);




stack.push_back(vch3);




}




break;








case OP_2OVER:




{




// (x1 x2 x3 x4  x1 x2 x3 x4 x1 x2)




if (stack.size() < 4)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch1 = stacktop(4);




valtype vch2 = stacktop(3);




stack.push_back(vch1);




stack.push_back(vch2);




}




break;








case OP_2ROT:




{




// (x1 x2 x3 x4 x5 x6  x3 x4 x5 x6 x1 x2)




if (stack.size() < 6)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch1 = stacktop(6);




valtype vch2 = stacktop(5);




stack.erase(stack.end()6, stack.end()4);




stack.push_back(vch1);




stack.push_back(vch2);




}




break;








case OP_2SWAP:




{




// (x1 x2 x3 x4  x3 x4 x1 x2)




if (stack.size() < 4)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




swap(stacktop(4), stacktop(2));




swap(stacktop(3), stacktop(1));




}




break;








case OP_IFDUP:




{




// (x  0  x x)




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch = stacktop(1);




if (CastToBool(vch))




stack.push_back(vch);




}




break;








case OP_DEPTH:




{




//  stacksize




CScriptNum bn(stack.size());




stack.push_back(bn.getvch());




}




break;








case OP_DROP:




{




// (x  )




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




popstack(stack);




}




break;








case OP_DUP:




{




// (x  x x)




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch = stacktop(1);




stack.push_back(vch);




}




break;








case OP_NIP:




{




// (x1 x2  x2)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




stack.erase(stack.end()  2);




}




break;








case OP_OVER:




{




// (x1 x2  x1 x2 x1)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch = stacktop(2);




stack.push_back(vch);




}




break;








case OP_PICK:




case OP_ROLL:




{




// (xn ... x2 x1 x0 n  xn ... x2 x1 x0 xn)




// (xn ... x2 x1 x0 n  ... x2 x1 x0 xn)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




int n = CScriptNum(stacktop(1), fRequireMinimal).getint();




popstack(stack);




if (n < 0  n >= (int)stack.size())




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch = stacktop(n1);




if (opcode == OP_ROLL)




stack.erase(stack.end()n1);




stack.push_back(vch);




}




break;








case OP_ROT:




{




// (x1 x2 x3  x2 x3 x1)




// x2 x1 x3 after first swap




// x2 x3 x1 after second swap




if (stack.size() < 3)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




swap(stacktop(3), stacktop(2));




swap(stacktop(2), stacktop(1));




}




break;








case OP_SWAP:




{




// (x1 x2  x2 x1)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




swap(stacktop(2), stacktop(1));




}




break;








case OP_TUCK:




{




// (x1 x2  x2 x1 x2)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype vch = stacktop(1);




stack.insert(stack.end()2, vch);




}




break;












case OP_SIZE:




{




// (in  in size)




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




CScriptNum bn(stacktop(1).size());




stack.push_back(bn.getvch());




}




break;












//




// Bitwise logic




//




case OP_EQUAL:




case OP_EQUALVERIFY:




//case OP_NOTEQUAL: // use OP_NUMNOTEQUAL




{




// (x1 x2  bool)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype& vch1 = stacktop(2);




valtype& vch2 = stacktop(1);




bool fEqual = (vch1 == vch2);




// OP_NOTEQUAL is disabled because it would be too easy to say




// something like n != 1 and have some wiseguy pass in 1 with extra




// zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)




//if (opcode == OP_NOTEQUAL)




// fEqual = !fEqual;




popstack(stack);




popstack(stack);




stack.push_back(fEqual ? vchTrue : vchFalse);




if (opcode == OP_EQUALVERIFY)




{




if (fEqual)




popstack(stack);




else




return set_error(serror, SCRIPT_ERR_EQUALVERIFY);




}




}




break;












//




// Numeric




//




case OP_1ADD:




case OP_1SUB:




case OP_NEGATE:




case OP_ABS:




case OP_NOT:




case OP_0NOTEQUAL:




{




// (in  out)




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




CScriptNum bn(stacktop(1), fRequireMinimal);




switch (opcode)




{




case OP_1ADD: bn += bnOne; break;




case OP_1SUB: bn = bnOne; break;




case OP_NEGATE: bn = bn; break;




case OP_ABS: if (bn < bnZero) bn = bn; break;




case OP_NOT: bn = (bn == bnZero); break;




case OP_0NOTEQUAL: bn = (bn != bnZero); break;




default: assert(!"invalid opcode"); break;




}




popstack(stack);




stack.push_back(bn.getvch());




}




break;








case OP_ADD:




case OP_SUB:




case OP_BOOLAND:




case OP_BOOLOR:




case OP_NUMEQUAL:




case OP_NUMEQUALVERIFY:




case OP_NUMNOTEQUAL:




case OP_LESSTHAN:




case OP_GREATERTHAN:




case OP_LESSTHANOREQUAL:




case OP_GREATERTHANOREQUAL:




case OP_MIN:




case OP_MAX:




{




// (x1 x2  out)




if (stack.size() < 2)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




CScriptNum bn1(stacktop(2), fRequireMinimal);




CScriptNum bn2(stacktop(1), fRequireMinimal);




CScriptNum bn(0);




switch (opcode)




{




case OP_ADD:




bn = bn1 + bn2;




break;








case OP_SUB:




bn = bn1  bn2;




break;








case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;




case OP_BOOLOR: bn = (bn1 != bnZero  bn2 != bnZero); break;




case OP_NUMEQUAL: bn = (bn1 == bn2); break;




case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;




case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;




case OP_LESSTHAN: bn = (bn1 < bn2); break;




case OP_GREATERTHAN: bn = (bn1 > bn2); break;




case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;




case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;




case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;




case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;




default: assert(!"invalid opcode"); break;




}




popstack(stack);




popstack(stack);




stack.push_back(bn.getvch());








if (opcode == OP_NUMEQUALVERIFY)




{




if (CastToBool(stacktop(1)))




popstack(stack);




else




return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY);




}




}




break;








case OP_WITHIN:




{




// (x min max  out)




if (stack.size() < 3)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




CScriptNum bn1(stacktop(3), fRequireMinimal);




CScriptNum bn2(stacktop(2), fRequireMinimal);




CScriptNum bn3(stacktop(1), fRequireMinimal);




bool fValue = (bn2 <= bn1 && bn1 < bn3);




popstack(stack);




popstack(stack);




popstack(stack);




stack.push_back(fValue ? vchTrue : vchFalse);




}




break;












//




// Crypto




//




case OP_RIPEMD160:




case OP_SHA1:




case OP_SHA256:




case OP_HASH160:




case OP_HASH256:




{




// (in  hash)




if (stack.size() < 1)




return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);




valtype& vch = stacktop(1);




valtype vchHash((opcode == OP_RIPEMD160  opcode == OP_SHA1  opcode == OP_HASH160) ? 20 : 32);




if (opcode == OP_RIPEMD160)




CRIPEMD160().Write(vch.data(), vch.size()).Finalize(vchHash.data());




else if (opcode == OP_SHA1)




CSHA1().Write(vch.data(), vch.size()).Finalize(vchHash.data());




else if (opcode == OP_SHA256)




CSHA256().Write(vch.data(), vch.size()).Finalize(vchHash.data());




else if (opcode == OP_HASH160)




CHash160().Write(vch.data(), vch.size()).Finalize(vchHash.data());




else if (opcode == OP_HASH256)




CHash256().Write(vch.data(), vch.size()).Finalize(vchHash.data());




popstack(stack);




stack.push_back(vchHash);




}




break;







