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
![]() |
|||||||||
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
![]() |
|||||||||
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
![]() 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
![]() 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
![]() |
|||||||||
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
![]() 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
![]() |
|||||||||
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
![]() 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
![]() |
|||||||||
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
![]() 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
![]() |
|||||||||
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
![]() |
|||||||||
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
![]() 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
![]() |
|||||||||
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 |