Completed
Push — master ( a32e00...7fb813 )
by thomas
364:59 queued 294:52
created

Math::decodeCompact()   D

Complexity

Conditions 10
Paths 33

Size

Total Lines 29
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 10

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 19
c 1
b 0
f 0
nc 33
nop 3
dl 0
loc 29
ccs 18
cts 18
cp 1
crap 10
rs 4.8196

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace BitWasp\Bitcoin\Math;
4
5
use \Mdanter\Ecc\Math\GmpMath;
6
use Mdanter\Ecc\Util\NumberSize;
7
8
class Math extends GmpMath
9
{
10
11
    /**
12
     * @param \GMP $integer
13
     * @return bool
14
     */
15 110
    public function isEven(\GMP $integer)
16
    {
17 110
        return $this->cmp($this->mod($integer, gmp_init(2)), gmp_init(0)) === 0;
18
    }
19
20
    /**
21
     * @param \GMP $int
22
     * @param \GMP $otherInt
23
     * @return \GMP
24
     */
25 946
    public function bitwiseOr(\GMP $int, \GMP $otherInt)
26
    {
27 946
        return gmp_or($int, $otherInt);
28
    }
29
30
    /**
31
     * Similar to gmp_div_qr, return a tuple containing the
32
     * result and the remainder
33
     *
34
     * @param \GMP $dividend
35
     * @param \GMP $divisor
36
     * @return array
37
     */
38 312
    public function divQr(\GMP $dividend, \GMP $divisor)
39
    {
40
        // $div = n / q
41 312
        $div = $this->div($dividend, $divisor);
42
        // $remainder = n - (n / q) * q
43 312
        $remainder = $this->sub($dividend, $this->mul($div, $divisor));
44 312
        return array($div, $remainder);
45
    }
46
47
    /**
48
     * @param int $compact
49
     * @param bool|false $isNegative
50
     * @param bool|false $isOverflow
51
     * @return \GMP
52
     */
53 1260
    public function decodeCompact($compact, &$isNegative, &$isOverflow)
54
    {
55 1260
        if ($compact < 0 || $compact > pow(2, 32) - 1) {
56 1260
            throw new \RuntimeException('Compact integer must be 32bit');
57 1260
        }
58 1260
59 78
        $compact = gmp_init($compact, 10);
60 78
        $size = $this->rightShift($compact, 24);
61 39
        $word = $this->bitwiseAnd($compact, gmp_init(0x007fffff));
62 1182
        if ($this->cmp($size, gmp_init(3)) <= 0) {
63 1182
            $positions = $this->toString($this->mul(gmp_init(8), $this->sub(gmp_init(3), $size)));
64
            $word = $this->rightShift($word, $positions);
65
        } else {
66
            $positions = $this->toString($this->mul(gmp_init(8), $this->sub($size, gmp_init(3))));
67
            $word = $this->leftShift($word, $positions);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->leftShift($word, $positions); of type resource adds the type resource to the return on line 80 which is incompatible with the return type documented by BitWasp\Bitcoin\Math\Math::decodeCompact of type GMP.
Loading history...
68 1260
        }
69 1260
70 1260
        // isNegative: $word !== 0 && $uint32 & 0x00800000 !== 0
71 1194
        // isOverflow: $word !== 0 && (($size > 34) || ($word > 0xff && $size > 33) || ($word > 0xffff && $size > 32))
72 1188
        $zero = gmp_init(0);
73 1224
        $isNegative = ($this->cmp($word, $zero) !== 0) && ($this->cmp($this->bitwiseAnd($compact, gmp_init(0x00800000)), $zero) === 1);
0 ignored issues
show
Bug introduced by
It seems like $word defined by $this->leftShift($word, $positions) on line 67 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
74 630
        $isOverflow = $this->cmp($word, $zero) !== 0 && (
0 ignored issues
show
Bug introduced by
It seems like $word defined by $this->leftShift($word, $positions) on line 67 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
75
                ($this->cmp($size, gmp_init(34)) > 0)
76 1260
                || ($this->cmp($word, gmp_init(0xff)) > 0 && $this->cmp($size, gmp_init(33)) > 0)
0 ignored issues
show
Bug introduced by
It seems like $word defined by $this->leftShift($word, $positions) on line 67 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
77
                || ($this->cmp($word, gmp_init(0xffff)) > 0 && $this->cmp($size, gmp_init(32)) > 0)
0 ignored issues
show
Bug introduced by
It seems like $word defined by $this->leftShift($word, $positions) on line 67 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::cmp() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
78
            );
79
80
        return $word;
81
    }
82
83 108
    /**
84
     * @param \GMP $integer
85 108
     * @return \GMP
86 108
     */
87 108
    public function getLow64(\GMP $integer)
88 108
    {
89
        $bits = gmp_strval($integer, 2);
90
        $bits = substr($bits, 0, 64);
91
        $bits = str_pad($bits, 64, '0', STR_PAD_LEFT);
92
        return gmp_init($bits, 2);
93
    }
94
95
    /**
96
     * @param \GMP $int
97
     * @param int $byteSize
98
     * @return string
99
     */
100
    public function fixedSizeInt(\GMP $int, $byteSize)
101
    {
102
        $two = gmp_init(2);
103
        $maskShift = gmp_pow($two, 8);
104
        $mask = gmp_mul(gmp_init(255), gmp_pow($two, 256));
105
106
        $x = '';
107
        for ($i = $byteSize - 1; $i >= 0; $i--) {
108
            $mask = gmp_div($mask, $maskShift);
109
            $x .= pack('C', gmp_strval(gmp_div(gmp_and($int, $mask), gmp_pow($two, $i * 8)), 10));
110
        }
111
112
        return $x;
113
    }
114
115
    /**
116 114
     * @param \GMP $integer
117
     * @param bool $fNegative
118 114
     * @return \GMP
119 6
     */
120
    public function encodeCompact(\GMP $integer, $fNegative)
121
    {
122 108
        if (!is_bool($fNegative)) {
123 108
            throw new \InvalidArgumentException('CompactInteger::read() - flag must be boolean!');
124 84
        }
125 42
126 24
        $size = (int) NumberSize::bnNumBytes($this, $integer);
127 24
        if ($size <= 3) {
128
            $compact = $this->leftShift($this->getLow64($integer), (8 * (3 - $size)));
129
        } else {
130 108
            $compact = $this->rightShift($integer, 8 * ($size - 3));
131 6
            $compact = $this->getLow64($compact);
132 6
        }
133 3
134
        if ($this->cmp($this->bitwiseAnd($compact, gmp_init(0x00800000, 10)), gmp_init(0)) > 0) {
135 108
            $compact = $this->rightShift($compact, 8);
136 108
            $size = $size + 1;
137 12
        }
138 6
139
        $compact = $this->bitwiseOr($compact, $this->leftShift(gmp_init($size, 10), 24));
0 ignored issues
show
Bug introduced by
It seems like $compact defined by $this->bitwiseOr($compac...p_init($size, 10), 24)) on line 139 can also be of type resource; however, BitWasp\Bitcoin\Math\Math::bitwiseOr() does only seem to accept object<GMP>, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
140 108
        if ($fNegative && $this->cmp($this->bitwiseAnd($compact, gmp_init(0x007fffff)), gmp_init(0)) > 0) { /// ?
141
            $compact = $this->bitwiseOr($compact, gmp_init(0x00800000));
142
        }
143
144
        return $compact;
145
    }
146
}
147