/** * @param Math $math * @param Opcodes $opcodes * @param BufferInterface|null $buffer */ public function __construct(Math $math, Opcodes $opcodes, BufferInterface $buffer = null) { if ($buffer !== null) { $this->script = $buffer->getBinary(); } $this->math = $math; $this->opcodes = $opcodes; }
/** * Encode a given hex string in base58 * * @param BufferInterface $binary * @return string * @throws \Exception */ public static function encode(BufferInterface $binary) { $size = $binary->getSize(); if ($binary->getBinary() === '') { return ''; } $math = Bitcoin::getMath(); $orig = $binary->getBinary(); $decimal = $binary->getInt(); $return = ''; while ($math->cmp($decimal, 0) > 0) { list($decimal, $rem) = $math->divQr($decimal, 58); $return .= self::$base58chars[$rem]; } $return = strrev($return); //leading zeros for ($i = 0; $i < $size && $orig[$i] === ""; $i++) { $return = '1' . $return; } return $return; }
/** * @param BufferInterface $sig * @return bool * @throws SignatureNotCanonical */ public static function isDERSignature(BufferInterface $sig) { $checkVal = function ($fieldName, $start, $length, $binaryString) { if ($length === 0) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' length is zero'); } $typePrefix = ord(substr($binaryString, $start - 2, 1)); if ($typePrefix !== 0x2) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value type mismatch'); } $val = substr($binaryString, $start, $length); $vAnd = $val[0] & chr(0x80); if (ord($vAnd) === 128) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value is negative'); } if ($length > 1 && $val[0] === "" && !ord($val[1] & chr(0x80))) { throw new SignatureNotCanonical('Signature ' . $fieldName . ' value excessively padded'); } }; $bin = $sig->getBinary(); $size = $sig->getSize(); if ($size < 9) { throw new SignatureNotCanonical('Signature too short'); } if ($size > 73) { throw new SignatureNotCanonical('Signature too long'); } if (ord($bin[0]) !== 0x30) { throw new SignatureNotCanonical('Signature has wrong type'); } if (ord($bin[1]) !== $size - 3) { throw new SignatureNotCanonical('Signature has wrong length marker'); } $lenR = ord($bin[3]); $startR = 4; if (5 + $lenR >= $size) { throw new SignatureNotCanonical('Signature S length misplaced'); } $lenS = ord($bin[5 + $lenR]); $startS = 4 + $lenR + 2; if ($lenR + $lenS + 7 !== $size) { throw new SignatureNotCanonical('Signature R+S length mismatch'); } $checkVal('R', $startR, $lenR, $bin); $checkVal('S', $startS, $lenS, $bin); return true; }
/** * @param BufferInterface $publicKey * @return bool */ public static function isCompressedOrUncompressed(BufferInterface $publicKey) { $vchPubKey = $publicKey->getBinary(); if ($publicKey->getSize() < 33) { return false; } if (ord($vchPubKey[0]) === 0x4) { if ($publicKey->getSize() !== 65) { // Invalid length for uncompressed key return false; } } elseif (in_array($vchPubKey[0], array(hex2bin(self::KEY_COMPRESSED_EVEN), hex2bin(self::KEY_COMPRESSED_ODD)))) { if ($publicKey->getSize() !== 33) { return false; } } else { return false; } return true; }
/** * @param BufferInterface $buffer * @return int */ private function parseBuffer(BufferInterface $buffer) { $size = $buffer->getSize(); if ($size === 0) { return '0'; } $chars = array_map(function ($binary) { return ord($binary); }, str_split($buffer->getBinary(), 1)); $result = 0; for ($i = 0; $i < $size; $i++) { $mul = $this->math->mul($i, 8); $byte = $this->math->leftShift($chars[$i], $mul); $result = $this->math->bitwiseOr($result, $byte); } if ($chars[count($chars) - 1] & 0x80) { $mask = gmp_strval(gmp_com($this->math->leftShift(0x80, 8 * ($size - 1))), 10); return $this->math->sub(0, $this->math->bitwiseAnd($result, $mask)); } return $result; }
/** * Determine whether the sighash byte appended to the signature encodes * a valid sighash type. * * @param BufferInterface $signature * @return bool */ public function isDefinedHashtypeSignature(BufferInterface $signature) { if ($signature->getSize() === 0) { return false; } $binary = $signature->getBinary(); $nHashType = ord(substr($binary, -1)) & ~SigHash::ANYONECANPAY; $math = $this->adapter->getMath(); return !($math->cmp($nHashType, SigHash::ALL) < 0 || $math->cmp($nHashType, SigHash::SINGLE) > 0); }
/** * Do HMAC hashing on $data and $salt * * @param string $algo * @param BufferInterface $data * @param BufferInterface $salt * @return BufferInterface */ public static function hmac($algo, BufferInterface $data, BufferInterface $salt) { return new Buffer(hash_hmac($algo, $data->getBinary(), $salt->getBinary(), true)); }
/** * @param BufferInterface $buffer * @return bool */ public function isKnownHeader(BufferInterface $buffer) { $binary = $buffer->getBinary(); foreach (array_keys($this->segments) as $segment) { if (isset($this->hashStorage[$segment][$binary])) { return true; } } return false; }
/** * @param BufferInterface $buffer * @return int */ public function getHeightFromHash(BufferInterface $buffer) { $binary = $buffer->getBinary(); foreach ($this->segments as $segment) { $hashes = $this->container->getHashes($segment); if (isset($hashes[$binary])) { return $hashes[$binary]; } } throw new \RuntimeException('Hash not found'); }
/** * @param BufferInterface $hash * @return $this */ public function markReceived(BufferInterface $hash) { unset($this->inFlight[$hash->getBinary()]); return $this; }
/** * @param BufferInterface $msg32 * @param PrivateKey $privateKey * @return CompactSignature */ private function doSignCompact(BufferInterface $msg32, PrivateKey $privateKey) { $sig_t = ''; /** @var resource $sig_t */ if (1 !== secp256k1_ecdsa_sign_recoverable($this->context, $msg32->getBinary(), $privateKey->getBinary(), $sig_t)) { throw new \RuntimeException('Secp256k1: failed to sign'); } $recid = ''; $ser = ''; if (!secp256k1_ecdsa_recoverable_signature_serialize_compact($this->context, $sig_t, $ser, $recid)) { throw new \RuntimeException('Failed to obtain recid'); } unset($ser); return new CompactSignature($this, $sig_t, $recid, $privateKey->isCompressed()); }
/** * @param BufferInterface $script * @param Opcodes|null $opCodes */ public function __construct(BufferInterface $script = null, Opcodes $opCodes = null) { $this->script = $script instanceof BufferInterface ? $script->getBinary() : ''; $this->opCodes = $opCodes ?: new Opcodes(); }
/** * @param PublicKeyInterface $publicKey * @return bool */ public function checkInvolvesKey(PublicKeyInterface $publicKey) { return $publicKey->getPubKeyHash()->getBinary() === $this->hash->getBinary(); }
/** * @param BufferInterface $hash * @param int $numAncestors * @return array */ public function findSuperMajorityInfoByHash(BufferInterface $hash, $numAncestors = 1000) { $this->fetchLftRgtByHash->execute(['hash' => $hash->getBinary()]); $id = $this->fetchLftRgtByHash->fetch(\PDO::FETCH_ASSOC); $this->fetchSuperMajorityVersions->execute(['lft' => $id['lft'], 'rgt' => $id['rgt']]); $stream = $this->fetchSuperMajorityVersions->fetchAll(\PDO::FETCH_COLUMN); return $stream; }
/** * @param int $opCode * @param BufferInterface $pushData * @return bool * @throws \Exception */ public function checkMinimalPush($opCode, BufferInterface $pushData) { $pushSize = $pushData->getSize(); $binary = $pushData->getBinary(); if ($pushSize === 0) { return $opCode === Opcodes::OP_0; } elseif ($pushSize === 1) { $first = ord($binary[0]); if ($first >= 1 && $first <= 16) { return $opCode === Opcodes::OP_1 + ($first - 1); } elseif ($first === 0x81) { return $opCode === Opcodes::OP_1NEGATE; } } elseif ($pushSize <= 75) { return $opCode === $pushSize; } elseif ($pushSize <= 255) { return $opCode === Opcodes::OP_PUSHDATA1; } elseif ($pushSize <= 65535) { return $opCode === Opcodes::OP_PUSHDATA2; } return true; }