Completed
Push — master ( 8782bc...7383d7 )
by thomas
27:08
created

PublicKey   A

Complexity

Total Complexity 21

Size/Duplication

Total Lines 162
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 87.27%

Importance

Changes 0
Metric Value
dl 0
loc 162
ccs 48
cts 55
cp 0.8727
rs 10
c 0
b 0
f 0
wmc 21
lcom 1
cbo 5

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 15 4
A verify() 0 8 1
A doEquals() 0 13 4
A equals() 0 5 1
A isCompressed() 0 4 1
A getResource() 0 4 1
A clonePubkey() 0 17 4
A tweakAdd() 0 12 2
A tweakMul() 0 12 2
A getBuffer() 0 4 1
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\Impl\Secp256k1\Signature\Signature;
10
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\Key;
11
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\KeyInterface;
12
use BitWasp\Bitcoin\Crypto\EcAdapter\Key\PublicKeyInterface;
13
use BitWasp\Bitcoin\Crypto\EcAdapter\Signature\SignatureInterface;
14
use BitWasp\Buffertools\Buffer;
15
use BitWasp\Buffertools\BufferInterface;
16
17
class PublicKey extends Key implements PublicKeyInterface
18
{
19
    /**
20
     * @var EcAdapter
21
     */
22
    private $ecAdapter;
23
24
    /**
25
     * @var bool|false
26
     */
27
    private $compressed;
28
29
    /**
30
     * @var resource
31
     */
32
    private $pubkey_t;
33
34
    /**
35
     * @param EcAdapter $ecAdapter
36
     * @param resource $secp256k1_pubkey_t
37
     * @param bool|false $compressed
38
     */
39 222
    public function __construct(EcAdapter $ecAdapter, $secp256k1_pubkey_t, bool $compressed = false)
40
    {
41 222
        if (!is_resource($secp256k1_pubkey_t) ||
42 222
            !get_resource_type($secp256k1_pubkey_t) === SECP256K1_TYPE_PUBKEY) {
43
            throw new \InvalidArgumentException('Secp256k1\Key\PublicKey expects ' . SECP256K1_TYPE_PUBKEY . ' resource');
44
        }
45
46 222
        if (false === is_bool($compressed)) {
47
            throw new \InvalidArgumentException('PublicKey: Compressed must be a boolean');
48
        }
49
50 222
        $this->ecAdapter = $ecAdapter;
51 222
        $this->pubkey_t = $secp256k1_pubkey_t;
52 222
        $this->compressed = $compressed;
53 222
    }
54
    
55
    /**
56
     * @param BufferInterface $msg32
57
     * @param SignatureInterface $signature
58
     * @return bool
59
     */
60 148
    public function verify(BufferInterface $msg32, SignatureInterface $signature): bool
61
    {
62 148
        $ctx = $this->ecAdapter->getContext();
63 148
        $normalized = null;
64 148
        secp256k1_ecdsa_signature_normalize($ctx, $normalized, $signature->getResource());
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface BitWasp\Bitcoin\Crypto\E...ture\SignatureInterface as the method getResource() does only exist in the following implementations of said interface: BitWasp\Bitcoin\Crypto\E...nature\CompactSignature, BitWasp\Bitcoin\Crypto\E...6k1\Signature\Signature.

Let’s take a look at an example:

interface User
{
    /** @return string */
    public function getPassword();
}

class MyUser implements User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different implementation of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
Documentation introduced by
$ctx is of type resource, but the function expects a object<resource>.

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...
65
        /** @var Signature $signature */
66 148
        return (bool) secp256k1_ecdsa_verify($ctx, $normalized, $msg32->getBinary(), $this->pubkey_t);
0 ignored issues
show
Documentation introduced by
$ctx is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$normalized is of type resource|null, but the function expects a object<resource>.

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...
Documentation introduced by
$this->pubkey_t is of type resource, but the function expects a object<resource>.

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...
67
    }
68
69
    /**
70
     * @param PublicKey $other
71
     * @return bool
72
     */
73 26
    private function doEquals(PublicKey $other): bool
74
    {
75 26
        $context = $this->ecAdapter->getContext();
76 26
        $pubA = '';
77 26
        $pubB = '';
78 26
        $flags = $this->compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
79
80 26
        if (!(secp256k1_ec_pubkey_serialize($context, $pubA, $this->pubkey_t, $flags) && secp256k1_ec_pubkey_serialize($context, $pubB, $other->pubkey_t, $flags))) {
0 ignored issues
show
Documentation introduced by
$context is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$this->pubkey_t is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$other->pubkey_t is of type resource, but the function expects a object<resource>.

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...
81
            throw new \RuntimeException('Unable to serialize public key during equals');
82
        }
83
84 26
        return hash_equals($pubA, $pubB);
85
    }
86
87
    /**
88
     * @param PublicKeyInterface $other
89
     * @return bool
90
     */
91 26
    public function equals(PublicKeyInterface $other): bool
92
    {
93
        /** @var PublicKey $other */
94 26
        return $this->doEquals($other);
95
    }
96
97
    /**
98
     * @return bool|false
99
     */
100 92
    public function isCompressed(): bool
101
    {
102 92
        return $this->compressed;
103
    }
104
105
    /**
106
     * @return resource
107
     */
108 82
    public function getResource()
109
    {
110 82
        return $this->pubkey_t;
111
    }
112
113
    /**
114
     * @return resource
115
     * @throws \Exception
116
     */
117 3
    private function clonePubkey()
118
    {
119 3
        $context = $this->ecAdapter->getContext();
120 3
        $serialized = '';
121 3
        $flags = $this->compressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED;
122 3
        if (1 !== secp256k1_ec_pubkey_serialize($context, $serialized, $this->pubkey_t, $flags)) {
0 ignored issues
show
Documentation introduced by
$context is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$this->pubkey_t is of type resource, but the function expects a object<resource>.

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...
123
            throw new \Exception('Secp256k1: pubkey serialize');
124
        }
125
126
        /** @var resource $clone */
127 3
        $clone = null;
128 3
        if (1 !== secp256k1_ec_pubkey_parse($context, $clone, $serialized)) {
0 ignored issues
show
Documentation introduced by
$context is of type resource, but the function expects a object<resource>.

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...
129
            throw new \Exception('Secp256k1 pubkey parse');
130
        }
131
132 3
        return $clone;
133
    }
134
135
    /**
136
     * @param \GMP $tweak
137
     * @return KeyInterface
138
     * @throws \Exception
139
     */
140 2
    public function tweakAdd(\GMP $tweak): KeyInterface
141
    {
142 2
        $context = $this->ecAdapter->getContext();
143 2
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
144
145 2
        $clone = $this->clonePubkey();
146 2
        if (1 !== secp256k1_ec_pubkey_tweak_add($context, $clone, $bin)) {
0 ignored issues
show
Documentation introduced by
$context is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$clone is of type resource|null, but the function expects a object<resource>.

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...
147
            throw new \RuntimeException('Secp256k1: tweak add failed.');
148
        }
149
150 2
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
151
    }
152
153
    /**
154
     * @param \GMP $tweak
155
     * @return KeyInterface
156
     * @throws \Exception
157
     */
158 1
    public function tweakMul(\GMP $tweak): KeyInterface
159
    {
160 1
        $context = $this->ecAdapter->getContext();
161 1
        $bin = Buffer::int(gmp_strval($tweak, 10), 32)->getBinary();
162
163 1
        $clone = $this->clonePubkey();
164 1
        if (1 !== secp256k1_ec_pubkey_tweak_mul($context, $clone, $bin)) {
0 ignored issues
show
Documentation introduced by
$context is of type resource, but the function expects a object<resource>.

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...
Documentation introduced by
$clone is of type resource|null, but the function expects a object<resource>.

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...
165
            throw new \RuntimeException('Secp256k1: tweak mul failed.');
166
        }
167
168 1
        return new PublicKey($this->ecAdapter, $clone, $this->compressed);
169
    }
170
171
    /**
172
     * @return BufferInterface
173
     */
174 77
    public function getBuffer(): BufferInterface
175
    {
176 77
        return (new PublicKeySerializer($this->ecAdapter))->serialize($this);
177
    }
178
}
179