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); }
bool CryptoECDSA::CheckPubPrivKeyMatch(BTC_PRIVKEY const & cppPrivKey, BTC_PUBKEY const & cppPubKey) { BTC_PUBKEY computedPubKey; cppPrivKey.MakePublicKey(computedPubKey); BTC_ECPOINT ppA = cppPubKey.GetPublicElement(); BTC_ECPOINT ppB = computedPubKey.GetPublicElement(); return (ppA.x==ppB.x && ppA.y==ppB.y); }
BTC_PUBKEY CryptoECDSA::ComputePublicKey(BTC_PRIVKEY const & cppPrivKey) { BTC_PUBKEY cppPubKey; cppPrivKey.MakePublicKey(cppPubKey); // Validate the public key -- not sure why this needs a prng... BTC_PRNG prng; assert(cppPubKey.Validate(prng, 3)); return cppPubKey; }
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)); }
///////////////////////////////////////////////////////////////////////////// // Deterministically generate new public key using a chaincode SecureBinaryData CryptoECDSA::ComputeChainedPublicKey( SecureBinaryData const & binPubKey, SecureBinaryData const & chainCode, SecureBinaryData* multiplierOut) { if(CRYPTO_DEBUG) { cout << "ComputeChainedPUBLICKey:" << endl; cout << " BinPub: " << binPubKey.toHexStr() << endl; cout << " BinChn: " << chainCode.toHexStr() << endl; } static SecureBinaryData SECP256K1_ORDER_BE = SecureBinaryData::CreateFromHex( "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); // Added extra entropy to chaincode by xor'ing with hash256 of pubkey BinaryData chainMod = binPubKey.getHash256(); BinaryData chainOrig = chainCode.getRawCopy(); BinaryData chainXor(32); for(uint8_t i=0; i<8; i++) { uint8_t offset = 4*i; *(uint32_t*)(chainXor.getPtr()+offset) = *(uint32_t*)( chainMod.getPtr()+offset) ^ *(uint32_t*)(chainOrig.getPtr()+offset); } // Parse the chaincode as a big-endian integer CryptoPP::Integer mult; mult.Decode(chainXor.getPtr(), chainXor.getSize(), UNSIGNED); // "new" init as "old", to make sure it's initialized on the correct curve BTC_PUBKEY oldPubKey = ParsePublicKey(binPubKey); BTC_PUBKEY newPubKey = ParsePublicKey(binPubKey); // Let Crypto++ do the EC math for us, serialize the new public key newPubKey.SetPublicElement( oldPubKey.ExponentiatePublicElement(mult) ); if(multiplierOut != NULL) (*multiplierOut) = SecureBinaryData(chainXor); //LOGINFO << "Computed new chained public key using:"; //LOGINFO << " Public key: " << binPubKey.toHexStr().c_str(); //LOGINFO << " PubKeyHash: " << chainMod.toHexStr().c_str(); //LOGINFO << " Chaincode: " << chainOrig.toHexStr().c_str(); //LOGINFO << " Multiplier: " << chainXor.toHexStr().c_str(); return CryptoECDSA::SerializePublicKey(newPubKey); }
bool CryptoECDSA::VerifyData(SecureBinaryData const & binMessage, SecureBinaryData const & binSignature, BTC_PUBKEY const & cppPubKey) { CryptoPP::SHA256 sha256; BTC_PRNG prng; assert(cppPubKey.Validate(prng, 3)); // We execute the first SHA256 op, here. Next one is done by Verifier SecureBinaryData hashVal(32); sha256.CalculateDigest(hashVal.getPtr(), binMessage.getPtr(), binMessage.getSize()); // Verifying message BTC_VERIFIER verifier(cppPubKey); return verifier.VerifyMessage((const byte*)hashVal.getPtr(), hashVal.getSize(), (const byte*)binSignature.getPtr(), binSignature.getSize()); }
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; }
SecureBinaryData CryptoECDSA::SerializePublicKey(BTC_PUBKEY const & pubKey) { BTC_ECPOINT publicPoint = pubKey.GetPublicElement(); CryptoPP::Integer pubX = publicPoint.x; CryptoPP::Integer pubY = publicPoint.y; SecureBinaryData pubData(65); pubData.fill(0x04); // we fill just to set the first byte... pubX.Encode(pubData.getPtr()+1, 32, UNSIGNED); pubY.Encode(pubData.getPtr()+33, 32, UNSIGNED); return pubData; }
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); }
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(); }