bool CryptoECDSA::VerifyPublicKeyValid(SecureBinaryData const & pubKey65)
{
   if(CRYPTO_DEBUG)
   {
      cout << "BinPub: " << pubKey65.toHexStr() << endl;
   }

   // Basically just copying the ParsePublicKey method, but without
   // the assert that would throw an error from C++
   SecureBinaryData pubXbin(pubKey65.getSliceRef( 1,32));
   SecureBinaryData pubYbin(pubKey65.getSliceRef(33,32));
   CryptoPP::Integer pubX;
   CryptoPP::Integer pubY;
   pubX.Decode(pubXbin.getPtr(), pubXbin.getSize(), UNSIGNED);
   pubY.Decode(pubYbin.getPtr(), pubYbin.getSize(), UNSIGNED);
   BTC_ECPOINT publicPoint(pubX, pubY);

   // Initialize the public key with the ECP point just created
   BTC_PUBKEY cppPubKey;
   cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), publicPoint);

   // Validate the public key -- not sure why this needs a PRNG
   static BTC_PRNG prng;
   return cppPubKey.Validate(prng, 3);
}
Exemple #2
0
void StackInterpreter::op_checksig()
{
   //pop sig and pubkey from the stack
   if (stack_.size() < 2)
      throw ScriptException("insufficient stack size for checksig operation");

   auto&& pubkey = pop_back();
   auto&& sigScript = pop_back();
   if (sigScript.getSize() < 65)
   {
      stack_.push_back(move(intToRawBinary(false)));
      return;
   }

   txInEvalState_.n_ = 1;
   txInEvalState_.m_ = 1;

   //extract sig and sighash type
   BinaryRefReader brrSig(sigScript);
   auto sigsize = sigScript.getSize() - 1;
   auto sig = brrSig.get_BinaryDataRef(sigsize);
   auto hashType = getSigHashSingleByte(brrSig.get_uint8_t());

   //get data for sighash
   if (sigHashDataObject_ == nullptr)
      sigHashDataObject_ = make_shared<SigHashDataLegacy>();
   auto&& sighashdata =
      sigHashDataObject_->getDataForSigHash(hashType, *txStubPtr_,
      outputScriptRef_, inputIndex_);

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

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

   //check point validity
   /*BTC_PRNG prng;
   if (!cppPubKey.Validate(prng, 3))
   throw ScriptException("invalid pubkey");*/

   //check signature
   auto&& rs = BtcUtils::extractRSFromDERSig(sig);

   bool result = CryptoECDSA().VerifyData(sighashdata, rs, cppPubKey);
   stack_.push_back(move(intToRawBinary(result)));

   if (result)
      txInEvalState_.pubKeyState_.insert(make_pair(pubkey, true));
}
bool CryptoECDSA::ECVerifyPoint(BinaryData const & x,
                                BinaryData const & y)
{
   BTC_PUBKEY cppPubKey;

   CryptoPP::Integer pubX;
   CryptoPP::Integer pubY;
   pubX.Decode(x.getPtr(), x.getSize(), UNSIGNED);
   pubY.Decode(y.getPtr(), y.getSize(), UNSIGNED);
   BTC_ECPOINT publicPoint(pubX, pubY);

   // Initialize the public key with the ECP point just created
   cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), publicPoint);

   // Validate the public key -- not sure why this needs a PRNG
   BTC_PRNG prng;
   return cppPubKey.Validate(prng, 3);
}
BTC_PUBKEY CryptoECDSA::ParsePublicKey(SecureBinaryData const & pubKeyX32B,
                                       SecureBinaryData const & pubKeyY32B)
{
   BTC_PUBKEY cppPubKey;

   CryptoPP::Integer pubX;
   CryptoPP::Integer pubY;
   pubX.Decode(pubKeyX32B.getPtr(), pubKeyX32B.getSize(), UNSIGNED);
   pubY.Decode(pubKeyY32B.getPtr(), pubKeyY32B.getSize(), UNSIGNED);
   BTC_ECPOINT publicPoint(pubX, pubY);

   // Initialize the public key with the ECP point just created
   cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), publicPoint);

   // Validate the public key -- not sure why this needs a PRNG
   BTC_PRNG prng;
   assert(cppPubKey.Validate(prng, 3));

   return cppPubKey;
}
bool CryptoECDSA::VerifyPublicKeyValid(SecureBinaryData const & pubKey)
{
   if(CRYPTO_DEBUG)
   {
      cout << "BinPub: " << pubKey.toHexStr() << endl;
   }

   SecureBinaryData keyToCheck(65);

   // To support compressed keys, we'll just check to see if a key is compressed
   // and then decompress it.
   if(pubKey.getSize() == 33) {
      keyToCheck = UncompressPoint(pubKey);
   }
   else {
      keyToCheck = pubKey;
   }

   // Basically just copying the ParsePublicKey method, but without
   // the assert that would throw an error from C++
   SecureBinaryData pubXbin(keyToCheck.getSliceRef( 1,32));
   SecureBinaryData pubYbin(keyToCheck.getSliceRef(33,32));
   CryptoPP::Integer pubX;
   CryptoPP::Integer pubY;
   pubX.Decode(pubXbin.getPtr(), pubXbin.getSize(), UNSIGNED);
   pubY.Decode(pubYbin.getPtr(), pubYbin.getSize(), UNSIGNED);
   BTC_ECPOINT publicPoint(pubX, pubY);

   // Initialize the public key with the ECP point just created
   BTC_PUBKEY cppPubKey;
   cppPubKey.Initialize(CryptoPP::ASN1::secp256k1(), publicPoint);

   // Validate the public key -- not sure why this needs a PRNG
   BTC_PRNG prng;
   return cppPubKey.Validate(prng, 3);
}
Exemple #6
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();
}