예제 #1
0
 /**
  * @param int $inputToSign
  * @param PrivateKeyInterface $privateKey
  * @param ScriptInterface $outputScript
  * @param ScriptInterface|null $redeemScript
  * @param int $sigHashType
  * @return $this
  */
 public function sign($inputToSign, PrivateKeyInterface $privateKey, ScriptInterface $outputScript, ScriptInterface $redeemScript = null, $sigHashType = SigHash::ALL)
 {
     // If the input state hasn't been set up, do so now.
     try {
         $inputState = $this->inputState($inputToSign);
     } catch (BuilderNoInputState $e) {
         $inputState = $this->createInputState($inputToSign, $outputScript, $redeemScript);
     }
     // If it's PayToPubkey / PayToPubkeyHash, TransactionBuilderInputState needs to know the public key.
     if ($inputState->getScriptType() === 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()) {
             $signature = $this->makeSignature($privateKey, $this->signatureHash->calculate($redeemScript ?: $outputScript, $inputToSign, $sigHashType), $sigHashType);
             //if ($inputState->getPrevOutType() === OutputClassifier::WITNESS) {
             //    $inputState->setWitness($idx, $signature);
             //} else {
             $inputState->setSignature($idx, $signature);
             //}
         }
     }
     return $this;
 }
예제 #2
0
 /**
  * @param ScriptInterface $script
  * @param BufferInterface $sigBuf
  * @param BufferInterface $keyBuf
  * @param int $sigVersion
  * @param int $flags
  * @return bool
  * @throws ScriptRuntimeException
  */
 public function checkSig(ScriptInterface $script, BufferInterface $sigBuf, BufferInterface $keyBuf, $sigVersion, $flags)
 {
     $this->checkSignatureEncoding($sigBuf, $flags)->checkPublicKeyEncoding($keyBuf, $flags);
     try {
         $txSignature = TransactionSignatureFactory::fromHex($sigBuf->getHex());
         $publicKey = PublicKeyFactory::fromHex($keyBuf->getHex());
         if ($sigVersion === 1) {
             $hasher = new V1Hasher($this->transaction, $this->amount);
         } else {
             $hasher = new Hasher($this->transaction);
         }
         $hash = $hasher->calculate($script, $this->nInput, $txSignature->getHashType());
         return $this->adapter->verify($hash, $publicKey, $txSignature->getSignature());
     } catch (\Exception $e) {
         return false;
     }
 }
예제 #3
0
 /**
  * @param PrivateKeyInterface $key
  * @param ScriptInterface $scriptCode
  * @param int $sigVersion
  * @return TransactionSignature
  */
 public function calculateSignature(PrivateKeyInterface $key, ScriptInterface $scriptCode, $sigVersion)
 {
     if ($sigVersion == 1) {
         $hasher = new V1Hasher($this->tx, $this->txOut->getValue());
     } else {
         $hasher = new Hasher($this->tx);
     }
     $hash = $hasher->calculate($scriptCode, $this->nInput, $this->sigHashType);
     return new TransactionSignature($this->ecAdapter, $this->ecAdapter->sign($hash, $key, new Rfc6979($this->ecAdapter, $key, $hash, 'sha256')), $this->sigHashType);
 }
예제 #4
0
 /**
  * @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;
 }