/**
  * @param callable|null $hashFunction
  * @return string
  * @throws MerkleTreeEmpty
  */
 public function calculateHash(callable $hashFunction = null)
 {
     $hashFxn = $hashFunction ?: function ($value) {
         return hash('sha256', hash('sha256', $value, true), true);
     };
     $txCount = count($this->transactions);
     if ($txCount == 0) {
         // TODO: Probably necessary. Should always have a coinbase at least.
         throw new MerkleTreeEmpty('Cannot compute Merkle root of an empty tree');
     }
     if ($txCount == 1) {
         $buffer = $hashFxn($this->transactions->getTransaction(0)->getBinary());
     } else {
         // Create a fixed size Merkle Tree
         $tree = new FixedSizeTree($txCount + $txCount % 2, $hashFxn);
         // Compute hash of each transaction
         $last = '';
         foreach ($this->transactions->getTransactions() as $i => $transaction) {
             $last = $transaction->getBinary();
             $tree->set($i, $last);
         }
         // Check if we need to repeat the last hash (odd number of transactions)
         if (!$this->math->isEven($txCount)) {
             $tree->set($txCount, $last);
         }
         $buffer = $tree->hash();
     }
     $hash = new Buffer(Buffertools::flipBytes($buffer));
     $hash = $hash->getHex();
     $this->setLastHash($hash);
     return $this->getLastHash();
 }
 public function testHashIsSerializedInReverseOrder()
 {
     $buffer = Buffer::hex('0001020300010203000102030001020300010203000102030001020300010203');
     $inv = Inventory::block($buffer);
     $results = unpack("Vtype/H64hash", $inv->getBinary());
     $parsedBuffer = Buffer::hex($results['hash']);
     $this->assertEquals($buffer->getHex(), Buffertools::flipBytes($parsedBuffer)->getHex());
 }
 /**
  * @dataProvider getVectors
  */
 public function testByteStringLe($math, $size, $string)
 {
     $buffer = Buffer::hex($string, $size);
     $t = new ByteString($math, $size, ByteOrder::LE);
     $out = $t->write($buffer);
     $eFlipped = Buffertools::flipBytes(pack("H*", $string));
     $this->assertEquals($eFlipped, $out);
     $parser = new Parser(new Buffer($out));
     $this->assertEquals($string, $t->read($parser)->getHex());
 }
 /**
  * @param $bitSize
  * @return array
  */
 private function generateSizeBasedTests($bitSize, $byteOrder)
 {
     $math = EccFactory::getAdapter();
     $halfPos = $math->baseConvert(str_pad('7', $bitSize / 4, 'f', STR_PAD_RIGHT), 16, 10);
     $maxPos = $math->baseConvert(str_pad('', $bitSize / 4, 'f', STR_PAD_RIGHT), 16, 10);
     $test = function ($integer) use($bitSize, $math, $byteOrder) {
         $hex = str_pad($math->baseConvert($integer, 10, 16), $bitSize / 4, '0', STR_PAD_LEFT);
         if ($byteOrder == ByteOrder::LE) {
             $hex = Buffertools::flipBytes(Buffer::hex($hex))->getHex();
         }
         return [$integer, $hex, null];
     };
     return [$test(0), $test(1), $test($halfPos), $test($maxPos)];
 }
 public function testFlipBytes()
 {
     $buffer = Buffer::hex('41');
     $string = $buffer->getBinary();
     $flip = Buffertools::flipBytes($string);
     $this->assertSame($flip, $string);
     $buffer = Buffer::hex('4141');
     $string = $buffer->getBinary();
     $flip = Buffertools::flipBytes($string);
     $this->assertSame($flip, $string);
     $buffer = Buffer::hex('4142');
     $string = $buffer->getBinary();
     $flip = Buffertools::flipBytes($string);
     $this->assertSame($flip, chr(0x42) . chr(0x41));
     $buffer = Buffer::hex('0102030405060708');
     $string = $buffer->getBinary();
     $flip = Buffertools::flipBytes($string);
     $this->assertSame($flip, chr(0x8) . chr(0x7) . chr(0x6) . chr(0x5) . chr(0x4) . chr(0x3) . chr(0x2) . chr(0x1));
 }
