Bit-Wasp /
bitcoin-php
| 1 | <?php |
||||||||
| 2 | |||||||||
| 3 | declare(strict_types=1); |
||||||||
| 4 | |||||||||
| 5 | namespace BitWasp\Bitcoin\Script\Interpreter; |
||||||||
| 6 | |||||||||
| 7 | use BitWasp\Bitcoin\Bitcoin; |
||||||||
| 8 | use BitWasp\Bitcoin\Math\Math; |
||||||||
| 9 | use BitWasp\Bitcoin\Serializable; |
||||||||
| 10 | use BitWasp\Buffertools\Buffer; |
||||||||
| 11 | use BitWasp\Buffertools\BufferInterface; |
||||||||
| 12 | |||||||||
| 13 | class Number extends Serializable |
||||||||
| 14 | { |
||||||||
| 15 | const MAX_NUM_SIZE = 4; |
||||||||
| 16 | const MAX = 2**31-1; |
||||||||
| 17 | const MIN = -2**31+1; |
||||||||
| 18 | |||||||||
| 19 | /** |
||||||||
| 20 | * @var Math |
||||||||
| 21 | */ |
||||||||
| 22 | private $math; |
||||||||
| 23 | |||||||||
| 24 | /** |
||||||||
| 25 | * @var int|string |
||||||||
| 26 | */ |
||||||||
| 27 | private $number; |
||||||||
| 28 | |||||||||
| 29 | /** |
||||||||
| 30 | * Number constructor. |
||||||||
| 31 | * @param int|string $number |
||||||||
| 32 | * @param Math $math |
||||||||
| 33 | */ |
||||||||
| 34 | 3501 | public function __construct($number, Math $math) |
|||||||
| 35 | { |
||||||||
| 36 | 3501 | $this->number = $number; |
|||||||
| 37 | 3501 | $this->math = $math; |
|||||||
| 38 | 3501 | } |
|||||||
| 39 | |||||||||
| 40 | /** |
||||||||
| 41 | * @param int|string $number |
||||||||
| 42 | * @param Math|null $math |
||||||||
| 43 | * @return self |
||||||||
| 44 | */ |
||||||||
| 45 | 3230 | public static function int($number, Math $math = null) |
|||||||
| 46 | { |
||||||||
| 47 | 3230 | return new self( |
|||||||
| 48 | 3230 | $number, |
|||||||
| 49 | 3230 | $math ?: Bitcoin::getMath() |
|||||||
| 50 | ); |
||||||||
| 51 | } |
||||||||
| 52 | |||||||||
| 53 | /** |
||||||||
| 54 | * @param \GMP $number |
||||||||
| 55 | * @param Math|null $math |
||||||||
| 56 | * @return self |
||||||||
| 57 | */ |
||||||||
| 58 | public static function gmp(\GMP $number, Math $math = null) |
||||||||
| 59 | { |
||||||||
| 60 | return new self( |
||||||||
| 61 | gmp_strval($number, 10), |
||||||||
| 62 | $math ?: Bitcoin::getMath() |
||||||||
| 63 | ); |
||||||||
| 64 | } |
||||||||
| 65 | |||||||||
| 66 | /** |
||||||||
| 67 | * @param BufferInterface $vch |
||||||||
| 68 | * @param bool $fRequireMinimal |
||||||||
| 69 | * @param int $maxNumSize |
||||||||
| 70 | * @param Math|null $math |
||||||||
| 71 | * @return self |
||||||||
| 72 | */ |
||||||||
| 73 | 2694 | public static function buffer(BufferInterface $vch, $fRequireMinimal, $maxNumSize = self::MAX_NUM_SIZE, Math $math = null) |
|||||||
| 74 | { |
||||||||
| 75 | 2694 | $size = $vch->getSize(); |
|||||||
| 76 | 2694 | if ($size > $maxNumSize) { |
|||||||
| 77 | 44 | throw new \RuntimeException('Script number overflow'); |
|||||||
| 78 | } |
||||||||
| 79 | |||||||||
| 80 | 2658 | if ($fRequireMinimal && $size > 0) { |
|||||||
| 81 | 220 | $binary = $vch->getBinary(); |
|||||||
| 82 | 220 | if ((ord($binary[$size - 1]) & 0x7f) === 0) { |
|||||||
| 83 | 220 | if ($size <= 1 || (ord($binary[$size - 2]) & 0x80) === 0) { |
|||||||
| 84 | 220 | throw new \RuntimeException('Non-minimally encoded script number'); |
|||||||
| 85 | } |
||||||||
| 86 | } |
||||||||
| 87 | } |
||||||||
| 88 | |||||||||
| 89 | 2510 | $math = $math ?: Bitcoin::getMath(); |
|||||||
| 90 | 2510 | $number = new self(0, $math); |
|||||||
| 91 | 2510 | $number->number = $number->parseBuffer($vch); |
|||||||
| 92 | 2510 | return $number; |
|||||||
| 93 | } |
||||||||
| 94 | |||||||||
| 95 | /** |
||||||||
| 96 | * @param BufferInterface $buffer |
||||||||
| 97 | * @return string |
||||||||
| 98 | */ |
||||||||
| 99 | 2510 | private function parseBuffer(BufferInterface $buffer): string |
|||||||
| 100 | { |
||||||||
| 101 | 2510 | $size = $buffer->getSize(); |
|||||||
| 102 | 2510 | if ($size === 0) { |
|||||||
| 103 | 1421 | return '0'; |
|||||||
| 104 | } |
||||||||
| 105 | |||||||||
| 106 | 1677 | $chars = array_values(unpack("C*", $buffer->getBinary())); |
|||||||
| 107 | |||||||||
| 108 | 1677 | $result = gmp_init(0); |
|||||||
| 109 | 1677 | for ($i = 0; $i < $size; $i++) { |
|||||||
| 110 | 1677 | $mul = $i * 8; |
|||||||
| 111 | 1677 | $byte = $this->math->leftShift(gmp_init($chars[$i], 10), $mul); |
|||||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||||||
| 112 | 1677 | $result = $this->math->bitwiseOr($result, $byte); |
|||||||
|
0 ignored issues
–
show
It seems like
$result can also be of type resource; however, parameter $int of BitWasp\Bitcoin\Math\Math::bitwiseOr() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 113 | } |
||||||||
| 114 | |||||||||
| 115 | 1677 | if ($chars[count($chars)-1] & 0x80) { |
|||||||
| 116 | 197 | $mask = gmp_com($this->math->leftShift(gmp_init(0x80), (8 * ($size - 1)))); |
|||||||
| 117 | 197 | $result = $this->math->sub(gmp_init(0), $this->math->bitwiseAnd($result, $mask)); |
|||||||
|
0 ignored issues
–
show
It seems like
$mask can also be of type resource; however, parameter $other of Mdanter\Ecc\Math\GmpMath::bitwiseAnd() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
$result can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMath::bitwiseAnd() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
gmp_init(0) can also be of type resource; however, parameter $minuend of Mdanter\Ecc\Math\GmpMath::sub() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 118 | } |
||||||||
| 119 | |||||||||
| 120 | 1677 | return gmp_strval($result, 10); |
|||||||
| 121 | } |
||||||||
| 122 | |||||||||
| 123 | /** |
||||||||
| 124 | * @return BufferInterface |
||||||||
| 125 | */ |
||||||||
| 126 | 3378 | private function serialize(): BufferInterface |
|||||||
| 127 | { |
||||||||
| 128 | 3378 | if ((int) $this->number === 0) { |
|||||||
| 129 | 1126 | return new Buffer('', 0); |
|||||||
| 130 | } |
||||||||
| 131 | |||||||||
| 132 | 3136 | $zero = gmp_init(0); |
|||||||
| 133 | // Using array of integers instead of bytes |
||||||||
| 134 | 3136 | $result = []; |
|||||||
| 135 | 3136 | $negative = $this->math->cmp(gmp_init($this->number), $zero) < 0; |
|||||||
|
0 ignored issues
–
show
It seems like
$zero can also be of type resource; however, parameter $other of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
gmp_init($this->number) can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 136 | 3136 | $abs = $negative ? $this->math->sub($zero, gmp_init($this->number, 10)) : gmp_init($this->number, 10); |
|||||||
|
0 ignored issues
–
show
It seems like
gmp_init($this->number, 10) can also be of type resource; however, parameter $subtrahend of Mdanter\Ecc\Math\GmpMath::sub() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
$zero can also be of type resource; however, parameter $minuend of Mdanter\Ecc\Math\GmpMath::sub() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 137 | 3136 | $mask = gmp_init(0xff); |
|||||||
| 138 | 3136 | while ($this->math->cmp($abs, $zero) > 0) { |
|||||||
| 139 | 3136 | $result[] = (int) gmp_strval($this->math->bitwiseAnd($abs, $mask), 10); |
|||||||
|
0 ignored issues
–
show
It seems like
$mask can also be of type resource; however, parameter $other of Mdanter\Ecc\Math\GmpMath::bitwiseAnd() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
$abs can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMath::bitwiseAnd() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 140 | 3136 | $abs = $this->math->rightShift($abs, 8); |
|||||||
|
0 ignored issues
–
show
It seems like
$abs can also be of type resource; however, parameter $number of Mdanter\Ecc\Math\GmpMath::rightShift() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 141 | } |
||||||||
| 142 | |||||||||
| 143 | 3136 | if ($result[count($result) - 1] & 0x80) { |
|||||||
| 144 | 26 | $result[] = $negative ? 0x80 : 0; |
|||||||
| 145 | 3118 | } else if ($negative) { |
|||||||
| 146 | 108 | $result[count($result) - 1] |= 0x80; |
|||||||
| 147 | } |
||||||||
| 148 | |||||||||
| 149 | 3136 | return new Buffer(pack("C*", ...$result)); |
|||||||
| 150 | } |
||||||||
| 151 | |||||||||
| 152 | /** |
||||||||
| 153 | * @return BufferInterface |
||||||||
| 154 | */ |
||||||||
| 155 | 3378 | public function getBuffer(): BufferInterface |
|||||||
| 156 | { |
||||||||
| 157 | 3378 | return $this->serialize(); |
|||||||
| 158 | } |
||||||||
| 159 | |||||||||
| 160 | /** |
||||||||
| 161 | * @return int |
||||||||
| 162 | */ |
||||||||
| 163 | 462 | public function getInt(): int |
|||||||
| 164 | { |
||||||||
| 165 | 462 | if ($this->math->cmp(gmp_init($this->number, 10), gmp_init(self::MAX)) > 0) { |
|||||||
|
0 ignored issues
–
show
It seems like
gmp_init(self::MAX) can also be of type resource; however, parameter $other of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
It seems like
gmp_init($this->number, 10) can also be of type resource; however, parameter $first of Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept GMP, maybe add an additional type check?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||||||
| 166 | return self::MAX; |
||||||||
| 167 | 462 | } else if ($this->math->cmp(gmp_init($this->number, 10), gmp_init(self::MIN)) < 0) { |
|||||||
| 168 | return self::MIN; |
||||||||
| 169 | } |
||||||||
| 170 | |||||||||
| 171 | 462 | return (int) $this->number; |
|||||||
| 172 | } |
||||||||
| 173 | |||||||||
| 174 | /** |
||||||||
| 175 | * @return \GMP |
||||||||
| 176 | */ |
||||||||
| 177 | 948 | public function getGmp() |
|||||||
| 178 | { |
||||||||
| 179 | 948 | return gmp_init($this->number, 10); |
|||||||
|
0 ignored issues
–
show
|
|||||||||
| 180 | } |
||||||||
| 181 | } |
||||||||
| 182 |