SecureBinaryData CryptoECDSA::CompressPoint(SecureBinaryData const & pubKey65) { CryptoPP::ECP ecp = Get_secp256k1_ECP(); BTC_ECPOINT ptPub; ecp.DecodePoint(ptPub, (byte*)pubKey65.getPtr(), 65); SecureBinaryData ptCompressed(33); ecp.EncodePoint((byte*)ptCompressed.getPtr(), ptPub, true); return ptCompressed; }
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)); }
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(); }