Completed
Pull Request — master (#591)
by thomas
23:06 queued 05:47
created

PublicKey::clonePubkey()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3.0987

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 3
nop 0
dl 0
loc 16
ccs 7
cts 9
cp 0.7778
crap 3.0987
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Key;
6
7
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\Adapter\EcAdapter;
8
use BitWasp\Bitcoin\Crypto\EcAdapter\Impl\Secp256k1\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\Buffer;
14
use BitWasp\Buffertools\BufferInterface;
15
16
class PublicKey extends Key implements PublicKeyInterface
17
{
18
    /**
19
     * @var EcAdapter
20
     */
21
    private $ecAdapter;
22
23
    /**
24
     * @var bool|false
25
     */
26
    private $compressed;
27
28
    /**
29
     * @var resource
30
     */
31
    private $pubkey_t;
32
33
    /**
34
     * @param EcAdapter $ecAdapter
35
     * @param resource $secp256k1_pubkey_t
36
     * @param bool|false $compressed
37
     */
38 302
    public function __construct(EcAdapter $ecAdapter, $secp256k1_pubkey_t, $compressed = false)
39
    {
40 302
        if (!is_resource($secp256k1_pubkey_t) ||
41 302
            !get_resource_type($secp256k1_pubkey_t) === SECP256K1_TYPE_PUBKEY) {
42
            throw new \InvalidArgumentException('Secp256k1\Key\PublicKey expects ' . SECP256K1_TYPE_PUBKEY . ' resource');
43
        }
44
45 302
        if (false === is_bool($compressed)) {
46
            throw new \InvalidArgumentException('PublicKey: Compressed must be a boolean');
47
        }
48
49 302
        $this->ecAdapter = $ecAdapter;
50 302
        $this->pubkey_t = $secp256k1_pubkey_t;
51 302
        $this->compressed = $compressed;
52 302
    }
53
    
54
    /**
55
     * @param BufferInterface $msg32
56
     * @param SignatureInterface $signature
57
     * @return bool
58
     */
59
    public function verify(BufferInterface $msg32, SignatureInterface $signature): bool
60
    {
61
        return $this->ecAdapter->verify($msg32, $this, $signature);
62
    }
63
64
    /**
65
     * @param PublicKey $other
66
     * @return bool
67
     */
68 58
    private function doEquals(PublicKey $other): bool
69
    {
70 58
        $context = $this->ecAdapter->getContext();
71 58
        $pubA = '';
72 58
        $pubB = '';
73 58
        if (!(secp256k1_ec_pubkey_serialize($context, $pubA, $this->pubkey_t, (int) $this->compressed) && secp256k1_ec_pubkey_serialize($context, $pubB, $other->pubkey_t, (int) $this->compressed))) {
0 ignored issues
show
Documentation introduced by
(int) $this->compressed is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
74
            throw new \RuntimeException('Unable to serialize public key during equals');
75
        }
76
77 58
        return hash_equals($pubA, $pubB);
78
    }
79
80
    /**
81
     * @param PublicKeyInterface $other
82
     * @return bool
83
     */
84 58
    public function equals(PublicKeyInterface $other): bool
85
    {
86
        /** @var PublicKey $other */
87 58
        return $this->doEquals($other);
88
    }
89
90
    /**
91
     * @return bool|false
92
     */
93 153
    public function isCompressed(): bool
94
    {
95 153
        return $this->compressed;
96
    }
97
98
    /**
99
     * @return resource
100
     */
101 284
    public function getResource()
102
    {
103 284
        return $this->pubkey_t;
104
    }
105
106
    /**
107
     * @return resource
108
     * @throws \Exception
109
     */
110 5
    private function clonePubkey()
111
    {
112 5
        $context = $this->ecAdapter->getContext();
113 5
        $serialized = '';
114 5
        if (1 !== secp256k1_ec_pubkey_serialize($context, $serialized, $this->pubkey_t, (int) $this->compressed)) {
0 ignored issues
show
Documentation introduced by
(int) $this->compressed is of type integer, but the function expects a boolean.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
115
            throw new \Exception('Secp256k1: pubkey serialize');
116
        }
117
118
        /** @var resource $clone */
119 5
        $clone = '';
120 5
        if (1 !== secp256k1_ec_pubkey_parse($context, $clone, $serialized)) {
121
            throw new \Exception('Secp256k1 pubkey parse');
122
        }
123
124 5
        return $clone;
125
    }
126
127
    /**
128
     * @param \GMP $tweak
129
     * @return KeyInterface
130
     * @throws \Exception
131
     */
132 4
    public function tweakAdd(\GMP $tweak): KeyInterface
133
    {
134 4
        $context = $this->ecAdapter->getContext();
135 4
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
136
137 4
        $clone = $this->clonePubkey();
138 4
        if (1 !== secp256k1_ec_pubkey_tweak_add($context, $clone, $bin)) {
139
            throw new \RuntimeException('Secp256k1: tweak add failed.');
140
        }
141
142 4
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
143
    }
144
145
    /**
146
     * @param \GMP $tweak
147
     * @return KeyInterface
148
     * @throws \Exception
149
     */
150 1
    public function tweakMul(\GMP $tweak): KeyInterface
151
    {
152 1
        $context = $this->ecAdapter->getContext();
153 1
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
154
155 1
        $clone = $this->clonePubkey();
156 1
        if (1 !== secp256k1_ec_pubkey_tweak_mul($context, $clone, $bin)) {
157
            throw new \RuntimeException('Secp256k1: tweak mul failed.');
158
        }
159
160 1
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
161
    }
162
163
    /**
164
     * @return BufferInterface
165
     */
166 118
    public function getBuffer(): BufferInterface
167
    {
168 118
        return (new PublicKeySerializer($this->ecAdapter))->serialize($this);
169
    }
170
}
171