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

PublicKey::isCompressedOrUncompressed()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 24
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6

Importance

Changes 0
Metric Value
cc 6
eloc 14
nc 6
nop 1
dl 0
loc 24
ccs 14
cts 14
cp 1
crap 6
rs 9.2222
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Key;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Adapter\EcAdapter;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\PhpEcc\Serializer\Key\PublicKeySerializer;
9
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\Key;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\KeyInterface;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
13
use BitWasp\Buffertools\BufferInterface;
14
use Mdanter\Ecc\Crypto\Signature\Signer;
15
use Mdanter\Ecc\Primitives\CurveFpInterface;
16
use Mdanter\Ecc\Primitives\GeneratorPoint;
17
use Mdanter\Ecc\Primitives\PointInterface;
18
19
class PublicKey extends Key implements PublicKeyInterface, \Mdanter\Ecc\Crypto\Key\PublicKeyInterface
20
{
21
    /**
22
     * @var EcAdapter
23
     */
24
    private $ecAdapter;
25
26
    /**
27
     * @var PointInterface
28
     */
29
    private $point;
30
31
    /**
32
     * @var string
33
     */
34
    private $prefix;
35
36
    /**
37
     * @var bool
38
     */
39
    private $compressed;
40
41
    /**
42
     * PublicKey constructor.
43
     * @param EcAdapter $ecAdapter
44
     * @param PointInterface $point
45
     * @param bool $compressed
46
     * @param string $prefix
47
     */
48 335
    public function __construct(
49
        EcAdapter $ecAdapter,
50
        PointInterface $point,
51
        bool $compressed = false,
52
        string $prefix = null
53
    ) {
54 335
        $this->ecAdapter = $ecAdapter;
55 335
        $this->point = $point;
56 335
        $this->prefix = $prefix;
57 335
        $this->compressed = $compressed;
58 335
    }
59
60
    /**
61
     * @return GeneratorPoint
62
     */
63 189
    public function getGenerator(): GeneratorPoint
64
    {
65 189
        return $this->ecAdapter->getGenerator();
66
    }
67
68
    /**
69
     * @return \Mdanter\Ecc\Primitives\CurveFpInterface
70
     */
71
    public function getCurve(): CurveFpInterface
72
    {
73
        return $this->ecAdapter->getGenerator()->getCurve();
74
    }
75
76
    /**
77
     * @return string
78
     */
79 171
    public function getPrefix()
80
    {
81 171
        return $this->prefix;
82
    }
83
84
    /**
85
     * @return PointInterface
86
     */
87 312
    public function getPoint(): PointInterface
88
    {
89 312
        return $this->point;
90
    }
91
92
    /**
93
     * @param BufferInterface $msg32
94
     * @param SignatureInterface $signature
95
     * @return bool
96
     */
97 189
    public function verify(BufferInterface $msg32, SignatureInterface $signature): bool
98
    {
99 189
        $hash = gmp_init($msg32->getHex(), 16);
100 189
        $signer = new Signer($this->ecAdapter->getMath());
101 189
        return $signer->verify($this, $signature, $hash);
0 ignored issues
show
Bug introduced by
$signature of type BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface is incompatible with the type Mdanter\Ecc\Crypto\Signature\SignatureInterface expected by parameter $signature of Mdanter\Ecc\Crypto\Signature\Signer::verify(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

101
        return $signer->verify($this, /** @scrutinizer ignore-type */ $signature, $hash);
Loading history...
102
    }
103
104
    /**
105
     * @param \GMP $tweak
106
     * @return KeyInterface
107
     */
108 5
    public function tweakAdd(\GMP $tweak): KeyInterface
109
    {
110 5
        $offset = $this->ecAdapter->getGenerator()->mul($tweak);
111 5
        $newPoint = $this->point->add($offset);
112 5
        return new PublicKey($this->ecAdapter, $newPoint, $this->compressed);
113
    }
114
115
    /**
116
     * @param \GMP $tweak
117
     * @return KeyInterface
118
     */
119 1
    public function tweakMul(\GMP $tweak): KeyInterface
120
    {
121 1
        $point = $this->point->mul($tweak);
122 1
        return new PublicKey($this->ecAdapter, $point, $this->compressed);
123
    }
124
125
    /**
126
     * @param BufferInterface $publicKey
127
     * @return bool
128
     */
129 93
    public static function isCompressedOrUncompressed(BufferInterface $publicKey): bool
130
    {
131 93
        $vchPubKey = $publicKey->getBinary();
132 93
        if ($publicKey->getSize() < self::LENGTH_COMPRESSED) {
133 5
            return false;
134
        }
135
136 89
        if ($vchPubKey[0] === self::KEY_UNCOMPRESSED) {
137 12
            if ($publicKey->getSize() !== self::LENGTH_UNCOMPRESSED) {
138
                // Invalid length for uncompressed key
139 12
                return false;
140
            }
141 81
        } elseif (in_array($vchPubKey[0], [
142 81
            self::KEY_COMPRESSED_EVEN,
143 81
            self::KEY_COMPRESSED_ODD
144
        ])) {
145 65
            if ($publicKey->getSize() !== self::LENGTH_COMPRESSED) {
146 65
                return false;
147
            }
148
        } else {
149 17
            return false;
150
        }
151
152 72
        return true;
153
    }
154
155
    /**
156
     * @return bool
157
     */
158 187
    public function isCompressed(): bool
159
    {
160 187
        return $this->compressed;
161
    }
162
163
    /**
164
     * @param PublicKey $other
165
     * @return bool
166
     */
167 58
    private function doEquals(PublicKey $other): bool
168
    {
169 58
        return $this->compressed === $other->compressed
170 58
            && $this->point->equals($other->point)
171 58
            && (($this->prefix === null || $other->prefix === null) || ($this->prefix === $other->prefix));
172
    }
173
174
    /**
175
     * @param PublicKeyInterface $other
176
     * @return bool
177
     */
178 58
    public function equals(PublicKeyInterface $other): bool
179
    {
180
        /** @var self $other */
181 58
        return $this->doEquals($other);
182
    }
183
184
    /**
185
     * @return BufferInterface
186
     */
187 135
    public function getBuffer(): BufferInterface
188
    {
189 135
        return (new PublicKeySerializer($this->ecAdapter))->serialize($this);
190
    }
191
}
192