Exemple #6
0
 /**
  * @return Buffer
  */
 public function flip()
 {
     return Buffertools::flipBytes($this);
 }
Exemple #7
0
 /**
  * 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 int $inputToSign
  * @param int $sighashType
  * @return BufferInterface
  * @throws \Exception
  */
 public function calculate(ScriptInterface $txOutScript, $inputToSign, $sighashType = SigHash::ALL)
 {
     $math = Bitcoin::getMath();
     $tx = new TxMutator($this->transaction);
     $inputs = $tx->inputsMutator();
     $outputs = $tx->outputsMutator();
     // Default SIGHASH_ALL procedure: null all input scripts
     foreach ($inputs as $input) {
         $input->script(new Script());
     }
     $inputs[$inputToSign]->script($txOutScript);
     if ($math->cmp($math->bitwiseAnd($sighashType, 31), SigHash::NONE) === 0) {
         // Set outputs to empty vector, and set sequence number of inputs to 0.
         $outputs->null();
         // Let the others update at will. Set sequence of inputs we're not signing to 0.
         foreach ($inputs as $i => $input) {
             if ($i !== $inputToSign) {
                 $input->sequence(0);
             }
         }
     } elseif ($math->cmp($math->bitwiseAnd($sighashType, 31), SigHash::SINGLE) === 0) {
         // Resize output array to $inputToSign + 1, set remaining scripts to null,
         // and set sequence's to zero.
         $nOutput = $inputToSign;
         if ($nOutput >= $this->nOutputs) {
             return Buffer::hex('0100000000000000000000000000000000000000000000000000000000000000', 32, $math);
         }
         // Resize, set to null
         $outputs->slice(0, $nOutput + 1);
         for ($i = 0; $i < $nOutput; $i++) {
             $outputs[$i]->null();
         }
         // Let the others update at will. Set sequence of inputs we're not signing to 0
         foreach ($inputs as $i => $input) {
             if ($i !== $inputToSign) {
                 $input->sequence(0);
             }
         }
     }
     // This can happen regardless of whether it's ALL, NONE, or SINGLE
     if ($math->cmp($math->bitwiseAnd($sighashType, SigHash::ANYONECANPAY), 0) > 0) {
         $input = $inputs[$inputToSign]->done();
         $inputs->null()->add($input);
     }
     return Hash::sha256d(Buffertools::concat($tx->done()->getBuffer(), Buffertools::flipBytes(Buffer::int($sighashType, 4, $math))));
 }
Exemple #8
0
 /**
  * Write $data as $bytes bytes. Can be flipped if needed.
  *
  * @param  integer $bytes
  * @param  $data
  * @param  bool $flipBytes
  * @return $this
  */
 public function writeBytes($bytes, $data, $flipBytes = false)
 {
     // Treat $data to ensure it's a buffer, with the correct size
     if ($data instanceof SerializableInterface) {
         $data = $data->getBuffer();
     }
     if ($data instanceof Buffer) {
         // only create a new buffer if the size does not match
         if ($data->getSize() != $bytes) {
             $data = new Buffer($data->getBinary(), $bytes, $this->math);
         }
     } else {
         // Convert to a buffer
         $data = Buffer::hex($data, $bytes, $this->math);
     }
     // At this point $data will be a Buffer
     $binary = $data->getBinary();
     if ($flipBytes) {
         $binary = Buffertools::flipBytes($binary);
     }
     $this->string .= $binary;
     return $this;
 }
 /**
  * @return string
  */
 public function getTransactionId()
 {
     $hash = bin2hex(Buffertools::flipBytes(Hash::sha256d($this->getBuffer())));
     return $hash;
 }