Completed
Push — master ( eabe8c...61f277 )
by thomas
25:26
created

Math::fixedSizeInt()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 8
nc 2
nop 2
dl 0
loc 13
ccs 0
cts 9
cp 0
crap 6
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Math;
6
7
use Mdanter\Ecc\Math\GmpMath;
8
use Mdanter\Ecc\Util\NumberSize;
9
10
class Math extends GmpMath
11
{
12
13
    /**
14
     * @param \GMP $integer
15
     * @return bool
16
     */
17 94
    public function isEven(\GMP $integer): bool
18
    {
19 94
        return $this->cmp($this->mod($integer, gmp_init(2)), gmp_init(0)) === 0;
20
    }
21
22
    /**
23
     * @param \GMP $int
24
     * @param \GMP $otherInt
25
     * @return \GMP
26
     */
27 1695
    public function bitwiseOr(\GMP $int, \GMP $otherInt): \GMP
28
    {
29 1695
        return gmp_or($int, $otherInt);
30
    }
31
32
    /**
33
     * Similar to gmp_div_qr, return a tuple containing the
34
     * result and the remainder
35
     *
36
     * @param \GMP $dividend
37
     * @param \GMP $divisor
38
     * @return array
39
     */
40
    public function divQr(\GMP $dividend, \GMP $divisor): array
41
    {
42
        // $div = n / q
43
        $div = $this->div($dividend, $divisor);
44
        // $remainder = n - (n / q) * q
45
        $remainder = $this->sub($dividend, $this->mul($div, $divisor));
46
        return [$div, $remainder];
47
    }
48
49
    /**
50
     * @param int $compact
51
     * @param bool|false $isNegative
52
     * @param bool|false $isOverflow
53
     * @return \GMP
54
     */
55 210
    public function decodeCompact($compact, &$isNegative, &$isOverflow): \GMP
56
    {
57 210
        if ($compact < 0 || $compact > pow(2, 32) - 1) {
58
            throw new \RuntimeException('Compact integer must be 32bit');
59
        }
60
61 210
        $compact = gmp_init($compact, 10);
62 210
        $size = $this->rightShift($compact, 24);
63 210
        $word = $this->bitwiseAnd($compact, gmp_init(0x007fffff, 10));
64 210
        if ($this->cmp($size, gmp_init(3)) <= 0) {
65 13
            $positions = (int) $this->toString($this->mul(gmp_init(8, 10), $this->sub(gmp_init(3, 10), $size)));
66 13
            $word = $this->rightShift($word, $positions);
67
        } else {
68 197
            $positions = (int) $this->toString($this->mul(gmp_init(8, 10), $this->sub($size, gmp_init(3, 10))));
69 197
            $word = $this->leftShift($word, $positions);
70
        }
71
72
        // isNegative: $word !== 0 && $uint32 & 0x00800000 !== 0
0 ignored issues
show
Unused Code Comprehensibility introduced by
41% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
73
        // isOverflow: $word !== 0 && (($size > 34) || ($word > 0xff && $size > 33) || ($word > 0xffff && $size > 32))
0 ignored issues
show
Unused Code Comprehensibility introduced by
46% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
74 210
        $zero = gmp_init(0);
75 210
        $isNegative = ($this->cmp($word, $zero) !== 0) && ($this->cmp($this->bitwiseAnd($compact, gmp_init(0x00800000)), $zero) === 1);
76 210
        $isOverflow = $this->cmp($word, $zero) !== 0 && (
77 199
                ($this->cmp($size, gmp_init(34, 10)) > 0)
78 198
                || ($this->cmp($word, gmp_init(0xff, 10)) > 0 && $this->cmp($size, gmp_init(33, 10)) > 0)
79 210
                || ($this->cmp($word, gmp_init(0xffff, 10)) > 0 && $this->cmp($size, gmp_init(32, 10)) > 0)
80
            );
81
82 210
        return $word;
83
    }
84
85
    /**
86
     * @param \GMP $integer
87
     * @return \GMP
88
     */
89 18
    public function getLow64(\GMP $integer): \GMP
90
    {
91 18
        $bits = gmp_strval($integer, 2);
92 18
        $bits = substr($bits, 0, 64);
93 18
        $bits = str_pad($bits, 64, '0', STR_PAD_LEFT);
94 18
        return gmp_init($bits, 2);
95
    }
96
97
    /**
98
     * @param \GMP $int
99
     * @param int $byteSize
100
     * @return string
101
     */
102
    public function fixedSizeInt(\GMP $int, int $byteSize): string
103
    {
104
        $two = gmp_init(2);
105
        $maskShift = gmp_pow($two, 8);
106
        $mask = gmp_mul(gmp_init(255), gmp_pow($two, 256));
107
108
        $x = '';
109
        for ($i = $byteSize - 1; $i >= 0; $i--) {
110
            $mask = gmp_div($mask, $maskShift);
111
            $x .= pack('C', gmp_strval(gmp_div(gmp_and($int, $mask), gmp_pow($two, $i * 8)), 10));
112
        }
113
114
        return $x;
115
    }
116
117
    /**
118
     * @param \GMP $integer
119
     * @param bool $fNegative
120
     * @return \GMP
121
     */
122 18
    public function encodeCompact(\GMP $integer, bool $fNegative): \GMP
123
    {
124 18
        if (!is_bool($fNegative)) {
0 ignored issues
show
introduced by
The condition is_bool($fNegative) is always true.
Loading history...
125
            throw new \InvalidArgumentException('CompactInteger::read() - flag must be boolean!');
126
        }
127
128 18
        $size = (int) NumberSize::bnNumBytes($this, $integer);
129 18
        if ($size <= 3) {
130 14
            $compact = $this->leftShift($this->getLow64($integer), (8 * (3 - $size)));
131
        } else {
132 4
            $compact = $this->rightShift($integer, 8 * ($size - 3));
133 4
            $compact = $this->getLow64($compact);
134
        }
135
136 18
        if ($this->cmp($this->bitwiseAnd($compact, gmp_init(0x00800000, 10)), gmp_init(0, 10)) > 0) {
137 1
            $compact = $this->rightShift($compact, 8);
138 1
            $size = $size + 1;
139
        }
140
141 18
        $compact = $this->bitwiseOr($compact, $this->leftShift(gmp_init($size, 10), 24));
142 18
        if ($fNegative && $this->cmp($this->bitwiseAnd($compact, gmp_init(0x007fffff, 10)), gmp_init(0, 10)) > 0) { /// ?
143 2
            $compact = $this->bitwiseOr($compact, gmp_init(0x00800000, 10));
144
        }
145
146 18
        return $compact;
147
    }
148
}
149