/** * TxSignerContext constructor. * @param EcAdapterInterface $ecAdapter * @param ScriptInterface $outputScript * @param ScriptInterface|null $redeemScript */ public function __construct(EcAdapterInterface $ecAdapter, ScriptInterface $outputScript, ScriptInterface $redeemScript = null) { $handler = ScriptFactory::info($outputScript, $redeemScript); $handler->getKeys(); $this->scriptType = $this->prevOutType = $handler->classification(); if ($handler instanceof ScriptHash) { $this->scriptType = $handler->getInfo()->classification(); } // Gather public keys from redeemScript / outputScript $this->ecAdapter = $ecAdapter; $this->redeemScript = $redeemScript; $this->prevOutScript = $outputScript; $this->scriptInfo = $handler; // According to scriptType, extract public keys $this->publicKeys = $this->scriptInfo->getKeys(); }
/** * @param TransactionInterface $tx * @param $inputToExtract * @return $this */ public function extractSigs(TransactionInterface $tx, $inputToExtract) { $inputs = $tx->getInputs(); $parsed = $inputs[$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(); $keys = $this->scriptInfo->getKeys(); foreach ($keys as $idx => $key) { $this->setSignature($idx, null); } if ($size > 2 && $size <= $this->scriptInfo->getKeyCount() + 2) { $sigs = []; foreach ($keys as $key) { $sigs[$key->getPubKeyHash()->getHex()] = []; } // Extract Signatures (as buffers), then compile arrays of [pubkeyHash => signature] $sigHash = new Hasher($tx); 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); $linked = $this->ecAdapter->associateSigs([$txSig->getSignature()], $sigHash->calculate($redeemScript, $inputToExtract, $txSig->getHashType()), $keys); if (count($linked)) { $key = array_keys($linked)[0]; $sigs[$key] = array_merge($sigs[$key], [$txSig]); } } } // We have all the signatures from the tx now. array_shift the sigs for a public key, as it's encountered. foreach ($keys as $idx => $key) { $hash = $key->getPubKeyHash()->getHex(); $this->setSignature($idx, isset($sigs[$hash]) ? array_shift($sigs[$hash]) : null); } } break; } return $this; }
/** * @return \BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface[] */ public function getKeys() { return $this->handler->getKeys(); }