Esempio n. 1
0
void interpret(uint16_t opcode){
	int firstnibble = (opcode & 0xF000) >> 12;
	switch(firstnibble){
	case 0:
		op_0(opcode);
		break;
	case 1:
		op_1(opcode);
		break;
	case 2:
		op_2(opcode);
		break;
	case 3:
		op_3(opcode);
		break;
	case 4:
		op_4(opcode);
		break;
	case 5:
		op_5(opcode);
		break;
	case 6:
		op_6(opcode);
		break;
	case 7:
		op_7(opcode);
		break;
	case 8:
		op_8(opcode);
		break;
	case 9:
		op_9(opcode);
		break;
	case 0xA:
		op_A(opcode);
		break;
	case 0xB:
		op_B(opcode);
		break;
	case 0xC:
		op_C(opcode);
		break;
	case 0xD:
		op_D(opcode);
		break;
	case 0xE:
		op_E(opcode);
		break;
	case 0xF:	
		op_F(opcode);
		break;
	}
}
Esempio n. 2
0
void StackInterpreter::op_checkmultisig()
{
   //stack needs to have at least m, n, output script
   if (stack_.size() < 3)
      throw ScriptException("insufficient stack size for checkmultisig operation");

   //pop n
   auto&& n = pop_back();
   auto nI = rawBinaryToInt(n);
   if (nI < 0 || nI > 20)
      throw ScriptException("invalid n");

   //pop pubkeys
   map<unsigned, pair<BTC_PUBKEY, BinaryData>> pubkeys;
   for (unsigned i = 0; i < nI; i++)
   {
      auto&& pubkey = pop_back();

      CryptoPP::ECP ecp = CryptoECDSA::Get_secp256k1_ECP();
      BTC_ECPOINT ptPub;
      ecp.DecodePoint(ptPub, (byte*)pubkey.getPtr(), pubkey.getSize());

      BTC_PUBKEY cppPubKey;
      cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), ptPub);

      BTC_PRNG prng;
      if (cppPubKey.Validate(prng, 3))
      {
         txInEvalState_.pubKeyState_.insert(make_pair(pubkey, false));
         auto&& pubkeypair = make_pair(move(cppPubKey), pubkey);
         pubkeys.insert(move(make_pair(i, move(pubkeypair))));
      }
   }

   //pop m
   auto&& m = pop_back();
   auto mI = rawBinaryToInt(m);
   if (mI < 0 || mI > nI)
      throw ScriptException("invalid m");

   txInEvalState_.n_ = nI;
   txInEvalState_.m_ = mI;

   //pop sigs
   struct sigData
   {
      BinaryData sig_;
      SIGHASH_TYPE hashType_;
   };
   vector<sigData> sigVec;

   while (stack_.size() > 0)
   {
      auto&& sig = pop_back();
      if (sig.getSize() == 0)
         break;

      sigData sdata;

      sdata.sig_ = sig.getSliceCopy(0, sig.getSize() - 1);

      //grab hash type
      sdata.hashType_ = 
         getSigHashSingleByte(*(sig.getPtr() + sig.getSize() - 1));

      //push to vector
      sigVec.push_back(move(sdata));
   }

   //should have at least as many sigs as m
   /*if (sigVec.size() < mI)
      throw ScriptException("invalid sig count");*/

   //check sigs
   map<SIGHASH_TYPE, BinaryData> dataToHash;

   //check sighashdata object
   if (sigHashDataObject_ == nullptr)
      sigHashDataObject_ = make_shared<SigHashDataLegacy>();

   unsigned validSigCount = 0;
   int index = nI - 1;
   auto sigIter = sigVec.rbegin();
   while(sigIter != sigVec.rend())
   {
      auto& sigD = *sigIter++;

      //get data to hash
      auto& hashdata = dataToHash[sigD.hashType_];
      if (hashdata.getSize() == 0)
      {
         hashdata = sigHashDataObject_->getDataForSigHash(
            sigD.hashType_, *txStubPtr_, outputScriptRef_, inputIndex_);
      }

      //prepare sig
      auto&& rs = BtcUtils::extractRSFromDERSig(sigD.sig_);
      BinaryWriter sigW;

      //pop pubkeys from deque to verify against sig
      while (pubkeys.size() > 0)
      {
         auto pubkey = pubkeys[index];
         pubkeys.erase(index--);

#ifdef SIGNER_DEBUG
         LOGWARN << "Verifying sig for: ";
         LOGWARN << "   pubkey: " << pubkey.second.toHexStr();

         auto&& msg_hash = BtcUtils::getHash256(hashdata);
         LOGWARN << "   message: " << hashdata.toHexStr();
#endif
            
         if (CryptoECDSA().VerifyData(hashdata, rs, pubkey.first))
         {
            txInEvalState_.pubKeyState_[pubkey.second] = true;
            validSigCount++;
            break;
         }        
      }
   }

   if (validSigCount >= mI)
      op_true();
   else
      op_0();
}
Esempio n. 3
0
void StackInterpreter::processOpCode(const OpCode& oc)
{
   ++opcount_;

   //handle push data by itself, doesn't play well with switch
   if (oc.opcode_ == 0)
   {
      op_0();
      return;
   }

   if (oc.opcode_ <= 75)
   {
      stack_.push_back(oc.dataRef_);
      return;
   }

   if (oc.opcode_ < 79)
   {
      //op push data
      stack_.push_back(oc.dataRef_);
      return;
   }

   if (oc.opcode_ == OP_1NEGATE)
   {
      op_1negate();
      return;
   }

   if (oc.opcode_ <= 96 && oc.opcode_ >= 81)
   {
      //op_1 - op_16
      uint8_t val = oc.opcode_ - 80;
      stack_.push_back(move(intToRawBinary(val)));
      return;
   }

   //If we got this far this op code is not push data. If this is the input
   //script, set the flag as per P2SH parsing rules (only push data in inputs)
   if (outputScriptRef_.getSize() == 0)
      onlyPushDataInInput_ = false;

   switch (oc.opcode_)
   {
   case OP_NOP:
      break;

   case OP_IF:
   {
      BinaryRefReader brr(oc.dataRef_);
      op_if(brr, false);
      break;
   }

   case OP_NOTIF:
   {
      op_not();
      BinaryRefReader brr(oc.dataRef_);
      op_if(brr, false);
      break;
   }

   case OP_ELSE:
      //processed by opening if statement
      throw ScriptException("a wild else appears");

   case OP_ENDIF:
      //processed by opening if statement
      throw ScriptException("a wild endif appears");

   case OP_VERIFY:
      op_verify();
      break;

   case OP_TOALTSTACK:
      op_toaltstack();
      break;

   case OP_FROMALTSTACK:
      op_fromaltstack();
      break;

   case OP_IFDUP:
      op_ifdup();
      break;

   case OP_2DROP:
   {
      stack_.pop_back();
      stack_.pop_back();
      break;
   }

   case OP_2DUP:
      op_2dup();
      break;

   case OP_3DUP:
      op_3dup();
      break;

   case OP_2OVER:
      op_2over();
      break;

   case OP_DEPTH:
      op_depth();
      break;

   case OP_DROP:
      stack_.pop_back();
      break;

   case OP_DUP:
      op_dup();
      break;

   case OP_NIP:
      op_nip();
      break;

   case OP_OVER:
      op_over();
      break;

   case OP_PICK:
      op_pick();
      break;

   case OP_ROLL:
      op_roll();
      break;

   case OP_ROT:
      op_rot();
      break;

   case OP_SWAP:
      op_swap();
      break;

   case OP_TUCK:
      op_tuck();
      break;

   case OP_SIZE:
      op_size();
      break;

   case OP_EQUAL:
   {
      op_equal();
      if (onlyPushDataInInput_ && p2shScript_.getSize() != 0)
      {
         //check the op_equal result
         op_verify();
         if (!isValid_)
            break;

         if (flags_ & SCRIPT_VERIFY_SEGWIT)
            if (p2shScript_.getSize() == 22 ||
               p2shScript_.getSize() == 34)
            {
               auto versionByte = p2shScript_.getPtr();
               if (*versionByte <= 16)
               {
                  processSW(p2shScript_);
                  return;
               }
            }

         processScript(p2shScript_, true);
      }
      break;
   }

   case OP_EQUALVERIFY:
   {
      op_equal();
      op_verify();
      break;
   }

   case OP_1ADD:
      op_1add();
      break;

   case OP_1SUB:
      op_1sub();
      break;

   case OP_NEGATE:
      op_negate();
      break;

   case OP_ABS:
      op_abs();
      break;

   case OP_NOT:
      op_not();
      break;

   case OP_0NOTEQUAL:
      op_0notequal();
      break;

   case OP_ADD:
      op_add();
      break;

   case OP_SUB:
      op_sub();
      break;

   case OP_BOOLAND:
      op_booland();
      break;

   case OP_BOOLOR:
      op_boolor();
      break;

   case OP_NUMEQUAL:
      op_numequal();
      break;

   case OP_NUMEQUALVERIFY:
   {
      op_numequal();
      op_verify();
      break;
   }

   case OP_NUMNOTEQUAL:
      op_numnotequal();
      break;

   case OP_LESSTHAN:
      op_lessthan();
      break;

   case OP_GREATERTHAN:
      op_greaterthan();
      break;

   case OP_LESSTHANOREQUAL:
      op_lessthanorequal();
      break;

   case OP_GREATERTHANOREQUAL:
      op_greaterthanorequal();
      break;

   case OP_MIN:
      op_min();
      break;

   case OP_MAX:
      op_max();
      break;

   case OP_WITHIN:
      op_within();
      break;

   case OP_RIPEMD160:
      op_ripemd160();
      break;

   case OP_SHA256:
   {
      //save the script if this output is a possible p2sh
      if (flags_ & SCRIPT_VERIFY_P2SH_SHA256)
         if (opcount_ == 1 && onlyPushDataInInput_)
            p2shScript_ = stack_back();

      op_sha256();
      break;
   }

   case OP_HASH160:
   {
      //save the script if this output is a possible p2sh
      if (flags_ & SCRIPT_VERIFY_P2SH)
         if (opcount_ == 1 && onlyPushDataInInput_)
            p2shScript_ = stack_back();

      op_hash160();
      break;
   }

   case OP_HASH256:
      op_hash256();
      break;

   case OP_CODESEPARATOR:
   {
      opcount_ = 0;
      if (outputScriptRef_.getSize() != 0)
         txStubPtr_->setLastOpCodeSeparator(inputIndex_, oc.offset_);
      break;
   }

   case OP_CHECKSIG:
      op_checksig();
      break;

   case OP_CHECKSIGVERIFY:
   {
      op_checksig();
      op_verify();
      break;
   }

   case OP_CHECKMULTISIG:
      op_checkmultisig();
      break;

   case OP_CHECKMULTISIGVERIFY:
   {
      op_checkmultisig();
      op_verify();
   }

   case OP_NOP1:
      break;

   case OP_NOP2:
   {
      if (!(flags_ & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY))
         break; // not enabled; treat as a NOP

      //CLTV mechanics
      throw ScriptException("OP_CLTV not supported");
   }

   case OP_NOP3:
   {
      if (!(flags_ & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY))
         break; // not enabled; treat as a NOP

      //CSV mechanics
      throw ScriptException("OP_CSV not supported");
   }

   case OP_NOP4:
      break;

   case OP_NOP5:
      break;

   case OP_NOP6:
      break;

   case OP_NOP7:
      break;

   case OP_NOP8:
      break;

   case OP_NOP9:
      break;

   case OP_NOP10:
      break;

   default:
   {
      stringstream ss;
      ss << "unknown opcode: " << (unsigned)oc.opcode_;
      throw runtime_error(ss.str());
   }
   }
}