/** * @param ScriptInterface $script * @param Buffer $sigBuf * @param Buffer $keyBuf * @return bool * @throws ScriptRuntimeException * @throws \Exception */ private function checkSig(ScriptInterface $script, Buffer $sigBuf, Buffer $keyBuf) { $this->checkSignatureEncoding($sigBuf)->checkPublicKeyEncoding($keyBuf); try { $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex()); $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex()); return $this->ecAdapter->verify($this->transaction->getSignatureHash()->calculate($script, $this->inputToSign, $txSignature->getHashType()), $publicKey, $txSignature->getSignature()); } catch (\Exception $e) { return false; } }
/** * @param PrivateKeyInterface $privateKey * @param ScriptInterface $outputScript * @param $inputToSign * @param int $sigHashType * @param RedeemScript $redeemScript * @return $this * @throws \Exception */ public function signInputWithKey(PrivateKeyInterface $privateKey, ScriptInterface $outputScript, $inputToSign, RedeemScript $redeemScript = null, $sigHashType = SignatureHashInterface::SIGHASH_ALL) { // If the input state hasn't been set up, do so now. try { $inputState = $this->getInputState($inputToSign); } catch (BuilderNoInputState $e) { $inputState = $this->createInputState($inputToSign, $outputScript, $redeemScript); } // If it's PayToPubkey / PayToPubkeyHash, TransactionBuilderInputState needs to know the public key. if (in_array($inputState->getPrevOutType(), [OutputClassifier::PAYTOPUBKEYHASH])) { $inputState->setPublicKeys([$privateKey->getPublicKey()]); } // loop over the publicKeys to find the key to sign with foreach ($inputState->getPublicKeys() as $idx => $publicKey) { if ($privateKey->getPublicKey()->getBinary() === $publicKey->getBinary()) { $inputState->setSignature($idx, $this->sign($privateKey, $this->transaction->getSignatureHash()->calculate($redeemScript ?: $outputScript, $inputToSign, $sigHashType), $sigHashType)); } } return $this; }
/** * @param TransactionInterface $tx * @param int $inputToExtract * @return $this */ public function extractSigs(TransactionInterface $tx, $inputToExtract) { $parsed = $tx->getInput($inputToExtract)->getScript()->getScriptParser()->decode(); $size = count($parsed); switch ($this->getScriptType()) { case OutputClassifier::PAYTOPUBKEYHASH: // Supply signature and public key in scriptSig if ($size === 2) { $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getData(), $this->ecAdapter)]; $this->publicKeys = [PublicKeyFactory::fromHex($parsed[1]->getData(), $this->ecAdapter)]; } break; case OutputClassifier::PAYTOPUBKEY: // Only has a signature in the scriptSig if ($size === 1) { $this->signatures = [TransactionSignatureFactory::fromHex($parsed[0]->getData(), $this->ecAdapter)]; } break; case OutputClassifier::MULTISIG: $redeemScript = $this->getRedeemScript(); $this->signatures = array_fill(0, count($this->publicKeys), null); if ($size > 2 && $size <= $this->scriptInfo->getKeyCount() + 2) { $sigHash = $tx->getSignatureHash(); $sigSort = new SignatureSort($this->ecAdapter); $sigs = new \SplObjectStorage(); foreach (array_slice($parsed, 1, -1) as $item) { /** @var \BitWasp\Bitcoin\Script\Parser\Operation $item */ if ($item->isPush()) { $txSig = TransactionSignatureFactory::fromHex($item->getData(), $this->ecAdapter); $hash = $sigHash->calculate($redeemScript, $inputToExtract, $txSig->getHashType()); $linked = $sigSort->link([$txSig->getSignature()], $this->publicKeys, $hash); foreach ($this->publicKeys as $key) { if ($linked->contains($key)) { $sigs[$key] = $txSig; } } } } // We have all the signatures from the input now. array_shift the sigs for a public key, as it's encountered. foreach ($this->publicKeys as $idx => $key) { $this->signatures[$idx] = isset($sigs[$key]) ? $sigs[$key] : null; } } break; } return $this; }
/** * @param EcAdapterInterface $ecAdapter * @param TransactionInterface $tx */ public function __construct(EcAdapterInterface $ecAdapter, TransactionInterface $tx) { $this->transaction = $tx; $this->signatureHash = $tx->getSignatureHash(); $this->ecAdapter = $ecAdapter; }