Completed
Pull Request — master (#317)
by thomas
16:45 queued 06:42
created

HierarchicalKeySequence::binaryMath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace BitWasp\Bitcoin\Key\Deterministic;
4
5
/**
6
 * NB: Paths returned by this library omit m/M. This is because
7
 * some knowledge is lost during derivations, so the full path
8
 * is already considered 'meta-data'. It also allows the library
9
 * to assume derivations are relative to the current instance.
10
 */
11
class HierarchicalKeySequence
12
{
13
14
    const START_HARDENED = 2147483648;
15
16
    /**
17
     * @param int $sequence
18
     * @return bool
19
     */
20 57
    public function isHardened($sequence)
21
    {
22 57
        return ($sequence >> 31) === 1;
23
    }
24
25
    /**
26
     * @param int $sequence
27
     * @return int
28
     */
29 42
    public function getHardened($sequence)
30
    {
31 42
        if ($this->isHardened($sequence)) {
32 3
            throw new \LogicException('Sequence is already for a hardened key');
33
        }
34
35 39
        $flag = 1 << 31;
36 39
        $hardened = $sequence | $flag;
37
38 39
        return $hardened;
39
    }
40
41
    /**
42
     * Convert a human readable path node (eg, "0", "0'", or "0h") into the correct sequence (0, 0x80000000, 0x80000000)
43
     *
44
     * @param $node
45
     * @return int|string
46
     */
47 48
    public function fromNode($node)
48
    {
49 48
        $hardened = false;
50 48
        if (in_array(substr(strtolower($node), -1), array('h', "'"), true) === true) {
51 39
            $intEnd = strlen($node) - 1;
52 39
            $node = substr($node, 0, $intEnd);
53 39
            $hardened = true;
54 26
        }
55
56 48
        if ($hardened) {
57 39
            $node = $this->getHardened($node);
58 26
        }
59
60 48
        return $node;
61
    }
62
63
    /**
64
     * Given a sequence, get the human readable node. Ie, 0 -> 0, 0x80000000 -> 0h
65
     *
66
     * @param int $sequence
67
     * @return string
68
     */
69 30
    public function getNode($sequence)
70
    {
71 30
        if ($this->isHardened($sequence)) {
72 24
            $sequence = $sequence - self::START_HARDENED;
73 24
            $sequence = (string) $sequence . 'h';
74 16
        }
75
76 30
        return $sequence;
77
    }
78
79
    /**
80
     * Decodes a human-readable path, into an array of integers (sequences)
81
     *
82
     * @param string $path
83
     * @return array
84
     */
85 36
    public function decodePath($path)
86
    {
87 36
        if ($path === '') {
88 3
            throw new \InvalidArgumentException('Invalid path passed to decodePath()');
89
        }
90
91 33
        $list = [];
92 33
        foreach (explode('/', $path) as $segment) {
93 33
            if ($segment !== 'm' && $segment !== 'M') {
94 33
                $list[] = $this->fromNode($segment);
95 22
            }
96 22
        }
97
98 33
        return $list;
99
    }
100
101
    /**
102
     * Encodes a list of sequences to the human-readable path.
103
     *
104
     * @param array|\stdClass|\Traversable $list
105
     * @return string
106
     */
107 9
    public function encodePath($list)
108
    {
109 9
        self::validateListType($list);
110
111 9
        $path = [];
112 9
        foreach ($list as $sequence) {
0 ignored issues
show
Bug introduced by
The expression $list of type array|object<stdClass>|object<Traversable> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
113 9
            $path[] = $this->getNode($sequence);
114 6
        }
115
116 9
        return implode('/', $path);
117
    }
118
119
    /**
120
     * Check the list, mainly that it works for foreach()
121
     *
122
     * @param \stdClass|array|\Traversable $list
123
     */
124 15
    public static function validateListType($list)
125
    {
126 15
        if (!is_array($list) && !$list instanceof \Traversable && !$list instanceof \stdClass) {
127
            throw new \InvalidArgumentException('Sequence list must be an array or \Traversable');
128
        }
129
130 15
    }
131
}
132