示例#1
0
 /**
  * @param                   $m
  * @param KeyInterface[]    $keys
  * @param bool              $sort
  * @return RedeemScript
  */
 public static function multisig($m, array $keys = array(), $sort = true)
 {
     if ($sort) {
         $keys = \BitWasp\Buffertools\Buffertools::sort($keys);
     }
     return new RedeemScript($m, $keys);
 }
示例#2
0
 /**
  * @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();
 }
 /**
  * @param int $m
  * @param PublicKeyInterface[] $keys
  * @param bool|true $sort
  * @return ScriptCreator|Script
  */
 public function multisig($m, array $keys = [], $sort = true)
 {
     $n = count($keys);
     if ($m > $n) {
         throw new \LogicException('Required number of sigs exceeds number of public keys');
     }
     if ($n > 16) {
         throw new \LogicException('Number of public keys is greater than 16');
     }
     if ($sort) {
         $keys = Buffertools::sort($keys);
     }
     $opM = \BitWasp\Bitcoin\Script\encodeOpN($m);
     $opN = \BitWasp\Bitcoin\Script\encodeOpN($n);
     $script = ScriptFactory::create();
     foreach ($keys as $key) {
         if (!$key instanceof PublicKeyInterface) {
             throw new \LogicException('Values in $keys[] must be a PublicKey');
         }
         $script->push($key->getBuffer());
     }
     $keyBuf = $script->getScript()->getBuffer();
     $script = new Script(new Buffer(chr($opM) . $keyBuf->getBinary() . chr($opN) . chr(Opcodes::OP_CHECKMULTISIG)));
     return $script;
 }
 /**
  * @param NetworkInterface $network
  * @param PrivateKeyInterface $privateKey
  * @return string
  */
 public function serialize(NetworkInterface $network, PrivateKeyInterface $privateKey)
 {
     $serialized = Buffertools::concat(Buffer::hex($network->getPrivByte()), $this->hexSerializer->serialize($privateKey));
     if ($privateKey->isCompressed()) {
         $serialized = Buffertools::concat($serialized, new Buffer("", 1));
     }
     return Base58::encodeCheck($serialized);
 }
 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());
 }
示例#7
0
 /**
  * @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)];
 }
示例#8
0
 /**
  * @expectedException \RuntimeException
  * @expectedExceptionMessage Invalid packet checksum
  */
 public function testInvalidChecksum()
 {
     $v = '60002';
     $services = Buffer::hex('0000000000000001');
     $time = '123456789';
     $recipient = new NetworkAddress(Buffer::hex('0000000000000001'), '10.0.0.1', '8332');
     $sender = new NetworkAddress(Buffer::hex('0000000000000001'), '10.0.0.2', '8332');
     $userAgent = new Buffer("/Satoshi:0.7.2/");
     $lastBlock = '212672';
     $random = new Random();
     $nonce = $random->bytes(8)->getInt();
     $version = new Version($v, $services, $time, $recipient, $sender, $nonce, $userAgent, $lastBlock, true);
     $msg = $version->getNetworkMessage();
     $realBuffer = $msg->getBuffer();
     $invalid = Buffertools::concat(Buffertools::concat($realBuffer->slice(0, 20), Buffer::hex('00000000')), $realBuffer->slice(24));
     $serializer = new NetworkMessageSerializer(Bitcoin::getDefaultNetwork());
     $serializer->parse($invalid);
 }
示例#9
0
 /**
  * @param int|string $m
  * @param string $path
  * @param array $keys
  * @param HierarchicalKeySequence $sequences
  * @param bool $sort
  */
 public function __construct($m, $path, array $keys, HierarchicalKeySequence $sequences, $sort = false)
 {
     if (count($keys) < 1) {
         throw new \RuntimeException('Must have at least one HierarchicalKey for Multisig HD Script');
     }
     // Sort here to guarantee calls to getKeys() returns keys in the same order as the redeemScript.
     if ($sort) {
         $keys = Buffertools::sort($keys, function (HierarchicalKey $key) {
             return $key->getPublicKey()->getBuffer();
         });
     }
     $this->m = $m;
     $this->path = $path;
     foreach ($keys as $key) {
         $this->keys[] = $key;
     }
     $this->sequences = $sequences;
     $this->sort = $sort;
 }
