/** * @param EcAdapterInterface $ecAdapter * @param KeyInterface $masterKey */ public function __construct(EcAdapterInterface $ecAdapter, KeyInterface $masterKey) { if ($masterKey->isCompressed()) { throw new \RuntimeException('Electrum keys are not compressed'); } $this->ecAdapter = $ecAdapter; if ($masterKey instanceof PrivateKeyInterface) { $this->masterKey = $masterKey; $masterKey = $this->masterKey->getPublicKey(); } $this->publicKey = $masterKey; }
/** * The function only returns true when $scriptPubKey could be classified * * @param PrivateKeyInterface $key * @param ScriptInterface $scriptPubKey * @param string $outputType * @param BufferInterface[] $results * @param int $sigVersion * @return bool */ private function doSignature(PrivateKeyInterface $key, ScriptInterface $scriptPubKey, &$outputType, array &$results, $sigVersion = 0) { $return = []; $outputType = (new OutputClassifier($scriptPubKey))->classify($return); if ($outputType === OutputClassifier::UNKNOWN) { throw new \RuntimeException('Cannot sign unknown script type'); } if ($outputType === OutputClassifier::PAYTOPUBKEY) { $publicKeyBuffer = $return; $results[] = $publicKeyBuffer; $this->requiredSigs = 1; $publicKey = PublicKeyFactory::fromHex($publicKeyBuffer); if ($publicKey->getBinary() === $key->getPublicKey()->getBinary()) { $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigVersion); } return true; } if ($outputType === OutputClassifier::PAYTOPUBKEYHASH) { /** @var BufferInterface $pubKeyHash */ $pubKeyHash = $return; $results[] = $pubKeyHash; $this->requiredSigs = 1; if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) { $this->signatures[0] = $this->calculateSignature($key, $scriptPubKey, $sigVersion); $this->publicKeys[0] = $key->getPublicKey(); } return true; } if ($outputType === OutputClassifier::MULTISIG) { $info = new Multisig($scriptPubKey); foreach ($info->getKeys() as $publicKey) { $results[] = $publicKey->getBuffer(); } $this->publicKeys = $info->getKeys(); $this->requiredSigs = $info->getKeyCount(); foreach ($this->publicKeys as $keyIdx => $publicKey) { if ($publicKey->getBinary() == $key->getPublicKey()->getBinary()) { $this->signatures[$keyIdx] = $this->calculateSignature($key, $scriptPubKey, $sigVersion); } } return true; } if ($outputType === OutputClassifier::PAYTOSCRIPTHASH) { /** @var BufferInterface $scriptHash */ $scriptHash = $return; $results[] = $scriptHash; return true; } if ($outputType === OutputClassifier::WITNESS_V0_KEYHASH) { /** @var BufferInterface $pubKeyHash */ $pubKeyHash = $return; $results[] = $pubKeyHash; $this->requiredSigs = 1; if ($pubKeyHash->getBinary() === $key->getPublicKey()->getPubKeyHash()->getBinary()) { $script = ScriptFactory::sequence([Opcodes::OP_DUP, Opcodes::OP_HASH160, $pubKeyHash, Opcodes::OP_EQUALVERIFY, Opcodes::OP_CHECKSIG]); $this->signatures[0] = $this->calculateSignature($key, $script, 1); $this->publicKeys[0] = $key->getPublicKey(); } return true; } if ($outputType === OutputClassifier::WITNESS_V0_SCRIPTHASH) { /** @var BufferInterface $scriptHash */ $scriptHash = $return; $results[] = $scriptHash; return true; } return false; }
/** * @param integer $inputToSign * @param PrivateKeyInterface $privateKey * @param ScriptInterface $outputScript * @param ScriptInterface $redeemScript * @param int $sigHashType * @return $this */ public function sign($inputToSign, PrivateKeyInterface $privateKey, ScriptInterface $outputScript, ScriptInterface $redeemScript = null, $sigHashType = SignatureHashInterface::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->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()) { $signature = $this->makeSignature($privateKey, $this->signatureHash->calculate($redeemScript ?: $outputScript, $inputToSign, $sigHashType), $sigHashType); $inputState->setSignature($idx, $signature); } } return $this; }