/** * @param \BitWasp\Bitcoin\Signature\TransactionSignature $txSig * @return \BitWasp\Buffertools\Buffer */ public function serialize(\BitWasp\Bitcoin\Signature\TransactionSignature $txSig) { $sig = $this->sigSerializer->serialize($txSig->getSignature()); $parser = new Parser($sig->getHex()); $parser->writeInt(1, $txSig->getHashType()); $buffer = $parser->getBuffer(); return $buffer; }
/** * Create a buffer containing data to be hashed hashed to yield the child offset * * @param integer|string $sequence * @return Buffer * @throws \Exception */ public function getHmacSeed($sequence) { $parser = new Parser(); $hardened = $this->ecAdapter->getMath()->getBinaryMath()->isNegative($sequence, 32); if ($hardened) { if ($this->isPrivate() === false) { throw new \Exception("Can't derive a hardened key without the private key"); } $parser->writeBytes(1, '00')->writeBytes(32, $this->getPrivateKey()->getBuffer()); } else { $parser->writeBytes(33, $this->getPublicKey()->getBuffer()); } return $parser->writeInt(4, $sequence)->getBuffer(); }
/** * Calculate the hash of the current transaction, when you are looking to * spend $txOut, and are signing $inputToSign. The SigHashType defaults to * SIGHASH_ALL, though SIGHASH_SINGLE, SIGHASH_NONE, SIGHASH_ANYONECANPAY * can be used. * * @param ScriptInterface $txOutScript * @param $inputToSign * @param int $sighashType * @return Buffer * @throws \Exception */ public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SignatureHashInterface::SIGHASH_ALL) { $copy = $this->transaction->makeCopy(); $inputs = $copy->getInputs(); $outputs = $copy->getOutputs(); if ($inputToSign > count($inputs)) { throw new \Exception('Input does not exist'); } // Default SIGHASH_ALL procedure: null all input scripts $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { $inputs->getInput($i)->setScript(new Script()); } $inputs->getInput($inputToSign)->setScript($txOutScript); $math = Bitcoin::getMath(); if ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_NONE) { // Set outputs to empty vector, and set sequence number of inputs to 0. $copy->setOutputs(new TransactionOutputCollection()); // Let the others update at will. Set sequence of inputs we're not signing to 0. $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { if ($math->cmp($i, $inputToSign) !== 0) { $inputs->getInput($i)->setSequence(0); } } } elseif ($math->bitwiseAnd($sighashType, 31) == SignatureHashInterface::SIGHASH_SINGLE) { // Resize output array to $inputToSign + 1, set remaining scripts to null, // and set sequence's to zero. $nOutput = $inputToSign; if ($math->cmp($nOutput, count($outputs)) >= 0) { return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000'); } // Resize.. $outputs = $outputs->slice(0, $nOutput + 1)->getOutputs(); // Set to null for ($i = 0; $i < $nOutput; $i++) { $outputs[$i] = new TransactionOutput($math->getBinaryMath()->getTwosComplement(-1, 64), new Script()); } $copy->setOutputs(new TransactionOutputCollection($outputs)); // Let the others update at will. Set sequence of inputs we're not signing to 0. $inputCount = count($inputs); for ($i = 0; $i < $inputCount; $i++) { if ($math->cmp($i, $inputToSign) != 0) { $inputs->getInput($i)->setSequence(0); } } } // This can happen regardless of whether it's ALL, NONE, or SINGLE if ($math->bitwiseAnd($sighashType, SignatureHashInterface::SIGHASH_ANYONECANPAY)) { $input = $inputs->getInput($inputToSign); $copy->setInputs(new TransactionInputCollection([$input])); } // Serialize the TxCopy and append the 4 byte hashtype (little endian); $txParser = new Parser($copy->getBuffer()); $txParser->writeInt(4, $sighashType, true); return Hash::sha256d($txParser->getBuffer()); }