示例#10
0
 /**
  * Push data into the stack.
  *
  * @param $data
  * @return $this
  * @throws \Exception
  */
 public function push(Buffer $data)
 {
     $length = $data->getSize();
     $parsed = new Parser('', $this->math);
     /** Note that larger integers are serialized without flipping bits - Big endian */
     if ($length < $this->opcodes->getOpByName('OP_PUSHDATA1')) {
         $varInt = Buffertools::numToVarInt($length);
         $data = new Buffer($varInt->getBinary() . $data->getBinary(), null, $this->math);
         $parsed->writeBytes($data->getSize(), $data);
     } else {
         if ($length <= 0xff) {
             $lengthSize = 1;
         } elseif ($length <= 0xffff) {
             $lengthSize = 2;
         } else {
             $lengthSize = 4;
         }
         $op = $this->opcodes->getOpByName('OP_PUSHDATA' . $lengthSize);
         $parsed->writeBytes(1, Buffer::int($op))->writeBytes($lengthSize, Buffer::int($length), true)->writeBytes($length, $data);
     }
     $this->script .= $parsed->getBuffer()->getBinary();
     return $this;
 }
示例#11
0
 /**
  * @param HierarchicalKey[] $keys
  * @return HierarchicalKey[]
  */
 private function sortHierarchicalKeys(array $keys)
 {
     return Buffertools::sort($keys, function (HierarchicalKey $key) {
         return $key->getPublicKey()->getBuffer();
     });
 }
示例#12
0
 /**
  * @return Buffer
  */
 public function flip()
 {
     return Buffertools::flipBytes($this);
 }
示例#13
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))));
 }
示例#14
0
 /**
  * Take an array containing serializable objects.
  * @param SerializableInterface []|Buffer[]
  * @return $this
  */
 public function writeArray($serializable)
 {
     $parser = new Parser(Buffertools::numToVarInt(count($serializable)), $this->math);
     foreach ($serializable as $object) {
         if ($object instanceof SerializableInterface) {
             $object = $object->getBuffer();
         }
         if ($object instanceof Buffer) {
             $parser->writeBytes($object->getSize(), $object);
         } else {
             throw new \RuntimeException('Input to writeArray must be Buffer[], or SerializableInterface[]');
         }
     }
     $this->string .= $parser->getBuffer()->getBinary();
     return $this;
 }
示例#15
0
 /**
  * @return Buffer
  */
 public function getMPK()
 {
     $math = $this->ecAdapter->getMath();
     $point = $this->getMasterPublicKey()->getPoint();
     return Buffertools::concat(Buffer::hex($math->decHex($point->getX()), 32), Buffer::hex($math->decHex($point->getY()), 32));
 }
 /**
  * @param TransactionInputInterface $input
  * @return Buffer
  */
 public function serialize(TransactionInputInterface $input)
 {
     return Buffertools::concat($this->outpointSerializer->serialize($input->getOutPoint()), $this->getInputTemplate()->write([$input->getScript()->getBuffer(), $input->getSequence()]));
 }
示例#17
0
 /**
  * @return string
  */
 public function getTransactionId()
 {
     $hash = bin2hex(Buffertools::flipBytes(Hash::sha256d($this->getBuffer())));
     return $hash;
 }
 public function testConcat()
 {
     $a = Buffer::hex("1100");
     $b = Buffer::hex("0011");
     $c = Buffer::hex("11", 2);
     $this->assertEquals("11000011", Buffertools::concat($a, $b)->getHex());
     $this->assertEquals("00111100", Buffertools::concat($b, $a)->getHex());
     $this->assertEquals("11000011", Buffertools::concat($a, $c)->getHex());
     $this->assertEquals("00111100", Buffertools::concat($c, $a)->getHex());
 }
示例#19
0
 /**
  * Encode the given data in base58, with a checksum to check integrity.
  *
  * @param BufferInterface $data
  * @return string
  * @throws \Exception
  */
 public static function encodeCheck(BufferInterface $data)
 {
     return self::encode(Buffertools::concat($data, self::checksum($data)));
 }
示例#20
0
 /**
  * @param Alert $alert
  * @return \BitWasp\Buffertools\Buffer
  */
 public function serialize(Alert $alert)
 {
     $sig = $alert->getSignature();
     return Buffertools::concat($alert->getDetail()->getBuffer(), $this->getSigTemplate()->write([$sig->getR(), $sig->getS()]));
 }
