Completed
Push — master ( b7c590...87bee6 )
by thomas
452:48 queued 382:47
created

Base58::decode()   C

Complexity

Conditions 7
Paths 10

Size

Total Lines 26
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 7

Importance

Changes 0
Metric Value
cc 7
eloc 17
nc 10
nop 1
dl 0
loc 26
ccs 15
cts 15
cp 1
crap 7
rs 6.7272
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin;
4
5
use BitWasp\Bitcoin\Crypto\Hash;
6
use BitWasp\Bitcoin\Exceptions\Base58ChecksumFailure;
7
use BitWasp\Bitcoin\Exceptions\Base58InvalidCharacter;
8
use BitWasp\Buffertools\Buffer;
9
use BitWasp\Buffertools\BufferInterface;
10
use BitWasp\Buffertools\Buffertools;
11
12
class Base58
13
{
14
    /**
15
     * @var string
16
     */
17
    private static $base58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
18
19
    /**
20
     * Encode a given hex string in base58
21
     *
22
     * @param BufferInterface $buffer
23
     * @return string
24
     * @throws \Exception
25 330
     */
26
    public static function encode(BufferInterface $buffer)
27 330
    {
28 330
        $size = $buffer->getSize();
29 6
        if ($buffer->getBinary() === '') {
30
            return '';
31
        }
32 324
33
        $math = Bitcoin::getMath();
34 324
35 324
        $orig = $buffer->getBinary();
36
        $decimal = $buffer->getGmp();
37 324
38 324
        $return = '';
39 324
        $zero = gmp_init(0);
40 324
        $_58 = gmp_init(58);
41 312
        while ($math->cmp($decimal, $zero) > 0) {
42 312
            list($decimal, $rem) = $math->divQr($decimal, $_58);
43 156
            $return .= self::$base58chars[(int) gmp_strval($rem, 10)];
44 324
        }
45
        $return = strrev($return);
46
47 324
        //leading zeros
48 138
        for ($i = 0; $i < $size && $orig[$i] === "\x00"; $i++) {
49 69
            $return = '1' . $return;
50
        }
51 324
52
        return $return;
53
    }
54
55
    /**
56
     * Decode a base58 string
57
     * @param string $base58
58
     * @return Buffer
59
     * @throws Base58InvalidCharacter
60 390
     */
61
    public static function decode($base58)
62 390
    {
63 390
        $math = Bitcoin::getMath();
64 6
        if ($base58 === '') {
65
            return new Buffer('', 0, $math);
66
        }
67 384
68 384
        $original = $base58;
69 384
        $length = strlen($base58);
70 384
        $return = gmp_init(0);
71 384
        $_58 = gmp_init(58);
72 384
        for ($i = 0; $i < $length; $i++) {
73 192
            $loc = strpos(self::$base58chars, $base58[$i]);
74
            if ($loc === false) {
75 384
                throw new Base58InvalidCharacter('Found character that is not allowed in base58: ' . $base58[$i]);
76 384
            }
77 126
            $return = $math->add($math->mul($return, $_58), gmp_init($loc, 10));
0 ignored issues
show
Bug introduced by
It seems like $return defined by $math->add($math->mul($r...8), gmp_init($loc, 10)) on line 77 can also be of type resource; however, Mdanter\Ecc\Math\GmpMath::mul() 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 63
        }
79
80 384
        $binary = $math->cmp($return, gmp_init(0)) === 0 ? '' : Buffer::int(gmp_strval($return, 10))->getBinary();
0 ignored issues
show
Bug introduced by
It seems like $return defined by $math->add($math->mul($r...8), gmp_init($loc, 10)) on line 77 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...
81
        for ($i = 0; $i < $length && $original[$i] === '1'; $i++) {
82
            $binary = "\x00" . $binary;
83
        }
84
85
        return new Buffer($binary);
86
    }
87
88
    /**
89 366
     * Calculate a checksum for the given data
90
     *
91 366
     * @param BufferInterface $data
92
     * @return BufferInterface
93
     */
94
    public static function checksum(BufferInterface $data)
95
    {
96
        return Hash::sha256d($data)->slice(0, 4);
97
    }
98
99
    /**
100
     * Decode a base58 checksum string and validate checksum
101 312
     *
102
     * @param string $base58
103 312
     * @return BufferInterface
104 312
     * @throws Base58ChecksumFailure
105 312
     */
106
    public static function decodeCheck($base58)
107 312
    {
108 12
        $hex = self::decode($base58);
109
        $data = $hex->slice(0, -4);
110
        $csVerify = $hex->slice(-4);
111 300
112
        if (self::checksum($data)->getBinary() !== $csVerify->getBinary()) {
113
            throw new Base58ChecksumFailure('Failed to verify checksum');
114
        }
115
116
        return $data;
117
    }
118
119
    /**
120
     * Encode the given data in base58, with a checksum to check integrity.
121 252
     *
122
     * @param BufferInterface $data
123 252
     * @return string
124
     * @throws \Exception
125
     */
126
    public static function encodeCheck(BufferInterface $data)
127
    {
128
        return self::encode(Buffertools::concat($data, self::checksum($data)));
129
    }
130
}
131