Number::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 2
dl 0
loc 4
ccs 3
cts 3
cp 1
crap 1
rs 10
c 0
b 0
f 0
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
It seems like gmp_init($chars[$i], 10) can also be of type resource; however, parameter $number of Mdanter\Ecc\Math\GmpMath::leftShift() 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 ignore-type  annotation

111
            $byte = $this->math->leftShift(/** @scrutinizer ignore-type */ gmp_init($chars[$i], 10), $mul);
Loading history...
112 1677
            $result = $this->math->bitwiseOr($result, $byte);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

112
            $result = $this->math->bitwiseOr(/** @scrutinizer ignore-type */ $result, $byte);
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
Bug introduced by
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 ignore-type  annotation

117
            $result = $this->math->sub(gmp_init(0), $this->math->bitwiseAnd($result, /** @scrutinizer ignore-type */ $mask));
Loading history...
Bug introduced by
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 ignore-type  annotation

117
            $result = $this->math->sub(gmp_init(0), $this->math->bitwiseAnd(/** @scrutinizer ignore-type */ $result, $mask));
Loading history...
Bug introduced by
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 ignore-type  annotation

117
            $result = $this->math->sub(/** @scrutinizer ignore-type */ gmp_init(0), $this->math->bitwiseAnd($result, $mask));
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
Bug introduced by
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 ignore-type  annotation

135
        $negative = $this->math->cmp(gmp_init($this->number), /** @scrutinizer ignore-type */ $zero) < 0;
Loading history...
Bug introduced by
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 ignore-type  annotation

135
        $negative = $this->math->cmp(/** @scrutinizer ignore-type */ gmp_init($this->number), $zero) < 0;
Loading history...
136 3136
        $abs = $negative ? $this->math->sub($zero, gmp_init($this->number, 10)) : gmp_init($this->number, 10);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

136
        $abs = $negative ? $this->math->sub($zero, /** @scrutinizer ignore-type */ gmp_init($this->number, 10)) : gmp_init($this->number, 10);
Loading history...
Bug introduced by
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 ignore-type  annotation

136
        $abs = $negative ? $this->math->sub(/** @scrutinizer ignore-type */ $zero, gmp_init($this->number, 10)) : gmp_init($this->number, 10);
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
Bug introduced by
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 ignore-type  annotation

139
            $result[] = (int) gmp_strval($this->math->bitwiseAnd($abs, /** @scrutinizer ignore-type */ $mask), 10);
Loading history...
Bug introduced by
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 ignore-type  annotation

139
            $result[] = (int) gmp_strval($this->math->bitwiseAnd(/** @scrutinizer ignore-type */ $abs, $mask), 10);
Loading history...
140 3136
            $abs = $this->math->rightShift($abs, 8);
0 ignored issues
show
Bug introduced by
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 ignore-type  annotation

140
            $abs = $this->math->rightShift(/** @scrutinizer ignore-type */ $abs, 8);
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
Bug introduced by
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 ignore-type  annotation

165
        if ($this->math->cmp(gmp_init($this->number, 10), /** @scrutinizer ignore-type */ gmp_init(self::MAX)) > 0) {
Loading history...
Bug introduced by
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 ignore-type  annotation

165
        if ($this->math->cmp(/** @scrutinizer ignore-type */ gmp_init($this->number, 10), gmp_init(self::MAX)) > 0) {
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
Bug Best Practice introduced by
The expression return gmp_init($this->number, 10) also could return the type resource which is incompatible with the documented return type GMP.
Loading history...
180
    }
181
}
182