示例#21
0
 /**
  * @param string $message
  * @return BufferInterface
  * @throws \Exception
  */
 private function calculateBody($message)
 {
     return new Buffer("Bitcoin Signed Message:\n" . Buffertools::numToVarInt(strlen($message))->getBinary() . $message, null, $this->ecAdapter->getMath());
 }
 /**
  * @param GetBlocks $msg
  * @return \BitWasp\Buffertools\Buffer
  */
 public function serialize(GetBlocks $msg)
 {
     return Buffertools::concat($this->getVersionTemplate()->write([$msg->getVersion()]), $this->locator->serialize($msg->getLocator()));
 }
示例#23
0
 /**
  * @param string $message
  * @return \BitWasp\Buffertools\Buffer
  */
 public function calculateMessageHash($message)
 {
     $content = new Buffer("Bitcoin Signed Message:\n" . Buffertools::numToVarInt(strlen($message))->getBinary() . $message);
     $hash = Hash::sha256d($content);
     return $hash;
 }
示例#24
0
 /**
  * @param BlockInterface $block
  * @return \BitWasp\Buffertools\Buffer
  */
 public function serialize(BlockInterface $block)
 {
     return Buffertools::concat($this->headerSerializer->serialize($block->getHeader()), $this->getTxsTemplate()->write([$block->getTransactions()->all()]));
 }
 /**
  * @param FilteredBlock $merkleBlock
  * @return \BitWasp\Buffertools\BufferInterface
  */
 public function serialize(FilteredBlock $merkleBlock)
 {
     return Buffertools::concat($this->headerSerializer->serialize($merkleBlock->getHeader()), $this->treeSerializer->serialize($merkleBlock->getPartialTree()));
 }
 /**
  * @param NetworkMessage $object
  * @return Buffer
  */
 public function serialize(NetworkMessage $object)
 {
     $payload = $object->getPayload()->getBuffer();
     $command = str_pad(unpack("H*", $object->getCommand())[1], 24, '0', STR_PAD_RIGHT);
     $header = $this->getHeaderTemplate()->write([Buffer::hex($this->network->getNetMagicBytes()), Buffer::hex($command), $payload->getSize(), $object->getChecksum()]);
     return Buffertools::concat($header, $payload);
 }
示例#27
0
 /**
  * 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)
 {
     $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");
         }
         $buffer = Buffertools::concat(new Buffer(""), $this->getPrivateKey()->getBuffer());
     } else {
         $buffer = $this->getPublicKey()->getBuffer();
     }
     return (new Parser($buffer))->writeBytes(4, Buffer::int($sequence, 4))->getBuffer();
 }
示例#28
0
 /**
  * Traverse the Merkle Tree hashes and extract those which have a matching bit.
  *
  * @param int $height
  * @param int $position
  * @param int $nBitsUsed
  * @param int $nHashUsed
  * @param BufferInterface[] $vMatch
  * @return BufferInterface
  */
 public function traverseAndExtract($height, $position, &$nBitsUsed, &$nHashUsed, &$vMatch)
 {
     if ($nBitsUsed >= count($this->vFlagBits)) {
         $this->fBad = true;
         return new Buffer();
     }
     $parent = $this->vFlagBits[$nBitsUsed++];
     if (0 === $height || !$parent) {
         if ($nHashUsed >= count($this->vHashes)) {
             $this->fBad = true;
             return new Buffer();
         }
         $hash = $this->vHashes[$nHashUsed++];
         if ($height === 0 && $parent) {
             $vMatch[] = $hash->flip();
         }
         return $hash;
     } else {
         $left = $this->traverseAndExtract($height - 1, $position * 2, $nBitsUsed, $nHashUsed, $vMatch);
         if ($position * 2 + 1 < $this->calcTreeWidth($height - 1)) {
             $right = $this->traverseAndExtract($height - 1, $position * 2 + 1, $nBitsUsed, $nHashUsed, $vMatch);
             if ($right === $left) {
                 $this->fBad = true;
             }
         } else {
             $right = $left;
         }
         return Hash::sha256d(Buffertools::concat($left, $right));
     }
 }
 /**
  * @param Alert $alert
  * @return \BitWasp\Buffertools\Buffer
  */
 public function serialize(Alert $alert)
 {
     $detail = $alert->getDetail()->getBuffer();
     $sig = $this->getSigBuf()->write([$alert->getSignature()->getBuffer()]);
     return Buffertools::concat($detail, $sig);
 }